Completed
Push — fix/9129-allow-analytics-js-wi... ( 41fabb...20f3a6 )
by
unknown
27:44 queued 11:52
created

modules/publicize/publicize.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
abstract class Publicize_Base {
4
5
	/**
6
	* Services that are currently connected to the given user
7
	* through publicize.
8
	*/
9
	public $connected_services = array();
10
11
	/**
12
	* Services that are supported by publicize. They don't
13
	* necessarily need to be connected to the current user.
14
	*/
15
	public $services;
16
17
	/**
18
	* key names for post meta
19
	*/
20
	public $ADMIN_PAGE        = 'wpas';
21
	public $POST_MESS         = '_wpas_mess';
22
	public $POST_SKIP         = '_wpas_skip_'; // connection id appended to indicate that a connection should NOT be publicized to
23
	public $POST_DONE         = '_wpas_done_'; // connection id appended to indicate a connection has already been publicized to
24
	public $USER_AUTH         = 'wpas_authorize';
25
	public $USER_OPT          = 'wpas_';
26
	public $PENDING           = '_publicize_pending'; // ready for Publicize to do its thing
27
	public $POST_SERVICE_DONE = '_publicize_done_external'; // array of external ids where we've Publicized
28
29
	/**
30
	* default pieces of the message used in constructing the
31
	* content pushed out to other social networks
32
	*/
33
34
	public $default_prefix  = '';
35
	public $default_message = '%title%';
36
	public $default_suffix  = ' ';
37
38
	/**
39
	 * What WP capability is require to create/delete global connections?
40
	 * All users with this cap can un-globalize all other global connections, and globalize any of their own
41
	 * Globalized connections cannot be unselected by users without this capability when publishing
42
	 */
43
	public $GLOBAL_CAP = 'edit_others_posts';
44
45
	/**
46
	* Sets up the basics of Publicize
47
	*/
48
	function __construct() {
49
		$this->default_message = self::build_sprintf( array(
50
			/**
51
			 * Filter the default Publicize message.
52
			 *
53
			 * @module publicize
54
			 *
55
			 * @since 2.0.0
56
			 *
57
			 * @param string $this->default_message Publicize's default message. Default is the post title.
58
			 */
59
			apply_filters( 'wpas_default_message', $this->default_message ),
60
			'title',
61
			'url',
62
		) );
63
64
		$this->default_prefix = self::build_sprintf( array(
65
			/**
66
			 * Filter the message prepended to the Publicize custom message.
67
			 *
68
			 * @module publicize
69
			 *
70
			 * @since 2.0.0
71
			 *
72
			 * @param string $this->default_prefix String prepended to the Publicize custom message.
73
			 */
74
			apply_filters( 'wpas_default_prefix', $this->default_prefix ),
75
			'url',
76
		) );
77
78
		$this->default_suffix = self::build_sprintf( array(
79
			/**
80
			 * Filter the message appended to the Publicize custom message.
81
			 *
82
			 * @module publicize
83
			 *
84
			 * @since 2.0.0
85
			 *
86
			 * @param string $this->default_suffix String appended to the Publicize custom message.
87
			 */
88
			apply_filters( 'wpas_default_suffix', $this->default_suffix ),
89
			'url',
90
		) );
91
92
		/**
93
		 * Filter the capability to change global Publicize connection options.
94
		 *
95
		 * All users with this cap can un-globalize all other global connections, and globalize any of their own
96
		 * Globalized connections cannot be unselected by users without this capability when publishing.
97
		 *
98
		 * @module publicize
99
		 *
100
		 * @since 2.2.1
101
		 *
102
		 * @param string $this->GLOBAL_CAP default capability in control of global Publicize connection options. Default to edit_others_posts.
103
		 */
104
		$this->GLOBAL_CAP = apply_filters( 'jetpack_publicize_global_connections_cap', $this->GLOBAL_CAP );
105
106
		// stage 1 and 2 of 3-stage Publicize. Flag for Publicize on creation, save meta,
107
		// then check meta and publicize based on that. stage 3 implemented on wpcom
108
		add_action( 'transition_post_status', array( $this, 'flag_post_for_publicize' ), 10, 3 );
109
		add_action( 'save_post', array( &$this, 'save_meta' ), 20, 2 );
110
		add_filter( 'post_updated_messages', array( $this, 'update_published_message' ), 20, 1 );
111
112
		// Connection test callback
113
		add_action( 'wp_ajax_test_publicize_conns', array( $this, 'test_publicize_conns' ) );
114
	}
115
116
	/**
117
	* Functions to be implemented by the extended class (publicize-wpcom or publicize-jetpack)
118
	*/
119
	abstract function get_connection_id( $connection );
120
	abstract function connect_url( $service_name );
121
	abstract function disconnect_url( $service_name, $id );
122
	abstract function get_connection_meta( $connection );
123
	abstract function get_services( $filter = 'all' );
124
	abstract function get_connections( $service, $_blog_id = false, $_user_id = false );
125
	abstract function get_connection( $service, $id, $_blog_id = false, $_user_id = false );
126
	abstract function flag_post_for_publicize( $new_status, $old_status, $post );
127
	abstract function test_connection( $service_name, $connection );
128
	abstract function disconnect( $service, $connection_id, $_blog_id = false, $_user_id = false, $force_delete = false );
129
130
	/**
131
	* Shared Functions
132
	*/
133
134
	/**
135
	* Returns an external URL to the connection's profile
136
	*/
137
	function get_profile_link( $service_name, $connection ) {
138
		$cmeta = $this->get_connection_meta( $connection );
139
140
		if ( isset( $cmeta['connection_data']['meta']['link'] ) ) {
141
			if ( 'facebook' == $service_name && 0 === strpos( parse_url( $cmeta['connection_data']['meta']['link'], PHP_URL_PATH ), '/app_scoped_user_id/' ) ) {
142
				// App-scoped Facebook user IDs are not usable profile links
143
				return false;
144
			}
145
146
			return $cmeta['connection_data']['meta']['link'];
147 View Code Duplication
		} elseif ( 'facebook' == $service_name && isset( $cmeta['connection_data']['meta']['facebook_page'] ) ) {
148
			return 'https://facebook.com/' . $cmeta['connection_data']['meta']['facebook_page'];
149
		} elseif ( 'tumblr' == $service_name && isset( $cmeta['connection_data']['meta']['tumblr_base_hostname'] ) ) {
150
			 return 'http://' . $cmeta['connection_data']['meta']['tumblr_base_hostname'];
151
		} elseif ( 'twitter' == $service_name ) {
152
			return 'https://twitter.com/' . substr( $cmeta['external_display'], 1 ); // Has a leading '@'
153 View Code Duplication
		} elseif ( 'google_plus' == $service_name && isset( $cmeta['connection_data']['meta']['google_plus_page'] ) ) {
154
			return 'https://plus.google.com/' . $cmeta['connection_data']['meta']['google_plus_page'];
155
		} elseif ( 'google_plus' == $service_name ) {
156
			return 'https://plus.google.com/' . $cmeta['external_id'];
157
		} else if ( 'linkedin' == $service_name ) {
158
			if ( !isset( $cmeta['connection_data']['meta']['profile_url'] ) ) {
159
				return false;
160
			}
161
162
			$profile_url_query = parse_url( $cmeta['connection_data']['meta']['profile_url'], PHP_URL_QUERY );
163
			wp_parse_str( $profile_url_query, $profile_url_query_args );
164
			if ( isset( $profile_url_query_args['key'] ) ) {
165
				$id = $profile_url_query_args['key'];
166
			} elseif ( isset( $profile_url_query_args['id'] ) ) {
167
				$id = $profile_url_query_args['id'];
168
			} else {
169
				return false;
170
			}
171
172
			return esc_url_raw( add_query_arg( 'id', urlencode( $id ), 'http://www.linkedin.com/profile/view' ) );
173
		} else {
174
			return false; // no fallback. we just won't link it
175
		}
176
	}
177
178
	/**
179
	* Returns a display name for the connection
180
	*/
181
	function get_display_name( $service_name, $connection ) {
182
		$cmeta = $this->get_connection_meta( $connection );
183
184
		if ( 'facebook' === $service_name ) {
185
			if ( isset( $cmeta['connection_data']['meta']['display_name'] ) ) {
186
				return $cmeta['connection_data']['meta']['display_name'];
187
			}
188
189
			return __( 'Connecting...', 'jetpack' );
190
191
		}
192
193
		if ( isset( $cmeta['connection_data']['meta']['display_name'] ) ) {
194
			return $cmeta['connection_data']['meta']['display_name'];
195 View Code Duplication
		} elseif ( $service_name == 'tumblr' && isset( $cmeta['connection_data']['meta']['tumblr_base_hostname'] ) ) {
196
			 return $cmeta['connection_data']['meta']['tumblr_base_hostname'];
197
		} elseif ( $service_name == 'twitter' ) {
198
			return $cmeta['external_display'];
199
		} else {
200
			$connection_display = $cmeta['external_display'];
201
			if ( empty( $connection_display ) )
202
				$connection_display = $cmeta['external_name'];
203
			return $connection_display;
204
		}
205
	}
206
207
	public static function get_service_label( $service_name ) {
208
		switch ( $service_name ) {
209
			case 'linkedin':
210
				return 'LinkedIn';
211
				break;
212
			case 'google_plus':
213
				return  'Google+';
214
				break;
215
			case 'twitter':
216
			case 'facebook':
217
			case 'tumblr':
218
			default:
219
				return ucfirst( $service_name );
220
				break;
221
		}
222
	}
223
224
	function show_options_popup( $service_name, $connection ) {
225
		$cmeta = $this->get_connection_meta( $connection );
226
227
		// always show if no selection has been made for facebook
228
		if ( 'facebook' == $service_name && empty( $cmeta['connection_data']['meta']['facebook_profile'] ) && empty( $cmeta['connection_data']['meta']['facebook_page'] ) )
229
			return true;
230
231
		// always show if no selection has been made for tumblr
232
		if ( 'tumblr' == $service_name && empty ( $cmeta['connection_data']['meta']['tumblr_base_hostname'] ) )
233
			return true;
234
235
		// if we have the specific connection info..
236
		if ( isset( $_GET['id'] ) ) {
237
			if ( $cmeta['connection_data']['id'] == $_GET['id'] )
238
				return true;
239
		} else {
240
			// otherwise, just show if this is the completed step / first load
241
			if ( !empty( $_GET['action'] ) && 'completed' == $_GET['action'] && !empty( $_GET['service'] ) && $service_name == $_GET['service'] && ! in_array( $_GET['service'], array( 'facebook', 'tumblr' ) ) )
242
				return true;
243
		}
244
245
		return false;
246
	}
247
248
	function user_id() {
249
		global $current_user;
250
		return $current_user->ID;
251
	}
252
253
	function blog_id() {
254
		return get_current_blog_id();
255
	}
256
257
	/**
258
	* Returns true if a user has a connection to a particular service, false otherwise
259
	*/
260
	function is_enabled( $service, $_blog_id = false, $_user_id = false ) {
261
		if ( !$_blog_id )
262
			$_blog_id = $this->blog_id();
263
264
		if ( !$_user_id )
265
			$_user_id = $this->user_id();
266
267
		$connections = $this->get_connections( $service, $_blog_id, $_user_id );
268
		return ( is_array( $connections ) && count( $connections ) > 0 ? true : false );
269
	}
270
271
	/**
272
	* Fires when a post is saved, checks conditions and saves state in postmeta so that it
273
	* can be picked up later by @see ::publicize_post() on WordPress.com codebase.
274
	*/
275
	function save_meta( $post_id, $post ) {
276
		$cron_user = null;
277
		$submit_post = true;
278
279
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) )
280
			return;
