Completed
Push — add/changelog-62 ( 9977bb...d371c2 )
by
unknown
10:21
created

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