Completed
Push — add/7.4-travis ( d7c6dc...d1fcb5 )
by
unknown
07:19
created

Sharing_Service   F

Complexity

Total Complexity 80

Size/Duplication

Total Lines 495
Duplicated Lines 10.71 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 53
loc 495
rs 2
c 0
b 0
f 0
wmc 80
lcom 1
cbo 4

14 Methods

Rating   Name   Duplication   Size   Complexity  
B new_service() 0 38 6
A delete_service() 0 14 3
A set_blog_services() 0 46 1
A __construct() 0 3 1
A get_all_services_blog() 0 21 5
B get_all_services() 0 55 6
D get_blog_services() 10 91 14
A get_service() 0 13 3
F set_global_options() 16 70 16
B get_global_options() 0 33 11
A set_service() 0 36 2
A get_total() 13 21 5
A get_services_total() 0 13 4
A get_posts_total() 14 16 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Sharing_Service often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Sharing_Service, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
use Automattic\Jetpack\Assets;
4
use Automattic\Jetpack\Sync\Settings;
5
6
include_once dirname( __FILE__ ) . '/sharing-sources.php';
7
8
define( 'WP_SHARING_PLUGIN_VERSION', JETPACK__VERSION );
9
10
class Sharing_Service {
11
	private $global               = false;
12
	public $default_sharing_label = '';
13
14
	public function __construct() {
15
		$this->default_sharing_label = __( 'Share this:', 'jetpack' );
16
	}
17
18
	/**
19
	 * Gets a generic list of all services, without any config
20
	 */
21
	public function get_all_services_blog() {
22
		$options = get_option( 'sharing-options' );
23
24
		$all      = $this->get_all_services();
25
		$services = array();
26
27
		foreach ( $all as $id => $name ) {
28
			if ( isset( $all[ $id ] ) ) {
29
				$config = array();
30
31
				// Pre-load custom modules otherwise they won't know who they are
32
				if ( substr( $id, 0, 7 ) == 'custom-' && is_array( $options[ $id ] ) ) {
33
					$config = $options[ $id ];
34
				}
35
36
				$services[ $id ] = new $all[ $id ]( $id, $config );
37
			}
38
		}
39
40
		return $services;
41
	}
42
43
	/**
44
	 * Gets a list of all available service names and classes
45
	 */
46
	public function get_all_services( $include_custom = true ) {
47
		// Default services
48
		// if you update this list, please update the REST API tests
49
		// in bin/tests/api/suites/SharingTest.php
50
		$services = array(
51
			'print'            => 'Share_Print',
52
			'facebook'         => 'Share_Facebook',
53
			'linkedin'         => 'Share_LinkedIn',
54
			'reddit'           => 'Share_Reddit',
55
			'twitter'          => 'Share_Twitter',
56
			'tumblr'           => 'Share_Tumblr',
57
			'pinterest'        => 'Share_Pinterest',
58
			'pocket'           => 'Share_Pocket',
59
			'telegram'         => 'Share_Telegram',
60
			'jetpack-whatsapp' => 'Jetpack_Share_WhatsApp',
61
			'skype'            => 'Share_Skype',
62
		);
63
64
		/**
65
		 * Filters if Email Sharing is enabled.
66
		 *
67
		 * E-Mail sharing is often problematic due to spam concerns, so this filter enables it to be quickly and simply toggled.
68
		 * @module sharedaddy
69
		 *
70
		 * @since 5.1.0
71
		 *
72
		 * @param bool $email Is e-mail sharing enabled? Default false if Akismet is not active or true if Akismet is active.
73
		 */
74
		if ( apply_filters( 'sharing_services_email', Jetpack::is_akismet_active() ) ) {
75
			$services['email'] = 'Share_Email';
76
		}
77
78
		if ( is_multisite() && is_plugin_active( 'press-this/press-this-plugin.php' ) ) {
79
			$services['press-this'] = 'Share_PressThis';
80
		}
81
82
		if ( $include_custom ) {
83
			// Add any custom services in
84
			$options = $this->get_global_options();
85
			foreach ( (array) $options['custom'] as $custom_id ) {
86
				$services[ $custom_id ] = 'Share_Custom';
87
			}
88
		}
89
90
		/**
91
		 * Filters the list of available Sharing Services.
92
		 *
93
		 * @module sharedaddy
94
		 *
95
		 * @since 1.1.0
96
		 *
97
		 * @param array $services Array of all available Sharing Services.
98
		 */
99
		return apply_filters( 'sharing_services', $services );
100
	}
101
102
	public function new_service( $label, $url, $icon ) {
103
		// Validate
104
		$label = trim( wp_html_excerpt( wp_kses( $label, array() ), 30 ) );
105
		$url   = trim( esc_url_raw( $url ) );
106
		$icon  = trim( esc_url_raw( $icon ) );
107
108
		if ( $label && $url && $icon ) {
109
			$options = get_option( 'sharing-options' );
110
			if ( ! is_array( $options ) ) {
111
				$options = array();
112
			}
113
114
			$service_id = 'custom-' . time();
115
116
			// Add a new custom service
117
			$options['global']['custom'][] = $service_id;
118
			if ( false !== $this->global ) {
119
				$this->global['custom'][] = $service_id;
120
			}
121
122
			update_option( 'sharing-options', $options );
123
124
			// Create a custom service and set the options for it
125
			$service = new Share_Custom(
126
				$service_id, array(
127
					'name' => $label,
128
					'url'  => $url,
129
					'icon' => $icon,
130
				)
131
			);
132
			$this->set_service( $service_id, $service );
133
134
			// Return the service
135
			return $service;
136
		}
137
138
		return false;
139
	}
140
141
	public function delete_service( $service_id ) {
142
		$options = get_option( 'sharing-options' );
143
		if ( isset( $options[ $service_id ] ) ) {
144
			unset( $options[ $service_id ] );
145
		}
146
147
		$key = array_search( $service_id, $options['global']['custom'] );
148
		if ( $key !== false ) {
149
			unset( $options['global']['custom'][ $key ] );
150
		}
151
152
		update_option( 'sharing-options', $options );
153
		return true;
154
	}
155
156
	public function set_blog_services( array $visible, array $hidden ) {
157
		$services = $this->get_all_services();
158
		// Validate the services
159
		$available = array_keys( $services );
160
161
		// Only allow services that we have defined
162
		$hidden  = array_intersect( $hidden, $available );
163
		$visible = array_intersect( $visible, $available );
164
165
		// Ensure we don't have the same ones in hidden and visible
166
		$hidden = array_diff( $hidden, $visible );
167
168
		/**
169
		 * Control the state of the list of sharing services.
170
		 *
171
		 * @module sharedaddy
172
		 *
173
		 * @since 1.1.0
174
		 *
175
		 * @param array $args {
176
		 *  Array of options describing the state of the sharing services.
177
		 *
178
		 *  @type array $services List of all available service names and classes.
179
		 *  @type array $available Validated list of all available service names and classes.
180
		 *  @type array $hidden List of services hidden behind a "More" button.
181
		 *  @type array $visible List of visible services.
182
		 *  @type array $this->get_blog_services() Array of Sharing Services currently enabled.
183
		 * }
184
		 */
185
		do_action(
186
			'sharing_get_services_state', array(
187
				'services'          => $services,
188
				'available'         => $available,
189
				'hidden'            => $hidden,
190
				'visible'           => $visible,
191
				'currently_enabled' => $this->get_blog_services(),
192
			)
193
		);
194
195
		return update_option(
196
			'sharing-services', array(
197
				'visible' => $visible,
198
				'hidden'  => $hidden,
199
			)
200
		);
201
	}
202
203
	public function get_blog_services() {
204
		$options  = get_option( 'sharing-options' );
205
		$enabled  = get_option( 'sharing-services' );
206
		$services = $this->get_all_services();
207
208
		/**
209
		 * Check if options exist and are well formatted.
210
		 * This avoids issues on sites with corrupted options.
211
		 * @see https://github.com/Automattic/jetpack/issues/6121
212
		 */
213
		if ( ! is_array( $options ) || ! isset( $options['button_style'], $options['global'] ) ) {
214
			$global_options = array( 'global' => $this->get_global_options() );
215
			$options        = is_array( $options )
216
				? array_merge( $options, $global_options )
217
				: $global_options;
218
		}
219
220
		$global = $options['global'];
221
222
		// Default services
223
		if ( ! is_array( $enabled ) ) {
224
			$enabled = array(
225
				'visible' => array(
226
					'twitter',
227
					'facebook',
228
				),
229
				'hidden'  => array(),
230
			);
231
232
			/**
233
			 * Filters the list of default Sharing Services.
234
			 *
235
			 * @module sharedaddy
236
			 *
237
			 * @since 1.1.0
238
			 *
239
			 * @param array $enabled Array of default Sharing Services.
240
			 */
241
			$enabled = apply_filters( 'sharing_default_services', $enabled );
242
		}
243
244
		// Cleanup after any filters that may have produced duplicate services
245 View Code Duplication
		if ( is_array( $enabled['visible'] ) ) {
246
			$enabled['visible'] = array_unique( $enabled['visible'] );
247
		} else {
248
			$enabled['visible'] = array();
249
		}
250
251 View Code Duplication
		if ( is_array( $enabled['hidden'] ) ) {
252
			$enabled['hidden'] = array_unique( $enabled['hidden'] );
253
		} else {
254
			$enabled['hidden'] = array();
255
		}
256
257
		// Form the enabled services
258
		$blog = array(
259
			'visible' => array(),
260
			'hidden'  => array(),
261
		);
262
263
		foreach ( $blog as $area => $stuff ) {
264
			foreach ( (array) $enabled[ $area ] as $service ) {
265
				if ( isset( $services[ $service ] ) ) {
266
					if ( ! isset( $options[ $service ] ) || ! is_array( $options[ $service ] ) ) {
267
						$options[ $service ] = array();
268
					}
269
					$blog[ $area ][ $service ] = new $services[ $service ]( $service, array_merge( $global, $options[ $service ] ) );
270
				}
271
			}
272
		}
273
274
		/**
275
		 * Filters the list of enabled Sharing Services.
276
		 *
277
		 * @module sharedaddy
278
		 *
279
		 * @since 1.1.0
280
		 *
281
		 * @param array $blog Array of enabled Sharing Services.
282
		 */
283
		$blog = apply_filters( 'sharing_services_enabled', $blog );
284
285
		// Add CSS for NASCAR
286
		if ( count( $blog['visible'] ) || count( $blog['hidden'] ) ) {
287
			add_filter( 'post_flair_block_css', 'post_flair_service_enabled_sharing' );
288
		}
289
290
		// Convenience for checking if a service is present
291
		$blog['all'] = array_flip( array_merge( array_keys( $blog['visible'] ), array_keys( $blog['hidden'] ) ) );
292
		return $blog;
293
	}
294
295
	public function get_service( $service_name ) {
296
		$services = $this->get_blog_services();
297
298
		if ( isset( $services['visible'][ $service_name ] ) ) {
299
			return $services['visible'][ $service_name ];
300
		}
301
302
		if ( isset( $services['hidden'][ $service_name ] ) ) {
303
			return $services['hidden'][ $service_name ];
304
		}
305
306
		return false;
307
	}
308
309
	public function set_global_options( $data ) {
310
		$options = get_option( 'sharing-options' );
311
312
		// No options yet.
313
		if ( ! is_array( $options ) ) {
314
			$options = array();
315
		}
316
317
		// Defaults.
318
		$options['global'] = array(
319
			'button_style'  => 'icon-text',
320
			'sharing_label' => $this->default_sharing_label,
321
			'open_links'    => 'same',
322
			'show'          => ! isset( $options['global'] ) ? array( 'post', 'page' ) : array(),
323
			'custom'        => isset( $options['global']['custom'] ) ? $options['global']['custom'] : array(),
324
		);
325
326
		/**
327
		 * Filters global sharing settings.
328
		 *
329
		 * @module sharedaddy
330
		 *
331
		 * @since 1.1.0
332
		 *
333
		 * @param array $options['global'] Array of global sharing settings.
334
		 */
335
		$options['global'] = apply_filters( 'sharing_default_global', $options['global'] );
336
337
		// Validate options and set from our data
338
		if ( isset( $data['button_style'] ) && in_array( $data['button_style'], array( 'icon-text', 'icon', 'text', 'official' ) ) ) {
339
			$options['global']['button_style'] = $data['button_style'];
340
		}
341
342
		if ( isset( $data['sharing_label'] ) ) {
343
			if ( $this->default_sharing_label === $data['sharing_label'] ) {
344
				$options['global']['sharing_label'] = false;
345
			} else {
346
				$options['global']['sharing_label'] = trim( wp_kses( stripslashes( $data['sharing_label'] ), array() ) );
347
			}
348
		}
349
350
		if ( isset( $data['open_links'] ) && in_array( $data['open_links'], array( 'new', 'same' ) ) ) {
351
			$options['global']['open_links'] = $data['open_links'];
352
		}
353
354
		$shows   = array_values( get_post_types( array( 'public' => true ) ) );
355
		$shows[] = 'index';
356
		if ( isset( $data['show'] ) ) {
357 View Code Duplication
			if ( is_scalar( $data['show'] ) ) {
358
				switch ( $data['show'] ) {
359
					case 'posts':
360
						$data['show'] = array( 'post', 'page' );
361
						break;
362
					case 'index':
363
						$data['show'] = array( 'index' );
364
						break;
365
					case 'posts-index':
366
						$data['show'] = array( 'post', 'page', 'index' );
367
						break;
368
				}
369
			}
370
371 View Code Duplication
			if ( $data['show'] = array_intersect( $data['show'], $shows ) ) {
372
				$options['global']['show'] = $data['show'];
373
			}
374
		}
375
376
		update_option( 'sharing-options', $options );
377
		return $options['global'];
378
	}
379
380
	public function get_global_options() {
381
		if ( $this->global === false ) {
382
			$options = get_option( 'sharing-options' );
383
384
			if ( is_array( $options ) && isset( $options['global'] ) && is_array( $options['global'] ) ) {
385
				$this->global = $options['global'];
0 ignored issues
show
Documentation Bug introduced by
It seems like $options['global'] of type array is incompatible with the declared type boolean of property $global.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
386
			} else {
387
				$this->global = $this->set_global_options( $options );
388
			}
389
		}
390
391
		if ( ! isset( $this->global['show'] ) ) {
392
			$this->global['show'] = array( 'post', 'page' );
393
		} elseif ( is_scalar( $this->global['show'] ) ) {
394
			switch ( $this->global['show'] ) {
395
				case 'posts':
396
					$this->global['show'] = array( 'post', 'page' );
397
					break;
398
				case 'index':
399
					$this->global['show'] = array( 'index' );
400
					break;
401
				case 'posts-index':
402
					$this->global['show'] = array( 'post', 'page', 'index' );
403
					break;
404
			}
405
		}
406
407
		if ( false === $this->global['sharing_label'] ) {
408
			$this->global['sharing_label'] = $this->default_sharing_label;
409
		}
410
411
		return $this->global;
412
	}
413
414
	public function set_service( $id, Sharing_Source $service ) {
415
		// Update the options for this service
416
		$options = get_option( 'sharing-options' );
417
418
		// No options yet
419
		if ( ! is_array( $options ) ) {
420
			$options = array();
421
		}
422
423
		/**
424
		 * Get the state of a sharing button.
425
		 *
426
		 * @module sharedaddy
427
		 *
428
		 * @since 1.1.0
429
		 *
430
		 * @param array $args {
431
		 *  State of a sharing button.
432
		 *
433
		 *  @type string $id Service ID.
434
		 *  @type array $options Array of all sharing options.
435
		 *  @type array $service Details about a service.
436
		 * }
437
		 */
438
		do_action(
439
			'sharing_get_button_state', array(
440
				'id'      => $id,
441
				'options' => $options,
442
				'service' => $service,
443
			)
444
		);
445
446
		$options[ $id ] = $service->get_options();
0 ignored issues
show
Bug introduced by
The method get_options cannot be called on $service (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
447
448
		update_option( 'sharing-options', array_filter( $options ) );
449
	}
450
451
	// Soon to come to a .org plugin near you!
452
	public function get_total( $service_name = false, $post_id = false, $_blog_id = false ) {
453
		global $wpdb, $blog_id;
454
		if ( ! $_blog_id ) {
455
			$_blog_id = $blog_id;
456
		}
457 View Code Duplication
		if ( $service_name == false ) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
458
			if ( $post_id > 0 ) {
459
				// total number of shares for this post
460
				return (int) $wpdb->get_var( $wpdb->prepare( 'SELECT SUM( count ) FROM sharing_stats WHERE blog_id = %d AND post_id = %d', $_blog_id, $post_id ) );
461
			} else {
462
				// total number of shares for this blog
463
				return (int) $wpdb->get_var( $wpdb->prepare( 'SELECT SUM( count ) FROM sharing_stats WHERE blog_id = %d', $_blog_id ) );
464
			}
465
		}
466
467 View Code Duplication
		if ( $post_id > 0 ) {
468
			return (int) $wpdb->get_var( $wpdb->prepare( 'SELECT SUM( count ) FROM sharing_stats WHERE blog_id = %d AND post_id = %d AND share_service = %s', $_blog_id, $post_id, $service_name ) );
469
		} else {
470
			return (int) $wpdb->get_var( $wpdb->prepare( 'SELECT SUM( count ) FROM sharing_stats WHERE blog_id = %d AND share_service = %s', $_blog_id, $service_name ) );
471
		}
472
	}
473
474
	public function get_services_total( $post_id = false ) {
475
		$totals   = array();
476
		$services = $this->get_blog_services();
477
478
		if ( ! empty( $services ) && isset( $services['all'] ) ) {
479
			foreach ( $services['all'] as $key => $value ) {
480
				$totals[ $key ] = new Sharing_Service_Total( $key, $this->get_total( $key, $post_id ) );
0 ignored issues
show
Documentation introduced by
$key is of type integer|string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
481
			}
482
		}
483
		usort( $totals, array( 'Sharing_Service_Total', 'cmp' ) );
484
485
		return $totals;
486
	}
487
488 View Code Duplication
	public function get_posts_total() {
489
		$totals = array();
490
		global $wpdb, $blog_id;
491
492
		$my_data = $wpdb->get_results( $wpdb->prepare( 'SELECT post_id as id, SUM( count ) as total FROM sharing_stats WHERE blog_id = %d GROUP BY post_id ORDER BY count DESC ', $blog_id ) );
493
494
		if ( ! empty( $my_data ) ) {
495
			foreach ( $my_data as $row ) {
496
				$totals[] = new Sharing_Post_Total( $row->id, $row->total );
497
			}
498
		}
499
500
		usort( $totals, array( 'Sharing_Post_Total', 'cmp' ) );
501
502
		return $totals;
503
	}
504
}
505
506
class Sharing_Service_Total {
507
	public $id      = '';
508
	public $name    = '';
509
	public $service = '';
510
	public $total   = 0;
511
512
	public function __construct( $id, $total ) {
513
		$services      = new Sharing_Service();
514
		$this->id      = esc_html( $id );
515
		$this->service = $services->get_service( $id );
516
		$this->total   = (int) $total;
517
518
		$this->name = $this->service->get_name();
519
	}
520
521
	static function cmp( $a, $b ) {
522
		if ( $a->total == $b->total ) {
523
			return $a->name < $b->name;
524
		}
525
		return $a->total < $b->total;
526
	}
527
}
528
529
class Sharing_Post_Total {
530
	public $id    = 0;
531
	public $total = 0;
532
	public $title = '';
533
	public $url   = '';
534
535
	public function __construct( $id, $total ) {
536
		$this->id    = (int) $id;
537
		$this->total = (int) $total;
538
		$this->title = get_the_title( $this->id );
539
		$this->url   = get_permalink( $this->id );
540
	}
541
542
	static function cmp( $a, $b ) {
543
		if ( $a->total == $b->total ) {
544
			return $a->id < $b->id;
545
		}
546
		return $a->total < $b->total;
547
	}
548
}
549
550
function sharing_register_post_for_share_counts( $post_id ) {
551
	global $jetpack_sharing_counts;
552
553
	if ( ! isset( $jetpack_sharing_counts ) || ! is_array( $jetpack_sharing_counts ) ) {
554
		$jetpack_sharing_counts = array();
555
	}
556
557
	$jetpack_sharing_counts[ (int) $post_id ] = get_permalink( $post_id );
558
}
559
560
function sharing_maybe_enqueue_scripts() {
561
	$sharer         = new Sharing_Service();
562
	$global_options = $sharer->get_global_options();
563
564
	$enqueue = false;
565
	if ( is_singular() && in_array( get_post_type(), $global_options['show'] ) ) {
566
		$enqueue = true;
567 View Code Duplication
	} elseif ( in_array( 'index', $global_options['show'] ) && ( is_home() || is_front_page() || is_archive() || is_search() || in_array( get_post_type(), $global_options['show'] ) ) ) {
568
		$enqueue = true;
569
	}
570
571
	/**
572
	 * Filter to decide when sharing scripts should be enqueued.
573
	 *
574
	 * @module sharedaddy
575
	 *
576
	 * @since 3.2.0
577
	 *
578
	 * @param bool $enqueue Decide if the sharing scripts should be enqueued.
579
	 */
580
	return (bool) apply_filters( 'sharing_enqueue_scripts', $enqueue );
581
}
582
583
function sharing_add_footer() {
584
	if (
585
		class_exists( 'Jetpack_AMP_Support' )
586
		&& Jetpack_AMP_Support::is_amp_request()
587
	) {
588
		return;
589
	}
590
591
	global $jetpack_sharing_counts;
592
593
	/**
594
	 * Filter all JavaScript output by the sharing module.
595
	 *
596
	 * @module sharedaddy
597
	 *
598
	 * @since 1.1.0
599
	 *
600
	 * @param bool true Control whether the sharing module should add any JavaScript to the site. Default to true.
601
	 */
602
	if ( apply_filters( 'sharing_js', true ) && sharing_maybe_enqueue_scripts() ) {
603
604
		/**
605
		 * Filter the display of sharing counts next to the sharing buttons.
606
		 *
607
		 * @module sharedaddy
608
		 *
609
		 * @since 3.2.0
610
		 *
611
		 * @param bool true Control the display of counters next to the sharing buttons. Default to true.
612
		 */
613
		if ( apply_filters( 'jetpack_sharing_counts', true ) && is_array( $jetpack_sharing_counts ) && count( $jetpack_sharing_counts ) ) :
614
			$sharing_post_urls = array_filter( $jetpack_sharing_counts );
615
			if ( $sharing_post_urls ) :
0 ignored issues
show
Bug Best Practice introduced by
The expression $sharing_post_urls of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
616
				?>
617
618
	<script type="text/javascript">
619
		window.WPCOM_sharing_counts = <?php echo json_encode( array_flip( $sharing_post_urls ) ); ?>;
620
	</script>
621
				<?php
622
			endif;
623
		endif;
624
625
		wp_enqueue_script( 'sharing-js' );
626
		$sharing_js_options = array(
627
			'lang'            => get_base_recaptcha_lang_code(),
628
			/** This filter is documented in modules/sharedaddy/sharing-service.php */
629
			'counts'          => apply_filters( 'jetpack_sharing_counts', true ),
630
			'is_stats_active' => Jetpack::is_module_active( 'stats' ),
631
		);
632
		wp_localize_script( 'sharing-js', 'sharing_js_options', $sharing_js_options );
633
	}
634
	$sharer  = new Sharing_Service();
635
	$enabled = $sharer->get_blog_services();
636
	foreach ( array_merge( $enabled['visible'], $enabled['hidden'] ) as $service ) {
637
		$service->display_footer();
638
	}
639
}
640
641
function sharing_add_header() {
642
	$sharer  = new Sharing_Service();
643
	$enabled = $sharer->get_blog_services();
644
645
	foreach ( array_merge( $enabled['visible'], $enabled['hidden'] ) as $service ) {
646
		$service->display_header();
647
	}
648
649
	if ( count( $enabled['all'] ) > 0 && sharing_maybe_enqueue_scripts() ) {
650
		wp_enqueue_style( 'sharedaddy', plugin_dir_url( __FILE__ ) . 'sharing.css', array(), JETPACK__VERSION );
651
		wp_enqueue_style( 'social-logos' );
652
	}
653
654
}
655
add_action( 'wp_head', 'sharing_add_header', 1 );
656
657
function sharing_process_requests() {
658
	global $post;
659
660
	// Only process if: single post and share=X defined
661
	if ( ( is_page() || is_single() ) && isset( $_GET['share'] ) ) {
662
		$sharer = new Sharing_Service();
663
664
		$service = $sharer->get_service( $_GET['share'] );
665
		if ( $service ) {
666
			$service->process_request( $post, $_POST );
667
		}
668
	}
669
}
670
add_action( 'template_redirect', 'sharing_process_requests', 9 );
671
672
/**
673
 * Append sharing links to text.
674
 *
675
 * @param string $text The original text to append sharing links onto.
676
 * @param bool   $echo Where to echo the text or return.
677
 *
678
 * @return string The original $text with, if conditions are met, the sharing links.
679
 */
