Completed
Push — feature/assets-cdn ( 13f9d8...5f1be1 )
by George
103:49 queued 72:28
created

Publicize::admin_page_load()   C

Complexity

Conditions 10
Paths 19

Size

Total Lines 76

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
nc 19
nop 0
dl 0
loc 76
rs 6.6569
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
		include_once( JETPACK__PLUGIN_DIR . 'modules/publicize/enhanced-open-graph.php' );
42
	}
43
44
	function force_user_connection() {
45
		global $current_user;
46
		$user_token        = Jetpack_Data::get_access_token( $current_user->ID );
47
		$is_user_connected = $user_token && ! is_wp_error( $user_token );
48
49
		// If the user is already connected via Jetpack, then we're good
50
		if ( $is_user_connected ) {
51
			return;
52
		}
53
54
		// If they're not connected, then remove the Publicize UI and tell them they need to connect first
55
		global $publicize_ui;
56
		remove_action( 'pre_admin_screen_sharing', array( $publicize_ui, 'admin_page' ) );
57
58
		// Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
59
		// Jetpack::init()->admin_styles();
60
		add_action( 'pre_admin_screen_sharing', array( $this, 'admin_page_warning' ), 1 );
61
	}
62
63
	function admin_page_warning() {
64
		$jetpack   = Jetpack::init();
65
		$blog_name = get_bloginfo( 'blogname' );
66
		if ( empty( $blog_name ) ) {
67
			$blog_name = home_url( '/' );
68
		}
69
70
		?>
71
		<div id="message" class="updated jetpack-message jp-connect">
72
			<div class="jetpack-wrap-container">
73
				<div class="jetpack-text-container">
74
					<p><?php printf(
75
							/* translators: %s is the name of the blog */
76
							esc_html( wptexturize( __( "To use Publicize, you'll need to link your %s account to your WordPress.com account using the link below.", 'jetpack' ) ) ),
77
							'<strong>' . esc_html( $blog_name ) . '</strong>'
78
						); ?></p>
79
					<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>
80
				</div>
81
				<div class="jetpack-install-container">
82
					<p class="submit"><a
83
							href="<?php echo $jetpack->build_connect_url( false, menu_page_url( 'sharing', false ) ); ?>"
84
							class="button-connector"
85
							id="wpcom-connect"><?php esc_html_e( 'Link account with WordPress.com', 'jetpack' ); ?></a>
86
					</p>
87
					<p class="jetpack-install-blurb">
88
						<?php jetpack_render_tos_blurb(); ?>
89
					</p>
90
				</div>
91
			</div>
92
		</div>
93
		<?php
94
	}
95
96
	/**
97
	 * Remove a Publicize connection
98
	 */
99
	function disconnect( $service_name, $connection_id, $_blog_id = false, $_user_id = false, $force_delete = false ) {
100
		Jetpack::load_xml_rpc_client();
101
		$xml = new Jetpack_IXR_Client();
102
		$xml->query( 'jetpack.deletePublicizeConnection', $connection_id );
103
104
		if ( ! $xml->isError() ) {
105
			Jetpack_Options::update_option( 'publicize_connections', $xml->getResponse() );
106
		} else {
107
			return false;
108
		}
109
	}
110
111
	function receive_updated_publicize_connections( $publicize_connections ) {
112
		Jetpack_Options::update_option( 'publicize_connections', $publicize_connections );
113
114
		return true;
115
	}
116
117
	function register_update_publicize_connections_xmlrpc_method( $methods ) {
118
		return array_merge( $methods, array(
119
			'jetpack.updatePublicizeConnections' => array( $this, 'receive_updated_publicize_connections' ),
120
		) );
121
	}
122
123
	function get_all_connections() {
124
		return Jetpack_Options::get_option( 'publicize_connections' );
125
	}
