Completed
Push — update/publicize-decouple-ui ( 2d53c3 )
by
unknown
39:23 queued 27:56
created

Publicize::get_connection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 4
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
					<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_all_connections_for_user() {
142
		$connections = Jetpack_Options::get_option( 'publicize_connections' );
143
144
		$connections_to_return = array();
145
		if ( ! empty( $connections ) ) {
146
			foreach ( (array) $connections as $service_name => $connections_for_service ) {
147
				foreach ( $connections_for_service as $id => $connection ) {
148
					$user_id = intval( $connection['connection_data']['user_id'] );
149
					// phpcs:ignore WordPress.PHP.YodaConditions.NotYoda
150
					if ( $user_id === 0 || $this->user_id() === $user_id ) {
151
						$connections_to_return[ $service_name ][ $id ] = $connection;
152
					}
153
				}
154
			}
155
156
			return $connections_to_return;
157
		}
158
159
		return false;
160
	}
161
162
	function get_connection_id( $connection ) {
163
		return $connection['connection_data']['id'];
164
	}
165
166
	function get_connection_meta( $connection ) {
167
		$connection['user_id'] = $connection['connection_data']['user_id']; // Allows for shared connections
168
		return $connection;
169
	}
170
171
	function admin_page_load() {
172
		if ( isset( $_GET['action'] ) ) {
173
			if ( isset( $_GET['service'] ) ) {
174
				$service_name = $_GET['service'];
175
			}
176
177
			switch ( $_GET['action'] ) {
178
				case 'error':
179
					add_action( 'pre_admin_screen_sharing', array( $this, 'display_connection_error' ), 9 );
180
					break;
181
182
				case 'request':
183
					check_admin_referer( 'keyring-request', 'kr_nonce' );
184
					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...
185
186
					$verification = Jetpack::generate_secrets( 'publicize' );
187
					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...
188
						$url = Jetpack::admin_url( 'jetpack#/settings' );
189
						wp_die( sprintf( __( "Jetpack is not connected. Please connect Jetpack by visiting <a href='%s'>Settings</a>.", 'jetpack' ), $url ) );
190
191
					}
192
					$stats_options = get_option( 'stats_options' );
193
					$wpcom_blog_id = Jetpack_Options::get_option( 'id' );
194
					$wpcom_blog_id = ! empty( $wpcom_blog_id ) ? $wpcom_blog_id : $stats_options['blog_id'];
195
196
					$user     = wp_get_current_user();
197
					$redirect = $this->api_url( $service_name, urlencode_deep( array(
198
						'action'       => 'request',
199
						'redirect_uri' => add_query_arg( array( 'action' => 'done' ), menu_page_url( 'sharing', false ) ),
200
						'for'          => 'publicize',
201
						// required flag that says this connection is intended for publicize
202
						'siteurl'      => site_url(),
203
						'state'        => $user->ID,
204
						'blog_id'      => $wpcom_blog_id,
205
						'secret_1'     => $verification['secret_1'],
206
						'secret_2'     => $verification['secret_2'],
207
						'eol'          => $verification['exp'],
208
					) ) );
209
					wp_redirect( $redirect );
210
					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...
211
					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...
212
213
				case 'completed':
214
					Jetpack::load_xml_rpc_client();
215
					$xml = new Jetpack_IXR_Client();
216
					$xml->query( 'jetpack.fetchPublicizeConnections' );
217
218
					if ( ! $xml->isError() ) {
219
						$response = $xml->getResponse();
220
						Jetpack_Options::update_option( 'publicize_connections', $response );
221
					}
222
223
					break;
224
225
				case 'delete':
226
					$id = $_GET['id'];
227
228
					check_admin_referer( 'keyring-request', 'kr_nonce' );
229
					check_admin_referer( "keyring-request-$service_name", 'nonce' );
230
231
					$this->disconnect( $service_name, $id );
232
233
					add_action( 'admin_notices', array( $this, 'display_disconnected' ) );
234
					break;
235
			}
236
		}
237
238
		// Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
239
		// Errors encountered on WordPress.com's end are passed back as a code
240
		/*
241
		if ( isset( $_GET['action'] ) && 'error' == $_GET['action'] ) {
242
			// Load Jetpack's styles to handle the box
243
			Jetpack::init()->admin_styles();
244
		}
245
		*/
246
	}
247
248
	function display_connection_error() {
249
		$code = false;
250
		if ( isset( $_GET['service'] ) ) {
251
			$service_name = $_GET['service'];
252
			$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 ) );
