Completed
Push — update/build-release-branch-sc... ( 8e05aa...6a7f53 )
by
unknown
277:00 queued 265:52
created

Publicize::display_disconnected()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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