Completed
Push — update/connect-url-authorize-s... ( 3a3ea9 )
by
unknown
10:56
created

Publicize::get_connection_id()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 3
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
				</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['eol'],
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
	function get_services( $filter ) {
358
		if ( ! in_array( $filter, array( 'all', 'connected' ) ) ) {
359
			$filter = 'all';
360
		}
361
362
		$services = array(
363
			'facebook'    => array(),
364
			'twitter'     => array(),
365
			'linkedin'    => array(),
366
			'tumblr'      => array(),
367
			'path'        => array(),
368
			'google_plus' => array(),
369
		);
370
371
		if ( 'all' == $filter ) {
372
			return $services;
373
		} else {
374
			$connected_services = array();
375
			foreach ( $services as $service => $empty ) {
376
				$connections = $this->get_connections( $service );
377
				if ( $connections ) {
378
					$connected_services[ $service ] = $connections;
379
				}
380
			}
381
382
			return $connected_services;
383
		}
384
	}
385
386
	function get_connection( $service, $id, $_blog_id = false, $_user_id = false ) {
387
		// Stub
388
	}
389
390
	function flag_post_for_publicize( $new_status, $old_status, $post ) {
391
		if ( 'publish' == $new_status && 'publish' != $old_status ) {
392
			/**
393
			 * Determines whether a post being published gets publicized.
394
			 *
395
			 * Side-note: Possibly our most alliterative filter name.
396
			 *
397
			 * @module publicize
398
			 *
399
			 * @since 4.1.0
400
			 *
401
			 * @param bool $should_publicize Should the post be publicized? Default to true.
402
			 * @param WP_POST $post Current Post object.
403
			 */
404
			$should_publicize = apply_filters( 'publicize_should_publicize_published_post', true, $post );
405
406
			if ( $should_publicize ) {
407
				update_post_meta( $post->ID, $this->PENDING, true );
408
			}
409
		}
410
	}
411
412
	function test_connection( $service_name, $connection ) {
413
		$connection_test_passed  = true;
414
		$connection_test_message = '';
415
		$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...
416
417
		$id = $this->get_connection_id( $connection );
418
419
		Jetpack::load_xml_rpc_client();
420
		$xml = new Jetpack_IXR_Client();
421
		$xml->query( 'jetpack.testPublicizeConnection', $id );
422
423
		if ( $xml->isError() ) {
424
			$xml_response            = $xml->getResponse();
425
			$connection_test_message = $xml_response['faultString'];
426
			$connection_test_passed  = false;
427
		}
428
429
		// Bail if all is well
430
		if ( $connection_test_passed ) {
431
			return true;
432
		}
433
434
		// Set up refresh if the user can
435
		$user_can_refresh = current_user_can( $this->GLOBAL_CAP );
436
		if ( $user_can_refresh ) {
437
			$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...
438
			$refresh_text = sprintf( _x( 'Refresh connection with %s', 'Refresh connection with {social media service}', 'jetpack' ), $this->get_service_label( $service_name ) );
439
			$refresh_url  = $this->refresh_url( $service_name );
440
		}
441
442
		$error_data = array(
443
			'user_can_refresh' => $user_can_refresh,
444
			'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...
445
			'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...
446
		);
447
448
		return new WP_Error( 'pub_conn_test_failed', $connection_test_message, $error_data );
449
	}
450
451
	/**
452
	 * Save a flag locally to indicate that this post has already been Publicized via the selected
453
	 * connections.
454
	 */
455
	function save_publicized( $post_ID, $post, $update ) {
456
		// Only do this when a post transitions to being published
457
		if ( get_post_meta( $post->ID, $this->PENDING ) && $this->post_type_is_publicizeable( $post->post_type ) ) {
458
			$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
459
			if ( ! empty( $connected_services ) ) {
460
				/**
461
				 * Fires when a post is saved that has is marked as pending publicizing
462
				 *
463
				 * @since 4.1.0
464
				 *
465
				 * @param int The post ID
466
				 */
467
				do_action_deprecated( 'jetpack_publicize_post', $post->ID, '4.8.0', 'jetpack_published_post_flags' );
468
			}
469
			delete_post_meta( $post->ID, $this->PENDING );
470
			update_post_meta( $post->ID, $this->POST_DONE . 'all', true );
471
		}
472
	}
473
474
	function set_post_flags( $flags, $post ) {
475
		$flags['publicize_post'] = false;
476
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
477
			return $flags;
478
		}
479
		/** This filter is already documented in modules/publicize/publicize-jetpack.php */
480
		if ( ! apply_filters( 'publicize_should_publicize_published_post', true, $post ) ) {
481
			return $flags;
482
		}
483
484
		$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
