Completed
Push — try/publicize-gutenberg-block-... ( 851db4...65bce8 )
by Marin
13:02
created

Publicize::options_page_facebook()   D

Complexity

Conditions 17
Paths 144

Size

Total Lines 91

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 17
nc 144
nop 0
dl 0
loc 91
rs 4.0763
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
class Publicize extends Publicize_Base {
4
5
	function __construct() {
6
		parent::__construct();
7
8
		add_filter( 'jetpack_xmlrpc_methods', array( $this, 'register_update_publicize_connections_xmlrpc_method' ) );
9
10
		add_action( 'load-settings_page_sharing', array( $this, 'admin_page_load' ), 9 );
11
12
		add_action( 'wp_ajax_publicize_tumblr_options_page', array( $this, 'options_page_tumblr' ) );
13
		add_action( 'wp_ajax_publicize_facebook_options_page', array( $this, 'options_page_facebook' ) );
14
		add_action( 'wp_ajax_publicize_twitter_options_page', array( $this, 'options_page_twitter' ) );
15
		add_action( 'wp_ajax_publicize_linkedin_options_page', array( $this, 'options_page_linkedin' ) );
16
		add_action( 'wp_ajax_publicize_path_options_page', array( $this, 'options_page_path' ) );
17
		add_action( 'wp_ajax_publicize_google_plus_options_page', array( $this, 'options_page_google_plus' ) );
18
19
		add_action( 'wp_ajax_publicize_tumblr_options_save', array( $this, 'options_save_tumblr' ) );
20
		add_action( 'wp_ajax_publicize_facebook_options_save', array( $this, 'options_save_facebook' ) );
21
		add_action( 'wp_ajax_publicize_twitter_options_save', array( $this, 'options_save_twitter' ) );
22
		add_action( 'wp_ajax_publicize_linkedin_options_save', array( $this, 'options_save_linkedin' ) );
23
		add_action( 'wp_ajax_publicize_path_options_save', array( $this, 'options_save_path' ) );
24
		add_action( 'wp_ajax_publicize_google_plus_options_save', array( $this, 'options_save_google_plus' ) );
25
26
		add_action( 'load-settings_page_sharing', array( $this, 'force_user_connection' ) );
27
28
		add_filter( 'publicize_checkbox_default', array( $this, 'publicize_checkbox_default' ), 10, 4 );
29
30
		add_filter( 'jetpack_published_post_flags', array( $this, 'set_post_flags' ), 10, 2 );
31
32
		add_action( 'wp_insert_post', array( $this, 'save_publicized' ), 11, 3 );
33
34
		add_filter( 'jetpack_twitter_cards_site_tag', array( $this, 'enhaced_twitter_cards_site_tag' ) );
35
36
		add_action( 'publicize_save_meta', array( $this, 'save_publicized_twitter_account' ), 10, 4 );
37
		add_action( 'publicize_save_meta', array( $this, 'save_publicized_facebook_account' ), 10, 4 );
38
39
		add_filter( 'jetpack_sharing_twitter_via', array( $this, 'get_publicized_twitter_account' ), 10, 2 );
40
41
		include_once( JETPACK__PLUGIN_DIR . 'modules/publicize/enhanced-open-graph.php' );
42
43
		include_once( JETPACK__PLUGIN_DIR . 'modules/publicize/class-jetpack-publicize-gutenberg.php' );
44
45
		// Extend publicize with support for Gutenberg
46
		$async_publicizer = new Jetpack_Publicize_Gutenberg( $this );
0 ignored issues
show
Unused Code introduced by
$async_publicizer 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...
47
	}
48
49
	function force_user_connection() {
50
		global $current_user;
51
		$user_token        = Jetpack_Data::get_access_token( $current_user->ID );
52
		$is_user_connected = $user_token && ! is_wp_error( $user_token );
53
54
		// If the user is already connected via Jetpack, then we're good
55
		if ( $is_user_connected ) {
56
			return;
57
		}
58
59
		// If they're not connected, then remove the Publicize UI and tell them they need to connect first
60
		global $publicize_ui;
61
		remove_action( 'pre_admin_screen_sharing', array( $publicize_ui, 'admin_page' ) );
62
63
		// Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
64
		// Jetpack::init()->admin_styles();
65
		add_action( 'pre_admin_screen_sharing', array( $this, 'admin_page_warning' ), 1 );
66
	}
67
68
	function admin_page_warning() {
69
		$jetpack   = Jetpack::init();
70
		$blog_name = get_bloginfo( 'blogname' );
71
		if ( empty( $blog_name ) ) {
72
			$blog_name = home_url( '/' );
73
		}
74
75
		?>
76
		<div id="message" class="updated jetpack-message jp-connect">
77
			<div class="jetpack-wrap-container">
78
				<div class="jetpack-text-container">
79
					<p><?php printf(
80
							/* translators: %s is the name of the blog */
81
							esc_html( wptexturize( __( "To use Publicize, you'll need to link your %s account to your WordPress.com account using the link below.", 'jetpack' ) ) ),
82
							'<strong>' . esc_html( $blog_name ) . '</strong>'
83
						); ?></p>
84
					<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>
85
				</div>
86
				<div class="jetpack-install-container">
87
					<p class="submit"><a
88
							href="<?php echo $jetpack->build_connect_url( false, menu_page_url( 'sharing', false ) ); ?>"
89
							class="button-connector"
90
							id="wpcom-connect"><?php esc_html_e( 'Link account with WordPress.com', 'jetpack' ); ?></a>
91
					</p>
92
					<p class="jetpack-install-blurb">
93
						<?php jetpack_render_tos_blurb(); ?>
94
					</p>
95
				</div>
96
			</div>
97
		</div>
98
		<?php
99
	}
100
101
	/**
102
	 * Remove a Publicize connection
103
	 */
104
	function disconnect( $service_name, $connection_id, $_blog_id = false, $_user_id = false, $force_delete = false ) {
105
		Jetpack::load_xml_rpc_client();
106
		$xml = new Jetpack_IXR_Client();
107
		$xml->query( 'jetpack.deletePublicizeConnection', $connection_id );
108
109
		if ( ! $xml->isError() ) {
110
			Jetpack_Options::update_option( 'publicize_connections', $xml->getResponse() );
111
		} else {
112
			return false;
113
		}
114
	}
115
116
	function receive_updated_publicize_connections( $publicize_connections ) {
117
		Jetpack_Options::update_option( 'publicize_connections', $publicize_connections );
118
119
		return true;
120
	}
121
122
	function register_update_publicize_connections_xmlrpc_method( $methods ) {
123
		return array_merge( $methods, array(
124
			'jetpack.updatePublicizeConnections' => array( $this, 'receive_updated_publicize_connections' ),
125
		) );
126
	}
127
128
	function get_all_connections() {
129
		return Jetpack_Options::get_option( 'publicize_connections' );
130
	}
131
132
	function get_connections( $service_name, $_blog_id = false, $_user_id = false ) {
133
		$connections           = $this->get_all_connections();
134
		$connections_to_return = array();
135
		if ( ! empty( $connections ) && is_array( $connections ) ) {
136
			if ( ! empty( $connections[ $service_name ] ) ) {
137
				foreach ( $connections[ $service_name ] as $id => $connection ) {
138
					if ( 0 == $connection['connection_data']['user_id'] || $this->user_id() == $connection['connection_data']['user_id'] ) {
139
						$connections_to_return[ $id ] = $connection;
140
					}
141
				}
142
			}
143
144
			return $connections_to_return;
145
		}
146
147
		return false;
148
	}
149
150
	function get_all_connections_for_user() {
151
		$connections = $this->get_all_connections();
152
153
		$connections_to_return = array();
154
		if ( ! empty( $connections ) ) {
155
			foreach ( (array) $connections as $service_name => $connections_for_service ) {
156
				foreach ( $connections_for_service as $id => $connection ) {
157
					$user_id = intval( $connection['connection_data']['user_id'] );
158
					// phpcs:ignore WordPress.PHP.YodaConditions.NotYoda
159
					if ( $user_id === 0 || $this->user_id() === $user_id ) {
160
						$connections_to_return[ $service_name ][ $id ] = $connection;
161
					}
162
				}
163
			}
164
165
			return $connections_to_return;
166
		}
167
168
		return false;
169
	}
170
171
	function get_connection_id( $connection ) {
172
		return $connection['connection_data']['id'];
173
	}
174
175
	function get_connection_meta( $connection ) {
176
		$connection['user_id'] = $connection['connection_data']['user_id']; // Allows for shared connections
177
		return $connection;
178
	}
179
180
	function admin_page_load() {
181
		if ( isset( $_GET['action'] ) ) {
182
			if ( isset( $_GET['service'] ) ) {
183
				$service_name = $_GET['service'];
184
			}
185
186
			switch ( $_GET['action'] ) {
187
				case 'error':
188
					add_action( 'pre_admin_screen_sharing', array( $this, 'display_connection_error' ), 9 );
189
					break;
190
191
				case 'request':
192
					check_admin_referer( 'keyring-request', 'kr_nonce' );
193
					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...
194
195
					$verification = Jetpack::generate_secrets( 'publicize' );
196
					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...
197
						$url = Jetpack::admin_url( 'jetpack#/settings' );
198
						wp_die( sprintf( __( "Jetpack is not connected. Please connect Jetpack by visiting <a href='%s'>Settings</a>.", 'jetpack' ), $url ) );
199
200
					}
201
					$stats_options = get_option( 'stats_options' );
202
					$wpcom_blog_id = Jetpack_Options::get_option( 'id' );
203
					$wpcom_blog_id = ! empty( $wpcom_blog_id ) ? $wpcom_blog_id : $stats_options['blog_id'];
204
205
					$user     = wp_get_current_user();
206
					$redirect = $this->api_url( $service_name, urlencode_deep( array(
207
						'action'       => 'request',
208
						'redirect_uri' => add_query_arg( array( 'action' => 'done' ), menu_page_url( 'sharing', false ) ),
209
						'for'          => 'publicize',
210
						// required flag that says this connection is intended for publicize
211
						'siteurl'      => site_url(),
212
						'state'        => $user->ID,
213
						'blog_id'      => $wpcom_blog_id,
214
						'secret_1'     => $verification['secret_1'],
215
						'secret_2'     => $verification['secret_2'],
216
						'eol'          => $verification['exp'],
217
					) ) );
218
					wp_redirect( $redirect );
219
					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...
220
					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...
221
222
				case 'completed':
223
					Jetpack::load_xml_rpc_client();
224
					$xml = new Jetpack_IXR_Client();
225
					$xml->query( 'jetpack.fetchPublicizeConnections' );
226
227
					if ( ! $xml->isError() ) {
228
						$response = $xml->getResponse();
229
						Jetpack_Options::update_option( 'publicize_connections', $response );
230
					}
231
232
					break;
233
234
				case 'delete':
235
					$id = $_GET['id'];
236
237
					check_admin_referer( 'keyring-request', 'kr_nonce' );
238
					check_admin_referer( "keyring-request-$service_name", 'nonce' );
239
240
					$this->disconnect( $service_name, $id );
241
242
					add_action( 'admin_notices', array( $this, 'display_disconnected' ) );
243
					break;
244
			}
245
		}
246
247
		// Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
248
		// Errors encountered on WordPress.com's end are passed back as a code
249
		/*
250
		if ( isset( $_GET['action'] ) && 'error' == $_GET['action'] ) {
251
			// Load Jetpack's styles to handle the box
252
			Jetpack::init()->admin_styles();
253
		}
254
		*/
255
	}