126
127
	function get_connections( $service_name, $_blog_id = false, $_user_id = false ) {
128
		$connections           = $this->get_all_connections();
129
		$connections_to_return = array();
130
		if ( ! empty( $connections ) && is_array( $connections ) ) {
131
			if ( ! empty( $connections[ $service_name ] ) ) {
132
				foreach ( $connections[ $service_name ] as $id => $connection ) {
133
					if ( 0 == $connection['connection_data']['user_id'] || $this->user_id() == $connection['connection_data']['user_id'] ) {
134
						$connections_to_return[ $id ] = $connection;
135
					}
136
				}
137
			}
138
139
			return $connections_to_return;
140
		}
141
142
		return false;
143
	}
144
145
	function get_all_connections_for_user() {
146
		$connections = $this->get_all_connections();
147
148
		$connections_to_return = array();
149
		if ( ! empty( $connections ) ) {
150
			foreach ( (array) $connections as $service_name => $connections_for_service ) {
151
				foreach ( $connections_for_service as $id => $connection ) {
152
					$user_id = intval( $connection['connection_data']['user_id'] );
153
					// phpcs:ignore WordPress.PHP.YodaConditions.NotYoda
154
					if ( $user_id === 0 || $this->user_id() === $user_id ) {
155
						$connections_to_return[ $service_name ][ $id ] = $connection;
156
					}
157
				}
158
			}
159
160
			return $connections_to_return;
161
		}
162
163
		return false;
164
	}
165
166
	function get_connection_id( $connection ) {
167
		return $connection['connection_data']['id'];
168
	}
169
170
	function get_connection_meta( $connection ) {
171
		$connection['user_id'] = $connection['connection_data']['user_id']; // Allows for shared connections
172
		return $connection;
173
	}
174
175
	function admin_page_load() {
176
		if ( isset( $_GET['action'] ) ) {
177
			if ( isset( $_GET['service'] ) ) {
178
				$service_name = $_GET['service'];
179
			}
180
181
			switch ( $_GET['action'] ) {
182
				case 'error':
183
					add_action( 'pre_admin_screen_sharing', array( $this, 'display_connection_error' ), 9 );
184
					break;
185
186
				case 'request':
187
					check_admin_referer( 'keyring-request', 'kr_nonce' );
188
					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...
189
190
					$verification = Jetpack::generate_secrets( 'publicize' );
191
					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...
192
						$url = Jetpack::admin_url( 'jetpack#/settings' );
193
						wp_die( sprintf( __( "Jetpack is not connected. Please connect Jetpack by visiting <a href='%s'>Settings</a>.", 'jetpack' ), $url ) );
194
195
					}
196
					$stats_options = get_option( 'stats_options' );
197
					$wpcom_blog_id = Jetpack_Options::get_option( 'id' );
198
					$wpcom_blog_id = ! empty( $wpcom_blog_id ) ? $wpcom_blog_id : $stats_options['blog_id'];
199
200
					$user     = wp_get_current_user();
201
					$redirect = $this->api_url( $service_name, urlencode_deep( array(
202
						'action'       => 'request',
203
						'redirect_uri' => add_query_arg( array( 'action' => 'done' ), menu_page_url( 'sharing', false ) ),
204
						'for'          => 'publicize',
205
						// required flag that says this connection is intended for publicize
206
						'siteurl'      => site_url(),
207
						'state'        => $user->ID,
208
						'blog_id'      => $wpcom_blog_id,
209
						'secret_1'     => $verification['secret_1'],
210
						'secret_2'     => $verification['secret_2'],
211
						'eol'          => $verification['exp'],
212
					) ) );
213
					wp_redirect( $redirect );
214
					exit;
215
					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...
216
217
				case 'completed':
218
					Jetpack::load_xml_rpc_client();
219
					$xml = new Jetpack_IXR_Client();
220
					$xml->query( 'jetpack.fetchPublicizeConnections' );
221
222
					if ( ! $xml->isError() ) {
223
						$response = $xml->getResponse();
224
						Jetpack_Options::update_option( 'publicize_connections', $response );
225
					}
226
227
					break;
228
229
				case 'delete':
230
					$id = $_GET['id'];
231
232
					check_admin_referer( 'keyring-request', 'kr_nonce' );
233
					check_admin_referer( "keyring-request-$service_name", 'nonce' );
234
235
					$this->disconnect( $service_name, $id );
236
237
					add_action( 'admin_notices', array( $this, 'display_disconnected' ) );
238
					break;
239
			}
240
		}