680
function sharing_display( $text = '', $echo = false ) {
681
	global $post, $wp_current_filter;
682
683
	if ( Settings::is_syncing() ) {
684
		return $text;
685
	}
686
687
	if ( empty( $post ) ) {
688
		return $text;
689
	}
690
691
	if ( ( is_preview() || is_admin() ) && ! ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
692
		return $text;
693
	}
694
695
	// Don't output flair on excerpts.
696
	if ( in_array( 'get_the_excerpt', (array) $wp_current_filter, true ) ) {
697
		return $text;
698
	}
699
700
	// Don't allow flair to be added to the_content more than once (prevent infinite loops).
701
	$done = false;
702
	foreach ( $wp_current_filter as $filter ) {
703
		if ( 'the_content' === $filter ) {
704
			if ( $done ) {
705
				return $text;
706
			} else {
707
				$done = true;
708
			}
709
		}
710
	}
711
712
	// check whether we are viewing the front page and whether the front page option is checked.
713
	$options         = get_option( 'sharing-options' );
714
	$display_options = null;
715
716
	if ( is_array( $options ) ) {
717
		$display_options = $options['global']['show'];
718
	}
719
720
	if ( is_front_page() && ( is_array( $display_options ) && ! in_array( 'index', $display_options, true ) ) ) {
721
		return $text;
722
	}
723
724
	if ( is_attachment() && in_array( 'the_excerpt', (array) $wp_current_filter, true ) ) {
725
		// Many themes run the_excerpt() conditionally on an attachment page, then run the_content().
726
		// We only want to output the sharing buttons once.  Let's stick with the_content().
727
		return $text;
728
	}
729
730
	$sharer = new Sharing_Service();
731
	$global = $sharer->get_global_options();
732
733
	$show = false;
734
	if ( ! is_feed() ) {
735
		if ( is_singular() && in_array( get_post_type(), $global['show'], true ) ) {
736
			$show = true;
737 View Code Duplication
		} elseif ( in_array( 'index', $global['show'], true ) && ( is_home() || is_front_page() || is_archive() || is_search() || in_array( get_post_type(), $global['show'], true ) ) ) {
738
			$show = true;
739
		}
740
	}
741
742
	/**
743
	 * Filter to decide if sharing buttons should be displayed.
744
	 *
745
	 * @module sharedaddy
746
	 *
747
	 * @since 1.1.0
748
	 *
749
	 * @param bool $show Should the sharing buttons be displayed.
750
	 * @param WP_Post $post The post to share.
751
	 */
752
	$show = apply_filters( 'sharing_show', $show, $post );
753
754
	// Disabled for this post?
755
	$switched_status = get_post_meta( $post->ID, 'sharing_disabled', false );
756
757
	if ( ! empty( $switched_status ) ) {
758
		$show = false;
759
	}
760
761
	// Is the post private?
762
	$post_status = get_post_status( $post->ID );
763
764
	if ( 'private' === $post_status ) {
765
		$show = false;
766
	}
767
768
	/**
769
	 * Filter the Sharing buttons' Ajax action name Jetpack checks for.
770
	 * This allows the use of the buttons with your own Ajax implementation.
771
	 *
772
	 * @module sharedaddy
773
	 *
774
	 * @since 7.3.0
775
	 *
776
	 * @param string $sharing_ajax_action_name Name of the Sharing buttons' Ajax action.
777
	 */
778
	$ajax_action = apply_filters( 'sharing_ajax_action', 'get_latest_posts' );
779
780
	// Allow to be used in ajax requests for latest posts.
781
	if (
782
		defined( 'DOING_AJAX' )
783
		&& DOING_AJAX
784
		&& isset( $_REQUEST['action'] )
785
		&& $ajax_action === $_REQUEST['action']
786
	) {
787
		$show = true;
788
	}
789
790
	$sharing_content = '';
791
	$enabled         = false;
792
793
	if ( $show ) {
794
		/**
795
		 * Filters the list of enabled Sharing Services.
796
		 *
797
		 * @module sharedaddy
798
		 *
799
		 * @since 2.2.3
800
		 *
801
		 * @param array $sharer->get_blog_services() Array of Sharing Services currently enabled.
802
		 */
803
		$enabled = apply_filters( 'sharing_enabled', $sharer->get_blog_services() );
804
805
		if ( count( $enabled['all'] ) > 0 ) {
806
			$dir = get_option( 'text_direction' );
807
808
			// Wrapper.
809
			$sharing_content .= '<div class="sharedaddy sd-sharing-enabled"><div class="robots-nocontent sd-block sd-social sd-social-' . $global['button_style'] . ' sd-sharing">';
810
			if ( '' !== $global['sharing_label'] ) {
811
				$sharing_content .= sprintf(
812
					/**
813
					 * Filter the sharing buttons' headline structure.
814
					 *
815
					 * @module sharedaddy
816
					 *
817
					 * @since 4.4.0
818
					 *
819
					 * @param string $sharing_headline Sharing headline structure.
820
					 * @param string $global['sharing_label'] Sharing title.
821
					 * @param string $sharing Module name.
822
					 */
823
					apply_filters( 'jetpack_sharing_headline_html', '<h3 class="sd-title">%s</h3>', $global['sharing_label'], 'sharing' ),
824
					esc_html( $global['sharing_label'] )
825
				);
826
			}
827
			$sharing_content .= '<div class="sd-content"><ul>';
828
829
			// Visible items.
830
			$visible = '';
831
			foreach ( $enabled['visible'] as $id => $service ) {
832
				$klasses = array( 'share-' . $service->get_class() );
833
				if ( $service->is_deprecated() ) {
834
					if ( ! current_user_can( 'manage_options' ) ) {
835
						continue;
836
					}
837
					$klasses[] = 'share-deprecated';
838
				}
839
				// Individual HTML for sharing service.
840
				$visible .= '<li class="' . implode( ' ', $klasses ) . '">' . $service->get_display( $post ) . '</li>';
841
			}
842
843
			$parts   = array();
844
			$parts[] = $visible;
845
			if ( count( $enabled['hidden'] ) > 0 ) {
846
				if ( count( $enabled['visible'] ) > 0 ) {
847
					$expand = __( 'More', 'jetpack' );
848
				} else {
849
					$expand = __( 'Share', 'jetpack' );
850
				}
851
				$parts[] = '<li><a href="#" class="sharing-anchor sd-button share-more"><span>' . $expand . '</span></a></li>';
852
			}
853
854
			if ( 'rtl' === $dir ) {
855
				$parts = array_reverse( $parts );
856
			}
857
858
			$sharing_content .= implode( '', $parts );
859
			$sharing_content .= '<li class="share-end"></li></ul>';
860
861
			if ( count( $enabled['hidden'] ) > 0 ) {
862
				$sharing_content .= '<div class="sharing-hidden"><div class="inner" style="display: none;';
863
864
				if ( count( $enabled['hidden'] ) === 1 ) {
865
					$sharing_content .= 'width:150px;';
866
				}
867
868
				$sharing_content .= '">';
869
870
				if ( count( $enabled['hidden'] ) === 1 ) {
871
					$sharing_content .= '<ul style="background-image:none;">';
872
				} else {
873
					$sharing_content .= '<ul>';
874
				}
875
876
				$count = 1;
877
				foreach ( $enabled['hidden'] as $id => $service ) {
878
					// Individual HTML for sharing service.
879
					$klasses = array( 'share-' . $service->get_class() );
880
					if ( $service->is_deprecated() ) {
881
						if ( ! current_user_can( 'manage_options' ) ) {
882
							continue;
883
						}
884
						$klasses[] = 'share-deprecated';
885
					}
886
					$sharing_content .= '<li class="' . implode( ' ', $klasses ) . '">';
887
					$sharing_content .= $service->get_display( $post );
888
					$sharing_content .= '</li>';
889
890
					if ( ( $count % 2 ) === 0 ) {
891
						$sharing_content .= '<li class="share-end"></li>';
892
					}
893
894
					$count ++;
895
				}
896
897
				// End of wrapper.
898
				$sharing_content .= '<li class="share-end"></li></ul></div></div>';
899
			}
900
901
			$sharing_content .= '</div></div></div>';
902
903
			// Register our JS.
904
			if ( defined( 'JETPACK__VERSION' ) ) {
905
				$ver = JETPACK__VERSION;
906
			} else {
907
				$ver = '20141212';
908
			}
909
910
			// @todo: Investigate if we can load this JS in the footer instead.
911
			wp_register_script(
912
				'sharing-js',
913
				Assets::get_file_url_for_environment(
914
					'_inc/build/sharedaddy/sharing.min.js',
915
					'modules/sharedaddy/sharing.js'
916
				),
917
				array( 'jquery' ),
918
				$ver,
919
				false
920
			);
921
922
			// Enqueue scripts for the footer.
923
			add_action( 'wp_footer', 'sharing_add_footer' );
924
		}
925
	}
926
927
	/**
928
	 * Filters the content markup of the Jetpack sharing links
929
	 *
930
	 * @module sharedaddy
931
	 *
932
	 * @since 3.8.0
933
	 * @since 6.2.0 Started sending $enabled as a second parameter.
934
	 *
935
	 * @param string $sharing_content Content markup of the Jetpack sharing links
936
	 * @param array  $enabled         Array of Sharing Services currently enabled.
937
	 */
938
	$sharing_markup = apply_filters( 'jetpack_sharing_display_markup', $sharing_content, $enabled );
939
940
	if ( $echo ) {
941
		echo $text . $sharing_markup;
942
	} else {
943
		return $text . $sharing_markup;
944
	}
945
}
946
947
add_filter( 'the_content', 'sharing_display', 19 );
948
add_filter( 'the_excerpt', 'sharing_display', 19 );
949
function get_base_recaptcha_lang_code() {
950
951
	$base_recaptcha_lang_code_mapping = array(
952
		'en'    => 'en',
953
		'nl'    => 'nl',
954
		'fr'    => 'fr',
955
		'fr-be' => 'fr',
956
		'fr-ca' => 'fr',
957
		'fr-ch' => 'fr',
958
		'de'    => 'de',
959
		'pt'    => 'pt',
960
		'pt-br' => 'pt',
961
		'ru'    => 'ru',
962
		'es'    => 'es',
963
		'tr'    => 'tr',
964
	);
965
966
	$blog_lang_code = function_exists( 'get_blog_lang_code' ) ? get_blog_lang_code() : get_bloginfo( 'language' );
967
	if ( isset( $base_recaptcha_lang_code_mapping[ $blog_lang_code ] ) ) {
968
		return $base_recaptcha_lang_code_mapping[ $blog_lang_code ];
969
	}
970
971
	// if no base mapping is found return default 'en'
972
	return 'en';
973
}
974