256
257
	function display_connection_error() {
258
		$code = false;
259
		if ( isset( $_GET['service'] ) ) {
260
			$service_name = $_GET['service'];
261
			$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 ) );
262
		} else {
263
			if ( isset( $_GET['publicize_error'] ) ) {
264
				$code = strtolower( $_GET['publicize_error'] );
265
				switch ( $code ) {
266
					case '400':
267
						$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' );
268
						break;
269
					case 'secret_mismatch':
270
						$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' );
271
						break;
272
					case 'empty_blog_id':
273
						$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' );
274
						break;
275
					case 'empty_state':
276
						$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() );
277
						break;
278
					default:
279
						$error = __( 'Something which should never happen, happened. Sorry about that. If you try again, maybe it will work.', 'jetpack' );
280
						break;
281
				}
282
			} else {
283
				$error = __( 'There was a problem connecting with Publicize. Please try again in a moment.', 'jetpack' );
284
			}
285
		}
286
		// Using the same formatting/style as Jetpack::admin_notices() error
287
		?>
288
		<div id="message" class="jetpack-message jetpack-err">
289
			<div class="squeezer">
290
				<h2><?php echo wp_kses( $error, array( 'a'      => array( 'href' => true ),
291
				                                       'code'   => true,
292
				                                       'strong' => true,
293
				                                       'br'     => true,
294
				                                       'b'      => true
295
					) ); ?></h2>