241
242
		// Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
243
		// Errors encountered on WordPress.com's end are passed back as a code
244
		/*
245
		if ( isset( $_GET['action'] ) && 'error' == $_GET['action'] ) {
246
			// Load Jetpack's styles to handle the box
247
			Jetpack::init()->admin_styles();
248
		}
249
		*/
250
	}
251
252
	function display_connection_error() {
253
		$code = false;
254
		if ( isset( $_GET['service'] ) ) {
255
			$service_name = $_GET['service'];
256
			$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 ) );
257
		} else {
258
			if ( isset( $_GET['publicize_error'] ) ) {
259
				$code = strtolower( $_GET['publicize_error'] );
260
				switch ( $code ) {
261
					case '400':
262
						$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' );
263
						break;
264
					case 'secret_mismatch':
265
						$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' );
266
						break;
267
					case 'empty_blog_id':
268
						$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' );
269
						break;
270
					case 'empty_state':
271
						$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() );
272
						break;
273
					default:
274
						$error = __( 'Something which should never happen, happened. Sorry about that. If you try again, maybe it will work.', 'jetpack' );
275
						break;
276
				}
277
			} else {
278
				$error = __( 'There was a problem connecting with Publicize. Please try again in a moment.', 'jetpack' );
279
			}
280
		}
281
		// Using the same formatting/style as Jetpack::admin_notices() error
282
		?>
283
		<div id="message" class="jetpack-message jetpack-err">
284
			<div class="squeezer">
285
				<h2><?php echo wp_kses( $error, array( 'a'      => array( 'href' => true ),
286
				                                       'code'   => true,
287
				                                       'strong' => true,
288
				                                       'br'     => true,
289
				                                       'b'      => true
290
					) ); ?></h2>
291
				<?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...
292
					<p><?php printf( __( 'Error code: %s', 'jetpack' ), esc_html( stripslashes( $code ) ) ); ?></p>
293
				<?php endif; ?>
294
			</div>
295
		</div>
296
		<?php
297
	}
298
299
	function display_disconnected() {
300
		echo "<div class='updated'>\n";
301
		echo '<p>' . esc_html( __( 'That connection has been removed.', 'jetpack' ) ) . "</p>\n";
302
		echo "</div>\n\n";
303
	}
304
305
	function globalization() {
306
		if ( 'on' == $_REQUEST['global'] ) {
307
			$id = $_REQUEST['connection'];
308
309
			if ( ! current_user_can( $this->GLOBAL_CAP ) ) {
310
				return;
311
			}
312
313
			Jetpack::load_xml_rpc_client();
314
			$xml = new Jetpack_IXR_Client();
315
			$xml->query( 'jetpack.globalizePublicizeConnection', $id, 'globalize' );
316
317
			if ( ! $xml->isError() ) {
318
				$response = $xml->getResponse();
319
				Jetpack_Options::update_option( 'publicize_connections', $response );
320
			}
321
		}
322
	}
323
324
	/**
325
	 * Gets a URL to the public-api actions. Works like WP's admin_url
326
	 *
327
	 * @param string $service Shortname of a specific service.
328
	 *
329
	 * @return URL to specific public-api process
330
	 */
331
	// on WordPress.com this is/calls Keyring::admin_url