253
		} else {
254
			if ( isset( $_GET['publicize_error'] ) ) {
255
				$code = strtolower( $_GET['publicize_error'] );
256
				switch ( $code ) {
257
					case '400':
258
						$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' );
259
						break;
260
					case 'secret_mismatch':
261
						$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' );
262
						break;
263
					case 'empty_blog_id':
264
						$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' );
265
						break;
266
					case 'empty_state':
267
						$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() );
268
						break;
269
					default:
270
						$error = __( 'Something which should never happen, happened. Sorry about that. If you try again, maybe it will work.', 'jetpack' );
271
						break;
272
				}
273
			} else {
274
				$error = __( 'There was a problem connecting with Publicize. Please try again in a moment.', 'jetpack' );
275
			}
276
		}
277
		// Using the same formatting/style as Jetpack::admin_notices() error
278
		?>
279
		<div id="message" class="jetpack-message jetpack-err">
280
			<div class="squeezer">
281
				<h2><?php echo wp_kses( $error, array( 'a'      => array( 'href' => true ),
282
				                                       'code'   => true,
283
				                                       'strong' => true,
284
				                                       'br'     => true,
285
				                                       'b'      => true
286
					) ); ?></h2>
287
				<?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...
288
					<p><?php printf( __( 'Error code: %s', 'jetpack' ), esc_html( stripslashes( $code ) ) ); ?></p>
289
				<?php endif; ?>
290
			</div>
291
		</div>
292
		<?php
293
	}
294
295
	function display_disconnected() {
296
		echo "<div class='updated'>\n";
297
		echo '<p>' . esc_html( __( 'That connection has been removed.', 'jetpack' ) ) . "</p>\n";
298
		echo "</div>\n\n";
299
	}
300
301
	function globalization() {
302
		if ( 'on' == $_REQUEST['global'] ) {
303
			$id = $_REQUEST['connection'];
304
305
			if ( ! current_user_can( $this->GLOBAL_CAP ) ) {
306
				return;
307
			}
308
309
			Jetpack::load_xml_rpc_client();
310
			$xml = new Jetpack_IXR_Client();
311
			$xml->query( 'jetpack.globalizePublicizeConnection', $id, 'globalize' );
312
313
			if ( ! $xml->isError() ) {
314
				$response = $xml->getResponse();
315
				Jetpack_Options::update_option( 'publicize_connections', $response );
316
			}
317
		}
318
	}
319
320
	/**
321
	 * Gets a URL to the public-api actions. Works like WP's admin_url
322
	 *
323
	 * @param string $service Shortname of a specific service.
324
	 *
325
	 * @return URL to specific public-api process
326
	 */
327
	// on WordPress.com this is/calls Keyring::admin_url
328
	function api_url( $service = false, $params = array() ) {
329
		/**
330
		 * Filters the API URL used to interact with WordPress.com.
331
		 *
332
		 * @module publicize
333
		 *
334
		 * @since 2.0.0
335
		 *
336
		 * @param string https://public-api.wordpress.com/connect/?jetpack=publicize Default Publicize API URL.
337
		 */
338
		$url = apply_filters( 'publicize_api_url', 'https://public-api.wordpress.com/connect/?jetpack=publicize' );
339
340
		if ( $service ) {
341
			$url = add_query_arg( array( 'service' => $service ), $url );
342
		}
343
344
		if ( count( $params ) ) {
345
			$url = add_query_arg( $params, $url );
346
		}
347
348
		return $url;
349
	}
