Completed
Push — add/publicize-data-purge ( 773d38...9047c2 )
by Kirk
15:51 queued 06:38
created

Publicize::purge_connection_data()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
class Publicize extends Publicize_Base {
4
5
	function __construct() {
6
		parent::__construct();
7
8
		add_filter( 'jetpack_xmlrpc_methods', array( $this, 'register_update_publicize_connections_xmlrpc_method' ) );
9
10
		add_action( 'load-settings_page_sharing', array( $this, 'admin_page_load' ), 9 );
11
12
		add_action( 'wp_ajax_publicize_tumblr_options_page', array( $this, 'options_page_tumblr' ) );
13
		add_action( 'wp_ajax_publicize_facebook_options_page', array( $this, 'options_page_facebook' ) );
14
		add_action( 'wp_ajax_publicize_twitter_options_page', array( $this, 'options_page_twitter' ) );
15
		add_action( 'wp_ajax_publicize_linkedin_options_page', array( $this, 'options_page_linkedin' ) );
16
		add_action( 'wp_ajax_publicize_path_options_page', array( $this, 'options_page_path' ) );
17
		add_action( 'wp_ajax_publicize_google_plus_options_page', array( $this, 'options_page_google_plus' ) );
18
19
		add_action( 'wp_ajax_publicize_tumblr_options_save', array( $this, 'options_save_tumblr' ) );
20
		add_action( 'wp_ajax_publicize_facebook_options_save', array( $this, 'options_save_facebook' ) );
21
		add_action( 'wp_ajax_publicize_twitter_options_save', array( $this, 'options_save_twitter' ) );
22
		add_action( 'wp_ajax_publicize_linkedin_options_save', array( $this, 'options_save_linkedin' ) );
23
		add_action( 'wp_ajax_publicize_path_options_save', array( $this, 'options_save_path' ) );
24
		add_action( 'wp_ajax_publicize_google_plus_options_save', array( $this, 'options_save_google_plus' ) );
25
26
		add_action( 'load-settings_page_sharing', array( $this, 'force_user_connection' ) );
27
28
		add_filter( 'publicize_checkbox_default', array( $this, 'publicize_checkbox_default' ), 10, 4 );
29
30
		add_filter( 'jetpack_published_post_flags', array( $this, 'set_post_flags' ), 10, 2 );
31
32
		add_action( 'wp_insert_post', array( $this, 'save_publicized' ), 11, 3 );
33
34
		add_filter( 'jetpack_twitter_cards_site_tag', array( $this, 'enhaced_twitter_cards_site_tag' ) );
35
36
		add_action( 'publicize_save_meta', array( $this, 'save_publicized_twitter_account' ), 10, 4 );
37
		add_action( 'publicize_save_meta', array( $this, 'save_publicized_facebook_account' ), 10, 4 );
38
39
		add_filter( 'jetpack_sharing_twitter_via', array( $this, 'get_publicized_twitter_account' ), 10, 2 );
40
41
		// Delete stored Publicize data if either the module or the Jetpack plugin are deactivated.
42
		add_action( 'jetpack_deactivate_module_publicize', array( $this, 'purge_connection_data' ) );
43
		register_deactivation_hook( plugin_basename( JETPACK__PLUGIN_FILE ), array( $this, 'purge_connection_data' ) );
44
45
		include_once( JETPACK__PLUGIN_DIR . 'modules/publicize/enhanced-open-graph.php' );
46
	}
47
48
	function purge_connection_data() {
49
		$request = sprintf( '/sites/%d/publicize-connections/delete', Jetpack_Options::get_option( 'id' ) );
50
		Jetpack_Client::wpcom_json_api_request_as_blog( $request, '1.1', array( 'method' => 'POST' ) );
51
	}
52
53
	function force_user_connection() {
54
		global $current_user;
55
		$user_token        = Jetpack_Data::get_access_token( $current_user->ID );
56
		$is_user_connected = $user_token && ! is_wp_error( $user_token );
57
58
		// If the user is already connected via Jetpack, then we're good
59
		if ( $is_user_connected ) {
60
			return;
61
		}
62
63
		// If they're not connected, then remove the Publicize UI and tell them they need to connect first
64
		global $publicize_ui;
65
		remove_action( 'pre_admin_screen_sharing', array( $publicize_ui, 'admin_page' ) );
66
67
		// Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
68
		// Jetpack::init()->admin_styles();
69
		add_action( 'pre_admin_screen_sharing', array( $this, 'admin_page_warning' ), 1 );
70
	}
71
72
	function admin_page_warning() {
73
		$jetpack   = Jetpack::init();
74
		$blog_name = get_bloginfo( 'blogname' );
75
		if ( empty( $blog_name ) ) {
76
			$blog_name = home_url( '/' );
77
		}
78
79
		?>
80
		<div id="message" class="updated jetpack-message jp-connect">
81
			<div class="jetpack-wrap-container">
82
				<div class="jetpack-text-container">
83
					<p><?php printf(
84
							/* translators: %s is the name of the blog */
85
							esc_html( wptexturize( __( "To use Publicize, you'll need to link your %s account to your WordPress.com account using the link below.", 'jetpack' ) ) ),
86
							'<strong>' . esc_html( $blog_name ) . '</strong>'
87
						); ?></p>
88
					<p><?php echo esc_html( wptexturize( __( "If you don't have a WordPress.com account yet, you can sign up for free in just a few seconds.", 'jetpack' ) ) ); ?></p>
89
				</div>
90
				<div class="jetpack-install-container">
91
					<p class="submit"><a
92
							href="<?php echo $jetpack->build_connect_url( false, menu_page_url( 'sharing', false ) ); ?>"
93
							class="button-connector"
94
							id="wpcom-connect"><?php esc_html_e( 'Link account with WordPress.com', 'jetpack' ); ?></a>
95
					</p>
96
					<p class="jetpack-install-blurb">
97
						<?php jetpack_render_tos_blurb(); ?>
98
					</p>
99
				</div>
100
			</div>
101
		</div>
102
		<?php
103
	}
104
105
	/**
106
	 * Remove a Publicize connection
107
	 */
108
	function disconnect( $service_name, $connection_id, $_blog_id = false, $_user_id = false, $force_delete = false ) {
109
		Jetpack::load_xml_rpc_client();
110
		$xml = new Jetpack_IXR_Client();
111
		$xml->query( 'jetpack.deletePublicizeConnection', $connection_id );
112
113
		if ( ! $xml->isError() ) {
114
			Jetpack_Options::update_option( 'publicize_connections', $xml->getResponse() );
115
		} else {
116
			return false;
117
		}
118
	}
119
120
	function receive_updated_publicize_connections( $publicize_connections ) {
121
		Jetpack_Options::update_option( 'publicize_connections', $publicize_connections );
122
123
		return true;
124
	}
125
126
	function register_update_publicize_connections_xmlrpc_method( $methods ) {
127
		return array_merge( $methods, array(
128
			'jetpack.updatePublicizeConnections' => array( $this, 'receive_updated_publicize_connections' ),
129
		) );
130
	}
131
132
	function get_connections( $service_name, $_blog_id = false, $_user_id = false ) {
133
		$connections           = Jetpack_Options::get_option( 'publicize_connections' );
134
		$connections_to_return = array();
135
		if ( ! empty( $connections ) && is_array( $connections ) ) {
136
			if ( ! empty( $connections[ $service_name ] ) ) {
137
				foreach ( $connections[ $service_name ] as $id => $connection ) {
138
					if ( 0 == $connection['connection_data']['user_id'] || $this->user_id() == $connection['connection_data']['user_id'] ) {
139
						$connections_to_return[ $id ] = $connection;
140
					}
141
				}
142
			}
143
144
			return $connections_to_return;
145
		}
146
147
		return false;
148
	}
149
150
	function get_connection_id( $connection ) {
151
		return $connection['connection_data']['id'];
152
	}
153
154
	function get_connection_meta( $connection ) {
155
		$connection['user_id'] = $connection['connection_data']['user_id']; // Allows for shared connections
156
		return $connection;
157
	}
158
159
	function admin_page_load() {
160
		if ( isset( $_GET['action'] ) ) {
161
			if ( isset( $_GET['service'] ) ) {
162
				$service_name = $_GET['service'];
163
			}
164
165
			switch ( $_GET['action'] ) {
166
				case 'error':
167
					add_action( 'pre_admin_screen_sharing', array( $this, 'display_connection_error' ), 9 );
168
					break;
169
170
				case 'request':
171
					check_admin_referer( 'keyring-request', 'kr_nonce' );
172
					check_admin_referer( "keyring-request-$service_name", 'nonce' );
0 ignored issues
show
Bug introduced by
The variable $service_name does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
173
174
					$verification = Jetpack::generate_secrets( 'publicize' );
175
					if ( ! $verification ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $verification of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
176
						$url = Jetpack::admin_url( 'jetpack#/settings' );
177
						wp_die( sprintf( __( "Jetpack is not connected. Please connect Jetpack by visiting <a href='%s'>Settings</a>.", 'jetpack' ), $url ) );
178
179
					}
180
					$stats_options = get_option( 'stats_options' );
181
					$wpcom_blog_id = Jetpack_Options::get_option( 'id' );
182
					$wpcom_blog_id = ! empty( $wpcom_blog_id ) ? $wpcom_blog_id : $stats_options['blog_id'];
183
184
					$user     = wp_get_current_user();
185
					$redirect = $this->api_url( $service_name, urlencode_deep( array(
186
						'action'       => 'request',
187
						'redirect_uri' => add_query_arg( array( 'action' => 'done' ), menu_page_url( 'sharing', false ) ),
188
						'for'          => 'publicize',
189
						// required flag that says this connection is intended for publicize
190
						'siteurl'      => site_url(),
191
						'state'        => $user->ID,
192
						'blog_id'      => $wpcom_blog_id,
193
						'secret_1'     => $verification['secret_1'],
194
						'secret_2'     => $verification['secret_2'],
195
						'eol'          => $verification['exp'],
196
					) ) );
197
					wp_redirect( $redirect );
198
					exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method admin_page_load() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
199
					break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
200
201
				case 'completed':
202
					Jetpack::load_xml_rpc_client();
203
					$xml = new Jetpack_IXR_Client();
204
					$xml->query( 'jetpack.fetchPublicizeConnections' );
205
206
					if ( ! $xml->isError() ) {
207
						$response = $xml->getResponse();
208
						Jetpack_Options::update_option( 'publicize_connections', $response );
209
					}
210
211
					break;
212
213
				case 'delete':
214
					$id = $_GET['id'];
215
216
					check_admin_referer( 'keyring-request', 'kr_nonce' );
217
					check_admin_referer( "keyring-request-$service_name", 'nonce' );
218
219
					$this->disconnect( $service_name, $id );
220
221
					add_action( 'admin_notices', array( $this, 'display_disconnected' ) );
222
					break;
223
			}
224
		}
225
226
		// Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
227
		// Errors encountered on WordPress.com's end are passed back as a code
228
		/*
229
		if ( isset( $_GET['action'] ) && 'error' == $_GET['action'] ) {
230
			// Load Jetpack's styles to handle the box
231
			Jetpack::init()->admin_styles();
232
		}
233
		*/
234
	}
235
236
	function display_connection_error() {
237
		$code = false;
238
		if ( isset( $_GET['service'] ) ) {
239
			$service_name = $_GET['service'];
240
			$error        = sprintf( __( 'There was a problem connecting to %s to create an authorized connection. Please try again in a moment.', 'jetpack' ), Publicize::get_service_label( $service_name ) );
241
		} else {
242
			if ( isset( $_GET['publicize_error'] ) ) {
243
				$code = strtolower( $_GET['publicize_error'] );
244
				switch ( $code ) {
245
					case '400':
246
						$error = __( 'An invalid request was made. This normally means that something intercepted or corrupted the request from your server to the Jetpack Server. Try again and see if it works this time.', 'jetpack' );
247
						break;
248
					case 'secret_mismatch':
249
						$error = __( 'We could not verify that your server is making an authorized request. Please try again, and make sure there is nothing interfering with requests from your server to the Jetpack Server.', 'jetpack' );
250
						break;
251
					case 'empty_blog_id':
252
						$error = __( 'No blog_id was included in your request. Please try disconnecting Jetpack from WordPress.com and then reconnecting it. Once you have done that, try connecting Publicize again.', 'jetpack' );
253
						break;
254
					case 'empty_state':
255
						$error = sprintf( __( 'No user information was included in your request. Please make sure that your user account has connected to Jetpack. Connect your user account by going to the <a href="%s">Jetpack page</a> within wp-admin.', 'jetpack' ), Jetpack::admin_url() );
256
						break;
257
					default:
258
						$error = __( 'Something which should never happen, happened. Sorry about that. If you try again, maybe it will work.', 'jetpack' );
259
						break;
260
				}
261
			} else {
262
				$error = __( 'There was a problem connecting with Publicize. Please try again in a moment.', 'jetpack' );
263
			}
264
		}
265
		// Using the same formatting/style as Jetpack::admin_notices() error
266
		?>
267
		<div id="message" class="jetpack-message jetpack-err">
268
			<div class="squeezer">
269
				<h2><?php echo wp_kses( $error, array( 'a'      => array( 'href' => true ),
270
				                                       'code'   => true,
271
				                                       'strong' => true,
272
				                                       'br'     => true,
273
				                                       'b'      => true
274
					) ); ?></h2>
275
				<?php if ( $code ) : ?>
0 ignored issues
show
Bug Best Practice introduced by
The expression $code of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
276
					<p><?php printf( __( 'Error code: %s', 'jetpack' ), esc_html( stripslashes( $code ) ) ); ?></p>
277
				<?php endif; ?>
278
			</div>
279
		</div>
280
		<?php
281
	}
282
283
	function display_disconnected() {
284
		echo "<div class='updated'>\n";
285
		echo '<p>' . esc_html( __( 'That connection has been removed.', 'jetpack' ) ) . "</p>\n";
286
		echo "</div>\n\n";
287
	}
288
289
	function globalization() {
290
		if ( 'on' == $_REQUEST['global'] ) {
291
			$id = $_REQUEST['connection'];
292
293
			if ( ! current_user_can( $this->GLOBAL_CAP ) ) {
294
				return;
295
			}
296
297
			Jetpack::load_xml_rpc_client();
298
			$xml = new Jetpack_IXR_Client();
299
			$xml->query( 'jetpack.globalizePublicizeConnection', $id, 'globalize' );
300
301
			if ( ! $xml->isError() ) {
302
				$response = $xml->getResponse();
303
				Jetpack_Options::update_option( 'publicize_connections', $response );
304
			}
305
		}
306
	}
307
308
	/**
309
	 * Gets a URL to the public-api actions. Works like WP's admin_url
310
	 *
311
	 * @param string $service Shortname of a specific service.
312
	 *
313
	 * @return URL to specific public-api process
314
	 */
315
	// on WordPress.com this is/calls Keyring::admin_url
316
	function api_url( $service = false, $params = array() ) {
317
		/**
318
		 * Filters the API URL used to interact with WordPress.com.
319
		 *
320
		 * @module publicize
321
		 *
322
		 * @since 2.0.0
323
		 *
324
		 * @param string https://public-api.wordpress.com/connect/?jetpack=publicize Default Publicize API URL.
325
		 */
326
		$url = apply_filters( 'publicize_api_url', 'https://public-api.wordpress.com/connect/?jetpack=publicize' );
327
328
		if ( $service ) {
329
			$url = add_query_arg( array( 'service' => $service ), $url );
330
		}
331
332
		if ( count( $params ) ) {
333
			$url = add_query_arg( $params, $url );
334
		}
335
336
		return $url;
337
	}
338
339 View Code Duplication
	function connect_url( $service_name ) {
340
		return add_query_arg( array(
341
			'action'   => 'request',
342
			'service'  => $service_name,
343
			'kr_nonce' => wp_create_nonce( 'keyring-request' ),
344
			'nonce'    => wp_create_nonce( "keyring-request-$service_name" ),
345
		), menu_page_url( 'sharing', false ) );
346
	}
347
348
	function refresh_url( $service_name ) {
349
		return add_query_arg( array(
350
			'action'   => 'request',
351
			'service'  => $service_name,
352
			'kr_nonce' => wp_create_nonce( 'keyring-request' ),
353
			'refresh'  => 1,
354
			'for'      => 'publicize',
355
			'nonce'    => wp_create_nonce( "keyring-request-$service_name" ),
356
		), admin_url( 'options-general.php?page=sharing' ) );
357
	}
358
359 View Code Duplication
	function disconnect_url( $service_name, $id ) {
360
		return add_query_arg( array(
361
			'action'   => 'delete',
362
			'service'  => $service_name,
363
			'id'       => $id,
364
			'kr_nonce' => wp_create_nonce( 'keyring-request' ),
365
			'nonce'    => wp_create_nonce( "keyring-request-$service_name" ),
366
		), menu_page_url( 'sharing', false ) );
367
	}
368
369
	/**
370
	 * Get social networks, either all available or only those that the site is connected to.
371
	 *
372
	 * @since 2.0
373
	 *
374
	 * @param string $filter Select the list of services that will be returned. Defaults to 'all', accepts 'connected'.
375
	 *
376
	 * @return array List of social networks.
377
	 */
378
	function get_services( $filter = 'all' ) {
379
		$services = array(
380
			'facebook'    => array(),
381
			'twitter'     => array(),
382
			'linkedin'    => array(),
383
			'tumblr'      => array(),
384
			'path'        => array(),
385
			'google_plus' => array(),
386
		);
387
388
		if ( 'all' == $filter ) {
389
			return $services;
390
		} else {
391
			$connected_services = array();
392
			foreach ( $services as $service => $empty ) {
393
				$connections = $this->get_connections( $service );
394
				if ( $connections ) {
395
					$connected_services[ $service ] = $connections;
396
				}
397
			}
398
			return $connected_services;
399
		}
400
	}
401
402
	function get_connection( $service, $id, $_blog_id = false, $_user_id = false ) {
403
		// Stub
404
	}
405
406
	function flag_post_for_publicize( $new_status, $old_status, $post ) {
407
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
408
			return;
409
		}
410
411
		if ( 'publish' == $new_status && 'publish' != $old_status ) {
412
			/**
413
			 * Determines whether a post being published gets publicized.
414
			 *
415
			 * Side-note: Possibly our most alliterative filter name.
416
			 *
417
			 * @module publicize
418
			 *
419
			 * @since 4.1.0
420
			 *
421
			 * @param bool $should_publicize Should the post be publicized? Default to true.
422
			 * @param WP_POST $post Current Post object.
423
			 */
424
			$should_publicize = apply_filters( 'publicize_should_publicize_published_post', true, $post );
425
426
			if ( $should_publicize ) {
427
				update_post_meta( $post->ID, $this->PENDING, true );
428
			}
429
		}
430
	}