296
				<?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...
297
					<p><?php printf( __( 'Error code: %s', 'jetpack' ), esc_html( stripslashes( $code ) ) ); ?></p>
298
				<?php endif; ?>
299
			</div>
300
		</div>
301
		<?php
302
	}
303
304
	function display_disconnected() {
305
		echo "<div class='updated'>\n";
306
		echo '<p>' . esc_html( __( 'That connection has been removed.', 'jetpack' ) ) . "</p>\n";
307
		echo "</div>\n\n";
308
	}
309
310
	function globalization() {
311
		if ( 'on' == $_REQUEST['global'] ) {
312
			$id = $_REQUEST['connection'];
313
314
			if ( ! current_user_can( $this->GLOBAL_CAP ) ) {
315
				return;
316
			}
317
318
			Jetpack::load_xml_rpc_client();
319
			$xml = new Jetpack_IXR_Client();
320
			$xml->query( 'jetpack.globalizePublicizeConnection', $id, 'globalize' );
321
322
			if ( ! $xml->isError() ) {
323
				$response = $xml->getResponse();
324
				Jetpack_Options::update_option( 'publicize_connections', $response );
325
			}
326
		}
327
	}
328
329
	/**
330
	 * Gets a URL to the public-api actions. Works like WP's admin_url
331
	 *
332
	 * @param string $service Shortname of a specific service.
333
	 *
334
	 * @return URL to specific public-api process
335
	 */
336
	// on WordPress.com this is/calls Keyring::admin_url
337
	function api_url( $service = false, $params = array() ) {
338
		/**
339
		 * Filters the API URL used to interact with WordPress.com.
340
		 *
341
		 * @module publicize
342
		 *
343
		 * @since 2.0.0
344
		 *
345
		 * @param string https://public-api.wordpress.com/connect/?jetpack=publicize Default Publicize API URL.
346
		 */
347
		$url = apply_filters( 'publicize_api_url', 'https://public-api.wordpress.com/connect/?jetpack=publicize' );
348
349
		if ( $service ) {
350
			$url = add_query_arg( array( 'service' => $service ), $url );
351
		}
352
353
		if ( count( $params ) ) {
354
			$url = add_query_arg( $params, $url );
355
		}
356
357
		return $url;
358
	}
359
360 View Code Duplication
	function connect_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
			'nonce'    => wp_create_nonce( "keyring-request-$service_name" ),
366
		), menu_page_url( 'sharing', false ) );
367
	}
368
369
	function refresh_url( $service_name ) {
370
		return add_query_arg( array(
371
			'action'   => 'request',
372
			'service'  => $service_name,
373
			'kr_nonce' => wp_create_nonce( 'keyring-request' ),
374
			'refresh'  => 1,
375
			'for'      => 'publicize',
376
			'nonce'    => wp_create_nonce( "keyring-request-$service_name" ),
377
		), admin_url( 'options-general.php?page=sharing' ) );
378
	}
379
380 View Code Duplication
	function disconnect_url( $service_name, $id ) {
381
		return add_query_arg( array(
382
			'action'   => 'delete',
383
			'service'  => $service_name,
384
			'id'       => $id,
385
			'kr_nonce' => wp_create_nonce( 'keyring-request' ),
386
			'nonce'    => wp_create_nonce( "keyring-request-$service_name" ),
387
		), menu_page_url( 'sharing', false ) );
388
	}