350
351 View Code Duplication
	function connect_url( $service_name ) {
352
		return add_query_arg( array(
353
			'action'   => 'request',
354
			'service'  => $service_name,
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
	function refresh_url( $service_name ) {
361
		return add_query_arg( array(
362
			'action'   => 'request',
363
			'service'  => $service_name,
364
			'kr_nonce' => wp_create_nonce( 'keyring-request' ),
365
			'refresh'  => 1,
366
			'for'      => 'publicize',
367
			'nonce'    => wp_create_nonce( "keyring-request-$service_name" ),
368
		), admin_url( 'options-general.php?page=sharing' ) );
369
	}
370
371 View Code Duplication
	function disconnect_url( $service_name, $id ) {
372
		return add_query_arg( array(
373
			'action'   => 'delete',
374
			'service'  => $service_name,
375
			'id'       => $id,
376
			'kr_nonce' => wp_create_nonce( 'keyring-request' ),
377
			'nonce'    => wp_create_nonce( "keyring-request-$service_name" ),
378
		), menu_page_url( 'sharing', false ) );
379
	}
380
381
	/**
382
	 * Get social networks, either all available or only those that the site is connected to.
383
	 *
384
	 * @since 2.0
385
	 *
386
	 * @param string $filter Select the list of services that will be returned. Defaults to 'all', accepts 'connected'.
387
	 *
388
	 * @return array List of social networks.
389
	 */
390
	function get_services( $filter = 'all' ) {
391
		$services = array(
392
			'facebook'    => array(),
393
			'twitter'     => array(),
394
			'linkedin'    => array(),
395
			'tumblr'      => array(),
396
			'path'        => array(),
397
			'google_plus' => array(),
398
		);
399
400
		if ( 'all' == $filter ) {
401
			return $services;
402
		} else {
403
			$connected_services = array();
404
			foreach ( $services as $service => $empty ) {
405
				$connections = $this->get_connections( $service );
406
				if ( $connections ) {
407
					$connected_services[ $service ] = $connections;
408
				}
409
			}
410
			return $connected_services;
411
		}
412
	}
413
414
	/**
415
	 * Retrieves current list of connections and applies filters.
416
	 *
417
	 * Retrieves current available connections and checks if the connections
418
	 * have already been used to share current post. Finally, the checkbox
419
	 * form UI fields are calculated. This function exposes connection form
420
	 * data directly as array so it can be retrieved for static HTML generation
421
	 * or JSON consumption.
422
	 *
423
	 * @since 6.2.0
424
	 *
425
	 * @param integer $selected_post_id Optional. Post ID to query connection status for.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $selected_post_id not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
426
	 *
427
	 * @return array {
428
	 *     Array of UI setup data for connection list form.
429
	 *
430
	 *     @type string 'unique_id'       ID string representing connection
431
	 *     @type bool   'checked'         Default value of checkbox for connection.
432
	 *     @type bool   'disabled'        String of HTML disabled property of checkbox. Empty if not disabled.
433
	 *     @type bool   'active'          True if connection is not skipped by filters and is not already done.
434
	 *     @type bool   'hidden_checkbox' True if the connection should not be shared to by current user.
435
	 *     @type string 'label'           Text description of checkbox.
436
	 *     @type string 'display_name'    Username for sharing account.
437
	 * }
438
	 */
439
	public function get_filtered_connection_data( $selected_post_id = null ) {
440
		$connection_list = array();
441
442
		$post = get_post( $selected_post_id ); // Defaults to current post if $post_id is null.
443
		// Handle case where there is no current post.
444
		if ( ! empty( $post ) ) {
445
			$post_id = $post->ID;
446
		} else {
447
			$post_id = null;
448
		}
449
450
		$services = $this->get_services( 'connected' );
451
		$all_done = $this->done_sharing_post( $post_id );
452
453
		// We don't allow Publicizing to the same external id twice, to prevent spam.
454
		$service_id_done = (array) get_post_meta( $post_id, $this->POST_SERVICE_DONE, true );
455
456
		foreach ( $services as $name => $connections ) {
457
			foreach ( $connections as $connection ) {
458
				$connection_data = '';
459 View Code Duplication
				if ( method_exists( $connection, 'get_meta' ) ) {
460
					$connection_data = $connection->get_meta( 'connection_data' );
461
				} elseif ( ! empty( $connection['connection_data'] ) ) {
462
					$connection_data = $connection['connection_data'];
463
				}
464
465
				/**
466
				 * Filter whether a post should be publicized to a given service.
467
				 *
468
				 * @module publicize
469
				 *
470
				 * @since 2.0.0
471
				 *
472
				 * @param bool true Should the post be publicized to a given service? Default to true.
473
				 * @param int $post_id Post ID.
474
				 * @param string $name Service name.
475
				 * @param array $connection_data Array of information about all Publicize details for the site.
476
				 */
477
				if ( ! apply_filters( 'wpas_submit_post?', true, $post_id, $name, $connection_data ) ) {
478
					continue;
479
				}
480
481 View Code Duplication
				if ( ! empty( $connection->unique_id ) ) {
482
					$unique_id = $connection->unique_id;
483
				} elseif ( ! empty( $connection['connection_data']['token_id'] ) ) {
484
					$unique_id = $connection['connection_data']['token_id'];
485
				}
486
487
				// Should we be skipping this one?
488
				$skip = (
489
					(
490
						! empty( $post )
491
						&&
492
						in_array( $post->post_status, array( 'publish', 'draft', 'future' ) )
493
						&&
494
						get_post_meta( $post_id, $this->POST_SKIP . $unique_id, true )
0 ignored issues
show
Bug introduced by
The variable $unique_id 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...
495
					)
496
					||
497
					(
498
						is_array( $connection )
499
						&&
500
						(
501
							(
502
									isset( $connection['meta']['external_id'] )
503
									&&
504
									! empty( $service_id_done[ $name ][ $connection['meta']['external_id'] ] )
505
							)
506
							||
507
							// Jetpack's connection data looks a little different.
508
							(
509
									isset( $connection['external_id'] )
510
									&&
511
									! empty( $service_id_done[ $name ][ $connection['external_id'] ] )
512
							)
513
						)
514
					)
515
				);
516
517
				// Was this connections (OR, old-format service) already Publicized to.
518
				$done = (
519
							( 1 == get_post_meta( $post_id, $this->POST_DONE . $unique_id, true ) )
520
							||
521
							( 1 == get_post_meta( $post_id, $this->POST_DONE . $name, true ) )
522
				); // New and old style flags.
523
524
				// If this one has already been publicized to, don't let it happen again.
525
				$disabled = false;
526
				if ( $done ) {
527
					$disabled = true;
528
				}
529
530
				/**
531
				 * If this is a global connection and this user doesn't have enough permissions to modify
532
				 * those connections, don't let them change it.
533
				 */
534
				$cmeta           = $this->get_connection_meta( $connection );
535
				$hidden_checkbox = false;
536
				if ( ! $done && ( 0 == $cmeta['connection_data']['user_id'] && ! current_user_can( $this->GLOBAL_CAP ) ) ) {
537
					$disabled = true;
538
					/**
539
					 * Filters the checkboxes for global connections with non-prilvedged users.
540
					 *
541
					 * @module publicize
542
					 *
543
					 * @since 3.7.0
544
					 *
545
					 * @param bool   $checked Indicates if this connection should be enabled. Default true.
546
					 * @param int    $post_id ID of the current post
547
					 * @param string $name Name of the connection (Facebook, Twitter, etc)
548
					 * @param array  $connection Array of data about the connection.
549
					 */
550
					$hidden_checkbox = apply_filters( 'publicize_checkbox_global_default', true, $post_id, $name, $connection );
551
				}
552
553
				// Determine the state of the checkbox (on/off) and allow filtering.
554
				$checked = ( ( 1 != $skip ) || $done );
555
				/**
556
				 * Filter the checkbox state of each Publicize connection appearing in the post editor.
557
				 *
558
				 * @module publicize
559
				 *
560
				 * @since 2.0.1
561
				 *
562
				 * @param bool $checked Should the Publicize checkbox be enabled for a given service.
563
				 * @param int $post_id Post ID.
564
				 * @param string $name Service name.
565
				 * @param array $connection Array of connection details.
566
				 */
567
				$checked = apply_filters( 'publicize_checkbox_default', $checked, $post_id, $name, $connection );
568
569
				// Force the checkbox to be checked if the post was DONE, regardless of what the filter does.
570
				if ( $done ) {
571
					$checked = true;
572
				}
573
574
				// This post has been handled, so disable everything.
575
				if ( $all_done ) {
576
					$disabled = true;
577
				}
578
579
				$label  = sprintf(
580
					_x( '%1$s: %2$s', 'Service: Account connected as', 'jetpack' ),
581
					esc_html( $this->get_service_label( $name ) ),
582
					esc_html( $this->get_display_name( $name, $connection ) )
583
				);
584
				$active = ! $skip || $done;
585
586
				$connection_list[] = array(
587
					'unique_id'       => $unique_id,
588
					'name'            => $name,
589
					'checked'         => $checked,
590
					'disabled'        => $disabled,
591
					'active'          => $active,
592
					'hidden_checkbox' => $hidden_checkbox,
593
					'label'           => esc_html( $label ),
594
					'display_name'    => $this->get_display_name( $name, $connection ),
595
				);
596
			}
597
		}
598
599
		return $connection_list;
600
	}
601
602
	/**
603
	 * Checks if post has already been shared by Publicize in the past.
604
	 *
605
	 * We can set an _all flag to indicate that this post is completely done as
606
	 * far as Publicize is concerned. Jetpack uses this approach. All published posts in Jetpack
607
	 * have Publicize disabled.
608
	 *
609
	 * @since 6.2.0
610
	 *
611
	 * @global Publicize_UI $publicize_ui UI instance that contains the 'in_jetpack' property
612
	 *
613
	 * @param integer $post_id Optional. Post ID to query connection status for: will use current post if missing.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $post_id not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
614
	 *
615
	 * @return bool True if post has already been shared by Publicize, false otherwise.
616
	 */
617
	public function done_sharing_post( $post_id = null ) {
618
		global $publicize_ui;
619
		$post = get_post( $post_id ); // Defaults to current post if $post_id is null.
620
		if ( is_null( $post ) ) {
621
			return false;
622
		}
623
		return get_post_meta( $post->ID, $this->POST_DONE . 'all', true ) || ( $publicize_ui->in_jetpack && 'publish' == $post->post_status );
624
	}
625
626
	/**
627
	 * Retrieves full list of available Publicize connection services.
628
	 *
629
	 * Retrieves current available publicize service connections
630
	 * with associated labels and URLs.
631
	 *
632
	 * @since 6.2.0
633
	 *
634
	 * @return array {
635
	 *     Array of UI service connection data for all services
636
	 *
637
	 *     @type string 'name'  Name of service.
638
	 *     @type string 'label' Display label for service.
639
	 *     @type string 'url'   URL for adding connection to service.
640
	 * }
641
	 */
642
	function get_available_service_data() {
643
		$available_services     = $this->get_services( 'all' );
644
		$available_service_data = array();
645
646
		foreach ( $available_services as $service_name => $service ) {
647
			$available_service_data[] = array(
648
				'name'  => $service_name,
649
				'label' => $this->get_service_label( $service_name ),
650
				'url'   => $this->connect_url( $service_name ),
651
			);
652
		}
653
654
		return $available_service_data;
655
	}
656
657
	function get_connection( $service, $id, $_blog_id = false, $_user_id = false ) {
658
		// Stub
659
	}
660
661
	function flag_post_for_publicize( $new_status, $old_status, $post ) {
662
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
663
			return;
664
		}
665
666
		if ( 'publish' == $new_status && 'publish' != $old_status ) {
667
			/**
668
			 * Determines whether a post being published gets publicized.
669
			 *
670
			 * Side-note: Possibly our most alliterative filter name.
671
			 *
672
			 * @module publicize
673
			 *
674
			 * @since 4.1.0
675
			 *
676
			 * @param bool $should_publicize Should the post be publicized? Default to true.
677
			 * @param WP_POST $post Current Post object.
678
			 */
679
			$should_publicize = apply_filters( 'publicize_should_publicize_published_post', true, $post );
680
681
			if ( $should_publicize ) {
682
				update_post_meta( $post->ID, $this->PENDING, true );
683
			}
684
		}
685
	}
686
687
	function test_connection( $service_name, $connection ) {
688
		$connection_test_passed  = true;
689
		$connection_test_message = '';
690
		$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...
691
692
		$id = $this->get_connection_id( $connection );
693
694
		Jetpack::load_xml_rpc_client();
695
		$xml = new Jetpack_IXR_Client();
696
		$xml->query( 'jetpack.testPublicizeConnection', $id );
697
698
		if ( $xml->isError() ) {
699
			$xml_response            = $xml->getResponse();
700
			$connection_test_message = $xml_response['faultString'];
701
			$connection_test_passed  = false;
702
		}
703
704
		// Bail if all is well
705
		if ( $connection_test_passed ) {
706
			return true;
707
		}
708
709
		// Set up refresh if the user can
710
		$user_can_refresh = current_user_can( $this->GLOBAL_CAP );
711
		if ( $user_can_refresh ) {
712
			$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...
713
			$refresh_text = sprintf( _x( 'Refresh connection with %s', 'Refresh connection with {social media service}', 'jetpack' ), $this->get_service_label( $service_name ) );
714
			$refresh_url  = $this->refresh_url( $service_name );
715
		}
716
717
		$error_data = array(
718
			'user_can_refresh' => $user_can_refresh,
719
			'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...
720
			'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...
721
		);
722
723
		return new WP_Error( 'pub_conn_test_failed', $connection_test_message, $error_data );
724
	}
725
726
	/**
727
	 * Save a flag locally to indicate that this post has already been Publicized via the selected
728
	 * connections.
729
	 */
730
	function save_publicized( $post_ID, $post = null, $update = null ) {
731
		if ( is_null( $post ) ) {
732
			return;
733
		}
734
		// Only do this when a post transitions to being published
735
		if ( get_post_meta( $post->ID, $this->PENDING ) && $this->post_type_is_publicizeable( $post->post_type ) ) {
736
			$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
737
			if ( ! empty( $connected_services ) ) {
738
				/**
739
				 * Fires when a post is saved that has is marked as pending publicizing
740
				 *
741
				 * @since 4.1.0
742
				 *
743
				 * @param int The post ID
744
				 */
745
				do_action_deprecated( 'jetpack_publicize_post', $post->ID, '4.8.0', 'jetpack_published_post_flags' );
746
			}
747
			delete_post_meta( $post->ID, $this->PENDING );
748
			update_post_meta( $post->ID, $this->POST_DONE . 'all', true );
749
		}
750
	}
751
752
	function set_post_flags( $flags, $post ) {
753
		$flags['publicize_post'] = false;
754
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
755
			return $flags;
756
		}
757
		/** This filter is already documented in modules/publicize/publicize-jetpack.php */
758
		if ( ! apply_filters( 'publicize_should_publicize_published_post', true, $post ) ) {
759
			return $flags;
760
		}
761
762
		$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
763
764
		if ( empty( $connected_services ) ) {
765
			return $flags;
766
		}
767
768
		$flags['publicize_post'] = true;
769
770
		return $flags;
771
	}
772
773
	/**
774
	 * Options Code
775
	 */
776
777
	function options_page_facebook() {
778
		$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
779
		$connection         = $connected_services['facebook'][ $_REQUEST['connection'] ];
780
		$options_to_show    = ( ! empty( $connection['connection_data']['meta']['options_responses'] ) ? $connection['connection_data']['meta']['options_responses'] : false );
781
782
		// Nonce check
783
		check_admin_referer( 'options_page_facebook_' . $_REQUEST['connection'] );
784
785
		$me    = ( ! empty( $options_to_show[0] ) ? $options_to_show[0] : false );
786
		$pages = ( ! empty( $options_to_show[1]['data'] ) ? $options_to_show[1]['data'] : false );
787
788
		$profile_checked = true;
789
		$page_selected   = false;
790
791
		if ( ! empty( $connection['connection_data']['meta']['facebook_page'] ) ) {
792
			$found = false;
793
			if ( $pages && is_array( $pages->data ) ) {
794
				foreach ( $pages->data as $page ) {
795
					if ( $page->id == $connection['connection_data']['meta']['facebook_page'] ) {
796
						$found = true;
797
						break;
798
					}
799
				}
800
			}
801
802
			if ( $found ) {
803
				$profile_checked = false;
804
				$page_selected   = $connection['connection_data']['meta']['facebook_page'];
805
			}
806
		}
807
808
		?>
809
810
		<div id="thickbox-content">
811
812
			<?php
813
			ob_start();
814
			Publicize_UI::connected_notice( 'Facebook' );
815
			$update_notice = ob_get_clean();
816
817
			if ( ! empty( $update_notice ) ) {
818
				echo $update_notice;
819
			}
820
			?>
821
822
			<?php if ( ! empty( $me['name'] ) ) : ?>
823
				<p><?php _e( 'Publicize to my <strong>Facebook Wall</strong>:', 'jetpack' ); ?></p>
824
				<table id="option-profile">
825
					<tbody>
826
					<tr>
827
						<td class="radio"><input type="radio" name="option" data-type="profile"
828
						                         id="<?php echo esc_attr( $me['id'] ) ?>"
829
						                         value="" <?php checked( $profile_checked, true ); ?> /></td>
830
						<td class="thumbnail"><label for="<?php echo esc_attr( $me['id'] ) ?>"><img
831
									src="<?php echo esc_url( $me['picture']['data']['url'] ) ?>" width="50"
832
									height="50"/></label></td>
833
						<td class="details"><label
834
								for="<?php echo esc_attr( $me['id'] ) ?>"><?php echo esc_html( $me['name'] ) ?></label>
835
						</td>
836
					</tr>
837
					</tbody>
838
				</table>
839
			<?php endif; ?>
840
841
			<?php if ( $pages ) : ?>
842
843
				<p><?php _e( 'Publicize to my <strong>Facebook Page</strong>:', 'jetpack' ); ?></p>
844
				<table id="option-fb-fanpage">
845
					<tbody>
846
847
					<?php foreach ( $pages as $i => $page ) : ?>
848
						<?php if ( ! ( $i % 2 ) ) : ?>
849
							<tr>
850
						<?php endif; ?>
851
						<td class="radio"><input type="radio" name="option" data-type="page"
852
						                         id="<?php echo esc_attr( $page['id'] ) ?>"
853
						                         value="<?php echo esc_attr( $page['id'] ) ?>" <?php checked( $page_selected && $page_selected == $page['id'], true ); ?> />
854
						</td>
855
						<td class="thumbnail"><label for="<?php echo esc_attr( $page['id'] ) ?>"><img
856
									src="<?php echo esc_url( str_replace( '_s', '_q', $page['picture']['data']['url'] ) ) ?>"
857
									width="50" height="50"/></label></td>
858
						<td class="details">
859
							<label for="<?php echo esc_attr( $page['id'] ) ?>">
860
								<span class="name"><?php echo esc_html( $page['name'] ) ?></span><br/>
861
								<span class="category"><?php echo esc_html( $page['category'] ) ?></span>
862
							</label>
863
						</td>
864
						<?php if ( ( $i % 2 ) || ( $i == count( $pages ) - 1 ) ): ?>
865
							</tr>
866
						<?php endif; ?>
867
					<?php endforeach; ?>
868
869
					</tbody>
870
				</table>
871
872
			<?php endif; ?>
873
874
			<?php Publicize_UI::global_checkbox( 'facebook', $_REQUEST['connection'] ); ?>
875
876
			<p style="text-align: center;">
877
				<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
878
				       class="button fb-options save-options" name="save"
879
				       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
880
				       rel="<?php echo wp_create_nonce( 'save_fb_token_' . $_REQUEST['connection'] ) ?>"/>
881
			</p><br/>
882
		</div>
883
884
		<?php
885
	}
886
887
	function options_save_facebook() {
888
		// Nonce check
889
		check_admin_referer( 'save_fb_token_' . $_REQUEST['connection'] );
890
891
		$id = $_POST['connection'];
892
893
		// Check for a numeric page ID
894
		$page_id = $_POST['selected_id'];
895
		if ( ! ctype_digit( $page_id ) ) {
896
			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...
897
		}
898
899
		if ( isset( $_POST['selected_id'] ) && 'profile' == $_POST['type'] ) {
900
			// Publish to User Wall/Profile
901
			$options = array(
902
				'facebook_page'    => null,
903
				'facebook_profile' => true
904
			);
905
906
		} else {
907
			if ( 'page' != $_POST['type'] || ! isset( $_POST['selected_id'] ) ) {
908
				return;
909
			}
910
911
			// Publish to Page
912
			$options = array(
913
				'facebook_page'    => $page_id,
914
				'facebook_profile' => null
915
			);
916
		}
917
918
		Jetpack::load_xml_rpc_client();
919
		$xml = new Jetpack_IXR_Client();
920
		$xml->query( 'jetpack.setPublicizeOptions', $id, $options );
921
922
		if ( ! $xml->isError() ) {
923
			$response = $xml->getResponse();
924
			Jetpack_Options::update_option( 'publicize_connections', $response );
925
		}
926
927
		$this->globalization();
928
	}
929
930
	function options_page_tumblr() {
931
		// Nonce check
932
		check_admin_referer( 'options_page_tumblr_' . $_REQUEST['connection'] );
933
934
		$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
935
		$connection         = $connected_services['tumblr'][ $_POST['connection'] ];
936
		$options_to_show    = $connection['connection_data']['meta']['options_responses'];
937
		$request            = $options_to_show[0];
938
939
		$blogs = $request['response']['user']['blogs'];
940
941
		$blog_selected = false;
942
943
		if ( ! empty( $connection['connection_data']['meta']['tumblr_base_hostname'] ) ) {
944
			foreach ( $blogs as $blog ) {
945
				if ( $connection['connection_data']['meta']['tumblr_base_hostname'] == $this->get_basehostname( $blog['url'] ) ) {
946
					$blog_selected = $connection['connection_data']['meta']['tumblr_base_hostname'];
947
					break;
948
				}
949
			}
950
951
		}
952
953
		// Use their Primary blog if they haven't selected one yet
954
		if ( ! $blog_selected ) {
955
			foreach ( $blogs as $blog ) {
956
				if ( $blog['primary'] ) {
957
					$blog_selected = $this->get_basehostname( $blog['url'] );
958
				}
959
			}
960
		} ?>
961
962
		<div id="thickbox-content">
963
964
			<?php
965
			ob_start();
966
			Publicize_UI::connected_notice( 'Tumblr' );
967
			$update_notice = ob_get_clean();
968
969
			if ( ! empty( $update_notice ) ) {
970
				echo $update_notice;
971
			}
972
			?>
973
974
			<p><?php _e( 'Publicize to my <strong>Tumblr blog</strong>:', 'jetpack' ); ?></p>
975
976
			<ul id="option-tumblr-blog">
977
978
				<?php
979
				foreach ( $blogs as $blog ) {
980
					$url = $this->get_basehostname( $blog['url'] ); ?>
981
					<li>
982
						<input type="radio" name="option" data-type="blog" id="<?php echo esc_attr( $url ) ?>"
983
						       value="<?php echo esc_attr( $url ) ?>" <?php checked( $blog_selected == $url, true ); ?> />
984
						<label for="<?php echo esc_attr( $url ) ?>"><span
985
								class="name"><?php echo esc_html( $blog['title'] ) ?></span></label>
986
					</li>
987
				<?php } ?>
988
989
			</ul>
990
991
			<?php Publicize_UI::global_checkbox( 'tumblr', $_REQUEST['connection'] ); ?>
992
993
			<p style="text-align: center;">
994
				<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
995
				       class="button tumblr-options save-options" name="save"
996
				       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
997
				       rel="<?php echo wp_create_nonce( 'save_tumblr_blog_' . $_REQUEST['connection'] ) ?>"/>
998
			</p> <br/>
999
		</div>
1000
1001
		<?php
1002
	}
1003
1004
	function get_basehostname( $url ) {
1005
		return parse_url( $url, PHP_URL_HOST );
1006
	}
1007
1008
	function options_save_tumblr() {
1009
		// Nonce check
1010
		check_admin_referer( 'save_tumblr_blog_' . $_REQUEST['connection'] );
1011
1012
		$id = $_POST['connection'];
1013
1014
		$options = array( 'tumblr_base_hostname' => $_POST['selected_id'] );
1015
1016
		Jetpack::load_xml_rpc_client();
1017
		$xml = new Jetpack_IXR_Client();
1018
		$xml->query( 'jetpack.setPublicizeOptions', $id, $options );
1019
1020
		if ( ! $xml->isError() ) {
1021
			$response = $xml->getResponse();
1022
			Jetpack_Options::update_option( 'publicize_connections', $response );
1023
		}
1024
1025
		$this->globalization();
1026
	}
1027
1028
	function options_page_twitter() {
1029
		Publicize_UI::options_page_other( 'twitter' );
1030
	}
1031
1032
	function options_page_linkedin() {
1033
		Publicize_UI::options_page_other( 'linkedin' );
1034
	}
1035
1036
	function options_page_path() {
1037
		Publicize_UI::options_page_other( 'path' );
1038
	}
1039
1040
	function options_page_google_plus() {
1041
		Publicize_UI::options_page_other( 'google_plus' );
1042
	}
1043
1044
	function options_save_twitter() {
1045
		$this->options_save_other( 'twitter' );
1046
	}
1047
1048
	function options_save_linkedin() {
1049
		$this->options_save_other( 'linkedin' );
1050
	}
1051
1052
	function options_save_path() {
1053
		$this->options_save_other( 'path' );
1054
	}
1055
1056
	function options_save_google_plus() {
1057
		$this->options_save_other( 'google_plus' );
1058
	}
1059
1060
	function options_save_other( $service_name ) {
1061
		// Nonce check
1062
		check_admin_referer( 'save_' . $service_name . '_token_' . $_REQUEST['connection'] );
1063
		$this->globalization();
1064
	}
1065
1066
	/**
1067
	 * Already-published posts should not be Publicized by default. This filter sets checked to
1068
	 * false if a post has already been published.
1069
	 */
1070
	function publicize_checkbox_default( $checked, $post_id, $name, $connection ) {
1071
		if ( 'publish' == get_post_status( $post_id ) ) {
1072
			return false;
1073
		}
1074
1075
		return $checked;
1076
	}
1077
1078
	/**
1079
	 * If there's only one shared connection to Twitter set it as twitter:site tag.
1080
	 */
1081
	function enhaced_twitter_cards_site_tag( $tag ) {
1082
		$custom_site_tag = get_option( 'jetpack-twitter-cards-site-tag' );
1083
		if ( ! empty( $custom_site_tag ) ) {
1084
			return $tag;
1085
		}
1086
		if ( ! $this->is_enabled( 'twitter' ) ) {
1087
			return $tag;
1088
		}
1089
		$connections = $this->get_connections( 'twitter' );
1090
		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...
1091
			$connection_meta = $this->get_connection_meta( $connection );
1092
			if ( 0 == $connection_meta['connection_data']['user_id'] ) {
1093
				// If the connection is shared
1094
				return $this->get_display_name( 'twitter', $connection );
1095
			}
1096
		}
1097
1098
		return $tag;
1099
	}