332
	function api_url( $service = false, $params = array() ) {
333
		/**
334
		 * Filters the API URL used to interact with WordPress.com.
335
		 *
336
		 * @module publicize
337
		 *
338
		 * @since 2.0.0
339
		 *
340
		 * @param string https://public-api.wordpress.com/connect/?jetpack=publicize Default Publicize API URL.
341
		 */
342
		$url = apply_filters( 'publicize_api_url', 'https://public-api.wordpress.com/connect/?jetpack=publicize' );
343
344
		if ( $service ) {
345
			$url = add_query_arg( array( 'service' => $service ), $url );
346
		}
347
348
		if ( count( $params ) ) {
349
			$url = add_query_arg( $params, $url );
350
		}
351
352
		return $url;
353
	}
354
355 View Code Duplication
	function connect_url( $service_name ) {
356
		return add_query_arg( array(
357
			'action'   => 'request',
358
			'service'  => $service_name,
359
			'kr_nonce' => wp_create_nonce( 'keyring-request' ),
360
			'nonce'    => wp_create_nonce( "keyring-request-$service_name" ),
361
		), menu_page_url( 'sharing', false ) );
362
	}
363
364
	function refresh_url( $service_name ) {
365
		return add_query_arg( array(
366
			'action'   => 'request',
367
			'service'  => $service_name,
368
			'kr_nonce' => wp_create_nonce( 'keyring-request' ),
369
			'refresh'  => 1,
370
			'for'      => 'publicize',
371
			'nonce'    => wp_create_nonce( "keyring-request-$service_name" ),
372
		), admin_url( 'options-general.php?page=sharing' ) );
373
	}
374
375 View Code Duplication
	function disconnect_url( $service_name, $id ) {
376
		return add_query_arg( array(
377
			'action'   => 'delete',
378
			'service'  => $service_name,
379
			'id'       => $id,
380
			'kr_nonce' => wp_create_nonce( 'keyring-request' ),
381
			'nonce'    => wp_create_nonce( "keyring-request-$service_name" ),
382
		), menu_page_url( 'sharing', false ) );
383
	}
384
385
	/**
386
	 * Get social networks, either all available or only those that the site is connected to.
387
	 *
388
	 * @since 2.0
389
	 *
390
	 * @param string $filter Select the list of services that will be returned. Defaults to 'all', accepts 'connected'.
391
	 *
392
	 * @return array List of social networks.
393
	 */
394
	function get_services( $filter = 'all' ) {
395
		$services = array(
396
			'facebook'    => array(),
397
			'twitter'     => array(),
398
			'linkedin'    => array(),
399
			'tumblr'      => array(),
400
			'path'        => array(),
401
			'google_plus' => array(),
402
		);
403
404
		if ( 'all' == $filter ) {
405
			return $services;
406
		} else {
407
			$connected_services = array();
408
			foreach ( $services as $service => $empty ) {
409
				$connections = $this->get_connections( $service );
410
				if ( $connections ) {
411
					$connected_services[ $service ] = $connections;
412
				}
413
			}
414
			return $connected_services;
415
		}
416
	}
417
418
	function get_connection( $service, $id, $_blog_id = false, $_user_id = false ) {
419
		// Stub
420
	}
421
422
	function flag_post_for_publicize( $new_status, $old_status, $post ) {
423
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
424
			return;
425
		}
426
427
		if ( 'publish' == $new_status && 'publish' != $old_status ) {
428
			/**
429
			 * Determines whether a post being published gets publicized.
430
			 *
431
			 * Side-note: Possibly our most alliterative filter name.
432
			 *
433
			 * @module publicize
434
			 *
435
			 * @since 4.1.0
436
			 *
437
			 * @param bool $should_publicize Should the post be publicized? Default to true.
438
			 * @param WP_POST $post Current Post object.
439
			 */
440
			$should_publicize = apply_filters( 'publicize_should_publicize_published_post', true, $post );
441
442
			if ( $should_publicize ) {
443
				update_post_meta( $post->ID, $this->PENDING, true );
444
			}
445
		}
446
	}