431
432
	function test_connection( $service_name, $connection ) {
433
		$connection_test_passed  = true;
434
		$connection_test_message = '';
435
		$user_can_refresh        = false;
0 ignored issues
show
Unused Code introduced by
$user_can_refresh is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
436
437
		$id = $this->get_connection_id( $connection );
438
439
		Jetpack::load_xml_rpc_client();
440
		$xml = new Jetpack_IXR_Client();
441
		$xml->query( 'jetpack.testPublicizeConnection', $id );
442
443
		if ( $xml->isError() ) {
444
			$xml_response            = $xml->getResponse();
445
			$connection_test_message = $xml_response['faultString'];
446
			$connection_test_passed  = false;
447
		}
448
449
		// Bail if all is well
450
		if ( $connection_test_passed ) {
451
			return true;
452
		}
453
454
		// Set up refresh if the user can
455
		$user_can_refresh = current_user_can( $this->GLOBAL_CAP );
456
		if ( $user_can_refresh ) {
457
			$nonce        = wp_create_nonce( "keyring-request-" . $service_name );
0 ignored issues
show
Unused Code introduced by
$nonce is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
458
			$refresh_text = sprintf( _x( 'Refresh connection with %s', 'Refresh connection with {social media service}', 'jetpack' ), $this->get_service_label( $service_name ) );
459
			$refresh_url  = $this->refresh_url( $service_name );
460
		}
461
462
		$error_data = array(
463
			'user_can_refresh' => $user_can_refresh,
464
			'refresh_text'     => $refresh_text,
0 ignored issues
show
Bug introduced by
The variable $refresh_text does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
465
			'refresh_url'      => $refresh_url
0 ignored issues
show
Bug introduced by
The variable $refresh_url does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
466
		);
467
468
		return new WP_Error( 'pub_conn_test_failed', $connection_test_message, $error_data );
469
	}