485
486
		if ( empty( $connected_services ) ) {
487
			return $flags;
488
		}
489
490
		$flags['publicize_post'] = true;
491
492
		return $flags;
493
	}
494
495
	/**
496
	 * Options Code
497
	 */
498
499
	function options_page_facebook() {
500
		$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
501
		$connection         = $connected_services['facebook'][ $_REQUEST['connection'] ];
502
		$options_to_show    = ( ! empty( $connection['connection_data']['meta']['options_responses'] ) ? $connection['connection_data']['meta']['options_responses'] : false );
503
504
		// Nonce check
505
		check_admin_referer( 'options_page_facebook_' . $_REQUEST['connection'] );
506
507
		$me    = ( ! empty( $options_to_show[0] ) ? $options_to_show[0] : false );
508
		$pages = ( ! empty( $options_to_show[1]['data'] ) ? $options_to_show[1]['data'] : false );
509
510
		$profile_checked = true;
511
		$page_selected   = false;
512
513
		if ( ! empty( $connection['connection_data']['meta']['facebook_page'] ) ) {
514
			$found = false;
515
			if ( is_array( $pages->data ) ) {
516
				foreach ( $pages->data as $page ) {
517
					if ( $page->id == $connection['connection_data']['meta']['facebook_page'] ) {
518
						$found = true;
519
						break;
520
					}
521
				}
522
			}
523
524
			if ( $found ) {
525
				$profile_checked = false;
526
				$page_selected   = $connection['connection_data']['meta']['facebook_page'];
527
			}
528
		}
529
530
		?>
531
532
		<div id="thickbox-content">
533
534
			<?php
535
			ob_start();
536
			Publicize_UI::connected_notice( 'Facebook' );
537
			$update_notice = ob_get_clean();
538
539
			if ( ! empty( $update_notice ) ) {
540
				echo $update_notice;
541
			}
542
			?>
543
544
			<?php if ( ! empty( $me['name'] ) ) : ?>
545
				<p><?php _e( 'Publicize to my <strong>Facebook Wall</strong>:', 'jetpack' ); ?></p>
546
				<table id="option-profile">
547
					<tbody>
548
					<tr>
549
						<td class="radio"><input type="radio" name="option" data-type="profile"
550
						                         id="<?php echo esc_attr( $me['id'] ) ?>"
551
						                         value="" <?php checked( $profile_checked, true ); ?> /></td>
552
						<td class="thumbnail"><label for="<?php echo esc_attr( $me['id'] ) ?>"><img
553
									src="<?php echo esc_url( $me['picture']['data']['url'] ) ?>" width="50"
554
									height="50"/></label></td>
555
						<td class="details"><label
556
								for="<?php echo esc_attr( $me['id'] ) ?>"><?php echo esc_html( $me['name'] ) ?></label>
557
						</td>
558
					</tr>
559
					</tbody>
560
				</table>
561
			<?php endif; ?>
562
563
			<?php if ( $pages ) : ?>
564
565
				<p><?php _e( 'Publicize to my <strong>Facebook Page</strong>:', 'jetpack' ); ?></p>
566
				<table id="option-fb-fanpage">
567
					<tbody>
568
569
					<?php foreach ( $pages as $i => $page ) : ?>
570
						<?php if ( ! ( $i % 2 ) ) : ?>
571
							<tr>
572
						<?php endif; ?>
573
						<td class="radio"><input type="radio" name="option" data-type="page"
574
						                         id="<?php echo esc_attr( $page['id'] ) ?>"
575
						                         value="<?php echo esc_attr( $page['id'] ) ?>" <?php checked( $page_selected && $page_selected == $page['id'], true ); ?> />
576
						</td>
577
						<td class="thumbnail"><label for="<?php echo esc_attr( $page['id'] ) ?>"><img
578
									src="<?php echo esc_url( str_replace( '_s', '_q', $page['picture']['data']['url'] ) ) ?>"
579
									width="50" height="50"/></label></td>
580
						<td class="details">
581
							<label for="<?php echo esc_attr( $page['id'] ) ?>">
582
								<span class="name"><?php echo esc_html( $page['name'] ) ?></span><br/>
583
								<span class="category"><?php echo esc_html( $page['category'] ) ?></span>
584
							</label>
585
						</td>
586
						<?php if ( ( $i % 2 ) || ( $i == count( $pages ) - 1 ) ): ?>
587
							</tr>
588
						<?php endif; ?>
589
					<?php endforeach; ?>
590
591
					</tbody>
592
				</table>
593
594
			<?php endif; ?>
595
596
			<?php Publicize_UI::global_checkbox( 'facebook', $_REQUEST['connection'] ); ?>
597
598
			<p style="text-align: center;">
599
				<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
600
				       class="button fb-options save-options" name="save"
601
				       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
602
				       rel="<?php echo wp_create_nonce( 'save_fb_token_' . $_REQUEST['connection'] ) ?>"/>
603
			</p><br/>
604
		</div>
605
606
		<?php
607
	}