281
282
		// Don't Publicize during certain contexts:
283
284
		// - import
285
		if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING  ) {
286
			$submit_post = false;
287
		}
288
289
		// - on quick edit, autosave, etc but do fire on p2, quickpress, and instapost ajax
290
		if (
291
			defined( 'DOING_AJAX' )
292
		&&
293
			DOING_AJAX
294
		&&
295
			!did_action( 'p2_ajax' )
296
		&&
297
			!did_action( 'wp_ajax_json_quickpress_post' )
298
		&&
299
			!did_action( 'wp_ajax_instapost_publish' )
300
		&&
301
			!did_action( 'wp_ajax_post_reblog' )
302
		&&
303
			!did_action( 'wp_ajax_press-this-save-post' )
304
		) {
305
			$submit_post = false;
306
		}
307
308
		// - bulk edit
309
		if ( isset( $_GET['bulk_edit'] ) ) {
310
			$submit_post = false;
311
		}
312
313
		// - API/XML-RPC Test Posts
314
		if (
315
			(
316
				defined( 'XMLRPC_REQUEST' )
317
			&&
318
				XMLRPC_REQUEST
319
			||
320
				defined( 'APP_REQUEST' )
321
			&&
322
				APP_REQUEST
323
			)
324
		&&
325
			0 === strpos( $post->post_title, 'Temporary Post Used For Theme Detection' )
326
		) {
327
			$submit_post = false;
328
		}
