Completed
Push — try/one-click-site-verify ( a1464a...36c23f )
by
unknown
10:19 queued 03:29
created

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