470
471
	/**
472
	 * Save a flag locally to indicate that this post has already been Publicized via the selected
473
	 * connections.
474
	 */
475
	function save_publicized( $post_ID, $post = null, $update = null ) {
476
		if ( is_null( $post ) ) {
477
			return;
478
		}
479
		// Only do this when a post transitions to being published
480
		if ( get_post_meta( $post->ID, $this->PENDING ) && $this->post_type_is_publicizeable( $post->post_type ) ) {
481
			$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
482
			if ( ! empty( $connected_services ) ) {
483
				/**
484
				 * Fires when a post is saved that has is marked as pending publicizing
485
				 *
486
				 * @since 4.1.0
487
				 *
488
				 * @param int The post ID
489
				 */
490
				do_action_deprecated( 'jetpack_publicize_post', $post->ID, '4.8.0', 'jetpack_published_post_flags' );
491
			}
492
			delete_post_meta( $post->ID, $this->PENDING );
493
			update_post_meta( $post->ID, $this->POST_DONE . 'all', true );
494
		}
495
	}
496
497
	function set_post_flags( $flags, $post ) {
498
		$flags['publicize_post'] = false;
499
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
500
			return $flags;
501
		}
502
		/** This filter is already documented in modules/publicize/publicize-jetpack.php */
503
		if ( ! apply_filters( 'publicize_should_publicize_published_post', true, $post ) ) {
504
			return $flags;
505
		}