1100
1101
	function save_publicized_twitter_account( $submit_post, $post_id, $service_name, $connection ) {
1102
		if ( 'twitter' == $service_name && $submit_post ) {
1103
			$connection_meta        = $this->get_connection_meta( $connection );
1104
			$publicize_twitter_user = get_post_meta( $post_id, '_publicize_twitter_user' );
1105
			if ( empty( $publicize_twitter_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
1106
				update_post_meta( $post_id, '_publicize_twitter_user', $this->get_display_name( 'twitter', $connection ) );
1107
			}
1108
		}
1109
	}
1110
1111
	function get_publicized_twitter_account( $account, $post_id ) {
1112
		if ( ! empty( $account ) ) {
1113
			return $account;
1114
		}
1115
		$account = get_post_meta( $post_id, '_publicize_twitter_user', true );
1116
		if ( ! empty( $account ) ) {
1117
			return $account;
1118
		}
1119
1120
		return '';
1121
	}
1122
1123
	/**
1124
	 * Save the Publicized Facebook account when publishing a post
1125
	 * Use only Personal accounts, not Facebook Pages
1126
	 */
1127
	function save_publicized_facebook_account( $submit_post, $post_id, $service_name, $connection ) {
1128
		$connection_meta = $this->get_connection_meta( $connection );
1129
		if ( 'facebook' == $service_name && isset( $connection_meta['connection_data']['meta']['facebook_profile'] ) && $submit_post ) {
1130
			$publicize_facebook_user = get_post_meta( $post_id, '_publicize_facebook_user' );
1131
			if ( empty( $publicize_facebook_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
1132
				$profile_link = $this->get_profile_link( 'facebook', $connection );
1133
1134
				if ( false !== $profile_link ) {
1135
					update_post_meta( $post_id, '_publicize_facebook_user', $profile_link );
1136
				}
1137
			}
1138
		}
1139
	}
1140
}
1141