447
448
	function test_connection( $service_name, $connection ) {
449
450
		$id = $this->get_connection_id( $connection );
451
452
		Jetpack::load_xml_rpc_client();
453
		$xml = new Jetpack_IXR_Client();
454
		$xml->query( 'jetpack.testPublicizeConnection', $id );
455
456
		// Bail if all is well
457
		if ( ! $xml->isError() ) {
458
			return true;
459
		}
460
461
		$xml_response            = $xml->getResponse();
462
		$connection_test_message = $xml_response['faultString'];
463
464
		// Set up refresh if the user can
465
		$user_can_refresh = current_user_can( $this->GLOBAL_CAP );
466
		if ( $user_can_refresh ) {
467
			$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...
468
			$refresh_text = sprintf( _x( 'Refresh connection with %s', 'Refresh connection with {social media service}', 'jetpack' ), $this->get_service_label( $service_name ) );
469
			$refresh_url  = $this->refresh_url( $service_name );
470
		}
471
472
		$error_data = array(
473
			'user_can_refresh' => $user_can_refresh,
474
			'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...
475
			'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...
476
		);
477
478
		return new WP_Error( 'pub_conn_test_failed', $connection_test_message, $error_data );
479
	}
480
481
	/**
482
	 * Save a flag locally to indicate that this post has already been Publicized via the selected
483
	 * connections.
484
	 */
485
	function save_publicized( $post_ID, $post = null, $update = null ) {
486
		if ( is_null( $post ) ) {
487
			return;
488
		}
489
		// Only do this when a post transitions to being published
490
		if ( get_post_meta( $post->ID, $this->PENDING ) && $this->post_type_is_publicizeable( $post->post_type ) ) {
491
			$connected_services = $this->get_all_connections();
492
			if ( ! empty( $connected_services ) ) {
493
				/**
494
				 * Fires when a post is saved that has is marked as pending publicizing
495
				 *
496
				 * @since 4.1.0
497
				 *
498
				 * @param int The post ID
499
				 */
500
				do_action_deprecated( 'jetpack_publicize_post', $post->ID, '4.8.0', 'jetpack_published_post_flags' );
501
			}
502
			delete_post_meta( $post->ID, $this->PENDING );
503
			update_post_meta( $post->ID, $this->POST_DONE . 'all', true );
504
		}
505
	}
506
507
	function set_post_flags( $flags, $post ) {
508
		$flags['publicize_post'] = false;
509
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
510
			return $flags;
511
		}
512
		/** This filter is already documented in modules/publicize/publicize-jetpack.php */
513
		if ( ! apply_filters( 'publicize_should_publicize_published_post', true, $post ) ) {
514
			return $flags;
515
		}
516
517
		$connected_services = $this->get_all_connections();
518
519
		if ( empty( $connected_services ) ) {
520
			return $flags;
521
		}
522
523
		$flags['publicize_post'] = true;
524
525
		return $flags;
526
	}
527
528
	/**
529
	 * Options Code
530
	 */
