Completed
Push — try/seperate-publicize-handlin... ( 77e1d0...27e7c1 )
by
unknown
06:45
created

Publicize::admin_page_load()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 0
dl 0
loc 5
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
		jetpack_require_lib( 'class.jetpack-keyring-service-helper' );
44
	}
45
46
	function force_user_connection() {
47
		global $current_user;
48
		$user_token        = Jetpack_Data::get_access_token( $current_user->ID );
49
		$is_user_connected = $user_token && ! is_wp_error( $user_token );
50
51
		// If the user is already connected via Jetpack, then we're good
52
		if ( $is_user_connected ) {
53
			return;
54
		}
55
56
		// If they're not connected, then remove the Publicize UI and tell them they need to connect first
57
		global $publicize_ui;
58
		remove_action( 'pre_admin_screen_sharing', array( $publicize_ui, 'admin_page' ) );
59
60
		// Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
61
		// Jetpack::init()->admin_styles();
62
		add_action( 'pre_admin_screen_sharing', array( $this, 'admin_page_warning' ), 1 );
63
	}
64
65
	function admin_page_warning() {
66
		$jetpack   = Jetpack::init();
67
		$blog_name = get_bloginfo( 'blogname' );
68
		if ( empty( $blog_name ) ) {
69
			$blog_name = home_url( '/' );
70
		}
71
72
		?>
73
		<div id="message" class="updated jetpack-message jp-connect">
74
			<div class="jetpack-wrap-container">
75
				<div class="jetpack-text-container">
76
					<p><?php printf(
77
							/* translators: %s is the name of the blog */
78
							esc_html( wptexturize( __( "To use Publicize, you'll need to link your %s account to your WordPress.com account using the link below.", 'jetpack' ) ) ),
79
							'<strong>' . esc_html( $blog_name ) . '</strong>'
80
						); ?></p>
81
					<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>
82
				</div>
83
				<div class="jetpack-install-container">
84
					<p class="submit"><a
85
							href="<?php echo $jetpack->build_connect_url( false, menu_page_url( 'sharing', false ) ); ?>"
86
							class="button-connector"
87
							id="wpcom-connect"><?php esc_html_e( 'Link account with WordPress.com', 'jetpack' ); ?></a>
88
					</p>
89
					<p class="jetpack-install-blurb">
90
						<?php jetpack_render_tos_blurb(); ?>
91
					</p>
92
				</div>
93
			</div>
94
		</div>
95
		<?php
96
	}
97
98
	/**
99
	 * Remove a Publicize connection
100
	 */
101
	function disconnect( $service_name, $connection_id, $_blog_id = false, $_user_id = false, $force_delete = false ) {
102
		return Jetpack_Keyring_Service_Helper::disconnect( $service_name, $connection_id, $_blog_id, $_user_id, $force_delete );
103
	}
104
105
	function receive_updated_publicize_connections( $publicize_connections ) {
106
		Jetpack_Options::update_option( 'publicize_connections', $publicize_connections );
107
108
		return true;
109
	}
110
111
	function register_update_publicize_connections_xmlrpc_method( $methods ) {
112
		return array_merge( $methods, array(
113
			'jetpack.updatePublicizeConnections' => array( $this, 'receive_updated_publicize_connections' ),
114
		) );
115
	}
116
117
	function get_all_connections() {
118
		return Jetpack_Options::get_option( 'publicize_connections' );
119
	}
120
121
	function get_connections( $service_name, $_blog_id = false, $_user_id = false ) {
122
		$connections           = $this->get_all_connections();
123
		$connections_to_return = array();
124
		if ( ! empty( $connections ) && is_array( $connections ) ) {
125
			if ( ! empty( $connections[ $service_name ] ) ) {
126
				foreach ( $connections[ $service_name ] as $id => $connection ) {
127
					if ( 0 == $connection['connection_data']['user_id'] || $this->user_id() == $connection['connection_data']['user_id'] ) {
128
						$connections_to_return[ $id ] = $connection;
129
					}
130
				}
131
			}
132
133
			return $connections_to_return;
134
		}
135
136
		return false;
137
	}