506
507
		$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
508
509
		if ( empty( $connected_services ) ) {
510
			return $flags;
511
		}
512
513
		$flags['publicize_post'] = true;
514
515
		return $flags;
516
	}
517
518
	/**
519
	 * Options Code
520
	 */
521
522
	function options_page_facebook() {
523
		$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
524
		$connection         = $connected_services['facebook'][ $_REQUEST['connection'] ];
525
		$options_to_show    = ( ! empty( $connection['connection_data']['meta']['options_responses'] ) ? $connection['connection_data']['meta']['options_responses'] : false );
526
527
		// Nonce check
528
		check_admin_referer( 'options_page_facebook_' . $_REQUEST['connection'] );
529
530
		$me    = ( ! empty( $options_to_show[0] ) ? $options_to_show[0] : false );
531
		$pages = ( ! empty( $options_to_show[1]['data'] ) ? $options_to_show[1]['data'] : false );
532
533
		$profile_checked = true;
534
		$page_selected   = false;
535
536
		if ( ! empty( $connection['connection_data']['meta']['facebook_page'] ) ) {
537
			$found = false;
538
			if ( $pages && is_array( $pages->data ) ) {
539
				foreach ( $pages->data as $page ) {
540
					if ( $page->id == $connection['connection_data']['meta']['facebook_page'] ) {
541
						$found = true;
542
						break;
543
					}
544
				}
545
			}
546
547
			if ( $found ) {
548
				$profile_checked = false;
549
				$page_selected   = $connection['connection_data']['meta']['facebook_page'];
550
			}
551
		}
552
553
		?>
554
555
		<div id="thickbox-content">
556
557
			<?php
558
			ob_start();
559
			Publicize_UI::connected_notice( 'Facebook' );
560
			$update_notice = ob_get_clean();
561
562
			if ( ! empty( $update_notice ) ) {
563
				echo $update_notice;
564
			}
565
			?>
566
567
			<?php if ( ! empty( $me['name'] ) ) : ?>
568
				<p><?php _e( 'Publicize to my <strong>Facebook Wall</strong>:', 'jetpack' ); ?></p>
569
				<table id="option-profile">
570
					<tbody>
571
					<tr>
572
						<td class="radio"><input type="radio" name="option" data-type="profile"
573
						                         id="<?php echo esc_attr( $me['id'] ) ?>"
574
						                         value="" <?php checked( $profile_checked, true ); ?> /></td>
575
						<td class="thumbnail"><label for="<?php echo esc_attr( $me['id'] ) ?>"><img
576
									src="<?php echo esc_url( $me['picture']['data']['url'] ) ?>" width="50"
577
									height="50"/></label></td>
578
						<td class="details"><label
579
								for="<?php echo esc_attr( $me['id'] ) ?>"><?php echo esc_html( $me['name'] ) ?></label>
580
						</td>
581
					</tr>
582
					</tbody>
583
				</table>
584
			<?php endif; ?>
585
586
			<?php if ( $pages ) : ?>
587
588
				<p><?php _e( 'Publicize to my <strong>Facebook Page</strong>:', 'jetpack' ); ?></p>
589
				<table id="option-fb-fanpage">
590
					<tbody>
591
592
					<?php foreach ( $pages as $i => $page ) : ?>
593
						<?php if ( ! ( $i % 2 ) ) : ?>
594
							<tr>
595
						<?php endif; ?>
596
						<td class="radio"><input type="radio" name="option" data-type="page"
597
						                         id="<?php echo esc_attr( $page['id'] ) ?>"
598
						                         value="<?php echo esc_attr( $page['id'] ) ?>" <?php checked( $page_selected && $page_selected == $page['id'], true ); ?> />
599
						</td>
600
						<td class="thumbnail"><label for="<?php echo esc_attr( $page['id'] ) ?>"><img
601
									src="<?php echo esc_url( str_replace( '_s', '_q', $page['picture']['data']['url'] ) ) ?>"
602
									width="50" height="50"/></label></td>
603
						<td class="details">
604
							<label for="<?php echo esc_attr( $page['id'] ) ?>">
605
								<span class="name"><?php echo esc_html( $page['name'] ) ?></span><br/>
606
								<span class="category"><?php echo esc_html( $page['category'] ) ?></span>
607
							</label>
608
						</td>
609
						<?php if ( ( $i % 2 ) || ( $i == count( $pages ) - 1 ) ): ?>
610
							</tr>
611
						<?php endif; ?>
612
					<?php endforeach; ?>
613
614
					</tbody>
615
				</table>
616
617
			<?php endif; ?>
618
619
			<?php Publicize_UI::global_checkbox( 'facebook', $_REQUEST['connection'] ); ?>
620
621
			<p style="text-align: center;">
622
				<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
623
				       class="button fb-options save-options" name="save"
624
				       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
625
				       rel="<?php echo wp_create_nonce( 'save_fb_token_' . $_REQUEST['connection'] ) ?>"/>
626
			</p><br/>
627
		</div>
628
629
		<?php
630
	}