389
390
	/**
391
	 * Get social networks, either all available or only those that the site is connected to.
392
	 *
393
	 * @since 2.0
394
	 *
395
	 * @param string $filter Select the list of services that will be returned. Defaults to 'all', accepts 'connected'.
396
	 *
397
	 * @return array List of social networks.
398
	 */
399
	function get_services( $filter = 'all' ) {
400
		$services = array(
401
			'facebook'    => array(),
402
			'twitter'     => array(),
403
			'linkedin'    => array(),
404
			'tumblr'      => array(),
405
			'path'        => array(),
406
			'google_plus' => array(),
407
		);
408
409
		if ( 'all' == $filter ) {
410
			return $services;
411
		} else {
412
			$connected_services = array();
413
			foreach ( $services as $service => $empty ) {
414
				$connections = $this->get_connections( $service );
415
				if ( $connections ) {
416
					$connected_services[ $service ] = $connections;
417
				}
418
			}
419
			return $connected_services;
420
		}
421
	}
422
423
	/**
424
	 * Retrieves current list of connections and applies filters.
425
	 *
426
	 * Retrieves current available connections and checks if the connections
427
	 * have already been used to share current post. Finally, the checkbox
428
	 * form UI fields are calculated. This function exposes connection form
429
	 * data directly as array so it can be retrieved for static HTML generation
430
	 * or JSON consumption.
431
	 *
432
	 * @since 6.2.0
433
	 *
434
	 * @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...
435
	 *
436
	 * @return array {
437
	 *     Array of UI setup data for connection list form.
438
	 *
439
	 *     @type string 'unique_id'       ID string representing connection
440
	 *     @type bool   'checked'         Default value of checkbox for connection.
441
	 *     @type bool   'disabled'        String of HTML disabled property of checkbox. Empty if not disabled.
442
	 *     @type bool   'active'          True if connection is not skipped by filters and is not already done.
443
	 *     @type bool   'hidden_checkbox' True if the connection should not be shared to by current user.
444
	 *     @type string 'label'           Text description of checkbox.
445
	 *     @type string 'display_name'    Username for sharing account.
446
	 * }
447
	 */
448
	public function get_filtered_connection_data( $selected_post_id = null ) {
449
		$connection_list = array();
450
451
		$post = get_post( $selected_post_id ); // Defaults to current post if $post_id is null.
452
		// Handle case where there is no current post.
453
		if ( ! empty( $post ) ) {
454
			$post_id = $post->ID;
455
		} else {
456
			$post_id = null;
457
		}
458
459
		$services = $this->get_services( 'connected' );
460
		$all_done = $this->done_sharing_post( $post_id );
461
462
		// We don't allow Publicizing to the same external id twice, to prevent spam.
463
		$service_id_done = (array) get_post_meta( $post_id, $this->POST_SERVICE_DONE, true );
464
465
		foreach ( $services as $name => $connections ) {
466
			foreach ( $connections as $connection ) {
467
				$connection_data = '';
468 View Code Duplication
				if ( method_exists( $connection, 'get_meta' ) ) {
469
					$connection_data = $connection->get_meta( 'connection_data' );
470
				} elseif ( ! empty( $connection['connection_data'] ) ) {
471
					$connection_data = $connection['connection_data'];
472
				}
473
474
				/**
475
				 * Filter whether a post should be publicized to a given service.
476
				 *
477
				 * @module publicize
478
				 *
479
				 * @since 2.0.0
480
				 *
481
				 * @param bool true Should the post be publicized to a given service? Default to true.
482
				 * @param int $post_id Post ID.
483
				 * @param string $name Service name.
484
				 * @param array $connection_data Array of information about all Publicize details for the site.
485
				 */
486
				if ( ! apply_filters( 'wpas_submit_post?', true, $post_id, $name, $connection_data ) ) {
487
					continue;
488
				}
489
490 View Code Duplication
				if ( ! empty( $connection->unique_id ) ) {
491
					$unique_id = $connection->unique_id;
492
				} elseif ( ! empty( $connection['connection_data']['token_id'] ) ) {
493
					$unique_id = $connection['connection_data']['token_id'];
494
				}
495
496
				// Should we be skipping this one?
497
				$skip = (
498
					(
499
						! empty( $post )
500
						&&
501
						in_array( $post->post_status, array( 'publish', 'draft', 'future' ) )
502
						&&
503
						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...
504
					)
505
					||
506
					(
507
						is_array( $connection )
508
						&&
509
						(
510
							(
511
									isset( $connection['meta']['external_id'] )
512
									&&
513
									! empty( $service_id_done[ $name ][ $connection['meta']['external_id'] ] )
514
							)
515
							||
516
							// Jetpack's connection data looks a little different.
517
							(
518
									isset( $connection['external_id'] )
519
									&&
520
									! empty( $service_id_done[ $name ][ $connection['external_id'] ] )
521
							)
522
						)
523
					)
524
				);
525
526
				// Was this connections (OR, old-format service) already Publicized to.
527
				$done = (
528
							( 1 == get_post_meta( $post_id, $this->POST_DONE . $unique_id, true ) )
529
							||
530
							( 1 == get_post_meta( $post_id, $this->POST_DONE . $name, true ) )
531
				); // New and old style flags.
532
533
				// If this one has already been publicized to, don't let it happen again.
534
				$disabled = false;
535
				if ( $done ) {
536
					$disabled = true;
537
				}
538
539
				/**
540
				 * If this is a global connection and this user doesn't have enough permissions to modify
541
				 * those connections, don't let them change it.
542
				 */
543
				$cmeta           = $this->get_connection_meta( $connection );
544
				$hidden_checkbox = false;
545
				if ( ! $done && ( 0 == $cmeta['connection_data']['user_id'] && ! current_user_can( $this->GLOBAL_CAP ) ) ) {
546
					$disabled = true;
547
					/**
548
					 * Filters the checkboxes for global connections with non-prilvedged users.
549
					 *
550
					 * @module publicize
551
					 *
552
					 * @since 3.7.0
553
					 *
554
					 * @param bool   $checked Indicates if this connection should be enabled. Default true.
555
					 * @param int    $post_id ID of the current post
556
					 * @param string $name Name of the connection (Facebook, Twitter, etc)
557
					 * @param array  $connection Array of data about the connection.
558
					 */
559
					$hidden_checkbox = apply_filters( 'publicize_checkbox_global_default', true, $post_id, $name, $connection );
560
				}
561
562
				// Determine the state of the checkbox (on/off) and allow filtering.
563
				$checked = ( ( 1 != $skip ) || $done );
564
				/**
565
				 * Filter the checkbox state of each Publicize connection appearing in the post editor.
566
				 *
567
				 * @module publicize
568
				 *
569
				 * @since 2.0.1
570
				 *
571
				 * @param bool $checked Should the Publicize checkbox be enabled for a given service.
572
				 * @param int $post_id Post ID.
573
				 * @param string $name Service name.
574
				 * @param array $connection Array of connection details.
575
				 */
576
				$checked = apply_filters( 'publicize_checkbox_default', $checked, $post_id, $name, $connection );
577
578
				// Force the checkbox to be checked if the post was DONE, regardless of what the filter does.
579
				if ( $done ) {
580
					$checked = true;
581
				}
582
583
				// This post has been handled, so disable everything.
584
				if ( $all_done ) {
585
					$disabled = true;
586
				}
587
588
				$label  = sprintf(
589
					_x( '%1$s: %2$s', 'Service: Account connected as', 'jetpack' ),
590
					esc_html( $this->get_service_label( $name ) ),
591
					esc_html( $this->get_display_name( $name, $connection ) )
592
				);
593
				$active = ! $skip || $done;
594
595
				$connection_list[] = array(
596
					'unique_id'       => $unique_id,
597
					'name'            => $name,
598
					'checked'         => $checked,
599
					'disabled'        => $disabled,
600
					'active'          => $active,
601
					'hidden_checkbox' => $hidden_checkbox,
602
					'label'           => esc_html( $label ),
603
					'display_name'    => $this->get_display_name( $name, $connection ),
604
				);
605
			}
606
		}
607
608
		return $connection_list;
609
	}