138
139
	function get_all_connections_for_user() {
140
		$connections = $this->get_all_connections();
141
142
		$connections_to_return = array();
143
		if ( ! empty( $connections ) ) {
144
			foreach ( (array) $connections as $service_name => $connections_for_service ) {
145
				foreach ( $connections_for_service as $id => $connection ) {
146
					$user_id = intval( $connection['connection_data']['user_id'] );
147
					// phpcs:ignore WordPress.PHP.YodaConditions.NotYoda
148
					if ( $user_id === 0 || $this->user_id() === $user_id ) {
149
						$connections_to_return[ $service_name ][ $id ] = $connection;
150
					}
151
				}
152
			}
153
154
			return $connections_to_return;
155
		}
156
157
		return false;
158
	}
159
160
	function get_connection_id( $connection ) {
161
		return $connection['connection_data']['id'];
162
	}
163
164
	function get_connection_meta( $connection ) {
165
		$connection['user_id'] = $connection['connection_data']['user_id']; // Allows for shared connections
166
		return $connection;
167
	}
168
169
	function admin_page_load() {
170
		if ( isset( $_GET['action'] ) && 'error' === $_GET['action'] ) {
171
					add_action( 'pre_admin_screen_sharing', array( $this, 'display_connection_error' ), 9 );
172
		}
173
	}
174
175
	function display_connection_error() {
176
		$code = false;
177
		if ( isset( $_GET['service'] ) ) {
178
			$service_name = $_GET['service'];
179
			$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 ) );
180
		} else {
181
			if ( isset( $_GET['publicize_error'] ) ) {
182
				$code = strtolower( $_GET['publicize_error'] );
183
				switch ( $code ) {
184
					case '400':
185
						$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' );
186
						break;
187
					case 'secret_mismatch':
188
						$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' );
189
						break;
190
					case 'empty_blog_id':
191
						$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' );
192
						break;
193
					case 'empty_state':
194
						$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() );
195
						break;
196
					default:
197
						$error = __( 'Something which should never happen, happened. Sorry about that. If you try again, maybe it will work.', 'jetpack' );
198
						break;
199
				}
200
			} else {
201
				$error = __( 'There was a problem connecting with Publicize. Please try again in a moment.', 'jetpack' );
202
			}
203
		}
204
		// Using the same formatting/style as Jetpack::admin_notices() error
205
		?>
206
		<div id="message" class="jetpack-message jetpack-err">
207
			<div class="squeezer">
208
				<h2><?php echo wp_kses( $error, array( 'a'      => array( 'href' => true ),
209
														'code'   => true,
210
														'strong' => true,
211
														'br'     => true,
212
														'b'      => true
213
					) ); ?></h2>
214
				<?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...
215
					<p><?php printf( __( 'Error code: %s', 'jetpack' ), esc_html( stripslashes( $code ) ) ); ?></p>
216
				<?php endif; ?>
217
			</div>
218
		</div>
219
		<?php
220
	}
221
222
	function display_disconnected() {
223
		echo "<div class='updated'>\n";
224
		echo '<p>' . esc_html( __( 'That connection has been removed.', 'jetpack' ) ) . "</p>\n";
225
		echo "</div>\n\n";
226
	}
227
228
	function globalization() {
229
		if ( 'on' == $_REQUEST['global'] ) {
230
			$id = $_REQUEST['connection'];
231
232
			if ( ! current_user_can( $this->GLOBAL_CAP ) ) {
233
				return;
234
			}
235
236
			Jetpack::load_xml_rpc_client();
237
			$xml = new Jetpack_IXR_Client();
238
			$xml->query( 'jetpack.globalizePublicizeConnection', $id, 'globalize' );
239
240
			if ( ! $xml->isError() ) {
241
				$response = $xml->getResponse();
242
				Jetpack_Options::update_option( 'publicize_connections', $response );
243
			}
244
		}
245
	}
246
247
	function connect_url( $service_name ) {
248
		return Jetpack_Keyring_Service_Helper::connect_url( $service_name );
249
	}
250
251
	function refresh_url( $service_name ) {
252
		return Jetpack_Keyring_Service_Helper::refresh_url( $service_name );
253
	}
254
255
	function disconnect_url( $service_name, $id ) {
256
		return Jetpack_Keyring_Service_Helper::disconnect_url( $service_name, $id );
257
	}
258
259
	/**
260
	 * Get social networks, either all available or only those that the site is connected to.
261
	 *
262
	 * @since 2.0
263
	 *
264
	 * @param string $filter Select the list of services that will be returned. Defaults to 'all', accepts 'connected'.
265
	 *
266
	 * @return array List of social networks.
267
	 */