631
632
	function options_save_facebook() {
633
		// Nonce check
634
		check_admin_referer( 'save_fb_token_' . $_REQUEST['connection'] );
635
636
		$id = $_POST['connection'];
637
638
		// Check for a numeric page ID
639
		$page_id = $_POST['selected_id'];
640
		if ( ! ctype_digit( $page_id ) ) {
641
			die( 'Security check' );
0 ignored issues
show
Coding Style Compatibility introduced by
The method options_save_facebook() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
642
		}
643
644
		if ( isset( $_POST['selected_id'] ) && 'profile' == $_POST['type'] ) {
645
			// Publish to User Wall/Profile
646
			$options = array(
647
				'facebook_page'    => null,
648
				'facebook_profile' => true
649
			);
650
651
		} else {
652
			if ( 'page' != $_POST['type'] || ! isset( $_POST['selected_id'] ) ) {
653
				return;
654
			}
655
656
			// Publish to Page
657
			$options = array(
658
				'facebook_page'    => $page_id,
659
				'facebook_profile' => null
660
			);
661
		}
662
663
		Jetpack::load_xml_rpc_client();
664
		$xml = new Jetpack_IXR_Client();
665
		$xml->query( 'jetpack.setPublicizeOptions', $id, $options );
666
667
		if ( ! $xml->isError() ) {
668
			$response = $xml->getResponse();
669
			Jetpack_Options::update_option( 'publicize_connections', $response );
670
		}
671
672
		$this->globalization();
673
	}
