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