268
	function get_services( $filter = 'all' ) {
269
		$services = array(
270
			'facebook'    => array(),
271
			'twitter'     => array(),
272
			'linkedin'    => array(),
273
			'tumblr'      => array(),
274
			'path'        => array(),
275
			'google_plus' => array(),
276
		);
277
278
		if ( 'all' == $filter ) {
279
			return $services;
280
		} else {
281
			$connected_services = array();
282
			foreach ( $services as $service => $empty ) {
283
				$connections = $this->get_connections( $service );
284
				if ( $connections ) {
285
					$connected_services[ $service ] = $connections;
286
				}
287
			}
288
			return $connected_services;
289
		}
290
	}
291
292
	function get_connection( $service, $id, $_blog_id = false, $_user_id = false ) {
293
		// Stub
294
	}
295
296
	function flag_post_for_publicize( $new_status, $old_status, $post ) {
297
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
298
			return;
299
		}
300
301
		if ( 'publish' == $new_status && 'publish' != $old_status ) {
302
			/**
303
			 * Determines whether a post being published gets publicized.
304
			 *
305
			 * Side-note: Possibly our most alliterative filter name.
306
			 *
307
			 * @module publicize
308
			 *
309
			 * @since 4.1.0
310
			 *
311
			 * @param bool $should_publicize Should the post be publicized? Default to true.
312
			 * @param WP_POST $post Current Post object.
313
			 */
314
			$should_publicize = apply_filters( 'publicize_should_publicize_published_post', true, $post );
315
316
			if ( $should_publicize ) {
317
				update_post_meta( $post->ID, $this->PENDING, true );
318
			}
319
		}
320
	}
321
322
	function test_connection( $service_name, $connection ) {
323
324
		$id = $this->get_connection_id( $connection );
325
326
		Jetpack::load_xml_rpc_client();
327
		$xml = new Jetpack_IXR_Client();
328
		$xml->query( 'jetpack.testPublicizeConnection', $id );
329
330
		// Bail if all is well
331
		if ( ! $xml->isError() ) {
332
			return true;
333
		}
334
335
		$xml_response            = $xml->getResponse();
336
		$connection_test_message = $xml_response['faultString'];
337
338
		// Set up refresh if the user can
339
		$user_can_refresh = current_user_can( $this->GLOBAL_CAP );
340
		if ( $user_can_refresh ) {
341
			$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...
342
			$refresh_text = sprintf( _x( 'Refresh connection with %s', 'Refresh connection with {social media service}', 'jetpack' ), $this->get_service_label( $service_name ) );
343
			$refresh_url  = $this->refresh_url( $service_name );
344
		}
345
346
		$error_data = array(
347
			'user_can_refresh' => $user_can_refresh,
348
			'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...
349
			'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...
350
		);
351
352
		return new WP_Error( 'pub_conn_test_failed', $connection_test_message, $error_data );
353
	}
354
355
	/**
356
	 * Save a flag locally to indicate that this post has already been Publicized via the selected
357
	 * connections.
358
	 */
359
	function save_publicized( $post_ID, $post = null, $update = null ) {
360
		if ( is_null( $post ) ) {
361
			return;
362
		}
363
		// Only do this when a post transitions to being published
364
		if ( get_post_meta( $post->ID, $this->PENDING ) && $this->post_type_is_publicizeable( $post->post_type ) ) {
365
			$connected_services = $this->get_all_connections();
366
			if ( ! empty( $connected_services ) ) {
367
				/**
368
				 * Fires when a post is saved that has is marked as pending publicizing
369
				 *
370
				 * @since 4.1.0
371
				 *
372
				 * @param int The post ID
373
				 */
374
				do_action_deprecated( 'jetpack_publicize_post', $post->ID, '4.8.0', 'jetpack_published_post_flags' );
375
			}
376
			delete_post_meta( $post->ID, $this->PENDING );
377
			update_post_meta( $post->ID, $this->POST_DONE . 'all', true );
378
		}
379
	}
380
381
	function set_post_flags( $flags, $post ) {
382
		$flags['publicize_post'] = false;
383
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
384
			return $flags;
385
		}
386
		/** This filter is already documented in modules/publicize/publicize-jetpack.php */
387
		if ( ! apply_filters( 'publicize_should_publicize_published_post', true, $post ) ) {
388
			return $flags;
389
		}