674
675
	function options_page_tumblr() {
676
		// Nonce check
677
		check_admin_referer( 'options_page_tumblr_' . $_REQUEST['connection'] );
678
679
		$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
680
		$connection         = $connected_services['tumblr'][ $_POST['connection'] ];
681
		$options_to_show    = $connection['connection_data']['meta']['options_responses'];
682
		$request            = $options_to_show[0];
683
684
		$blogs = $request['response']['user']['blogs'];
685
686
		$blog_selected = false;
687
688
		if ( ! empty( $connection['connection_data']['meta']['tumblr_base_hostname'] ) ) {
689
			foreach ( $blogs as $blog ) {
690
				if ( $connection['connection_data']['meta']['tumblr_base_hostname'] == $this->get_basehostname( $blog['url'] ) ) {
691
					$blog_selected = $connection['connection_data']['meta']['tumblr_base_hostname'];
692
					break;
693
				}
694
			}
695
696
		}
697
698
		// Use their Primary blog if they haven't selected one yet
699
		if ( ! $blog_selected ) {
700
			foreach ( $blogs as $blog ) {
701
				if ( $blog['primary'] ) {
702
					$blog_selected = $this->get_basehostname( $blog['url'] );
703
				}
704
			}
705
		} ?>
706
707
		<div id="thickbox-content">
708
709
			<?php
710
			ob_start();
711
			Publicize_UI::connected_notice( 'Tumblr' );
712
			$update_notice = ob_get_clean();
713
714
			if ( ! empty( $update_notice ) ) {
715
				echo $update_notice;
716
			}
717
			?>
718
719
			<p><?php _e( 'Publicize to my <strong>Tumblr blog</strong>:', 'jetpack' ); ?></p>
720
721
			<ul id="option-tumblr-blog">
722
723
				<?php
724
				foreach ( $blogs as $blog ) {
725
					$url = $this->get_basehostname( $blog['url'] ); ?>
726
					<li>
727
						<input type="radio" name="option" data-type="blog" id="<?php echo esc_attr( $url ) ?>"
728
						       value="<?php echo esc_attr( $url ) ?>" <?php checked( $blog_selected == $url, true ); ?> />
729
						<label for="<?php echo esc_attr( $url ) ?>"><span
730
								class="name"><?php echo esc_html( $blog['title'] ) ?></span></label>
731
					</li>
732
				<?php } ?>
733
734
			</ul>
735
736
			<?php Publicize_UI::global_checkbox( 'tumblr', $_REQUEST['connection'] ); ?>
737
738
			<p style="text-align: center;">
739
				<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
740
				       class="button tumblr-options save-options" name="save"
741
				       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
742
				       rel="<?php echo wp_create_nonce( 'save_tumblr_blog_' . $_REQUEST['connection'] ) ?>"/>
743
			</p> <br/>
744
		</div>
745
746
		<?php
747
	}