531
532
	function options_page_facebook() {
533
		$connected_services = $this->get_all_connections();
534
		$connection         = $connected_services['facebook'][ $_REQUEST['connection'] ];
535
		$options_to_show    = ( ! empty( $connection['connection_data']['meta']['options_responses'] ) ? $connection['connection_data']['meta']['options_responses'] : false );
536
537
		// Nonce check
538
		check_admin_referer( 'options_page_facebook_' . $_REQUEST['connection'] );
539
540
		$pages = ( ! empty( $options_to_show[1]['data'] ) ? $options_to_show[1]['data'] : false );
541
542
		$page_selected   = false;
543
		if ( ! empty( $connection['connection_data']['meta']['facebook_page'] ) ) {
544
			$found = false;
545
			if ( $pages && isset( $pages->data ) && is_array( $pages->data )  ) {
546
				foreach ( $pages->data as $page ) {
547
					if ( $page->id == $connection['connection_data']['meta']['facebook_page'] ) {
548
						$found = true;
549
						break;
550
					}
551
				}
552
			}
553
554
			if ( $found ) {
555
				$page_selected   = $connection['connection_data']['meta']['facebook_page'];
556
			}
557
		}
558
559
		?>
560
561
		<div id="thickbox-content">
562
563
			<?php
564
			ob_start();
565
			Publicize_UI::connected_notice( 'Facebook' );
566
			$update_notice = ob_get_clean();
567
568
			if ( ! empty( $update_notice ) ) {
569
				echo $update_notice;
570
			}
571
			$page_info_message = sprintf(
572
				__( 'Facebook supports Publicize connections to Facebook Pages, but not to Facebook Profiles. <a href="%s">Learn More about Publicize for Facebook</a>', 'jetpack' ),
573
				'https://jetpack.com/support/publicize/facebook'
574
			);
575
576
			if ( $pages ) : ?>
577
				<p><?php _e( 'Publicize to my <strong>Facebook Page</strong>:', 'jetpack' ); ?></p>
578
				<table id="option-fb-fanpage">
579
					<tbody>
580
581
					<?php foreach ( $pages as $i => $page ) : ?>
582
						<?php if ( ! ( $i % 2 ) ) : ?>
583
							<tr>
584
						<?php endif; ?>
585
						<td class="radio"><input type="radio" name="option" data-type="page"
586
						                         id="<?php echo esc_attr( $page['id'] ) ?>"
587
						                         value="<?php echo esc_attr( $page['id'] ) ?>" <?php checked( $page_selected && $page_selected == $page['id'], true ); ?> />
588
						</td>
589
						<td class="thumbnail"><label for="<?php echo esc_attr( $page['id'] ) ?>"><img
590
									src="<?php echo esc_url( str_replace( '_s', '_q', $page['picture']['data']['url'] ) ) ?>"
591
									width="50" height="50"/></label></td>
592
						<td class="details">
593
							<label for="<?php echo esc_attr( $page['id'] ) ?>">
594
								<span class="name"><?php echo esc_html( $page['name'] ) ?></span><br/>
595
								<span class="category"><?php echo esc_html( $page['category'] ) ?></span>
596
							</label>
597
						</td>
598
						<?php if ( ( $i % 2 ) || ( $i == count( $pages ) - 1 ) ): ?>
599
							</tr>
600
						<?php endif; ?>
601
					<?php endforeach; ?>
602
603
					</tbody>
604
				</table>
605
606
				<?php Publicize_UI::global_checkbox( 'facebook', $_REQUEST['connection'] ); ?>
607
				<p style="text-align: center;">
608
					<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
609
					       class="button fb-options save-options" name="save"
610
					       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
611
					       rel="<?php echo wp_create_nonce( 'save_fb_token_' . $_REQUEST['connection'] ) ?>"/>
612
				</p><br/>
613
				<p><?php echo $page_info_message; ?></p>
614
			<?php else: ?>
615
				<div>
616
					<p><?php echo $page_info_message; ?></p>
617
					<p><?php printf( __( '<a class="button" href="%s" target="%s">Create a Facebook page</a> to get started.', 'jetpack' ), 'https://www.facebook.com/pages/creation/', '_blank noopener noreferrer' ); ?></p>
618
				</div>
619
			<?php endif; ?>
620
		</div>
621
		<?php
622
	}
623
624
	function options_save_facebook() {
625
		// Nonce check
626
		check_admin_referer( 'save_fb_token_' . $_REQUEST['connection'] );
627
628
		// Check for a numeric page ID
629
		$page_id = $_POST['selected_id'];
630
		if ( ! ctype_digit( $page_id ) ) {
631
			die( 'Security check' );
632
		}
633
634
		if ( 'page' != $_POST['type'] || ! isset( $_POST['selected_id'] ) ) {
635
			return;
636
		}
637
638
		// Publish to Page
639
		$options = array(
640
			'facebook_page'    => $page_id,
641
			'facebook_profile' => null
642
		);
643
644
		$this->set_remote_publicize_options( $_POST['connection'], $options );
645
	}