390
391
		$connected_services = $this->get_all_connections();
392
393
		if ( empty( $connected_services ) ) {
394
			return $flags;
395
		}
396
397
		$flags['publicize_post'] = true;
398
399
		return $flags;
400
	}
401
402
	/**
403
	 * Options Code
404
	 */
405
406
	function options_page_facebook() {
407
		$connected_services = $this->get_all_connections();
408
		$connection         = $connected_services['facebook'][ $_REQUEST['connection'] ];
409
		$options_to_show    = ( ! empty( $connection['connection_data']['meta']['options_responses'] ) ? $connection['connection_data']['meta']['options_responses'] : false );
410
411
		// Nonce check
412
		check_admin_referer( 'options_page_facebook_' . $_REQUEST['connection'] );
413
414
		$pages = ( ! empty( $options_to_show[1]['data'] ) ? $options_to_show[1]['data'] : false );
415
416
		$page_selected   = false;
417
		if ( ! empty( $connection['connection_data']['meta']['facebook_page'] ) ) {
418
			$found = false;
419
			if ( $pages && isset( $pages->data ) && is_array( $pages->data )  ) {
420
				foreach ( $pages->data as $page ) {
421
					if ( $page->id == $connection['connection_data']['meta']['facebook_page'] ) {
422
						$found = true;
423
						break;
424
					}
425
				}
426
			}
427
428
			if ( $found ) {
429
				$page_selected   = $connection['connection_data']['meta']['facebook_page'];
430
			}
431
		}
432
433
		?>
434
435
		<div id="thickbox-content">
436
437
			<?php
438
			ob_start();
439
			Publicize_UI::connected_notice( 'Facebook' );
440
			$update_notice = ob_get_clean();
441
442
			if ( ! empty( $update_notice ) ) {
443
				echo $update_notice;
444
			}
445
			$page_info_message = sprintf(
446
				__( 'Facebook supports Publicize connections to Facebook Pages, but not to Facebook Profiles. <a href="%s">Learn More about Publicize for Facebook</a>', 'jetpack' ),
447
				'https://jetpack.com/support/publicize/facebook'
448
			);
449
450
			if ( $pages ) : ?>
451
				<p><?php _e( 'Publicize to my <strong>Facebook Page</strong>:', 'jetpack' ); ?></p>
452
				<table id="option-fb-fanpage">
453
					<tbody>
454
455
					<?php foreach ( $pages as $i => $page ) : ?>
456
						<?php if ( ! ( $i % 2 ) ) : ?>
457
							<tr>
458
						<?php endif; ?>
459
						<td class="radio"><input type="radio" name="option" data-type="page"
460
						                         id="<?php echo esc_attr( $page['id'] ) ?>"
461
						                         value="<?php echo esc_attr( $page['id'] ) ?>" <?php checked( $page_selected && $page_selected == $page['id'], true ); ?> />
462
						</td>
463
						<td class="thumbnail"><label for="<?php echo esc_attr( $page['id'] ) ?>"><img
464
									src="<?php echo esc_url( str_replace( '_s', '_q', $page['picture']['data']['url'] ) ) ?>"
465
									width="50" height="50"/></label></td>
466
						<td class="details">
467
							<label for="<?php echo esc_attr( $page['id'] ) ?>">
468
								<span class="name"><?php echo esc_html( $page['name'] ) ?></span><br/>
469
								<span class="category"><?php echo esc_html( $page['category'] ) ?></span>
470
							</label>
471
						</td>
472
						<?php if ( ( $i % 2 ) || ( $i == count( $pages ) - 1 ) ): ?>
473
							</tr>
474
						<?php endif; ?>
475
					<?php endforeach; ?>
476
477
					</tbody>
478
				</table>
479
480
				<?php Publicize_UI::global_checkbox( 'facebook', $_REQUEST['connection'] ); ?>
481
				<p style="text-align: center;">
482
					<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
483
					       class="button fb-options save-options" name="save"
484
					       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
485
					       rel="<?php echo wp_create_nonce( 'save_fb_token_' . $_REQUEST['connection'] ) ?>"/>
486
				</p><br/>
487
				<p><?php echo $page_info_message; ?></p>
488
			<?php else: ?>
489
				<div>
490
					<p><?php echo $page_info_message; ?></p>
491
					<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>
492
				</div>
493
			<?php endif; ?>
494
		</div>
495
		<?php
496
	}