748
749
	function get_basehostname( $url ) {
750
		return parse_url( $url, PHP_URL_HOST );
751
	}
752
753
	function options_save_tumblr() {
754
		// Nonce check
755
		check_admin_referer( 'save_tumblr_blog_' . $_REQUEST['connection'] );
756
757
		$id = $_POST['connection'];
758
759
		$options = array( 'tumblr_base_hostname' => $_POST['selected_id'] );
760
761
		Jetpack::load_xml_rpc_client();
762
		$xml = new Jetpack_IXR_Client();
763
		$xml->query( 'jetpack.setPublicizeOptions', $id, $options );
764
765
		if ( ! $xml->isError() ) {
766
			$response = $xml->getResponse();
767
			Jetpack_Options::update_option( 'publicize_connections', $response );
768
		}
769
770
		$this->globalization();
771
	}
772
773
	function options_page_twitter() {
774
		Publicize_UI::options_page_other( 'twitter' );
775
	}
776
777
	function options_page_linkedin() {
778
		Publicize_UI::options_page_other( 'linkedin' );
779
	}
780
781
	function options_page_path() {
782
		Publicize_UI::options_page_other( 'path' );
783
	}
784
785
	function options_page_google_plus() {
786
		Publicize_UI::options_page_other( 'google_plus' );
787
	}