610
611
	/**
612
	 * Checks if post has already been shared by Publicize in the past.
613
	 *
614
	 * We can set an _all flag to indicate that this post is completely done as
615
	 * far as Publicize is concerned. Jetpack uses this approach. All published posts in Jetpack
616
	 * have Publicize disabled.
617
	 *
618
	 * @since 6.2.0
619
	 *
620
	 * @global Publicize_UI $publicize_ui UI instance that contains the 'in_jetpack' property
621
	 *
622
	 * @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...
623
	 *
624
	 * @return bool True if post has already been shared by Publicize, false otherwise.
625
	 */
626
	public function done_sharing_post( $post_id = null ) {
627
		global $publicize_ui;
628
		$post = get_post( $post_id ); // Defaults to current post if $post_id is null.
629
		if ( is_null( $post ) ) {
630
			return false;
631
		}
632
		return get_post_meta( $post->ID, $this->POST_DONE . 'all', true ) || ( $publicize_ui->in_jetpack && 'publish' == $post->post_status );
633
	}
634
635
	/**
636
	 * Retrieves full list of available Publicize connection services.
637
	 *
638
	 * Retrieves current available publicize service connections
639
	 * with associated labels and URLs.
640
	 *
641
	 * @since 6.2.0
642
	 *
643
	 * @return array {
644
	 *     Array of UI service connection data for all services
645
	 *
646
	 *     @type string 'name'  Name of service.
647
	 *     @type string 'label' Display label for service.
648
	 *     @type string 'url'   URL for adding connection to service.
649
	 * }
650
	 */
651
	function get_available_service_data() {
652
		$available_services     = $this->get_services( 'all' );
653
		$available_service_data = array();
654
655
		foreach ( $available_services as $service_name => $service ) {
656
			$available_service_data[] = array(
657
				'name'  => $service_name,
658
				'label' => $this->get_service_label( $service_name ),
659
				'url'   => $this->connect_url( $service_name ),
660
			);
661
		}
662
663
		return $available_service_data;
664
	}
665
666
	function get_connection( $service, $id, $_blog_id = false, $_user_id = false ) {
667
		// Stub
668
	}
669
670
	function flag_post_for_publicize( $new_status, $old_status, $post ) {
671
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
672
			return;
673
		}