608
609
	function options_save_facebook() {
610
		// Nonce check
611
		check_admin_referer( 'save_fb_token_' . $_REQUEST['connection'] );
612
613
		$id = $_POST['connection'];
614
615
		// Check for a numeric page ID
616
		$page_id = $_POST['selected_id'];
617
		if ( ! ctype_digit( $page_id ) ) {
618
			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...
619
		}
620
621
		if ( isset( $_POST['selected_id'] ) && 'profile' == $_POST['type'] ) {
622
			// Publish to User Wall/Profile
623
			$options = array(
624
				'facebook_page'    => null,
625
				'facebook_profile' => true
626
			);
627
628
		} else {
629
			if ( 'page' != $_POST['type'] || ! isset( $_POST['selected_id'] ) ) {
630
				return;
631
			}
632
633
			// Publish to Page
634
			$options = array(
635
				'facebook_page'    => $page_id,
636
				'facebook_profile' => null
637
			);
638
		}
639
640
		Jetpack::load_xml_rpc_client();
641
		$xml = new Jetpack_IXR_Client();
642
		$xml->query( 'jetpack.setPublicizeOptions', $id, $options );
643
644
		if ( ! $xml->isError() ) {
645
			$response = $xml->getResponse();
646
			Jetpack_Options::update_option( 'publicize_connections', $response );
647
		}
648
649
		$this->globalization();
650
	}
651
652
	function options_page_tumblr() {
653
		// Nonce check
654
		check_admin_referer( 'options_page_tumblr_' . $_REQUEST['connection'] );
655
656
		$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
657
		$connection         = $connected_services['tumblr'][ $_POST['connection'] ];
658
		$options_to_show    = $connection['connection_data']['meta']['options_responses'];
659
		$request            = $options_to_show[0];
660
661
		$blogs = $request['response']['user']['blogs'];
662
663
		$blog_selected = false;
664
665
		if ( ! empty( $connection['connection_data']['meta']['tumblr_base_hostname'] ) ) {
666
			foreach ( $blogs as $blog ) {
667
				if ( $connection['connection_data']['meta']['tumblr_base_hostname'] == $this->get_basehostname( $blog['url'] ) ) {
668
					$blog_selected = $connection['connection_data']['meta']['tumblr_base_hostname'];
669
					break;
670
				}
671
			}
672
673
		}
674
675
		// Use their Primary blog if they haven't selected one yet
676
		if ( ! $blog_selected ) {
677
			foreach ( $blogs as $blog ) {
678
				if ( $blog['primary'] ) {
679
					$blog_selected = $this->get_basehostname( $blog['url'] );
680
				}
681
			}
682
		} ?>
683
684
		<div id="thickbox-content">
685
686
			<?php
687
			ob_start();
688
			Publicize_UI::connected_notice( 'Tumblr' );
689
			$update_notice = ob_get_clean();
690
691
			if ( ! empty( $update_notice ) ) {
692
				echo $update_notice;
693
			}
694
			?>
695
696
			<p><?php _e( 'Publicize to my <strong>Tumblr blog</strong>:', 'jetpack' ); ?></p>
697
698
			<ul id="option-tumblr-blog">
699
700
				<?php
701
				foreach ( $blogs as $blog ) {
702
					$url = $this->get_basehostname( $blog['url'] ); ?>
703
					<li>
704
						<input type="radio" name="option" data-type="blog" id="<?php echo esc_attr( $url ) ?>"
705
						       value="<?php echo esc_attr( $url ) ?>" <?php checked( $blog_selected == $url, true ); ?> />
706
						<label for="<?php echo esc_attr( $url ) ?>"><span
707
								class="name"><?php echo esc_html( $blog['title'] ) ?></span></label>
708
					</li>
709
				<?php } ?>
710
711
			</ul>
712
713
			<?php Publicize_UI::global_checkbox( 'tumblr', $_REQUEST['connection'] ); ?>
714
715
			<p style="text-align: center;">
716
				<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
717
				       class="button tumblr-options save-options" name="save"
718
				       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
719
				       rel="<?php echo wp_create_nonce( 'save_tumblr_blog_' . $_REQUEST['connection'] ) ?>"/>
720
			</p> <br/>
721
		</div>
722
723
		<?php
724
	}
725
726
	function get_basehostname( $url ) {
727
		return parse_url( $url, PHP_URL_HOST );
728
	}