646
647
	function options_page_tumblr() {
648
		// Nonce check
649
		check_admin_referer( 'options_page_tumblr_' . $_REQUEST['connection'] );
650
651
		$connected_services = $this->get_all_connections();
652
		$connection         = $connected_services['tumblr'][ $_POST['connection'] ];
653
		$options_to_show    = $connection['connection_data']['meta']['options_responses'];
654
		$request            = $options_to_show[0];
655
656
		$blogs = $request['response']['user']['blogs'];
657
658
		$blog_selected = false;
659
660
		if ( ! empty( $connection['connection_data']['meta']['tumblr_base_hostname'] ) ) {
661
			foreach ( $blogs as $blog ) {
662
				if ( $connection['connection_data']['meta']['tumblr_base_hostname'] == $this->get_basehostname( $blog['url'] ) ) {
663
					$blog_selected = $connection['connection_data']['meta']['tumblr_base_hostname'];
664
					break;
665
				}
666
			}
667
668
		}
669
670
		// Use their Primary blog if they haven't selected one yet
671
		if ( ! $blog_selected ) {
672
			foreach ( $blogs as $blog ) {
673
				if ( $blog['primary'] ) {
674
					$blog_selected = $this->get_basehostname( $blog['url'] );
675
				}
676
			}
677
		} ?>
678
679
		<div id="thickbox-content">
680
681
			<?php
682
			ob_start();
683
			Publicize_UI::connected_notice( 'Tumblr' );
684
			$update_notice = ob_get_clean();
685
686
			if ( ! empty( $update_notice ) ) {
687
				echo $update_notice;
688
			}
689
			?>
690
691
			<p><?php _e( 'Publicize to my <strong>Tumblr blog</strong>:', 'jetpack' ); ?></p>
692
693
			<ul id="option-tumblr-blog">
694
695
				<?php
696
				foreach ( $blogs as $blog ) {
697
					$url = $this->get_basehostname( $blog['url'] ); ?>
698
					<li>
699
						<input type="radio" name="option" data-type="blog" id="<?php echo esc_attr( $url ) ?>"
700
						       value="<?php echo esc_attr( $url ) ?>" <?php checked( $blog_selected == $url, true ); ?> />
701
						<label for="<?php echo esc_attr( $url ) ?>"><span
702
								class="name"><?php echo esc_html( $blog['title'] ) ?></span></label>
703
					</li>
704
				<?php } ?>
705
706
			</ul>
707
708
			<?php Publicize_UI::global_checkbox( 'tumblr', $_REQUEST['connection'] ); ?>
709
710
			<p style="text-align: center;">
711
				<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
712
				       class="button tumblr-options save-options" name="save"
713
				       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
714
				       rel="<?php echo wp_create_nonce( 'save_tumblr_blog_' . $_REQUEST['connection'] ) ?>"/>
715
			</p> <br/>
716
		</div>
717
718
		<?php
719
	}
720
721
	function get_basehostname( $url ) {
722
		return parse_url( $url, PHP_URL_HOST );
723
	}
724
725
	function options_save_tumblr() {
726
		// Nonce check
727
		check_admin_referer( 'save_tumblr_blog_' . $_REQUEST['connection'] );
728
		$options = array( 'tumblr_base_hostname' => $_POST['selected_id'] );
729
730
		$this->set_remote_publicize_options( $_POST['connection'], $options );
731
732
	}
733
734
	function set_remote_publicize_options( $id, $options ) {
735
		Jetpack::load_xml_rpc_client();
736
		$xml = new Jetpack_IXR_Client();
737
		$xml->query( 'jetpack.setPublicizeOptions', $id, $options );
738
739
		if ( ! $xml->isError() ) {
740
			$response = $xml->getResponse();
741
			Jetpack_Options::update_option( 'publicize_connections', $response );
742
			$this->globalization();
743
		}
744
	}
745
746
	function options_page_twitter() {
747
		Publicize_UI::options_page_other( 'twitter' );
748
	}