674
675
		if ( 'publish' == $new_status && 'publish' != $old_status ) {
676
			/**
677
			 * Determines whether a post being published gets publicized.
678
			 *
679
			 * Side-note: Possibly our most alliterative filter name.
680
			 *
681
			 * @module publicize
682
			 *
683
			 * @since 4.1.0
684
			 *
685
			 * @param bool $should_publicize Should the post be publicized? Default to true.
686
			 * @param WP_POST $post Current Post object.
687
			 */
688
			$should_publicize = apply_filters( 'publicize_should_publicize_published_post', true, $post );
689
690
			if ( $should_publicize ) {
691
				update_post_meta( $post->ID, $this->PENDING, true );
692
			}
693
		}
694
	}
695
696
	function test_connection( $service_name, $connection ) {
697
698
		$id = $this->get_connection_id( $connection );
699
700
		Jetpack::load_xml_rpc_client();
701
		$xml = new Jetpack_IXR_Client();
702
		$xml->query( 'jetpack.testPublicizeConnection', $id );
703
704
		// Bail if all is well
705
		if ( ! $xml->isError() ) {
706
			return true;
707
		}
708
709
		$xml_response            = $xml->getResponse();
710
		$connection_test_message = $xml_response['faultString'];
711
712
		// Set up refresh if the user can
713
		$user_can_refresh = current_user_can( $this->GLOBAL_CAP );
714
		if ( $user_can_refresh ) {
715
			$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...
716
			$refresh_text = sprintf( _x( 'Refresh connection with %s', 'Refresh connection with {social media service}', 'jetpack' ), $this->get_service_label( $service_name ) );
717
			$refresh_url  = $this->refresh_url( $service_name );
718
		}
719
720
		$error_data = array(
721
			'user_can_refresh' => $user_can_refresh,
722
			'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...
723
			'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...
724
		);
725
726
		return new WP_Error( 'pub_conn_test_failed', $connection_test_message, $error_data );
727
	}
728
729
	/**
730
	 * Save a flag locally to indicate that this post has already been Publicized via the selected
731
	 * connections.
732
	 */
733
	function save_publicized( $post_ID, $post = null, $update = null ) {
734
		if ( is_null( $post ) ) {
735
			return;
736
		}
737
		// Only do this when a post transitions to being published
738
		if ( get_post_meta( $post->ID, $this->PENDING ) && $this->post_type_is_publicizeable( $post->post_type ) ) {
739
			$connected_services = $this->get_all_connections();
740
			if ( ! empty( $connected_services ) ) {
741
				/**
742
				 * Fires when a post is saved that has is marked as pending publicizing
743
				 *
744
				 * @since 4.1.0
745
				 *
746
				 * @param int The post ID
747
				 */
748
				do_action_deprecated( 'jetpack_publicize_post', $post->ID, '4.8.0', 'jetpack_published_post_flags' );
749
			}
750
			delete_post_meta( $post->ID, $this->PENDING );
751
			update_post_meta( $post->ID, $this->POST_DONE . 'all', true );
752
		}
753
	}
754
755
	function set_post_flags( $flags, $post ) {
756
		$flags['publicize_post'] = false;
757
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
758
			return $flags;
759
		}
760
		/** This filter is already documented in modules/publicize/publicize-jetpack.php */
761
		if ( ! apply_filters( 'publicize_should_publicize_published_post', true, $post ) ) {
762
			return $flags;
763
		}
764
765
		$connected_services = $this->get_all_connections();
766
767
		if ( empty( $connected_services ) ) {
768
			return $flags;
769
		}
770
771
		$flags['publicize_post'] = true;
772
773
		return $flags;
774
	}
775
776
	/**
777
	 * Options Code
778
	 */