497
498
	function options_save_facebook() {
499
		// Nonce check
500
		check_admin_referer( 'save_fb_token_' . $_REQUEST['connection'] );
501
502
		// Check for a numeric page ID
503
		$page_id = $_POST['selected_id'];
504
		if ( ! ctype_digit( $page_id ) ) {
505
			die( 'Security check' );
506
		}
507
508
		if ( 'page' != $_POST['type'] || ! isset( $_POST['selected_id'] ) ) {
509
			return;
510
		}
511
512
		// Publish to Page
513
		$options = array(
514
			'facebook_page'    => $page_id,
515
			'facebook_profile' => null
516
		);
517
518
		$this->set_remote_publicize_options( $_POST['connection'], $options );
519
	}
520
521
	function options_page_tumblr() {
522
		// Nonce check
523
		check_admin_referer( 'options_page_tumblr_' . $_REQUEST['connection'] );
524
525
		$connected_services = $this->get_all_connections();
526
		$connection         = $connected_services['tumblr'][ $_POST['connection'] ];
527
		$options_to_show    = $connection['connection_data']['meta']['options_responses'];
528
		$request            = $options_to_show[0];
529
530
		$blogs = $request['response']['user']['blogs'];
531
532
		$blog_selected = false;
533
534
		if ( ! empty( $connection['connection_data']['meta']['tumblr_base_hostname'] ) ) {
535
			foreach ( $blogs as $blog ) {
536
				if ( $connection['connection_data']['meta']['tumblr_base_hostname'] == $this->get_basehostname( $blog['url'] ) ) {
537
					$blog_selected = $connection['connection_data']['meta']['tumblr_base_hostname'];
538
					break;
539
				}
540
			}
541
542
		}
543
544
		// Use their Primary blog if they haven't selected one yet
545
		if ( ! $blog_selected ) {
546
			foreach ( $blogs as $blog ) {
547
				if ( $blog['primary'] ) {
548
					$blog_selected = $this->get_basehostname( $blog['url'] );
549
				}
550
			}
551
		} ?>
552
553
		<div id="thickbox-content">
554
555
			<?php
556
			ob_start();
557
			Publicize_UI::connected_notice( 'Tumblr' );
558
			$update_notice = ob_get_clean();
559
560
			if ( ! empty( $update_notice ) ) {
561
				echo $update_notice;
562
			}
563
			?>
564
565
			<p><?php _e( 'Publicize to my <strong>Tumblr blog</strong>:', 'jetpack' ); ?></p>
566
567
			<ul id="option-tumblr-blog">
568
569
				<?php
570
				foreach ( $blogs as $blog ) {
571
					$url = $this->get_basehostname( $blog['url'] ); ?>
572
					<li>
573
						<input type="radio" name="option" data-type="blog" id="<?php echo esc_attr( $url ) ?>"
574
						       value="<?php echo esc_attr( $url ) ?>" <?php checked( $blog_selected == $url, true ); ?> />
575
						<label for="<?php echo esc_attr( $url ) ?>"><span
576
								class="name"><?php echo esc_html( $blog['title'] ) ?></span></label>
577
					</li>
578
				<?php } ?>
579
580
			</ul>
581
582
			<?php Publicize_UI::global_checkbox( 'tumblr', $_REQUEST['connection'] ); ?>
583
584
			<p style="text-align: center;">
585
				<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
586
				       class="button tumblr-options save-options" name="save"
587
				       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
588
				       rel="<?php echo wp_create_nonce( 'save_tumblr_blog_' . $_REQUEST['connection'] ) ?>"/>
589
			</p> <br/>
590
		</div>
591
592
		<?php
593
	}
594
595
	function get_basehostname( $url ) {
596
		return parse_url( $url, PHP_URL_HOST );
597
	}
598
599
	function options_save_tumblr() {
600
		// Nonce check
601
		check_admin_referer( 'save_tumblr_blog_' . $_REQUEST['connection'] );
602
		$options = array( 'tumblr_base_hostname' => $_POST['selected_id'] );
603
604
		$this->set_remote_publicize_options( $_POST['connection'], $options );
605
606
	}