729
730
	function options_save_tumblr() {
731
		// Nonce check
732
		check_admin_referer( 'save_tumblr_blog_' . $_REQUEST['connection'] );
733
734
		$id = $_POST['connection'];
735
736
		$options = array( 'tumblr_base_hostname' => $_POST['selected_id'] );
737
738
		Jetpack::load_xml_rpc_client();
739
		$xml = new Jetpack_IXR_Client();
740
		$xml->query( 'jetpack.setPublicizeOptions', $id, $options );
741
742
		if ( ! $xml->isError() ) {
743
			$response = $xml->getResponse();
744
			Jetpack_Options::update_option( 'publicize_connections', $response );
745
		}
746
747
		$this->globalization();
748
	}
749
750
	function options_page_twitter() {
751
		Publicize_UI::options_page_other( 'twitter' );
752
	}
753
754
	function options_page_linkedin() {
755
		Publicize_UI::options_page_other( 'linkedin' );
756
	}
757
758
	function options_page_path() {
759
		Publicize_UI::options_page_other( 'path' );
760
	}
761
762
	function options_page_google_plus() {
763
		Publicize_UI::options_page_other( 'google_plus' );
764
	}
765
766
	function options_save_twitter() {
767
		$this->options_save_other( 'twitter' );
768
	}
769
770
	function options_save_linkedin() {
771
		$this->options_save_other( 'linkedin' );
772
	}
773
774
	function options_save_path() {
775
		$this->options_save_other( 'path' );
776
	}
777
778
	function options_save_google_plus() {
779
		$this->options_save_other( 'google_plus' );
780
	}
781
782
	function options_save_other( $service_name ) {
783
		// Nonce check
784
		check_admin_referer( 'save_' . $service_name . '_token_' . $_REQUEST['connection'] );
785
		$this->globalization();
786
	}
787
788
	/**
789
	 * Already-published posts should not be Publicized by default. This filter sets checked to
790
	 * false if a post has already been published.
791
	 */
792
	function publicize_checkbox_default( $checked, $post_id, $name, $connection ) {
793
		if ( 'publish' == get_post_status( $post_id ) ) {
794
			return false;
795
		}
796
797
		return $checked;
798
	}
799
800
	/**
801
	 * If there's only one shared connection to Twitter set it as twitter:site tag.
802
	 */
803
	function enhaced_twitter_cards_site_tag( $tag ) {
804
		$custom_site_tag = get_option( 'jetpack-twitter-cards-site-tag' );
805
		if ( ! empty( $custom_site_tag ) ) {
806
			return $tag;
807
		}
808
		if ( ! $this->is_enabled( 'twitter' ) ) {
809
			return $tag;
810
		}
811
		$connections = $this->get_connections( 'twitter' );
812
		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...
813
			$connection_meta = $this->get_connection_meta( $connection );
814
			if ( 0 == $connection_meta['connection_data']['user_id'] ) {
815
				// If the connection is shared
816
				return $this->get_display_name( 'twitter', $connection );
817
			}
818
		}
819
820
		return $tag;
821
	}
822
823
	function save_publicized_twitter_account( $submit_post, $post_id, $service_name, $connection ) {
824
		if ( 'twitter' == $service_name && $submit_post ) {
825
			$connection_meta        = $this->get_connection_meta( $connection );
826
			$publicize_twitter_user = get_post_meta( $post_id, '_publicize_twitter_user' );
827
			if ( empty( $publicize_twitter_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
828
				update_post_meta( $post_id, '_publicize_twitter_user', $this->get_display_name( 'twitter', $connection ) );
829
			}
830
		}
831
	}
832
833
	function get_publicized_twitter_account( $account, $post_id ) {
834
		if ( ! empty( $account ) ) {
835
			return $account;
836
		}
837
		$account = get_post_meta( $post_id, '_publicize_twitter_user', true );
838
		if ( ! empty( $account ) ) {
839
			return $account;
840
		}
841
842
		return '';
843
	}
844
845
	/**
846
	 * Save the Publicized Facebook account when publishing a post
847
	 * Use only Personal accounts, not Facebook Pages
848
	 */
849
	function save_publicized_facebook_account( $submit_post, $post_id, $service_name, $connection ) {
850
		$connection_meta = $this->get_connection_meta( $connection );
851
		if ( 'facebook' == $service_name && isset( $connection_meta['connection_data']['meta']['facebook_profile'] ) && $submit_post ) {
852
			$publicize_facebook_user = get_post_meta( $post_id, '_publicize_facebook_user' );
853
			if ( empty( $publicize_facebook_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
854
				$profile_link = $this->get_profile_link( 'facebook', $connection );
855
856
				if ( false !== $profile_link ) {
857
					update_post_meta( $post_id, '_publicize_facebook_user', $profile_link );
858
				}
859
			}
860
		}
861
	}
862
}
863