329
330
		// only work with certain statuses (avoids inherits, auto drafts etc)
331
		if ( !in_array( $post->post_status, array( 'publish', 'draft', 'future' ) ) ) {
332
			$submit_post = false;
333
		}
334
335
		// don't publish password protected posts
336
		if ( '' !== $post->post_password ) {
337
			$submit_post = false;
338
		}
339
340
		// Did this request happen via wp-admin?
341
		$from_web = isset( $_SERVER['REQUEST_METHOD'] )
342
			&&
343
			'post' == strtolower( $_SERVER['REQUEST_METHOD'] )
344
			&&
345
			isset( $_POST[$this->ADMIN_PAGE] );
346
347
		if ( ( $from_web || defined( 'POST_BY_EMAIL' ) ) && isset( $_POST['wpas_title'] ) ) {
348
			if ( empty( $_POST['wpas_title'] ) ) {
349
				delete_post_meta( $post_id, $this->POST_MESS );
350
			} else {
351
				update_post_meta( $post_id, $this->POST_MESS, trim( stripslashes( $_POST['wpas_title'] ) ) );
352
			}
353
		}
354
355
		// change current user to provide context for get_services() if we're running during cron
356
		if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
357
			$cron_user = (int) $GLOBALS['user_ID'];
358
			wp_set_current_user( $post->post_author );