607
608
	function set_remote_publicize_options( $id, $options ) {
609
		Jetpack::load_xml_rpc_client();
610
		$xml = new Jetpack_IXR_Client();
611
		$xml->query( 'jetpack.setPublicizeOptions', $id, $options );
612
613
		if ( ! $xml->isError() ) {
614
			$response = $xml->getResponse();
615
			Jetpack_Options::update_option( 'publicize_connections', $response );
616
			$this->globalization();
617
		}
618
	}
619
620
	function options_page_twitter() {
621
		Publicize_UI::options_page_other( 'twitter' );
622
	}
623
624
	function options_page_linkedin() {
625
		Publicize_UI::options_page_other( 'linkedin' );
626
	}
627
628
	function options_page_path() {
629
		Publicize_UI::options_page_other( 'path' );
630
	}
631
632
	function options_page_google_plus() {
633
		Publicize_UI::options_page_other( 'google_plus' );
634
	}
635
636
	function options_save_twitter() {
637
		$this->options_save_other( 'twitter' );
638
	}
639
640
	function options_save_linkedin() {
641
		$this->options_save_other( 'linkedin' );
642
	}
643
644
	function options_save_path() {
645
		$this->options_save_other( 'path' );
646
	}
647
648
	function options_save_google_plus() {
649
		$this->options_save_other( 'google_plus' );
650
	}
651
652
	function options_save_other( $service_name ) {
653
		// Nonce check
654
		check_admin_referer( 'save_' . $service_name . '_token_' . $_REQUEST['connection'] );
655
		$this->globalization();
656
	}
657
658
	/**
659
	 * Already-published posts should not be Publicized by default. This filter sets checked to
660
	 * false if a post has already been published.
661
	 */
662
	function publicize_checkbox_default( $checked, $post_id, $name, $connection ) {
663
		if ( 'publish' == get_post_status( $post_id ) ) {
664
			return false;
665
		}
666
667
		return $checked;
668
	}
669
670
	/**
671
	 * If there's only one shared connection to Twitter set it as twitter:site tag.
672
	 */
673
	function enhaced_twitter_cards_site_tag( $tag ) {
674
		$custom_site_tag = get_option( 'jetpack-twitter-cards-site-tag' );
675
		if ( ! empty( $custom_site_tag ) ) {
676
			return $tag;
677
		}
678
		if ( ! $this->is_enabled( 'twitter' ) ) {
679
			return $tag;
680
		}
681
		$connections = $this->get_connections( 'twitter' );
682
		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...
683
			$connection_meta = $this->get_connection_meta( $connection );
684
			if ( 0 == $connection_meta['connection_data']['user_id'] ) {
685
				// If the connection is shared
686
				return $this->get_display_name( 'twitter', $connection );
687
			}
688
		}
689
690
		return $tag;
691
	}
692
693
	function save_publicized_twitter_account( $submit_post, $post_id, $service_name, $connection ) {
694
		if ( 'twitter' == $service_name && $submit_post ) {
695
			$connection_meta        = $this->get_connection_meta( $connection );
696
			$publicize_twitter_user = get_post_meta( $post_id, '_publicize_twitter_user' );
697
			if ( empty( $publicize_twitter_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
698
				update_post_meta( $post_id, '_publicize_twitter_user', $this->get_display_name( 'twitter', $connection ) );
699
			}
700
		}
701
	}
702
703
	function get_publicized_twitter_account( $account, $post_id ) {
704
		if ( ! empty( $account ) ) {
705
			return $account;
706
		}
707
		$account = get_post_meta( $post_id, '_publicize_twitter_user', true );
708
		if ( ! empty( $account ) ) {
709
			return $account;
710
		}
711
712
		return '';
713
	}
714
715
	/**
716
	 * Save the Publicized Facebook account when publishing a post
717
	 * Use only Personal accounts, not Facebook Pages
718
	 */
719
	function save_publicized_facebook_account( $submit_post, $post_id, $service_name, $connection ) {
720
		$connection_meta = $this->get_connection_meta( $connection );
721
		if ( 'facebook' == $service_name && isset( $connection_meta['connection_data']['meta']['facebook_profile'] ) && $submit_post ) {
722
			$publicize_facebook_user = get_post_meta( $post_id, '_publicize_facebook_user' );
723
			if ( empty( $publicize_facebook_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
724
				$profile_link = $this->get_profile_link( 'facebook', $connection );
725
726
				if ( false !== $profile_link ) {
727
					update_post_meta( $post_id, '_publicize_facebook_user', $profile_link );
728
				}
729
			}
730
		}
731
	}
732
}
733