788
789
	function options_save_twitter() {
790
		$this->options_save_other( 'twitter' );
791
	}
792
793
	function options_save_linkedin() {
794
		$this->options_save_other( 'linkedin' );
795
	}
796
797
	function options_save_path() {
798
		$this->options_save_other( 'path' );
799
	}
800
801
	function options_save_google_plus() {
802
		$this->options_save_other( 'google_plus' );
803
	}
804
805
	function options_save_other( $service_name ) {
806
		// Nonce check
807
		check_admin_referer( 'save_' . $service_name . '_token_' . $_REQUEST['connection'] );
808
		$this->globalization();
809
	}
810
811
	/**
812
	 * Already-published posts should not be Publicized by default. This filter sets checked to
813
	 * false if a post has already been published.
814
	 */
815
	function publicize_checkbox_default( $checked, $post_id, $name, $connection ) {
816
		if ( 'publish' == get_post_status( $post_id ) ) {
817
			return false;
818
		}
819
820
		return $checked;
821
	}
822
823
	/**
824
	 * If there's only one shared connection to Twitter set it as twitter:site tag.
825
	 */
826
	function enhaced_twitter_cards_site_tag( $tag ) {
827
		$custom_site_tag = get_option( 'jetpack-twitter-cards-site-tag' );
828
		if ( ! empty( $custom_site_tag ) ) {
829
			return $tag;
830
		}
831
		if ( ! $this->is_enabled( 'twitter' ) ) {
832
			return $tag;
833
		}
834
		$connections = $this->get_connections( 'twitter' );
835
		foreach ( $connections as $connection ) {
0 ignored issues
show
Bug introduced by
The expression $connections of type array|false is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
836
			$connection_meta = $this->get_connection_meta( $connection );
837
			if ( 0 == $connection_meta['connection_data']['user_id'] ) {
838
				// If the connection is shared
839
				return $this->get_display_name( 'twitter', $connection );
840
			}
841
		}
842
843
		return $tag;
844
	}
845
846
	function save_publicized_twitter_account( $submit_post, $post_id, $service_name, $connection ) {
847
		if ( 'twitter' == $service_name && $submit_post ) {
848
			$connection_meta        = $this->get_connection_meta( $connection );
849
			$publicize_twitter_user = get_post_meta( $post_id, '_publicize_twitter_user' );
850
			if ( empty( $publicize_twitter_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
851
				update_post_meta( $post_id, '_publicize_twitter_user', $this->get_display_name( 'twitter', $connection ) );
852
			}
853
		}
854
	}
855
856
	function get_publicized_twitter_account( $account, $post_id ) {
857
		if ( ! empty( $account ) ) {
858
			return $account;
859
		}
860
		$account = get_post_meta( $post_id, '_publicize_twitter_user', true );
861
		if ( ! empty( $account ) ) {
862
			return $account;
863
		}
864
865
		return '';
866
	}
867
868
	/**
869
	 * Save the Publicized Facebook account when publishing a post
870
	 * Use only Personal accounts, not Facebook Pages
871
	 */
872
	function save_publicized_facebook_account( $submit_post, $post_id, $service_name, $connection ) {
873
		$connection_meta = $this->get_connection_meta( $connection );
874
		if ( 'facebook' == $service_name && isset( $connection_meta['connection_data']['meta']['facebook_profile'] ) && $submit_post ) {
875
			$publicize_facebook_user = get_post_meta( $post_id, '_publicize_facebook_user' );
876
			if ( empty( $publicize_facebook_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
877
				$profile_link = $this->get_profile_link( 'facebook', $connection );
878
879
				if ( false !== $profile_link ) {
880
					update_post_meta( $post_id, '_publicize_facebook_user', $profile_link );
881
				}
882
			}
883
		}
884
	}
885
}
886