359
		}
360
361
		/**
362
		 * In this phase, we mark connections that we want to SKIP. When Publicize is actually triggered,
363
		 * it will Publicize to everything *except* those marked for skipping.
364
		 */
365
		foreach ( (array) $this->get_services( 'connected' ) as $service_name => $connections ) {
366
			foreach ( $connections as $connection ) {
367
				$connection_data = '';
368 View Code Duplication
				if ( method_exists( $connection, 'get_meta' ) )
369
					$connection_data = $connection->get_meta( 'connection_data' );
370
				elseif ( ! empty( $connection['connection_data'] ) )
371
					$connection_data = $connection['connection_data'];
372
373
				/** This action is documented in modules/publicize/ui.php */
374
				if ( false == apply_filters( 'wpas_submit_post?', $submit_post, $post_id, $service_name, $connection_data ) ) {
375
					delete_post_meta( $post_id, $this->PENDING );
376
					continue;
377
				}
378
379 View Code Duplication
				if ( !empty( $connection->unique_id ) )
380
					$unique_id = $connection->unique_id;
381
				else if ( !empty( $connection['connection_data']['token_id'] ) )
382
					$unique_id = $connection['connection_data']['token_id'];
383
384
				// This was a wp-admin request, so we need to check the state of checkboxes
385
				if ( $from_web ) {
386
					// delete stray service-based post meta
387
					delete_post_meta( $post_id, $this->POST_SKIP . $service_name );
388
389
					// We *unchecked* this stream from the admin page, or it's set to readonly, or it's a new addition
390
					if ( empty( $_POST[$this->ADMIN_PAGE]['submit'][$unique_id] ) ) {
391
						// Also make sure that the service-specific input isn't there.
392
						// If the user connected to a new service 'in-page' then a hidden field with the service
393
						// name is added, so we just assume they wanted to Publicize to that service.
394
						if ( empty( $_POST[$this->ADMIN_PAGE]['submit'][$service_name] ) ) {
395
							// Nothing seems to be checked, so we're going to mark this one to be skipped
396
							update_post_meta( $post_id, $this->POST_SKIP . $unique_id, 1 );
397
							continue;
398
						} else {
399
							// clean up any stray post meta
400
							delete_post_meta( $post_id, $this->POST_SKIP . $unique_id );
401
						}
402
					} else {
403
						// The checkbox for this connection is explicitly checked -- make sure we DON'T skip it
404
						delete_post_meta( $post_id, $this->POST_SKIP . $unique_id );
405
					}
406
				}
407
408
				/**
409
				 * Fires right before the post is processed for Publicize.
410
				 * Users may hook in here and do anything else they need to after meta is written,
411
				 * and before the post is processed for Publicize.
412
				 *
413
				 * @since 2.1.2
414
				 *
415
				 * @param bool $submit_post Should the post be publicized.
416
				 * @param int $post->ID Post ID.
417
				 * @param string $service_name Service name.
418
				 * @param array $connection Array of connection details.
419
				 */
420
				do_action( 'publicize_save_meta', $submit_post, $post_id, $service_name, $connection );
421
			}
422
		}