779
780
	function options_page_facebook() {
781
		$connected_services = $this->get_all_connections();
782
		$connection         = $connected_services['facebook'][ $_REQUEST['connection'] ];
783
		$options_to_show    = ( ! empty( $connection['connection_data']['meta']['options_responses'] ) ? $connection['connection_data']['meta']['options_responses'] : false );
784
785
		// Nonce check
786
		check_admin_referer( 'options_page_facebook_' . $_REQUEST['connection'] );
787
788
		$pages = ( ! empty( $options_to_show[1]['data'] ) ? $options_to_show[1]['data'] : false );
789
790
		$page_selected   = false;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 3 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
791
		if ( ! empty( $connection['connection_data']['meta']['facebook_page'] ) ) {
792
			$found = false;
793
			if ( $pages && isset( $pages->data ) && 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
				$page_selected   = $connection['connection_data']['meta']['facebook_page'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 3 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
804
			}
805
		}
806
807
		?>
808
809
		<div id="thickbox-content">
810
811
			<?php
812
			ob_start();
813
			Publicize_UI::connected_notice( 'Facebook' );
814
			$update_notice = ob_get_clean();
815
816
			if ( ! empty( $update_notice ) ) {
817
				echo $update_notice;
818
			}
819
			$page_info_message = sprintf(
820
				__( 'Facebook supports Publicize connections to Facebook Pages, but not to Facebook Profiles. <a href="%s">Learn More about Publicize for Facebook</a>', 'jetpack' ),
821
				'https://jetpack.com/support/publicize/facebook'
822
			);
823
824
			if ( $pages ) : ?>
825
				<p><?php _e( 'Publicize to my <strong>Facebook Page</strong>:', 'jetpack' ); ?></p>
826
				<table id="option-fb-fanpage">
827
					<tbody>
828
829
					<?php foreach ( $pages as $i => $page ) : ?>
830
						<?php if ( ! ( $i % 2 ) ) : ?>
831
							<tr>
832
						<?php endif; ?>
833
						<td class="radio"><input type="radio" name="option" data-type="page"
834
						                         id="<?php echo esc_attr( $page['id'] ) ?>"
835
						                         value="<?php echo esc_attr( $page['id'] ) ?>" <?php checked( $page_selected && $page_selected == $page['id'], true ); ?> />
836
						</td>
837
						<td class="thumbnail"><label for="<?php echo esc_attr( $page['id'] ) ?>"><img
838
									src="<?php echo esc_url( str_replace( '_s', '_q', $page['picture']['data']['url'] ) ) ?>"
839
									width="50" height="50"/></label></td>
840
						<td class="details">
841
							<label for="<?php echo esc_attr( $page['id'] ) ?>">
842
								<span class="name"><?php echo esc_html( $page['name'] ) ?></span><br/>
843
								<span class="category"><?php echo esc_html( $page['category'] ) ?></span>
844
							</label>
845
						</td>
846
						<?php if ( ( $i % 2 ) || ( $i == count( $pages ) - 1 ) ): ?>
847
							</tr>
848
						<?php endif; ?>
849
					<?php endforeach; ?>
850
851
					</tbody>
852
				</table>
853
854
				<?php Publicize_UI::global_checkbox( 'facebook', $_REQUEST['connection'] ); ?>
855
				<p style="text-align: center;">
856
					<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
857
					       class="button fb-options save-options" name="save"
858
					       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
859
					       rel="<?php echo wp_create_nonce( 'save_fb_token_' . $_REQUEST['connection'] ) ?>"/>
860
				</p><br/>
861
				<p><?php echo $page_info_message; ?></p>
862
			<?php else: ?>
863
				<div>
864
					<p><?php echo $page_info_message; ?></p>
865
					<p><?php printf( __( '<a class="button" href="%s" target="%s">Create a Facebook page</a> to get started.', 'jetpack' ), 'https://www.facebook.com/pages/creation/', '_blank noopener noreferrer' ); ?></p>
866
				</div>
867
			<?php endif; ?>
868
		</div>
869
		<?php
870
	}
871
872
	function options_save_facebook() {
873
		// Nonce check
874
		check_admin_referer( 'save_fb_token_' . $_REQUEST['connection'] );
875
876
		// Check for a numeric page ID
877
		$page_id = $_POST['selected_id'];
878
		if ( ! ctype_digit( $page_id ) ) {
879
			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...
880
		}
881
882
		if ( 'page' != $_POST['type'] || ! isset( $_POST['selected_id'] ) ) {
883
			return;
884
		}
885
886
		// Publish to Page
887
		$options = array(
888
			'facebook_page'    => $page_id,
889
			'facebook_profile' => null
890
		);
891
892
		$this->set_remote_publicize_options( $_POST['connection'], $options );
893
	}
894
895
	function options_page_tumblr() {
896
		// Nonce check
897
		check_admin_referer( 'options_page_tumblr_' . $_REQUEST['connection'] );
898
899
		$connected_services = $this->get_all_connections();
900
		$connection         = $connected_services['tumblr'][ $_POST['connection'] ];
901
		$options_to_show    = $connection['connection_data']['meta']['options_responses'];
902
		$request            = $options_to_show[0];
903
904
		$blogs = $request['response']['user']['blogs'];
905
906
		$blog_selected = false;
907
908
		if ( ! empty( $connection['connection_data']['meta']['tumblr_base_hostname'] ) ) {
909
			foreach ( $blogs as $blog ) {
910
				if ( $connection['connection_data']['meta']['tumblr_base_hostname'] == $this->get_basehostname( $blog['url'] ) ) {
911
					$blog_selected = $connection['connection_data']['meta']['tumblr_base_hostname'];
912
					break;
913
				}
914
			}
915
916
		}
917
918
		// Use their Primary blog if they haven't selected one yet
919
		if ( ! $blog_selected ) {
920
			foreach ( $blogs as $blog ) {
921
				if ( $blog['primary'] ) {
922
					$blog_selected = $this->get_basehostname( $blog['url'] );
923
				}
924
			}
925
		} ?>
926
927
		<div id="thickbox-content">
928
929
			<?php
930
			ob_start();
931
			Publicize_UI::connected_notice( 'Tumblr' );
932
			$update_notice = ob_get_clean();
933
934
			if ( ! empty( $update_notice ) ) {
935
				echo $update_notice;
936
			}
937
			?>
938
939
			<p><?php _e( 'Publicize to my <strong>Tumblr blog</strong>:', 'jetpack' ); ?></p>
940
941
			<ul id="option-tumblr-blog">
942
943
				<?php
944
				foreach ( $blogs as $blog ) {
945
					$url = $this->get_basehostname( $blog['url'] ); ?>
946
					<li>
947
						<input type="radio" name="option" data-type="blog" id="<?php echo esc_attr( $url ) ?>"
948
						       value="<?php echo esc_attr( $url ) ?>" <?php checked( $blog_selected == $url, true ); ?> />
949
						<label for="<?php echo esc_attr( $url ) ?>"><span
950
								class="name"><?php echo esc_html( $blog['title'] ) ?></span></label>
951
					</li>
952
				<?php } ?>
953
954
			</ul>
955
956
			<?php Publicize_UI::global_checkbox( 'tumblr', $_REQUEST['connection'] ); ?>
957
958
			<p style="text-align: center;">
959
				<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
960
				       class="button tumblr-options save-options" name="save"
961
				       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
962
				       rel="<?php echo wp_create_nonce( 'save_tumblr_blog_' . $_REQUEST['connection'] ) ?>"/>
963
			</p> <br/>
964
		</div>
965
966
		<?php
967
	}
968
969
	function get_basehostname( $url ) {
970
		return parse_url( $url, PHP_URL_HOST );
971
	}
972
973
	function options_save_tumblr() {
974
		// Nonce check
975
		check_admin_referer( 'save_tumblr_blog_' . $_REQUEST['connection'] );
976
		$options = array( 'tumblr_base_hostname' => $_POST['selected_id'] );
977
978
		$this->set_remote_publicize_options( $_POST['connection'], $options );
979
980
	}
981
982
	function set_remote_publicize_options( $id, $options ) {
983
		Jetpack::load_xml_rpc_client();
984
		$xml = new Jetpack_IXR_Client();
985
		$xml->query( 'jetpack.setPublicizeOptions', $id, $options );
986
987
		if ( ! $xml->isError() ) {
988
			$response = $xml->getResponse();
989
			Jetpack_Options::update_option( 'publicize_connections', $response );
990
			$this->globalization();
991
		}
992
	}
993
994
	function options_page_twitter() {
995
		Publicize_UI::options_page_other( 'twitter' );
996
	}
997
998
	function options_page_linkedin() {
999
		Publicize_UI::options_page_other( 'linkedin' );
1000
	}
1001
1002
	function options_page_path() {
1003
		Publicize_UI::options_page_other( 'path' );
1004
	}
1005
1006
	function options_page_google_plus() {
1007
		Publicize_UI::options_page_other( 'google_plus' );
1008
	}
1009
1010
	function options_save_twitter() {
1011
		$this->options_save_other( 'twitter' );
1012
	}
1013
1014
	function options_save_linkedin() {
1015
		$this->options_save_other( 'linkedin' );
1016
	}
1017
1018
	function options_save_path() {
1019
		$this->options_save_other( 'path' );
1020
	}
1021
1022
	function options_save_google_plus() {
1023
		$this->options_save_other( 'google_plus' );
1024
	}
1025
1026
	function options_save_other( $service_name ) {
1027
		// Nonce check
1028
		check_admin_referer( 'save_' . $service_name . '_token_' . $_REQUEST['connection'] );
1029
		$this->globalization();
1030
	}
1031
1032
	/**
1033
	 * Already-published posts should not be Publicized by default. This filter sets checked to
1034
	 * false if a post has already been published.
1035
	 */
1036
	function publicize_checkbox_default( $checked, $post_id, $name, $connection ) {
1037
		if ( 'publish' == get_post_status( $post_id ) ) {
1038
			return false;
1039
		}
1040
1041
		return $checked;
1042
	}
1043
1044
	/**
1045
	 * If there's only one shared connection to Twitter set it as twitter:site tag.
1046
	 */
1047
	function enhaced_twitter_cards_site_tag( $tag ) {
1048
		$custom_site_tag = get_option( 'jetpack-twitter-cards-site-tag' );
1049
		if ( ! empty( $custom_site_tag ) ) {
1050
			return $tag;
1051
		}
1052
		if ( ! $this->is_enabled( 'twitter' ) ) {
1053
			return $tag;
1054
		}
1055
		$connections = $this->get_connections( 'twitter' );
1056
		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...
1057
			$connection_meta = $this->get_connection_meta( $connection );
1058
			if ( 0 == $connection_meta['connection_data']['user_id'] ) {
1059
				// If the connection is shared
1060
				return $this->get_display_name( 'twitter', $connection );
1061
			}
1062
		}
1063
1064
		return $tag;
1065
	}