749
750
	function options_page_linkedin() {
751
		Publicize_UI::options_page_other( 'linkedin' );
752
	}
753
754
	function options_page_path() {
755
		Publicize_UI::options_page_other( 'path' );
756
	}
757
758
	function options_page_google_plus() {
759
		Publicize_UI::options_page_other( 'google_plus' );
760
	}
761
762
	function options_save_twitter() {
763
		$this->options_save_other( 'twitter' );
764
	}
765
766
	function options_save_linkedin() {
767
		$this->options_save_other( 'linkedin' );
768
	}
769
770
	function options_save_path() {
771
		$this->options_save_other( 'path' );
772
	}
773
774
	function options_save_google_plus() {
775
		$this->options_save_other( 'google_plus' );
776
	}
777
778
	function options_save_other( $service_name ) {
779
		// Nonce check
780
		check_admin_referer( 'save_' . $service_name . '_token_' . $_REQUEST['connection'] );
781
		$this->globalization();
782
	}
783
784
	/**
785
	 * Already-published posts should not be Publicized by default. This filter sets checked to
786
	 * false if a post has already been published.
787
	 */
788
	function publicize_checkbox_default( $checked, $post_id, $name, $connection ) {
789
		if ( 'publish' == get_post_status( $post_id ) ) {
790
			return false;
791
		}
792
793
		return $checked;
794
	}
795
796
	/**
797
	 * If there's only one shared connection to Twitter set it as twitter:site tag.
798
	 */
799
	function enhaced_twitter_cards_site_tag( $tag ) {
800
		$custom_site_tag = get_option( 'jetpack-twitter-cards-site-tag' );
801
		if ( ! empty( $custom_site_tag ) ) {
802
			return $tag;
803
		}
804
		if ( ! $this->is_enabled( 'twitter' ) ) {
805
			return $tag;
806
		}
807
		$connections = $this->get_connections( 'twitter' );
808
		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...
809
			$connection_meta = $this->get_connection_meta( $connection );
810
			if ( 0 == $connection_meta['connection_data']['user_id'] ) {
811
				// If the connection is shared
812
				return $this->get_display_name( 'twitter', $connection );
813
			}
814
		}
815
816
		return $tag;
817
	}
818
819
	function save_publicized_twitter_account( $submit_post, $post_id, $service_name, $connection ) {
820
		if ( 'twitter' == $service_name && $submit_post ) {
821
			$connection_meta        = $this->get_connection_meta( $connection );
822
			$publicize_twitter_user = get_post_meta( $post_id, '_publicize_twitter_user' );
823
			if ( empty( $publicize_twitter_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
824
				update_post_meta( $post_id, '_publicize_twitter_user', $this->get_display_name( 'twitter', $connection ) );
825
			}
826
		}
827
	}
828
829
	function get_publicized_twitter_account( $account, $post_id ) {
830
		if ( ! empty( $account ) ) {
831
			return $account;
832
		}
833
		$account = get_post_meta( $post_id, '_publicize_twitter_user', true );
834
		if ( ! empty( $account ) ) {
835
			return $account;
836
		}
837
838
		return '';
839
	}
840
841
	/**
842
	 * Save the Publicized Facebook account when publishing a post
843
	 * Use only Personal accounts, not Facebook Pages
844
	 */
845
	function save_publicized_facebook_account( $submit_post, $post_id, $service_name, $connection ) {
846
		$connection_meta = $this->get_connection_meta( $connection );
847
		if ( 'facebook' == $service_name && isset( $connection_meta['connection_data']['meta']['facebook_profile'] ) && $submit_post ) {
848
			$publicize_facebook_user = get_post_meta( $post_id, '_publicize_facebook_user' );
849
			if ( empty( $publicize_facebook_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
850
				$profile_link = $this->get_profile_link( 'facebook', $connection );
851
852
				if ( false !== $profile_link ) {
853
					update_post_meta( $post_id, '_publicize_facebook_user', $profile_link );
854
				}
855
			}
856
		}
857
	}
858
}
859