423
424
		if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
425
			wp_set_current_user( $cron_user );
426
		}
427
428
		// Next up will be ::publicize_post()
429
	}
430
431
	public function update_published_message( $messages ) {
432
		global $post_type, $post_type_object, $post;
433
		if ( ! $this->post_type_is_publicizeable( $post_type ) ) {
434
			return $messages;
435
		}
436
		$view_post_link_html = '';
437
		$viewable = is_post_type_viewable( $post_type_object );
438
		if ( $viewable ) {
439
			$view_text = esc_html__( 'View post' ); // intentionally omitted domain
440
441
			if ( 'jetpack-portfolio' == $post_type ) {
442
				$view_text = esc_html__( 'View project', 'jetpack' );
443
			}
444
445
			$view_post_link_html = sprintf( ' <a href="%1$s">%2$s</a>',
446
				esc_url( get_permalink( $post ) ),
447
				$view_text
448
			);
449
		}
450
451
		$services = $this->get_publicizing_services( $post->ID );
452
		if ( empty( $services ) ) {
453
			return $messages;
454
		}
455
456
		$labels = array();
457
		foreach ( $services as $service => $display_names ) {
458
			$labels[] = sprintf(
459
				/* translators: Service name is %1$s, and account name is %2$s. */
460
				esc_html__( '%1$s (%2$s)', 'jetpack' ),
461
				esc_html( $service ),
462
				esc_html( implode( ', ', $display_names ) )
463
			);
464
		}
465
466
		$messages['post'][6] = sprintf(
467
			/* translators: %1$s is a comma-separated list of services and accounts. Ex. Facebook (@jetpack), Twitter (@jetpack) */
468
			esc_html__( 'Post published and sharing on %1$s.', 'jetpack' ),
469
			implode( ', ', $labels )
470
		) . $view_post_link_html;
471
472
		if ( $post_type == 'post' && class_exists('Jetpack_Subscriptions' ) ) {
473
			$subscription = Jetpack_Subscriptions::init();
474
			if ( $subscription->should_email_post_to_subscribers( $post ) ) {
475
				$messages['post'][6] = sprintf(
476
					/* translators: %1$s is a comma-separated list of services and accounts. Ex. Facebook (@jetpack), Twitter (@jetpack) */
477
					esc_html__( 'Post published, sending emails to subscribers and sharing post on %1$s.', 'jetpack' ),
478
					implode( ', ', $labels )
479
				) . $view_post_link_html;
480
			}
481
		}
482
483
		$messages['jetpack-portfolio'][6] = sprintf(
484
			/* translators: %1$s is a comma-separated list of services and accounts. Ex. Facebook (@jetpack), Twitter (@jetpack) */
485
			esc_html__( 'Project published and sharing project on %1$s.', 'jetpack' ),
486
			implode( ', ', $labels )
487
		) . $view_post_link_html;
488
489
		return $messages;
490
	}
491
492
	function get_publicizing_services( $post_id ) {
493
		$services = array();
494
495
		foreach ( (array) $this->get_services( 'connected' ) as $service_name => $connections ) {
496
			// services have multiple connections.
497
			foreach ( $connections as $connection ) {
498
				$unique_id = '';
499 View Code Duplication
				if ( ! empty( $connection->unique_id ) )
500
					$unique_id = $connection->unique_id;
501
				else if ( ! empty( $connection['connection_data']['token_id'] ) )
502
					$unique_id = $connection['connection_data']['token_id'];
503
504
				// Did we skip this connection?
505
				if ( get_post_meta( $post_id, $this->POST_SKIP . $unique_id,  true ) ) {
506
					continue;
507
				}
508
				$services[ $this->get_service_label( $service_name ) ][] = $this->get_display_name( $service_name, $connection );
509
			}
510
		}
511
512
		return $services;
513
	}
514
515
	/**
516
	* Is a given post type Publicize-able?
517
	*
518
	* Not every CPT lends itself to Publicize-ation.  Allow CPTs to register by adding their CPT via
519
	* the publicize_post_types array filter.
520
	*
521
	* @param string $post_type The post type to check.
522
	* @return bool True if the post type can be Publicized.
523
	*/