1066
1067
	function save_publicized_twitter_account( $submit_post, $post_id, $service_name, $connection ) {
1068
		if ( 'twitter' == $service_name && $submit_post ) {
1069
			$connection_meta        = $this->get_connection_meta( $connection );
1070
			$publicize_twitter_user = get_post_meta( $post_id, '_publicize_twitter_user' );
1071
			if ( empty( $publicize_twitter_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
1072
				update_post_meta( $post_id, '_publicize_twitter_user', $this->get_display_name( 'twitter', $connection ) );
1073
			}
1074
		}
1075
	}
1076
1077
	function get_publicized_twitter_account( $account, $post_id ) {
1078
		if ( ! empty( $account ) ) {
1079
			return $account;
1080
		}
1081
		$account = get_post_meta( $post_id, '_publicize_twitter_user', true );
1082
		if ( ! empty( $account ) ) {
1083
			return $account;
1084
		}
1085
1086
		return '';
1087
	}
1088
1089
	/**
1090
	 * Save the Publicized Facebook account when publishing a post
1091
	 * Use only Personal accounts, not Facebook Pages
1092
	 */
1093
	function save_publicized_facebook_account( $submit_post, $post_id, $service_name, $connection ) {
1094
		$connection_meta = $this->get_connection_meta( $connection );
1095
		if ( 'facebook' == $service_name && isset( $connection_meta['connection_data']['meta']['facebook_profile'] ) && $submit_post ) {
1096
			$publicize_facebook_user = get_post_meta( $post_id, '_publicize_facebook_user' );
1097
			if ( empty( $publicize_facebook_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
1098
				$profile_link = $this->get_profile_link( 'facebook', $connection );
1099
1100
				if ( false !== $profile_link ) {
1101
					update_post_meta( $post_id, '_publicize_facebook_user', $profile_link );
1102
				}
1103
			}
1104
		}
1105
	}
1106
}
1107