524
	function post_type_is_publicizeable( $post_type ) {
525
		if ( 'post' == $post_type )
526
			return true;
527
528
		return post_type_supports( $post_type, 'publicize' );
529
	}
530
531
	function is_valid_facebook_connection( $connection ) {
532
		if ( $this->is_connecting_connection( $connection ) ) {
533
			return true;
534
		}
535
		return isset( $connection['connection_data']['meta']['facebook_page'] );
536
	}
537
538
	function is_connecting_connection( $connection ) {
539
		return isset( $connection['connection_data']['meta']['options_responses'] );
540
	}
541
542
	/**
543
	 * Runs tests on all the connections and returns the results to the caller
544
	 */
545
	function test_publicize_conns() {
546
		$test_results = array();
547
548
		foreach ( (array) $this->get_services( 'connected' ) as $service_name => $connections ) {
549
			foreach ( $connections as $connection ) {
550
551
				$id = $this->get_connection_id( $connection );
552
553
				$connection_test_passed = true;
554
				$connection_test_message = __( 'This connection is working correctly.' , 'jetpack' );
555
				$user_can_refresh = false;
556
				$refresh_text = '';
557
				$refresh_url = '';
558
559
				$connection_test_result = true;
560
				if ( method_exists( $this, 'test_connection' ) ) {
561
					$connection_test_result = $this->test_connection( $service_name, $connection );
562
				}
563
564
				if ( is_wp_error( $connection_test_result ) ) {
565
					$connection_test_passed = false;
566
					$connection_test_message = $connection_test_result->get_error_message();
567
					$error_data = $connection_test_result->get_error_data();
568
569
					$user_can_refresh = $error_data['user_can_refresh'];
570
					$refresh_text = $error_data['refresh_text'];
571
					$refresh_url = $error_data['refresh_url'];
572
				}
573
574
				// Mark facebook profiles as deprecated
575
				if ( 'facebook' === $service_name && ! $this->is_valid_facebook_connection( $connection ) ) {
576
					$connection_test_passed = false;
577
					$user_can_refresh = false;
578
					$connection_test_message = __( 'Facebook no longer supports Publicize connections to Facebook Profiles, but you can still connect Facebook Pages. Please select a Facebook Page to publish updates to.', 'jetpack');
579
				}
580
581
				$unique_id = null;
582 View Code Duplication
				if ( ! empty( $connection->unique_id ) ) {
583
					$unique_id = $connection->unique_id;
584
				} else if ( ! empty( $connection['connection_data']['token_id'] ) ) {
585
					$unique_id = $connection['connection_data']['token_id'];
586
				}
587
588
				$test_results[] = array(
589
					'connectionID'          => $id,
590
					'serviceName'           => $service_name,
591
					'connectionTestPassed'  => $connection_test_passed,
592
					'connectionTestMessage' => esc_attr( $connection_test_message ),
593
					'userCanRefresh'        => $user_can_refresh,
594
					'refreshText'           => esc_attr( $refresh_text ),
595
					'refreshURL'            => $refresh_url,
596
					'unique_id'             => $unique_id,
597
				);
598
			}
599
		}
600
601
		wp_send_json_success( $test_results );
602
	}
603
604
	protected static function build_sprintf( $args ) {
605
		$search = array();
606
		$replace = array();
607
		foreach ( $args as $k => $arg ) {
608
			if ( 0 == $k ) {
609
				$string = $arg;
610
				continue;
611
			}
612
			$search[] = "%$arg%";
613
			$replace[] = "%$k\$s";
614
		}
615
		return str_replace( $search, $replace, $string );
616
	}
617
}
618
619
function publicize_calypso_url() {
620
	$calypso_sharing_url = 'https://wordpress.com/sharing/';
621
	if ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'build_raw_urls' ) ) {
622
		$site_suffix = Jetpack::build_raw_urls( home_url() );
623
	} elseif ( class_exists( 'WPCOM_Masterbar' ) && method_exists( 'WPCOM_Masterbar', 'get_calypso_site_slug' ) ) {
624
		$site_suffix = WPCOM_Masterbar::get_calypso_site_slug( get_current_blog_id() );
625
	}
626
627
	if ( $site_suffix ) {
628
		return $calypso_sharing_url . $site_suffix;
0 ignored issues
show
The variable $site_suffix 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...
629
	} else {
630
		return $calypso_sharing_url;
631
	}
632
}
633