PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 13.6
Jetpack – WP Security, Backup, Speed, & Growth v13.6
16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
jetpack / modules / sharedaddy / sharing-sources.php

sharing-sources.php in Jetpack – WP Security, Backup, Speed, & Growth 13.6, at modules/sharedaddy/sharing-sources.php

3,493 lines 87.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Define all sharing sources.
4 *
5 * phpcs:disable Generic.Files.OneObjectStructurePerFile.MultipleFound
6 */
7
8 use Automattic\Jetpack\Device_Detection\User_Agent_Info;
9
10 /**
11 * Base class for sharing sources.
12 * See individual sharing classes below for the implementation of this class.
13 */
14 abstract class Sharing_Source {
15 /**
16 * Button style (icon, icon-text, text, or official).
17 *
18 * @var string
19 */
20 public $button_style;
21
22 /**
23 * Does the service have an official version.
24 *
25 * @var bool
26 */
27 public $smart;
28
29 /**
30 * Should the sharing link open in a new tab.
31 *
32 * @var bool
33 */
34 protected $open_link_in_new;
35
36 /**
37 * Sharing unique ID.
38 *
39 * @var int
40 */
41 protected $id;
42
43 /**
44 * Constructor.
45 *
46 * @param int $id Sharing source ID.
47 * @param array $settings Sharing settings.
48 */
49 public function __construct( $id, array $settings ) {
50 $this->id = $id;
51 /**
52 * Filter the way sharing links open.
53 *
54 * By default, sharing links open in a new window.
55 *
56 * @module sharedaddy
57 *
58 * @since 3.4.0
59 *
60 * @param bool true Should Sharing links open in a new window. Default to true.
61 */
62 $this->open_link_in_new = apply_filters( 'jetpack_open_sharing_in_new_window', true );
63
64 if ( isset( $settings['button_style'] ) ) {
65 $this->button_style = $settings['button_style'];
66 }
67
68 if ( isset( $settings['smart'] ) ) {
69 $this->smart = $settings['smart'];
70 }
71 }
72
73 /**
74 * Is a service deprecated.
75 *
76 * @return bool
77 */
78 public function is_deprecated() {
79 return false;
80 }
81
82 /**
83 * Get the protocol to use for a sharing service, based on the site settings.
84 *
85 * @return string
86 */
87 public function http() {
88 return is_ssl() ? 'https' : 'http';
89 }
90
91 /**
92 * Get unique sharing ID.
93 *
94 * @return int
95 */
96 public function get_id() {
97 return $this->id;
98 }
99
100 /**
101 * Get unique sharing ID. Similar to get_id().
102 *
103 * @return int
104 */
105 public function get_class() {
106 return $this->id;
107 }
108
109 /**
110 * Get a post's permalink to use for sharing.
111 *
112 * @param int $post_id Post ID.
113 *
114 * @return string
115 */
116 public function get_share_url( $post_id ) {
117 /**
118 * Filter the sharing permalink.
119 *
120 * @module sharedaddy
121 *
122 * @since 1.2.0
123 *
124 * @param string get_permalink( $post_id ) Post Permalink.
125 * @param int $post_id Post ID.
126 * @param int $this->id Sharing ID.
127 */
128 return apply_filters( 'sharing_permalink', get_permalink( $post_id ), $post_id, $this->id );
129 }
130
131 /**
132 * Get a post's title to use for sharing.
133 *
134 * @param int $post_id Post ID.
135 *
136 * @return string
137 */
138 public function get_share_title( $post_id ) {
139 $post = get_post( $post_id );
140 /**
141 * Filter the sharing title.
142 *
143 * @module sharedaddy
144 *
145 * @since 2.8.0
146 *
147 * @param string $post->post_title Post Title.
148 * @param int $post_id Post ID.
149 * @param int $this->id Sharing ID.
150 */
151 $title = apply_filters( 'sharing_title', $post->post_title, $post_id, $this->id );
152
153 return html_entity_decode( wp_kses( $title, '' ), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
154 }
155
156 /**
157 * Get a comma-separated list of the post's tags to use for sharing.
158 * Prepends a '#' to each tag.
159 *
160 * @param int $post_id Post ID.
161 *
162 * @return string
163 */
164 public function get_share_tags( $post_id ) {
165 $tags = get_the_tags( $post_id );
166 if ( ! $tags ) {
167 return '';
168 }
169
170 $tags = array_map(
171 function ( $tag ) {
172 // Camel case the tag name and remove spaces as well as apostrophes.
173 $tag = preg_replace( '/\s+|\'/', '', ucwords( $tag->name ) );
174
175 // Return with a '#' prepended.
176 return '#' . $tag;
177 },
178 $tags
179 );
180
181 /**
182 * Allow customizing how the list of tags is displayed.
183 *
184 * @module sharedaddy
185 * @since 11.9
186 *
187 * @param string $tags Comma-separated list of tags.
188 * @param int $post_id Post ID.
189 * @param int $this->id Sharing ID.
190 */
191 $tag_list = (string) apply_filters( 'jetpack_sharing_tag_list', implode( ', ', $tags ), $post_id, $this->id );
192
193 return html_entity_decode( wp_kses( $tag_list, '' ), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
194 }
195
196 /**
197 * Does this sharing source have a custom style.
198 *
199 * @return bool
200 */
201 public function has_custom_button_style() {
202 return false;
203 }
204
205 /**
206 * Get the HTML markup to display a sharing link.
207 *
208 * @param string $url Post URL to share.
209 * @param string $text Sharing display text.
210 * @param string $title The title for the link.
211 * @param string $query Additional query arguments to add to the link. They should be in 'foo=bar&baz=1' format.
212 * @param bool|string $id Sharing ID to include in the data-shared attribute.
213 * @param array $data_attributes The keys are used as additional attribute names with 'data-' prefix.
214 * The values are used as the attribute values.
215 *
216 * @return string The HTML for the link.
217 */
218 public function get_link( $url, $text, $title, $query = '', $id = false, $data_attributes = array() ) {
219 $args = func_get_args();
220 $klasses = array( 'share-' . $this->get_class(), 'sd-button' );
221
222 if ( 'icon' === $this->button_style || 'icon-text' === $this->button_style ) {
223 $klasses[] = 'share-icon';
224 }
225
226 if ( 'icon' === $this->button_style ) {
227 $text = $title;
228 $klasses[] = 'no-text';
229
230 if ( true === $this->open_link_in_new ) {
231 $text .= __( ' (Opens in new window)', 'jetpack' );
232 }
233 }
234
235 /**
236 * Filter the sharing display ID.
237 *
238 * @module sharedaddy
239 *
240 * @since 3.4.0
241 *
242 * @param string|false $id Sharing ID.
243 * @param object $this Sharing service properties.
244 * @param array $args Array of sharing service options.
245 */
246 $id = apply_filters( 'jetpack_sharing_display_id', $id, $this, $args );
247 /**
248 * Filter the sharing display link.
249 *
250 * @module sharedaddy
251 *
252 * @since 2.8.0
253 *
254 * @param string $url Post URL.
255 * @param object $this Sharing service properties.
256 * @param string|false $id Sharing ID.
257 * @param array $args Array of sharing service options.
258 */
259 $url = apply_filters( 'sharing_display_link', $url, $this, $id, $args ); // backwards compatibility
260 /**
261 * Filter the sharing display link.
262 *
263 * @module sharedaddy
264 *
265 * @since 2.8.0
266 *
267 * @param string $url Post URL.
268 * @param object $this Sharing service properties.
269 * @param string|false $id Sharing ID.
270 * @param array $args Array of sharing service options.
271 */
272 $url = apply_filters( 'jetpack_sharing_display_link', $url, $this, $id, $args );
273 /**
274 * Filter the sharing display query.
275 *
276 * @module sharedaddy
277 *
278 * @since 2.8.0
279 *
280 * @param string $query Sharing service URL parameter.
281 * @param object $this Sharing service properties.
282 * @param string|false $id Sharing ID.
283 * @param array $args Array of sharing service options.
284 */
285 $query = apply_filters( 'jetpack_sharing_display_query', $query, $this, $id, $args );
286
287 if ( ! empty( $query ) ) {
288 if ( false === stripos( $url, '?' ) ) {
289 $url .= '?' . $query;
290 } else {
291 $url .= '&amp;' . $query;
292 }
293 }
294
295 if ( 'text' === $this->button_style ) {
296 $klasses[] = 'no-icon';
297 }
298
299 /**
300 * Filter the sharing display classes.
301 *
302 * @module sharedaddy
303 *
304 * @since 3.4.0
305 *
306 * @param array $klasses Sharing service classes.
307 * @param object $this Sharing service properties.
308 * @param string|false $id Sharing ID.
309 * @param array $args Array of sharing service options.
310 */
311 $klasses = apply_filters( 'jetpack_sharing_display_classes', $klasses, $this, $id, $args );
312 /**
313 * Filter the sharing display title.
314 *
315 * @module sharedaddy
316 *
317 * @since 3.4.0
318 *
319 * @param string $title Sharing service title.
320 * @param object $this Sharing service properties.
321 * @param string|false $id Sharing ID.
322 * @param array $args Array of sharing service options.
323 */
324 $title = apply_filters( 'jetpack_sharing_display_title', $title, $this, $id, $args );
325 /**
326 * Filter the sharing display text.
327 *
328 * @module sharedaddy
329 *
330 * @since 3.4.0
331 *
332 * @param string $text Sharing service text.
333 * @param object $this Sharing service properties.
334 * @param string|false $id Sharing ID.
335 * @param array $args Array of sharing service options.
336 */
337 $text = apply_filters( 'jetpack_sharing_display_text', $text, $this, $id, $args );
338
339 /**
340 * Filter the sharing data attributes.
341 *
342 * @module sharedaddy
343 *
344 * @since 11.0
345 *
346 * @param array $data_attributes Attributes supplied from the sharing source.
347 * Note that 'data-' will be prepended to all keys.
348 * @param Sharing_Source $this Sharing source instance.
349 * @param string|false $id Sharing ID.
350 * @param array $args Array of sharing service options.
351 */
352 $data_attributes = apply_filters( 'jetpack_sharing_data_attributes', (array) $data_attributes, $this, $id, $args );
353
354 $encoded_data_attributes = '';
355 if ( ! empty( $data_attributes ) ) {
356 $encoded_data_attributes = implode(
357 ' ',
358 array_map(
359 /** Filter for formatting attributes */
360 function ( $data_key, $data_value ) {
361 return sprintf(
362 'data-%s="%s"',
363 esc_attr( str_replace( array( ' ', '"' ), '', $data_key ) ),
364 esc_attr( $data_value )
365 );
366 },
367 array_keys( $data_attributes ),
368 array_values( $data_attributes )
369 )
370 );
371 }
372
373 return sprintf(
374 '<a rel="nofollow%s" data-shared="%s" class="%s" href="%s"%s title="%s" %s><span%s>%s</span></a>',
375 ( true === $this->open_link_in_new ) ? ' noopener noreferrer' : '',
376 ( $id ? esc_attr( $id ) : '' ),
377 implode( ' ', $klasses ),
378 $url,
379 ( true === $this->open_link_in_new ) ? ' target="_blank"' : '',
380 $title,
381 $encoded_data_attributes,
382 ( 'icon' === $this->button_style ) ? '></span><span class="sharing-screen-reader-text"' : '',
383 $text
384 );
385 }
386
387 /**
388 * Get an unfiltered post permalink to use when generating a sharing URL with get_link.
389 * Use instead of get_share_url for non-official styles as get_permalink ensures that process_request
390 * will be executed more reliably, in the case that the filtered URL uses a service that strips query parameters.
391 *
392 * @since 3.7.0
393 * @param int $post_id Post ID.
394 *
395 * @uses get_permalink
396 *
397 * @return string get_permalink( $post_id ) Post permalink.
398 */
399 public function get_process_request_url( $post_id ) {
400 return get_permalink( $post_id );
401 }
402
403 /**
404 * Get sharing name.
405 */
406 abstract public function get_name();
407
408 /**
409 * Get the markup of the sharing button.
410 *
411 * @param WP_Post $post Post object.
412 */
413 abstract public function get_display( $post );
414
415 /**
416 * Add content specific to a service in the head.
417 */
418 public function display_header() {
419 }
420
421 /**
422 * Add content specific to a service in the footer.
423 */
424 public function display_footer() {
425 }
426
427 /**
428 * Does the service have advanced options.
429 *
430 * @return bool
431 */
432 public function has_advanced_options() {
433 return false;
434 }
435
436 /**
437 * Get the AMP specific markup for a sharing button.
438 *
439 * @param \WP_Post $post The current post being viewed.
440 *
441 * @return bool|string
442 */
443 public function get_amp_display( $post ) {
444 // Only display markup if we're on a post.
445 if ( empty( $post ) ) {
446 return false;
447 }
448
449 return $this->build_amp_markup();
450 }
451
452 /**
453 * Generates and returns the markup for an AMP sharing button.
454 *
455 * @param array $attrs Custom attributes for rendering the social icon.
456 *
457 * @return string
458 */
459 protected function build_amp_markup( $attrs = array() ) {
460
461 $title = sprintf(
462 /* translators: placeholder is a service name, such as "Twitter" or "Facebook". */
463 __( 'Click to share on %s', 'jetpack' ),
464 $this->get_name()
465 );
466
467 $attrs = array_merge(
468 array(
469 'type' => $this->get_id(),
470 'height' => '32px',
471 'width' => '32px',
472 'aria-label' => $title,
473 'title' => $title,
474 ),
475 $attrs
476 );
477 $sharing_link = '<amp-social-share';
478 foreach ( $attrs as $key => $value ) {
479 $sharing_link .= sprintf( ' %s="%s"', sanitize_key( $key ), esc_attr( $value ) );
480 }
481 $sharing_link .= '></amp-social-share>';
482 return $sharing_link;
483 }
484
485 /**
486 * Display a preview of the sharing button.
487 *
488 * @param bool $echo Whether to echo the output or return it.
489 * @param bool $force_smart Whether to force the smart (official) services to be shown.
490 * @param null|string $button_style Button style.
491 *
492 * @return string|void
493 */
494 public function display_preview( $echo = true, $force_smart = false, $button_style = null ) {
495 $text = '&nbsp;';
496 $button_style = ( ! empty( $button_style ) ) ? $button_style : $this->button_style;
497 if ( ! $this->smart && ! $force_smart ) {
498 if ( $button_style !== 'icon' ) {
499 $text = $this->get_name();
500 }
501 }
502
503 $klasses = array( 'share-' . $this->get_class(), 'sd-button' );
504
505 if ( $button_style === 'icon' || $button_style === 'icon-text' ) {
506 $klasses[] = 'share-icon';
507 }
508
509 if ( $button_style === 'icon' ) {
510 $klasses[] = 'no-text';
511 }
512
513 if ( $button_style === 'text' ) {
514 $klasses[] = 'no-icon';
515 }
516
517 $is_deprecated = $this->is_deprecated();
518
519 $link = sprintf(
520 '<a rel="nofollow" class="%s" href="javascript:void(0)" title="%s"><span>%s</span></a>',
521 implode( ' ', $klasses ),
522 esc_attr(
523 $is_deprecated
524 /* translators: %1$s is the name of a deprecated Sharing Service like "Google+" */
525 ? sprintf( __( 'The %1$s sharing service has shut down or discontinued support for sharing buttons. This sharing button is not displayed to your visitors and should be removed.', 'jetpack' ), $this->get_name() )
526 : $this->get_name()
527 ),
528 esc_html(
529 $is_deprecated
530 /* translators: %1$s is the name of a deprecated Sharing Service like "Google+" */
531 ? sprintf( __( '%1$s is no longer supported', 'jetpack' ), $this->get_name() )
532 : $text
533 )
534 );
535
536 $smart = ( $this->smart || $force_smart ) ? 'on' : 'off';
537 $return = "<div class='option option-smart-$smart'>$link</div>";
538 if ( $echo ) {
539 echo $return; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- we escape things above.
540 }
541
542 return $return;
543 }
544
545 /**
546 * Get sharing stats for a specific post or sharing service.
547 *
548 * @param bool|WP_Post $post Post object.
549 *
550 * @return int
551 */
552 public function get_total( $post = false ) {
553 global $wpdb, $blog_id;
554
555 $name = strtolower( $this->get_id() );
556
557 if ( $post === false ) {
558 // get total number of shares for service
559 return (int) $wpdb->get_var( $wpdb->prepare( 'SELECT SUM( count ) FROM sharing_stats WHERE blog_id = %d AND share_service = %s', $blog_id, $name ) );
560 }
561
562 // get total shares for a post
563 return (int) $wpdb->get_var( $wpdb->prepare( 'SELECT count FROM sharing_stats WHERE blog_id = %d AND post_id = %d AND share_service = %s', $blog_id, $post->ID, $name ) );
564 }
565
566 /**
567 * Get sharing stats for all posts on the site.
568 *
569 * @return array
570 */
571 public function get_posts_total() {
572 global $wpdb, $blog_id;
573
574 $totals = array();
575 $name = strtolower( $this->get_id() );
576
577 $my_data = $wpdb->get_results( $wpdb->prepare( 'SELECT post_id as id, SUM( count ) as total FROM sharing_stats WHERE blog_id = %d AND share_service = %s GROUP BY post_id ORDER BY count DESC ', $blog_id, $name ) );
578
579 if ( ! empty( $my_data ) ) {
580 foreach ( $my_data as $row ) {
581 $totals[] = new Sharing_Post_Total( $row->id, $row->total );
582 }
583 }
584
585 usort( $totals, array( 'Sharing_Post_Total', 'cmp' ) );
586
587 return $totals;
588 }
589
590 /**
591 * Process sharing request. Add actions that need to happen when sharing here.
592 *
593 * @param WP_Post $post Post object.
594 * @param array $post_data Array of information about the post we're sharing.
595 *
596 * @return void
597 */
598 public function process_request( $post, array $post_data ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
599 /**
600 * Fires when a post is shared via one of the sharing buttons.
601 *
602 * @module sharedaddy
603 *
604 * @since 1.1.0
605 *
606 * @param array $args Aray of information about the sharing service.
607 */
608 do_action(
609 'sharing_bump_stats',
610 array(
611 'service' => $this,
612 'post' => $post,
613 )
614 );
615 }
616
617 /**
618 * Redirect to an external social network site to finish sharing.
619 *
620 * @param string $url Sharing URL for a given service.
621 * @return never
622 */
623 public function redirect_request( $url ) {
624 wp_redirect( $url ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- We allow external redirects here; we define them ourselves.
625
626 // We set up this custom header to indicate to search engines not to index this page.
627 header( 'X-Robots-Tag: noindex, nofollow' );
628 die();
629 }
630
631 /**
632 * Add extra JavaScript to a sharing service.
633 *
634 * @param string $name Sharing service name.
635 * @param array $params Array of sharing options.
636 *
637 * @return void
638 */
639 public function js_dialog( $name, $params = array() ) {
640 if ( true !== $this->open_link_in_new ) {
641 return;
642 }
643
644 $defaults = array(
645 'menubar' => 1,
646 'resizable' => 1,
647 'width' => 600,
648 'height' => 400,
649 );
650 $params = array_merge( $defaults, $params );
651 $opts = array();
652 foreach ( $params as $key => $val ) {
653 $opts[] = "$key=$val";
654 }
655 $opts = implode( ',', $opts );
656
657 // Add JS after sharing-js has been enqueued.
658 wp_add_inline_script(
659 'sharing-js',
660 "var windowOpen;
661 ( function () {
662 function matches( el, sel ) {
663 return !! (
664 el.matches && el.matches( sel ) ||
665 el.msMatchesSelector && el.msMatchesSelector( sel )
666 );
667 }
668
669 document.body.addEventListener( 'click', function ( event ) {
670 if ( ! event.target ) {
671 return;
672 }
673
674 var el;
675 if ( matches( event.target, 'a.share-$name' ) ) {
676 el = event.target;
677 } else if ( event.target.parentNode && matches( event.target.parentNode, 'a.share-$name' ) ) {
678 el = event.target.parentNode;
679 }
680
681 if ( el ) {
682 event.preventDefault();
683
684 // If there's another sharing window open, close it.
685 if ( typeof windowOpen !== 'undefined' ) {
686 windowOpen.close();
687 }
688 windowOpen = window.open( el.getAttribute( 'href' ), 'wpcom$name', '$opts' );
689 return false;
690 }
691 } );
692 } )();"
693 );
694 }
695 }
696
697 /**
698 * Handle the display of deprecated sharing services.
699 */
700 abstract class Deprecated_Sharing_Source extends Sharing_Source {
701 /**
702 * Button style (icon-text, icon, or text)
703 *
704 * @var string
705 */
706 public $button_style = 'text';
707
708 /**
709 * Does the service have an official version.
710 *
711 * @var bool
712 */
713 public $smart = false;
714
715 /**
716 * Should the sharing link open in a new tab.
717 *
718 * @var bool
719 */
720 protected $open_link_in_new = false;
721
722 /**
723 * Sharing unique ID.
724 *
725 * @var int
726 */
727 protected $id;
728
729 /**
730 * Is the service deprecated.
731 *
732 * @var bool
733 */
734 protected $deprecated = true;
735
736 /**
737 * Constructor.
738 *
739 * @param int $id Sharing source ID.
740 * @param array $settings Sharing settings.
741 */
742 final public function __construct( $id, array $settings ) {
743 $this->id = $id;
744
745 if ( isset( $settings['button_style'] ) ) {
746 $this->button_style = $settings['button_style'];
747 }
748 }
749
750 /**
751 * Is the service deprecated.
752 *
753 * @return bool
754 */
755 final public function is_deprecated() {
756 return true;
757 }
758
759 /**
760 * Get a post's permalink to use for sharing.
761 *
762 * @param int $post_id Post ID.
763 *
764 * @return string
765 */
766 final public function get_share_url( $post_id ) {
767 return get_permalink( $post_id );
768 }
769
770 /**
771 * No AMP display for deprecated sources.
772 *
773 * @param \WP_Post $post The current post being viewed.
774 */
775 final public function get_amp_display( $post ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
776 return false;
777 }
778
779 /**
780 * Display a preview of the sharing button.
781 *
782 * @param bool $echo Whether to echo the output or return it.
783 * @param bool $force_smart Whether to force the smart (official) services to be shown.
784 * @param null|string $button_style Button style.
785 *
786 * @return string|void
787 */
788 final public function display_preview( $echo = true, $force_smart = false, $button_style = null ) {
789 return parent::display_preview( $echo, false, $button_style );
790 }
791
792 /**
793 * Get sharing stats for a specific post or sharing service.
794 *
795 * @param bool|WP_Post $post Post object.
796 *
797 * @return int
798 */
799 final public function get_total( $post = false ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
800 return 0;
801 }
802
803 /**
804 * Get sharing stats for all posts on the site.
805 *
806 * @return int|array
807 */
808 final public function get_posts_total() {
809 return 0;
810 }
811
812 /**
813 * Process sharing request. Add actions that need to happen when sharing here.
814 *
815 * @param WP_Post $post Post object.
816 * @param array $post_data Array of information about the post we're sharing.
817 *
818 * @return void
819 */
820 final public function process_request( $post, array $post_data ) { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod.Found
821 parent::process_request( $post, $post_data );
822 }
823
824 /**
825 * Get the markup of the sharing button.
826 *
827 * @param WP_Post $post Post object.
828 *
829 * @return string
830 */
831 final public function get_display( $post ) {
832 if ( current_user_can( 'manage_options' ) ) {
833 return $this->display_deprecated( $post );
834 }
835
836 return '';
837 }
838
839 /**
840 * Display a custom message for deprecated services.
841 *
842 * @param WP_Post $post Post object.
843 *
844 * @return string
845 */
846 public function display_deprecated( $post ) {
847 return $this->get_link(
848 $this->get_share_url( $post->ID ),
849 /* translators: %1$s is the name of a deprecated Sharing Service like "Google+" */
850 sprintf( __( '%1$s is no longer supported', 'jetpack' ), $this->get_name() ),
851 /* translators: %1$s is the name of a deprecated Sharing Service like "Google+" */
852 sprintf( __( 'The %1$s sharing service has shut down or discontinued support for sharing buttons. This sharing button is not displayed to your visitors and should be removed.', 'jetpack' ), $this->get_name() )
853 );
854 }
855 }
856
857 /**
858 * Handle the display of advanced sharing services.
859 * Custom sharing buttons we create ourselves will be such services.
860 */
861 abstract class Sharing_Advanced_Source extends Sharing_Source {
862 /**
863 * Does the service have advanced options.
864 *
865 * @return bool
866 */
867 public function has_advanced_options() {
868 return true;
869 }
870
871 /**
872 * Display options for our sharing buttons.
873 */
874 abstract public function display_options();
875
876 /**
877 * Sanitize and save options for our sharing buttons.
878 *
879 * @param array $data Data to be saved.
880 *
881 * @return void
882 */
883 abstract public function update_options( array $data );
884
885 /**
886 * Get array of information about the service.
887 *
888 * @return array
889 */
890 abstract public function get_options();
891 }
892
893 /**
894 * Handle the display of the email sharing button.
895 */
896 class Share_Email extends Sharing_Source {
897 /**
898 * Service short name.
899 *
900 * @var string
901 */
902 public $shortname = 'email';
903
904 /**
905 * Service icon font code.
906 *
907 * @var string
908 */
909 public $icon = '\f410';
910
911 /**
912 * Constructor.
913 *
914 * @param int $id Sharing source ID.
915 * @param array $settings Sharing settings.
916 */
917 public function __construct( $id, array $settings ) {
918 parent::__construct( $id, $settings );
919
920 if ( 'official' === $this->button_style ) {
921 $this->smart = true;
922 } else {
923 $this->smart = false;
924 }
925 }
926
927 /**
928 * Service name.
929 *
930 * @return string
931 */
932 public function get_name() {
933 return _x( 'Email', 'as sharing source', 'jetpack' );
934 }
935
936 /**
937 * Helper function to return a nonce action based on the current post.
938 *
939 * @param WP_Post|null $post The current post if it is defined.
940 * @return string The nonce action name.
941 */
942 protected function get_email_share_nonce_action( $post ) {
943 if ( ! empty( $post ) && $post instanceof WP_Post ) {
944 return 'jetpack-email-share-' . $post->ID;
945 }
946
947 return 'jetpack-email-share';
948 }
949
950 /**
951 * Process sharing request. Add actions that need to happen when sharing here.
952 *
953 * @param WP_Post $post Post object.
954 * @param array $post_data Array of information about the post we're sharing.
955 *
956 * @return void
957 */
958 public function process_request( $post, array $post_data ) {
959 $is_ajax = false;
960 if (
961 isset( $_SERVER['HTTP_X_REQUESTED_WITH'] )
962 && strtolower( sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_REQUESTED_WITH'] ) ) ) === 'xmlhttprequest'
963 ) {
964 $is_ajax = true;
965 }
966
967 // Require an AJAX-driven submit and a valid nonce to process the request
968 if (
969 $is_ajax
970 && isset( $post_data['email-share-nonce'] )
971 && wp_verify_nonce( $post_data['email-share-nonce'], $this->get_email_share_nonce_action( $post ) )
972 ) {
973 // Ensure that we bump stats
974 parent::process_request( $post, $post_data );
975 }
976
977 if ( $is_ajax ) {
978 wp_send_json_success();
979 } else {
980 wp_safe_redirect( get_permalink( $post->ID ) . '?shared=email&msg=fail' );
981 exit;
982 }
983
984 wp_die();
985 }
986
987 /**
988 * Get the markup of the sharing button.
989 *
990 * @param WP_Post $post Post object.
991 *
992 * @return string The HTML for the button.
993 */
994 public function get_display( $post ) {
995 $tracking_url = $this->get_process_request_url( $post->ID );
996 if ( false === stripos( $tracking_url, '?' ) ) {
997 $tracking_url .= '?';
998 } else {
999 $tracking_url .= '&';
1000 }
1001 $tracking_url .= 'share=email';
1002
1003 $data_attributes = array(
1004 'email-share-error-title' => __( 'Do you have email set up?', 'jetpack' ),
1005 'email-share-error-text' => __(
1006 "If you're having problems sharing via email, you might not have email set up for your browser. You may need to create a new email yourself.",
1007 'jetpack'
1008 ),
1009 'email-share-nonce' => wp_create_nonce( $this->get_email_share_nonce_action( $post ) ),
1010 'email-share-track-url' => $tracking_url,
1011 );
1012
1013 $post_title = $this->get_share_title( $post->ID );
1014 $post_url = $this->get_share_url( $post->ID );
1015
1016 /** This filter is documented in plugins/jetpack/modules/sharedaddy/sharedaddy.php */
1017 $email_subject = apply_filters(
1018 'wp_sharing_email_send_post_subject',
1019 sprintf( '[%s] %s', __( 'Shared Post', 'jetpack' ), $post_title )
1020 );
1021
1022 $mailto_query = sprintf(
1023 'subject=%s&body=%s&share=email',
1024 rawurlencode( $email_subject ),
1025 rawurlencode( $post_url )
1026 );
1027
1028 return $this->get_link(
1029 'mailto:',
1030 _x( 'Email', 'share to', 'jetpack' ),
1031 __( 'Click to email a link to a friend', 'jetpack' ),
1032 $mailto_query,
1033 false,
1034 $data_attributes
1035 );
1036 }
1037
1038 /**
1039 * AMP display for email.
1040 *
1041 * @param \WP_Post $post The current post being viewed.
1042 */
1043 public function get_amp_display( $post ) { // phpcs:ignore
1044 $attrs = array(
1045 // Prevents an empty window from opening on desktop: https://github.com/ampproject/amphtml/issues/9157.
1046 'data-target' => '_self',
1047 );
1048
1049 return $this->build_amp_markup( $attrs );
1050 }
1051 }
1052
1053 /**
1054 * Twitter sharing button.
1055 */
1056 class Share_Twitter extends Sharing_Source {
1057 /**
1058 * Service short name.
1059 *
1060 * @var string
1061 */
1062 public $shortname = 'twitter';
1063
1064 /**
1065 * Service icon font code.
1066 *
1067 * @var string
1068 */
1069 public $icon = '\f202';
1070
1071 /**
1072 * Length of a URL on Twitter.
1073 * 'https://dev.twitter.com/rest/reference/get/help/configuration'
1074 * ( 2015/02/06 ) short_url_length is 22, short_url_length_https is 23
1075 *
1076 * @var int
1077 */
1078 public $short_url_length = 24;
1079
1080 /**
1081 * Constructor.
1082 *
1083 * @param int $id Sharing source ID.
1084 * @param array $settings Sharing settings.
1085 */
1086 public function __construct( $id, array $settings ) {
1087 parent::__construct( $id, $settings );
1088
1089 if ( 'official' === $this->button_style ) {
1090 $this->smart = true;
1091 } else {
1092 $this->smart = false;
1093 }
1094 }
1095
1096 /**
1097 * Service name.
1098 *
1099 * @return string
1100 */
1101 public function get_name() {
1102 return __( 'Twitter', 'jetpack' );
1103 }
1104
1105 /**
1106 * Determine the Twitter 'via' value for a post.
1107 *
1108 * @param WP_Post|int $post Post object or post ID.
1109 * @return string Twitter handle without the preceding @.
1110 **/
1111 public static function sharing_twitter_via( $post ) {
1112 $post = get_post( $post );
1113 /**
1114 * Allow third-party plugins to customize the Twitter username used as "twitter:site" Twitter Card Meta Tag.
1115 *
1116 * @module sharedaddy
1117 *
1118 * @since 3.0.0
1119 *
1120 * @param string $string Twitter Username.
1121 * @param array $args Array of Open Graph Meta Tags and Twitter Cards tags.
1122 */
1123 $twitter_site_tag_value = apply_filters(
1124 'jetpack_twitter_cards_site_tag',
1125 '',
1126 /** This action is documented in modules/sharedaddy/sharing-sources.php */
1127 array( 'twitter:creator' => apply_filters( 'jetpack_sharing_twitter_via', '', $post->ID ) )
1128 );
1129
1130 /*
1131 * Hack to remove the unwanted behavior of adding 'via @jetpack' which
1132 * was introduced with the adding of the Twitter cards.
1133 * This should be a temporary solution until a better method is setup.
1134 */
1135 if ( 'jetpack' === $twitter_site_tag_value ) {
1136 $twitter_site_tag_value = '';
1137 }
1138
1139 /**
1140 * Filters the Twitter username used as "via" in the Twitter sharing button.
1141 *
1142 * @module sharedaddy
1143 *
1144 * @since 1.7.0
1145 *
1146 * @param string $twitter_site_tag_value Twitter Username.
1147 * @param int $post->ID Post ID.
1148 */
1149 $twitter_site_tag_value = apply_filters( 'jetpack_sharing_twitter_via', $twitter_site_tag_value, $post->ID );
1150
1151 // Strip out anything other than a letter, number, or underscore.
1152 // This will prevent the inadvertent inclusion of an extra @, as well as normalizing the handle.
1153 return preg_replace( '/[^\da-z_]+/i', '', $twitter_site_tag_value );
1154 }
1155
1156 /**
1157 * Determine the 'related' Twitter accounts for a post.
1158 *
1159 * @param WP_Post|int $post Post object or post ID.
1160 * @return string Comma-separated list of Twitter handles.
1161 **/
1162 public static function get_related_accounts( $post ) {
1163 $post = get_post( $post );
1164 /**
1165 * Filter the list of related Twitter accounts added to the Twitter sharing button.
1166 *
1167 * @module sharedaddy
1168 *
1169 * @since 1.7.0
1170 *
1171 * @param array $args Array of Twitter usernames. Format is 'username' => 'Optional description'
1172 * @param int $post->ID Post ID.
1173 */
1174 $related_accounts = apply_filters( 'jetpack_sharing_twitter_related', array(), $post->ID );
1175
1176 // Example related string: account1,account2:Account 2 description,account3
1177 $related = array();
1178
1179 foreach ( $related_accounts as $related_account_username => $related_account_description ) {
1180 // Join the description onto the end of the username
1181 if ( $related_account_description ) {
1182 $related_account_username .= ':' . $related_account_description;
1183 }
1184
1185 $related[] = $related_account_username;
1186 }
1187
1188 return implode( ',', $related );
1189 }
1190
1191 /**
1192 * Get the markup of the sharing button.
1193 *
1194 * @param WP_Post $post Post object.
1195 *
1196 * @return string
1197 */
1198 public function get_display( $post ) {
1199 $via = static::sharing_twitter_via( $post );
1200
1201 if ( $via ) {
1202 $via = 'data-via="' . esc_attr( $via ) . '"';
1203 } else {
1204 $via = '';
1205 }
1206
1207 $related = static::get_related_accounts( $post );
1208 if ( ! empty( $related ) && $related !== $via ) {
1209 $related = 'data-related="' . esc_attr( $related ) . '"';
1210 } else {
1211 $related = '';
1212 }
1213
1214 if ( $this->smart ) {
1215 $share_url = $this->get_share_url( $post->ID );
1216 $post_title = $this->get_share_title( $post->ID );
1217 return sprintf(
1218 '<a href="https://twitter.com/share" class="twitter-share-button" data-url="%1$s" data-text="%2$s" %3$s %4$s>Tweet</a>',
1219 esc_url( $share_url ),
1220 esc_attr( $post_title ),
1221 $via,
1222 $related
1223 );
1224 } else {
1225 if (
1226 /**
1227 * Allow plugins to disable sharing counts for specific sharing services.
1228 *
1229 * @module sharedaddy
1230 *
1231 * @since 3.0.0
1232 *
1233 * @param bool true Should sharing counts be enabled for this specific service. Default to true.
1234 * @param int $post->ID Post ID.
1235 * @param string $str Sharing service name.
1236 */
1237 apply_filters( 'jetpack_register_post_for_share_counts', true, $post->ID, 'twitter' )
1238 ) {
1239 sharing_register_post_for_share_counts( $post->ID );
1240 }
1241 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Twitter', 'share to', 'jetpack' ), __( 'Click to share on Twitter', 'jetpack' ), 'share=twitter', 'sharing-twitter-' . $post->ID );
1242 }
1243 }
1244
1245 /**
1246 * Process sharing request. Add actions that need to happen when sharing here.
1247 *
1248 * @param WP_Post $post Post object.
1249 * @param array $post_data Array of information about the post we're sharing.
1250 *
1251 * @return void
1252 */
1253 public function process_request( $post, array $post_data ) {
1254 $post_title = $this->get_share_title( $post->ID );
1255 $post_link = $this->get_share_url( $post->ID );
1256
1257 if ( function_exists( 'mb_stripos' ) ) {
1258 $strlen = 'mb_strlen';
1259 $substr = 'mb_substr';
1260 } else {
1261 $strlen = 'strlen';
1262 $substr = 'substr';
1263 }
1264
1265 $via = static::sharing_twitter_via( $post );
1266 $related = static::get_related_accounts( $post );
1267 if ( $via ) {
1268 $sig = " via @$via";
1269 if ( $related === $via ) {
1270 $related = false;
1271 }
1272 } else {
1273 $via = false;
1274 $sig = '';
1275 }
1276
1277 $suffix_length = $this->short_url_length + $strlen( $sig );
1278 // $sig is handled by twitter in their 'via' argument.
1279 // $post_link is handled by twitter in their 'url' argument.
1280 if ( 280 < $strlen( $post_title ) + $suffix_length ) {
1281 // The -1 is for "\xE2\x80\xA6", a UTF-8 ellipsis.
1282 $text = $substr( $post_title, 0, 280 - $suffix_length - 1 ) . "\xE2\x80\xA6";
1283 } else {
1284 $text = $post_title;
1285 }
1286
1287 // Record stats
1288 parent::process_request( $post, $post_data );
1289
1290 $url = $post_link;
1291 $twitter_url = add_query_arg(
1292 rawurlencode_deep( array_filter( compact( 'via', 'related', 'text', 'url' ) ) ),
1293 'https://twitter.com/intent/tweet'
1294 );
1295
1296 parent::redirect_request( $twitter_url );
1297 }
1298
1299 /**
1300 * Does this sharing source have a custom style.
1301 *
1302 * @return bool
1303 */
1304 public function has_custom_button_style() {
1305 return $this->smart;
1306 }
1307
1308 /**
1309 * Add content specific to a service in the footer.
1310 */
1311 public function display_footer() {
1312 if ( $this->smart ) {
1313 ?>
1314 <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
1315 <?php
1316 } else {
1317 $this->js_dialog( $this->shortname, array( 'height' => 350 ) );
1318 }
1319 }
1320 }
1321
1322 /**
1323 * X sharing button.
1324 *
1325 * While the old Twitter button had an official button,
1326 * this new X button does not, since there is no official X button yet.
1327 */
1328 class Share_X extends Sharing_Source {
1329 /**
1330 * Service short name.
1331 *
1332 * @var string
1333 */
1334 public $shortname = 'x';
1335
1336 /**
1337 * Service icon font code.
1338 *
1339 * @var string
1340 */
1341 public $icon = '\f10e';
1342
1343 /**
1344 * Length of a URL on X.
1345 * https://developer.twitter.com/en/docs/tco
1346 *
1347 * @var int
1348 */
1349 public $short_url_length = 24;
1350
1351 /**
1352 * Constructor.
1353 *
1354 * @param int $id Sharing source ID.
1355 * @param array $settings Sharing settings.
1356 */
1357 public function __construct( $id, array $settings ) {
1358 parent::__construct( $id, $settings );
1359
1360 if ( 'official' === $this->button_style ) {
1361 $this->smart = true;
1362 } else {
1363 $this->smart = false;
1364 }
1365 }
1366
1367 /**
1368 * Service name.
1369 *
1370 * @return string
1371 */
1372 public function get_name() {
1373 return __( 'X', 'jetpack' );
1374 }
1375
1376 /**
1377 * Get the markup of the sharing button.
1378 *
1379 * @param WP_Post $post Post object.
1380 *
1381 * @return string
1382 */
1383 public function get_display( $post ) {
1384 $via = static::sharing_x_via( $post );
1385
1386 if ( $via ) {
1387 $via = 'data-via="' . esc_attr( $via ) . '"';
1388 } else {
1389 $via = '';
1390 }
1391
1392 $related = static::get_related_accounts( $post );
1393 if ( ! empty( $related ) && $related !== $via ) {
1394 $related = 'data-related="' . esc_attr( $related ) . '"';
1395 } else {
1396 $related = '';
1397 }
1398
1399 if ( $this->smart ) {
1400 $share_url = $this->get_share_url( $post->ID );
1401 $post_title = $this->get_share_title( $post->ID );
1402 return sprintf(
1403 '<a href="https://x.com/share" class="twitter-share-button" data-url="%1$s" data-text="%2$s" %3$s %4$s>%5$s</a>',
1404 esc_url( $share_url ),
1405 esc_attr( $post_title ),
1406 $via,
1407 $related,
1408 esc_html__( 'Post', 'jetpack' )
1409 );
1410 } else {
1411 if (
1412 /** This filter is documented in modules/sharedaddy/sharing-sources.php */
1413 apply_filters( 'jetpack_register_post_for_share_counts', true, $post->ID, 'x' )
1414 ) {
1415 sharing_register_post_for_share_counts( $post->ID );
1416 }
1417 return $this->get_link(
1418 $this->get_process_request_url( $post->ID ),
1419 _x( 'X', 'share to', 'jetpack' ),
1420 __( 'Click to share on X', 'jetpack' ),
1421 'share=x',
1422 'sharing-x-' . $post->ID
1423 );
1424 }
1425 }
1426
1427 /**
1428 * Determine the X 'via' value for a post.
1429 *
1430 * @param WP_Post|int $post Post object or post ID.
1431 * @return string X handle without the preceding @.
1432 **/
1433 public static function sharing_x_via( $post ) {
1434 $post = get_post( $post );
1435 /** This filter is documented in modules/sharedaddy/sharing-sources.php */
1436 $twitter_site_tag_value = apply_filters(
1437 'jetpack_twitter_cards_site_tag',
1438 '',
1439 /** This action is documented in modules/sharedaddy/sharing-sources.php */
1440 array( 'twitter:creator' => apply_filters( 'jetpack_sharing_twitter_via', '', $post->ID ) )
1441 );
1442
1443 /*
1444 * Hack to remove the unwanted behavior of adding 'via @jetpack' which
1445 * was introduced with the adding of the Twitter cards.
1446 * This should be a temporary solution until a better method is setup.
1447 */
1448 if ( 'jetpack' === $twitter_site_tag_value ) {
1449 $twitter_site_tag_value = '';
1450 }
1451
1452 /** This filter is documented in modules/sharedaddy/sharing-sources.php */
1453 $twitter_site_tag_value = apply_filters( 'jetpack_sharing_twitter_via', $twitter_site_tag_value, $post->ID );
1454
1455 // Strip out anything other than a letter, number, or underscore.
1456 // This will prevent the inadvertent inclusion of an extra @, as well as normalizing the handle.
1457 return preg_replace( '/[^\da-z_]+/i', '', $twitter_site_tag_value );
1458 }
1459
1460 /**
1461 * Determine the 'related' X accounts for a post.
1462 *
1463 * @param WP_Post|int $post Post object or post ID.
1464 * @return string Comma-separated list of X handles.
1465 **/
1466 public static function get_related_accounts( $post ) {
1467 $post = get_post( $post );
1468 /** This filter is documented in modules/sharedaddy/sharing-sources.php */
1469 $related_accounts = apply_filters( 'jetpack_sharing_twitter_related', array(), $post->ID );
1470
1471 // Example related string: account1,account2:Account 2 description,account3
1472 $related = array();
1473
1474 foreach ( $related_accounts as $related_account_username => $related_account_description ) {
1475 // Join the description onto the end of the username
1476 if ( $related_account_description ) {
1477 $related_account_username .= ':' . $related_account_description;
1478 }
1479
1480 $related[] = $related_account_username;
1481 }
1482
1483 return implode( ',', $related );
1484 }
1485
1486 /**
1487 * Add content specific to a service in the footer.
1488 */
1489 public function display_footer() {
1490 if ( $this->smart ) {
1491 ?>
1492 <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
1493 <?php
1494 } else {
1495 $this->js_dialog( $this->shortname, array( 'height' => 350 ) );
1496 }
1497 }
1498
1499 /**
1500 * Process sharing request. Add actions that need to happen when sharing here.
1501 *
1502 * @param WP_Post $post Post object.
1503 * @param array $post_data Array of information about the post we're sharing.
1504 *
1505 * @return void
1506 */
1507 public function process_request( $post, array $post_data ) {
1508 $post_title = $this->get_share_title( $post->ID );
1509 $post_link = $this->get_share_url( $post->ID );
1510
1511 if ( function_exists( 'mb_stripos' ) ) {
1512 $strlen = 'mb_strlen';
1513 $substr = 'mb_substr';
1514 } else {
1515 $strlen = 'strlen';
1516 $substr = 'substr';
1517 }
1518
1519 $via = static::sharing_x_via( $post );
1520 $related = static::get_related_accounts( $post );
1521 if ( $via ) {
1522 $sig = " via @$via";
1523 if ( $related === $via ) {
1524 $related = false;
1525 }
1526 } else {
1527 $via = false;
1528 $sig = '';
1529 }
1530
1531 $suffix_length = $this->short_url_length + $strlen( $sig );
1532 // $sig is handled by twitter in their 'via' argument.
1533 // $post_link is handled by twitter in their 'url' argument.
1534 if ( 280 < $strlen( $post_title ) + $suffix_length ) {
1535 // The -1 is for "\xE2\x80\xA6", a UTF-8 ellipsis.
1536 $text = $substr( $post_title, 0, 280 - $suffix_length - 1 ) . "\xE2\x80\xA6";
1537 } else {
1538 $text = $post_title;
1539 }
1540
1541 // Record stats
1542 parent::process_request( $post, $post_data );
1543
1544 $url = $post_link;
1545 $twitter_url = add_query_arg(
1546 rawurlencode_deep( array_filter( compact( 'via', 'related', 'text', 'url' ) ) ),
1547 'https://x.com/intent/tweet'
1548 );
1549
1550 parent::redirect_request( $twitter_url );
1551 }
1552
1553 /**
1554 * Does this sharing source have a custom style.
1555 *
1556 * @return bool
1557 */
1558 public function has_custom_button_style() {
1559 return $this->smart;
1560 }
1561 }
1562
1563 /**
1564 * Reddit sharing button.
1565 */
1566 class Share_Reddit extends Sharing_Source {
1567 /**
1568 * Service short name.
1569 *
1570 * @var string
1571 */
1572 public $shortname = 'reddit';
1573
1574 /**
1575 * Service icon font code.
1576 *
1577 * @var string
1578 */
1579 public $icon = '\f222';
1580
1581 /**
1582 * Service name.
1583 *
1584 * @return string
1585 */
1586 public function get_name() {
1587 return __( 'Reddit', 'jetpack' );
1588 }
1589
1590 /**
1591 * Get the markup of the sharing button.
1592 *
1593 * @param WP_Post $post Post object.
1594 *
1595 * @return string
1596 */
1597 public function get_display( $post ) {
1598 return $this->get_link(
1599 $this->get_process_request_url( $post->ID ),
1600 _x( 'Reddit', 'share to', 'jetpack' ),
1601 __( 'Click to share on Reddit', 'jetpack' ),
1602 'share=reddit'
1603 );
1604 }
1605
1606 /**
1607 * AMP display for Reddit.
1608 *
1609 * @param \WP_Post $post The current post being viewed.
1610 */
1611 public function get_amp_display( $post ) {
1612 $attrs = array(
1613 'data-share-endpoint' => esc_url_raw( 'https://reddit.com/submit?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $this->get_share_title( $post->ID ) ) ),
1614 );
1615
1616 return $this->build_amp_markup( $attrs );
1617 }
1618
1619 /**
1620 * Process sharing request. Add actions that need to happen when sharing here.
1621 *
1622 * @param WP_Post $post Post object.
1623 * @param array $post_data Array of information about the post we're sharing.
1624 *
1625 * @return void
1626 */
1627 public function process_request( $post, array $post_data ) {
1628 $reddit_url = $this->http() . '://reddit.com/submit?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $this->get_share_title( $post->ID ) );
1629
1630 // Record stats
1631 parent::process_request( $post, $post_data );
1632
1633 parent::redirect_request( $reddit_url );
1634 }
1635 }
1636
1637 /**
1638 * LinkedIn sharing button.
1639 */
1640 class Share_LinkedIn extends Sharing_Source {
1641 /**
1642 * Service short name.
1643 *
1644 * @var string
1645 */
1646 public $shortname = 'linkedin';
1647
1648 /**
1649 * Service icon font code.
1650 *
1651 * @var string
1652 */
1653 public $icon = '\f207';
1654
1655 /**
1656 * Constructor.
1657 *
1658 * @param int $id Sharing source ID.
1659 * @param array $settings Sharing settings.
1660 */
1661 public function __construct( $id, array $settings ) {
1662 parent::__construct( $id, $settings );
1663
1664 if ( 'official' === $this->button_style ) {
1665 $this->smart = true;
1666 } else {
1667 $this->smart = false;
1668 }
1669 }
1670
1671 /**
1672 * Service name.
1673 *
1674 * @return string
1675 */
1676 public function get_name() {
1677 return __( 'LinkedIn', 'jetpack' );
1678 }
1679
1680 /**
1681 * Does this sharing source have a custom style.
1682 *
1683 * @return bool
1684 */
1685 public function has_custom_button_style() {
1686 return $this->smart;
1687 }
1688
1689 /**
1690 * Get the markup of the sharing button.
1691 *
1692 * @param WP_Post $post Post object.
1693 *
1694 * @return string
1695 */
1696 public function get_display( $post ) {
1697 $display = '';
1698
1699 if ( $this->smart ) {
1700 $share_url = $this->get_share_url( $post->ID );
1701 $display .= sprintf( '<div class="linkedin_button"><script type="in/share" data-url="%s" data-counter="right"></script></div>', esc_url( $share_url ) );
1702 } else {
1703 $display = $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'LinkedIn', 'share to', 'jetpack' ), __( 'Click to share on LinkedIn', 'jetpack' ), 'share=linkedin', 'sharing-linkedin-' . $post->ID );
1704 }
1705
1706 /** This filter is already documented in modules/sharedaddy/sharing-sources.php */
1707 if ( apply_filters( 'jetpack_register_post_for_share_counts', true, $post->ID, 'linkedin' ) ) {
1708 sharing_register_post_for_share_counts( $post->ID );
1709 }
1710
1711 return $display;
1712 }
1713
1714 /**
1715 * Process sharing request. Add actions that need to happen when sharing here.
1716 *
1717 * @param WP_Post $post Post object.
1718 * @param array $post_data Array of information about the post we're sharing.
1719 *
1720 * @return void
1721 */
1722 public function process_request( $post, array $post_data ) {
1723
1724 $post_link = $this->get_share_url( $post->ID );
1725
1726 // Using the same URL as the official button, which is *not* LinkedIn's documented sharing link
1727 // https://www.linkedin.com/cws/share?url={url}&token=&isFramed=false
1728 $linkedin_url = add_query_arg(
1729 array(
1730 'url' => rawurlencode( $post_link ),
1731 ),
1732 'https://www.linkedin.com/cws/share?token=&isFramed=false'
1733 );
1734
1735 // Record stats
1736 parent::process_request( $post, $post_data );
1737
1738 parent::redirect_request( $linkedin_url );
1739 }
1740
1741 /**
1742 * Add content specific to a service in the footer.
1743 */
1744 public function display_footer() {
1745 if ( ! $this->smart ) {
1746 $this->js_dialog(
1747 $this->shortname,
1748 array(
1749 'width' => 580,
1750 'height' => 450,
1751 )
1752 );
1753 } else {
1754 ?>
1755 <script type="text/javascript">
1756 ( function () {
1757 var currentScript = document.currentScript;
1758
1759 // Helper function to load an external script.
1760 function loadScript( url, cb ) {
1761 var script = document.createElement( 'script' );
1762 var prev = currentScript || document.getElementsByTagName( 'script' )[ 0 ];
1763 script.setAttribute( 'async', true );
1764 script.setAttribute( 'src', url );
1765 prev.parentNode.insertBefore( script, prev );
1766 script.addEventListener( 'load', cb );
1767 }
1768
1769 function init() {
1770 loadScript( 'https://platform.linkedin.com/in.js?async=true', function () {
1771 if ( typeof IN !== 'undefined' ) {
1772 IN.init();
1773 }
1774 } );
1775 }
1776
1777 if ( document.readyState === 'loading' ) {
1778 document.addEventListener( 'DOMContentLoaded', init );
1779 } else {
1780 init();
1781 }
1782
1783 document.body.addEventListener( 'is.post-load', function() {
1784 if ( typeof IN !== 'undefined' ) {
1785 IN.parse();
1786 }
1787 } );
1788 } )();
1789 </script>
1790 <?php
1791 }
1792 }
1793 }
1794
1795 /**
1796 * Facebook sharing button.
1797 */
1798 class Share_Facebook extends Sharing_Source {
1799 /**
1800 * Service short name.
1801 *
1802 * @var string
1803 */
1804 public $shortname = 'facebook';
1805
1806 /**
1807 * Service icon font code.
1808 *
1809 * @var string
1810 */
1811 public $icon = '\f204';
1812
1813 /**
1814 * Sharing type.
1815 *
1816 * @var string
1817 */
1818 private $share_type = 'default';
1819
1820 /**
1821 * Constructor.
1822 *
1823 * @param int $id Sharing source ID.
1824 * @param array $settings Sharing settings.
1825 */
1826 public function __construct( $id, array $settings ) {
1827 parent::__construct( $id, $settings );
1828
1829 if ( isset( $settings['share_type'] ) ) {
1830 $this->share_type = $settings['share_type'];
1831 }
1832
1833 if ( 'official' === $this->button_style ) {
1834 $this->smart = true;
1835 } else {
1836 $this->smart = false;
1837 }
1838 }
1839
1840 /**
1841 * Service name.
1842 *
1843 * @return string
1844 */
1845 public function get_name() {
1846 return __( 'Facebook', 'jetpack' );
1847 }
1848
1849 /**
1850 * Add content specific to a service in the head.
1851 */
1852 public function display_header() {
1853 }
1854
1855 /**
1856 * Guess locale from language code.
1857 *
1858 * @param string $lang Language code.
1859 *
1860 * @return string|bool
1861 */
1862 public function guess_locale_from_lang( $lang ) {
1863 if ( 'en' === $lang || 'en_US' === $lang || ! $lang ) {
1864 return 'en_US';
1865 }
1866
1867 if ( ! class_exists( 'GP_Locales' ) ) {
1868 if ( ! defined( 'JETPACK__GLOTPRESS_LOCALES_PATH' ) || ! file_exists( JETPACK__GLOTPRESS_LOCALES_PATH ) ) {
1869 return false;
1870 }
1871
1872 require JETPACK__GLOTPRESS_LOCALES_PATH;
1873 }
1874
1875 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
1876 // WP.com: get_locale() returns 'it'
1877 $locale = GP_Locales::by_slug( $lang );
1878 } else {
1879 // Jetpack: get_locale() returns 'it_IT';
1880 $locale = GP_Locales::by_field( 'wp_locale', $lang );
1881 }
1882
1883 if ( ! $locale ) {
1884 return false;
1885 }
1886
1887 if ( empty( $locale->facebook_locale ) ) {
1888 if ( empty( $locale->wp_locale ) ) {
1889 return false;
1890 } else {
1891 // Facebook SDK is smart enough to fall back to en_US if a
1892 // locale isn't supported. Since supported Facebook locales
1893 // can fall out of sync, we'll attempt to use the known
1894 // wp_locale value and rely on said fallback.
1895 return $locale->wp_locale;
1896 }
1897 }
1898
1899 return $locale->facebook_locale;
1900 }
1901
1902 /**
1903 * Get the markup of the sharing button.
1904 *
1905 * @param WP_Post $post Post object.
1906 *
1907 * @return string
1908 */
1909 public function get_display( $post ) {
1910 if ( $this->smart ) {
1911 $share_url = $this->get_share_url( $post->ID );
1912 $fb_share_html = '<div class="fb-share-button" data-href="' . esc_attr( $share_url ) . '" data-layout="button_count"></div>';
1913 /**
1914 * Filter the output of the Facebook Sharing button.
1915 *
1916 * @module sharedaddy
1917 *
1918 * @since 3.6.0
1919 *
1920 * @param string $fb_share_html Facebook Sharing button HTML.
1921 * @param string $share_url URL of the post to share.
1922 */
1923 return apply_filters( 'jetpack_sharing_facebook_official_button_output', $fb_share_html, $share_url );
1924 }
1925
1926 /** This filter is already documented in modules/sharedaddy/sharing-sources.php */
1927 if ( apply_filters( 'jetpack_register_post_for_share_counts', true, $post->ID, 'facebook' ) ) {
1928 sharing_register_post_for_share_counts( $post->ID );
1929 }
1930 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Facebook', 'share to', 'jetpack' ), __( 'Click to share on Facebook', 'jetpack' ), 'share=facebook', 'sharing-facebook-' . $post->ID );
1931 }
1932
1933 /**
1934 * AMP display for Facebook.
1935 *
1936 * @param \WP_Post $post The current post being viewed.
1937 */
1938 public function get_amp_display( $post ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
1939 $attrs = array(
1940 /** This filter is documented in modules/sharedaddy/sharing-sources.php */
1941 'data-param-app_id' => apply_filters( 'jetpack_sharing_facebook_app_id', '249643311490' ),
1942 );
1943
1944 return $this->build_amp_markup( $attrs );
1945 }
1946
1947 /**
1948 * Process sharing request. Add actions that need to happen when sharing here.
1949 *
1950 * @param WP_Post $post Post object.
1951 * @param array $post_data Array of information about the post we're sharing.
1952 *
1953 * @return void
1954 */
1955 public function process_request( $post, array $post_data ) {
1956 $fb_url = $this->http() . '://www.facebook.com/sharer.php?u=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&t=' . rawurlencode( $this->get_share_title( $post->ID ) );
1957
1958 // Record stats
1959 parent::process_request( $post, $post_data );
1960
1961 parent::redirect_request( $fb_url );
1962 }
1963
1964 /**
1965 * Add content specific to a service in the footer.
1966 */
1967 public function display_footer() {
1968 $this->js_dialog( $this->shortname );
1969 if ( $this->smart ) {
1970 $locale = $this->guess_locale_from_lang( get_locale() );
1971 if ( ! $locale ) {
1972 $locale = 'en_US';
1973 }
1974 /**
1975 * Filter the App ID used in the official Facebook Share button.
1976 *
1977 * @since 3.8.0
1978 *
1979 * @param int $fb_app_id Facebook App ID. Default to 249643311490 (WordPress.com's App ID).
1980 */
1981 $fb_app_id = apply_filters( 'jetpack_sharing_facebook_app_id', '249643311490' );
1982 if ( is_numeric( $fb_app_id ) ) {
1983 $fb_app_id = '&appId=' . $fb_app_id;
1984 } else {
1985 $fb_app_id = '';
1986 }
1987 ?>
1988 <div id="fb-root"></div>
1989 <script>(function(d, s, id) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js = d.createElement(s); js.id = id; js.src = 'https://connect.facebook.net/<?php echo esc_attr( $locale ); ?>/sdk.js#xfbml=1<?php echo esc_attr( $fb_app_id ); ?>&version=v2.3'; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk'));</script>
1990 <script>
1991 document.body.addEventListener( 'is.post-load', function() {
1992 if ( 'undefined' !== typeof FB ) {
1993 FB.XFBML.parse();
1994 }
1995 } );
1996 </script>
1997 <?php
1998 }
1999 }
2000 }
2001
2002 /**
2003 * Print button.
2004 */
2005 class Share_Print extends Sharing_Source {
2006 /**
2007 * Service short name.
2008 *
2009 * @var string
2010 */
2011 public $shortname = 'print';
2012
2013 /**
2014 * Service icon font code.
2015 *
2016 * @var string
2017 */
2018 public $icon = '\f469';
2019
2020 /**
2021 * Constructor.
2022 *
2023 * @param int $id Sharing source ID.
2024 * @param array $settings Sharing settings.
2025 */
2026 public function __construct( $id, array $settings ) {
2027 parent::__construct( $id, $settings );
2028
2029 if ( 'official' === $this->button_style ) {
2030 $this->smart = true;
2031 } else {
2032 $this->smart = false;
2033 }
2034 }
2035
2036 /**
2037 * Service name.
2038 *
2039 * @return string
2040 */
2041 public function get_name() {
2042 return __( 'Print', 'jetpack' );
2043 }
2044
2045 /**
2046 * Get the markup of the sharing button.
2047 *
2048 * @param WP_Post $post Post object.
2049 *
2050 * @return string
2051 */
2052 public function get_display( $post ) {
2053 return $this->get_link( $this->get_process_request_url( $post->ID ) . ( ( is_single() || is_page() ) ? '#print' : '' ), _x( 'Print', 'share to', 'jetpack' ), __( 'Click to print', 'jetpack' ) );
2054 }
2055
2056 /**
2057 * AMP display for Print.
2058 *
2059 * @param \WP_Post $post The current post being viewed.
2060 */
2061 public function get_amp_display( $post ) {
2062 if ( empty( $post ) ) {
2063 return false;
2064 }
2065
2066 return '<button class="amp-social-share print" on="tap:AMP.print">Print</button>';
2067 }
2068 }
2069
2070 /**
2071 * Press This Button.
2072 */
2073 class Share_PressThis extends Sharing_Source {
2074 /**
2075 * Service short name.
2076 *
2077 * @var string
2078 */
2079 public $shortname = 'pressthis';
2080
2081 /**
2082 * Service icon font code.
2083 *
2084 * @var string
2085 */
2086 public $icon = '\f205';
2087
2088 /**
2089 * Constructor.
2090 *
2091 * @param int $id Sharing source ID.
2092 * @param array $settings Sharing settings.
2093 */
2094 public function __construct( $id, array $settings ) {
2095 parent::__construct( $id, $settings );
2096
2097 if ( 'official' === $this->button_style ) {
2098 $this->smart = true;
2099 } else {
2100 $this->smart = false;
2101 }
2102 }
2103
2104 /**
2105 * Service name.
2106 *
2107 * @return string
2108 */
2109 public function get_name() {
2110 return __( 'Press This', 'jetpack' );
2111 }
2112
2113 /**
2114 * Process sharing request. Add actions that need to happen when sharing here.
2115 *
2116 * @param WP_Post $post Post object.
2117 * @param array $post_data Array of information about the post we're sharing.
2118 *
2119 * @return void
2120 */
2121 public function process_request( $post, array $post_data ) {
2122 global $current_user;
2123
2124 $primary_blog = (int) get_user_meta( $current_user->ID, 'primary_blog', true );
2125 if ( $primary_blog ) {
2126 $primary_blog_details = get_blog_details( $primary_blog );
2127 } else {
2128 $primary_blog_details = false;
2129 }
2130
2131 if ( $primary_blog_details ) {
2132 $blogs = array( $primary_blog_details );
2133 } elseif ( function_exists( 'get_active_blogs_for_user' ) ) {
2134 $blogs = get_active_blogs_for_user();
2135 if ( empty( $blogs ) ) {
2136 $blogs = get_blogs_of_user( $current_user->ID );
2137 }
2138 } else {
2139 $blogs = get_blogs_of_user( $current_user->ID );
2140 }
2141
2142 if ( empty( $blogs ) ) {
2143 wp_safe_redirect( get_permalink( $post->ID ) );
2144 die();
2145 }
2146
2147 $blog = current( $blogs );
2148
2149 $args = array(
2150 'u' => rawurlencode( $this->get_share_url( $post->ID ) ),
2151 );
2152
2153 $args['url-scan-submit'] = 'Scan';
2154 $args['_wpnonce'] = wp_create_nonce( 'scan-site' );
2155
2156 $url = $blog->siteurl . '/wp-admin/press-this.php';
2157 $url = add_query_arg( $args, $url );
2158
2159 // Record stats
2160 parent::process_request( $post, $post_data );
2161
2162 parent::redirect_request( $url );
2163 }
2164
2165 /**
2166 * Get the markup of the sharing button.
2167 *
2168 * @param WP_Post $post Post object.
2169 *
2170 * @return string
2171 */
2172 public function get_display( $post ) {
2173 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Press This', 'share to', 'jetpack' ), __( 'Click to Press This!', 'jetpack' ), 'share=press-this' );
2174 }
2175
2176 /**
2177 * No AMP display for PressThis.
2178 *
2179 * @param \WP_Post $post The current post being viewed.
2180 */
2181 public function get_amp_display( $post ) { // phpcs:ignore
2182 return false;
2183 }
2184 }
2185
2186 /**
2187 * Custom (user-defined) sharing button.
2188 */
2189 class Share_Custom extends Sharing_Advanced_Source {
2190 /**
2191 * Sharing service name.
2192 *
2193 * @var string
2194 */
2195 private $name;
2196
2197 /**
2198 * Sharing icon.
2199 *
2200 * @var string
2201 */
2202 private $icon;
2203
2204 /**
2205 * Sharing service URL.
2206 *
2207 * @var string
2208 */
2209 private $url;
2210
2211 /**
2212 * Does the service have an official version.
2213 *
2214 * @var bool
2215 */
2216 public $smart = true;
2217
2218 /**
2219 * Service short name.
2220 *
2221 * @var string
2222 */
2223 public $shortname;
2224
2225 /**
2226 * Custom sharing class.
2227 *
2228 * @return string
2229 */
2230 public function get_class() {
2231 return 'custom share-custom-' . sanitize_html_class( strtolower( $this->name ) );
2232 }
2233
2234 /**
2235 * Constructor.
2236 *
2237 * @param int $id Sharing source ID.
2238 * @param array $settings Sharing settings.
2239 */
2240 public function __construct( $id, array $settings ) {
2241 parent::__construct( $id, $settings );
2242
2243 if ( isset( $settings['name'] ) ) {
2244 $this->name = $settings['name'];
2245 $this->shortname = preg_replace( '/[^a-z0-9]*/', '', $settings['name'] );
2246 }
2247
2248 if ( isset( $settings['icon'] ) ) {
2249 $this->icon = $settings['icon'];
2250
2251 $new_icon = esc_url_raw( wp_specialchars_decode( $this->icon, ENT_QUOTES ) );
2252 $i = 0;
2253 while ( $new_icon !== $this->icon ) {
2254 if ( $i > 5 ) {
2255 $this->icon = false;
2256 break;
2257 } else {
2258 $this->icon = $new_icon;
2259 $new_icon = esc_url_raw( wp_specialchars_decode( $this->icon, ENT_QUOTES ) );
2260 }
2261 ++$i;
2262 }
2263 }
2264
2265 if ( isset( $settings['url'] ) ) {
2266 $this->url = $settings['url'];
2267 }
2268 }
2269
2270 /**
2271 * Service name.
2272 *
2273 * @return string
2274 */
2275 public function get_name() {
2276 return $this->name;
2277 }
2278
2279 /**
2280 * Get the markup of the sharing button.
2281 *
2282 * @param WP_Post $post Post object.
2283 *
2284 * @return string
2285 */
2286 public function get_display( $post ) {
2287 $str = $this->get_link(
2288 $this->get_process_request_url( $post->ID ),
2289 esc_html( $this->name ),
2290 sprintf(
2291 /* Translators: placeholder is the name of a social network. */
2292 __( 'Click to share on %s', 'jetpack' ),
2293 esc_attr( $this->name )
2294 ),
2295 'share=' . $this->id
2296 );
2297 return str_replace( '<span>', '<span style="' . esc_attr( 'background-image:url("' . addcslashes( esc_url_raw( $this->icon ), '"' ) . '");' ) . '">', $str );
2298 }
2299
2300 /**
2301 * No AMP display for custom elements.
2302 *
2303 * @param \WP_Post $post The current post being viewed.
2304 */
2305 public function get_amp_display( $post ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
2306 return false;
2307 }
2308
2309 /**
2310 * Process sharing request. Add actions that need to happen when sharing here.
2311 *
2312 * @param WP_Post $post Post object.
2313 * @param array $post_data Array of information about the post we're sharing.
2314 *
2315 * @return void
2316 */
2317 public function process_request( $post, array $post_data ) {
2318 $url = str_replace( '&amp;', '&', $this->url );
2319 $url = str_replace( '%post_id%', rawurlencode( $post->ID ), $url );
2320 $url = str_replace( '%post_url%', rawurlencode( $this->get_share_url( $post->ID ) ), $url );
2321 $url = str_replace( '%post_full_url%', rawurlencode( get_permalink( $post->ID ) ), $url );
2322 $url = str_replace( '%post_title%', rawurlencode( $this->get_share_title( $post->ID ) ), $url );
2323 $url = str_replace( '%home_url%', rawurlencode( home_url() ), $url );
2324 $url = str_replace( '%post_slug%', rawurlencode( $post->post_name ), $url );
2325
2326 if ( strpos( $url, '%post_tags%' ) !== false ) {
2327 $tags = get_the_tags( $post->ID );
2328 $tagged = '';
2329
2330 if ( $tags ) {
2331 $tagged_raw = array();
2332 foreach ( $tags as $tag ) {
2333 $tagged_raw[] = rawurlencode( $tag->name );
2334 }
2335
2336 $tagged = implode( ',', $tagged_raw );
2337 }
2338
2339 $url = str_replace( '%post_tags%', $tagged, $url );
2340 }
2341
2342 if ( strpos( $url, '%post_excerpt%' ) !== false ) {
2343 $url_excerpt = $post->post_excerpt;
2344 if ( empty( $url_excerpt ) ) {
2345 $url_excerpt = $post->post_content;
2346 }
2347
2348 $url_excerpt = wp_strip_all_tags( strip_shortcodes( $url_excerpt ) );
2349 $url_excerpt = wp_html_excerpt( $url_excerpt, 100 );
2350 $url_excerpt = rtrim( preg_replace( '/[^ .]*$/', '', $url_excerpt ) );
2351 $url = str_replace( '%post_excerpt%', rawurlencode( $url_excerpt ), $url );
2352 }
2353
2354 // Record stats
2355 parent::process_request( $post, $post_data );
2356
2357 parent::redirect_request( $url );
2358 }
2359
2360 /**
2361 * Display options for our sharing buttons.
2362 *
2363 * @return void
2364 */
2365 public function display_options() {
2366 ?>
2367 <div class="input">
2368 <table class="form-table">
2369 <tbody>
2370 <tr>
2371 <th scope="row"><?php esc_html_e( 'Label', 'jetpack' ); ?></th>
2372 <td><input type="text" name="name" value="<?php echo esc_attr( $this->name ); ?>" /></td>
2373 </tr>
2374
2375 <tr>
2376 <th scope="row"><?php esc_html_e( 'URL', 'jetpack' ); ?></th>
2377 <td><input type="text" name="url" value="<?php echo esc_attr( $this->url ); ?>" /></td>
2378 </tr>
2379
2380 <tr>
2381 <th scope="row"><?php esc_html_e( 'Icon', 'jetpack' ); ?></th>
2382 <td><input type="text" name="icon" value="<?php echo esc_attr( $this->icon ); ?>" /></td>
2383 </tr>
2384
2385 <tr>
2386 <th scope="row"></th>
2387 <td>
2388 <input class="button-secondary" type="submit" value="<?php esc_attr_e( 'Save', 'jetpack' ); ?>" />
2389 <a href="#" class="remove"><small><?php esc_html_e( 'Remove Service', 'jetpack' ); ?></small></a>
2390 </td>
2391 </tr>
2392 </tbody>
2393 </table>
2394 </div>
2395 <?php
2396 }
2397
2398 /**
2399 * Sanitize and save options for our sharing buttons.
2400 *
2401 * @param array $data Data to be saved.
2402 *
2403 * @return void
2404 */
2405 public function update_options( array $data ) {
2406 $name = trim( wp_html_excerpt( wp_kses( stripslashes( $data['name'] ), array() ), 30 ) );
2407 $url = trim( esc_url_raw( $data['url'] ) );
2408 $icon = trim( esc_url_raw( $data['icon'] ) );
2409
2410 if ( $name ) {
2411 $this->name = $name;
2412 }
2413
2414 if ( $url ) {
2415 $this->url = $url;
2416 }
2417
2418 if ( $icon ) {
2419 $this->icon = $icon;
2420 }
2421 }
2422
2423 /**
2424 * Get array of information about the service.
2425 *
2426 * @return array
2427 */
2428 public function get_options() {
2429 return array(
2430 'name' => $this->name,
2431 'icon' => $this->icon,
2432 'url' => $this->url,
2433 );
2434 }
2435
2436 /**
2437 * Display a preview of the sharing button.
2438 *
2439 * @param bool $echo Whether to echo the output or return it.
2440 * @param bool $force_smart Whether to force the smart (official) services to be shown.
2441 * @param null|string $button_style Button style.
2442 *
2443 * @return void
2444 */
2445 public function display_preview( $echo = true, $force_smart = false, $button_style = null ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
2446 $opts = $this->get_options();
2447
2448 $text = '&nbsp;';
2449 if ( ! $this->smart ) {
2450 if ( $this->button_style !== 'icon' ) {
2451 $text = $this->get_name();
2452 }
2453 }
2454
2455 $klasses = array( 'share-' . $this->shortname );
2456
2457 if ( $this->button_style === 'icon' || $this->button_style === 'icon-text' ) {
2458 $klasses[] = 'share-icon';
2459 }
2460
2461 if ( $this->button_style === 'icon' ) {
2462 $text = '';
2463 $klasses[] = 'no-text';
2464 }
2465
2466 if ( $this->button_style === 'text' ) {
2467 $klasses[] = 'no-icon';
2468 }
2469
2470 $link = sprintf(
2471 '<a rel="nofollow" class="%s" href="javascript:void(0)" title="%s"><span style="background-image:url(&quot;%s&quot;) !important;background-position:left center;background-repeat:no-repeat;">%s</span></a>',
2472 esc_attr( implode( ' ', $klasses ) ),
2473 esc_attr( $this->get_name() ),
2474 addcslashes( esc_url_raw( $opts['icon'] ), '"' ),
2475 esc_html( $text )
2476 );
2477 ?>
2478 <div class="option option-smart-off">
2479 <?php echo $link; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped above. ?>
2480 </div>
2481 <?php
2482 }
2483 }
2484
2485 /**
2486 * Tumblr sharing service.
2487 */
2488 class Share_Tumblr extends Sharing_Source {
2489 /**
2490 * Service short name.
2491 *
2492 * @var string
2493 */
2494 public $shortname = 'tumblr';
2495
2496 /**
2497 * Service icon font code.
2498 *
2499 * @var string
2500 */
2501 public $icon = '\f214';
2502
2503 /**
2504 * Constructor.
2505 *
2506 * @param int $id Sharing source ID.
2507 * @param array $settings Sharing settings.
2508 */
2509 public function __construct( $id, array $settings ) {
2510 parent::__construct( $id, $settings );
2511 if ( 'official' === $this->button_style ) {
2512 $this->smart = true;
2513 } else {
2514 $this->smart = false;
2515 }
2516 }
2517
2518 /**
2519 * Service name.
2520 *
2521 * @return string
2522 */
2523 public function get_name() {
2524 return __( 'Tumblr', 'jetpack' );
2525 }
2526
2527 /**
2528 * Get the markup of the sharing button.
2529 *
2530 * @param WP_Post $post Post object.
2531 *
2532 * @return string
2533 */
2534 public function get_display( $post ) {
2535 if ( $this->smart ) {
2536 $target = '';
2537 if ( true === $this->open_link_in_new ) {
2538 $target = '_blank';
2539 }
2540
2541 /**
2542 * If we are looking at a single post, let Tumblr figure out the post type (text, photo, link, quote, chat, or video)
2543 * based on the content available on the page.
2544 * If we are not looking at a single post, content from other posts can appear on the page and Tumblr will pick that up.
2545 * In this case, we want Tumblr to focus on our current post, so we will limit the post type to link, where we can give Tumblr a link to our post.
2546 */
2547 if ( ! is_single() ) {
2548 $posttype = 'data-posttype="link"';
2549 } else {
2550 $posttype = '';
2551 }
2552
2553 // Documentation: https://www.tumblr.com/docs/en/share_button
2554 return sprintf(
2555 '<a class="tumblr-share-button" target="%1$s" href="%2$s" data-title="%3$s" data-content="%4$s" title="%5$s"%6$s>%5$s</a>',
2556 $target,
2557 'https://www.tumblr.com/share',
2558 $this->get_share_title( $post->ID ),
2559 $this->get_share_url( $post->ID ),
2560 __( 'Share on Tumblr', 'jetpack' ),
2561 $posttype
2562 );
2563 } else {
2564 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Tumblr', 'share to', 'jetpack' ), __( 'Click to share on Tumblr', 'jetpack' ), 'share=tumblr' );
2565 }
2566 }
2567
2568 /**
2569 * Process sharing request. Add actions that need to happen when sharing here.
2570 *
2571 * @param WP_Post $post Post object.
2572 * @param array $post_data Array of information about the post we're sharing.
2573 *
2574 * @return void
2575 */
2576 public function process_request( $post, array $post_data ) {
2577 // Record stats
2578 parent::process_request( $post, $post_data );
2579
2580 // Redirect to Tumblr's sharing endpoint (a la their bookmarklet)
2581 $url = 'https://www.tumblr.com/share?v=3&u=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&t=' . rawurlencode( $this->get_share_title( $post->ID ) ) . '&s=';
2582
2583 parent::redirect_request( $url );
2584 }
2585
2586 /**
2587 * Add content specific to a service in the footer.
2588 */
2589 public function display_footer() {
2590 if ( $this->smart ) {
2591 // phpcs:disable WordPress.WP.EnqueuedResources.NonEnqueuedScript
2592 ?>
2593 <script id="tumblr-js" type="text/javascript" src="https://assets.tumblr.com/share-button.js"></script>
2594 <?php
2595 // phpcs:enable WordPress.WP.EnqueuedResources.NonEnqueuedScript
2596 } else {
2597 $this->js_dialog(
2598 $this->shortname,
2599 array(
2600 'width' => 450,
2601 'height' => 450,
2602 )
2603 );
2604 }
2605 }
2606 }
2607
2608 /**
2609 * Pinterest sharing service.
2610 */
2611 class Share_Pinterest extends Sharing_Source {
2612 /**
2613 * Service short name.
2614 *
2615 * @var string
2616 */
2617 public $shortname = 'pinterest';
2618
2619 /**
2620 * Service icon font code.
2621 *
2622 * @var string
2623 */
2624 public $icon = '\f209';
2625
2626 /**
2627 * Constructor.
2628 *
2629 * @param int $id Sharing source ID.
2630 * @param array $settings Sharing settings.
2631 */
2632 public function __construct( $id, array $settings ) {
2633 parent::__construct( $id, $settings );
2634 if ( 'official' === $this->button_style ) {
2635 $this->smart = true;
2636 } else {
2637 $this->smart = false;
2638 }
2639 }
2640
2641 /**
2642 * Service name.
2643 *
2644 * @return string
2645 */
2646 public function get_name() {
2647 return __( 'Pinterest', 'jetpack' );
2648 }
2649
2650 /**
2651 * Get image representative of the post to pass on to Pinterest.
2652 *
2653 * @param WP_Post $post Post object.
2654 *
2655 * @return string
2656 */
2657 public function get_image( $post ) {
2658 if ( class_exists( 'Jetpack_PostImages' ) ) {
2659 $image = Jetpack_PostImages::get_image( $post->ID, array( 'fallback_to_avatars' => true ) );
2660 if ( ! empty( $image ) ) {
2661 return $image['src'];
2662 }
2663 }
2664
2665 /**
2666 * Filters the default image used by the Pinterest Pin It share button.
2667 *
2668 * @module sharedaddy
2669 *
2670 * @since 3.6.0
2671 *
2672 * @param string $url Default image URL.
2673 */
2674 return apply_filters( 'jetpack_sharing_pinterest_default_image', 'https://s0.wp.com/i/blank.jpg' );
2675 }
2676
2677 /**
2678 * Get Pinterest external sharing URL.
2679 *
2680 * @param WP_Post $post Post object.
2681 *
2682 * @return string
2683 */
2684 public function get_external_url( $post ) {
2685 $url = 'https://www.pinterest.com/pin/create/button/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&media=' . rawurlencode( $this->get_image( $post ) ) . '&description=' . rawurlencode( $post->post_title );
2686
2687 /**
2688 * Filters the Pinterest share URL used in sharing button output.
2689 *
2690 * @module sharedaddy
2691 *
2692 * @since 3.6.0
2693 *
2694 * @param string $url Pinterest share URL.
2695 */
2696 return apply_filters( 'jetpack_sharing_pinterest_share_url', $url );
2697 }
2698
2699 /**
2700 * Get Pinterest widget type.
2701 *
2702 * @return string
2703 */
2704 public function get_widget_type() {
2705 /**
2706 * Filters the Pinterest widget type.
2707 *
2708 * @see https://business.pinterest.com/en/widget-builder
2709 *
2710 * @module sharedaddy
2711 *
2712 * @since 3.6.0
2713 *
2714 * @param string $type Pinterest widget type. Default of 'buttonPin' for single-image selection. 'buttonBookmark' for multi-image modal.
2715 */
2716 return apply_filters( 'jetpack_sharing_pinterest_widget_type', 'buttonPin' );
2717 }
2718
2719 /**
2720 * Get the markup of the sharing button.
2721 *
2722 * @param WP_Post $post Post object.
2723 *
2724 * @return string
2725 */
2726 public function get_display( $post ) {
2727 $display = '';
2728
2729 if ( $this->smart ) {
2730 $display = sprintf(
2731 '<div class="pinterest_button"><a href="%s" data-pin-do="%s" data-pin-config="beside"><img src="//assets.pinterest.com/images/pidgets/pinit_fg_en_rect_gray_20.png" /></a></div>',
2732 esc_url( $this->get_external_url( $post ) ),
2733 esc_attr( $this->get_widget_type() )
2734 );
2735 } else {
2736 $display = $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Pinterest', 'share to', 'jetpack' ), __( 'Click to share on Pinterest', 'jetpack' ), 'share=pinterest', 'sharing-pinterest-' . $post->ID );
2737 }
2738
2739 /** This filter is already documented in modules/sharedaddy/sharing-sources.php */
2740 if ( apply_filters( 'jetpack_register_post_for_share_counts', true, $post->ID, 'linkedin' ) ) {
2741 sharing_register_post_for_share_counts( $post->ID );
2742 }
2743
2744 return $display;
2745 }
2746
2747 /**
2748 * Process sharing request. Add actions that need to happen when sharing here.
2749 *
2750 * @param WP_Post $post Post object.
2751 * @param array $post_data Array of information about the post we're sharing.
2752 *
2753 * @return void
2754 */
2755 public function process_request( $post, array $post_data ) {
2756 // Record stats
2757 parent::process_request( $post, $post_data );
2758 // If we're triggering the multi-select panel, then we don't need to redirect to Pinterest
2759 if ( ! isset( $_GET['js_only'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
2760 $pinterest_url = esc_url_raw( $this->get_external_url( $post ) );
2761 parent::redirect_request( $pinterest_url );
2762 } else {
2763 echo '// share count bumped';
2764 die();
2765 }
2766 }
2767
2768 /**
2769 * Add content specific to a service in the footer.
2770 */
2771 public function display_footer() {
2772 /**
2773 * Filter the Pin it button appearing when hovering over images when using the official button style.
2774 *
2775 * @module sharedaddy
2776 *
2777 * @since 3.6.0
2778 *
2779 * @param bool $jetpack_pinit_over True by default, displays the Pin it button when hovering over images.
2780 */
2781 $jetpack_pinit_over = apply_filters( 'jetpack_pinit_over_button', true );
2782 ?>
2783 <?php if ( $this->smart ) : ?>
2784 <script type="text/javascript">
2785 ( function () {
2786 // Pinterest shared resources
2787 var s = document.createElement( 'script' );
2788 s.type = 'text/javascript';
2789 s.async = true;
2790 <?php
2791 if ( $jetpack_pinit_over ) {
2792 echo "s.setAttribute( 'data-pin-hover', true );";
2793 }
2794 ?>
2795 s.src = window.location.protocol + '//assets.pinterest.com/js/pinit.js';
2796 var x = document.getElementsByTagName( 'script' )[ 0 ];
2797 x.parentNode.insertBefore(s, x);
2798 // if 'Pin it' button has 'counts' make container wider
2799 function init() {
2800 var shares = document.querySelectorAll( 'li.share-pinterest' );
2801 for ( var i = 0; i < shares.length; i++ ) {
2802 var share = shares[ i ];
2803 var countElement = share.querySelector( 'a span' );
2804 if (countElement) {
2805 var countComputedStyle = window.getComputedStyle(countElement);
2806 if ( countComputedStyle.display === 'block' ) {
2807 var countWidth = parseInt( countComputedStyle.width, 10 );
2808 share.style.marginRight = countWidth + 11 + 'px';
2809 }
2810 }
2811 }
2812 }
2813
2814 if ( document.readyState !== 'complete' ) {
2815 document.addEventListener( 'load', init );
2816 } else {
2817 init();
2818 }
2819 } )();
2820 </script>
2821 <?php elseif ( 'buttonPin' !== $this->get_widget_type() ) : ?>
2822 <script type="text/javascript">
2823 ( function () {
2824 function init() {
2825 document.body.addEventListener( 'click', function ( e ) {
2826 if ( e.target && (
2827 e.target.matches && e.target.matches( 'a.share-pinterest' ) ||
2828 e.target.msMatchesSelector && e.target.msMatchesSelector( 'a.share-pinterest' )
2829 ) ) {
2830 e.preventDefault();
2831 // Load Pinterest Bookmarklet code
2832 var s = document.createElement( 'script' );
2833 s.type = 'text/javascript';
2834 s.src = window.location.protocol + '//assets.pinterest.com/js/pinmarklet.js?r=' + ( Math.random() * 99999999 );
2835 var x = document.getElementsByTagName( 'script' )[ 0 ];
2836 x.parentNode.insertBefore( s, x );
2837 // Trigger Stats
2838 var s = document.createElement( 'script' );
2839 s.type = 'text/javascript';
2840 s.src = e.target.href + ( e.target.href.indexOf( '?' ) ? '&' : '?' ) + 'js_only=1';
2841 var x = document.getElementsByTagName( 'script' )[ '0' ];
2842 x.parentNode.insertBefore( s, x );
2843 }
2844 } );
2845 }
2846
2847 if ( document.readyState === 'loading' ) {
2848 document.addEventListener( 'DOMContentLoaded', init );
2849 } else {
2850 init();
2851 }
2852 } )();
2853 </script>
2854 <?php
2855 endif;
2856 }
2857 }
2858
2859 /**
2860 * Pocket sharing service.
2861 */
2862 class Share_Pocket extends Sharing_Source {
2863 /**
2864 * Service short name.
2865 *
2866 * @var string
2867 */
2868 public $shortname = 'pocket';
2869
2870 /**
2871 * Service icon font code.
2872 *
2873 * @var string
2874 */
2875 public $icon = '\f224';
2876
2877 /**
2878 * Constructor.
2879 *
2880 * @param int $id Sharing source ID.
2881 * @param array $settings Sharing settings.
2882 */
2883 public function __construct( $id, array $settings ) {
2884 parent::__construct( $id, $settings );
2885
2886 if ( 'official' === $this->button_style ) {
2887 $this->smart = true;
2888 } else {
2889 $this->smart = false;
2890 }
2891 }
2892
2893 /**
2894 * Service name.
2895 *
2896 * @return string
2897 */
2898 public function get_name() {
2899 return __( 'Pocket', 'jetpack' );
2900 }
2901
2902 /**
2903 * Process sharing request. Add actions that need to happen when sharing here.
2904 *
2905 * @param WP_Post $post Post object.
2906 * @param array $post_data Array of information about the post we're sharing.
2907 *
2908 * @return void
2909 */
2910 public function process_request( $post, array $post_data ) {
2911 // Record stats
2912 parent::process_request( $post, $post_data );
2913
2914 $pocket_url = esc_url_raw( 'https://getpocket.com/save/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $this->get_share_title( $post->ID ) ) );
2915
2916 parent::redirect_request( $pocket_url );
2917 }
2918
2919 /**
2920 * Get the markup of the sharing button.
2921 *
2922 * @param WP_Post $post Post object.
2923 *
2924 * @return string
2925 */
2926 public function get_display( $post ) {
2927 if ( $this->smart ) {
2928 $post_count = 'horizontal';
2929
2930 $button = '';
2931 $button .= '<div class="pocket_button">';
2932 $button .= sprintf( '<a href="https://getpocket.com/save" class="pocket-btn" data-lang="%s" data-save-url="%s" data-pocket-count="%s" >%s</a>', 'en', esc_attr( $this->get_share_url( $post->ID ) ), $post_count, esc_attr__( 'Pocket', 'jetpack' ) );
2933 $button .= '</div>';
2934
2935 return $button;
2936 } else {
2937 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Pocket', 'share to', 'jetpack' ), __( 'Click to share on Pocket', 'jetpack' ), 'share=pocket' );
2938 }
2939 }
2940
2941 /**
2942 * AMP display for Pocket.
2943 *
2944 * @param \WP_Post $post The current post being viewed.
2945 */
2946 public function get_amp_display( $post ) {
2947 $attrs = array(
2948 'data-share-endpoint' => esc_url_raw( 'https://getpocket.com/save/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $this->get_share_title( $post->ID ) ) ),
2949 );
2950
2951 return $this->build_amp_markup( $attrs );
2952 }
2953
2954 /**
2955 * Add content specific to a service in the footer.
2956 */
2957 public function display_footer() {
2958 if ( $this->smart ) :
2959 ?>
2960 <script>
2961 ( function () {
2962 var currentScript = document.currentScript;
2963
2964 // Don't use Pocket's default JS as it we need to force init new Pocket share buttons loaded via JS.
2965 function jetpack_sharing_pocket_init() {
2966 var script = document.createElement( 'script' );
2967 var prev = currentScript || document.getElementsByTagName( 'script' )[ 0 ];
2968 script.setAttribute( 'async', true );
2969 script.setAttribute( 'src', 'https://widgets.getpocket.com/v1/j/btn.js?v=1' );
2970 prev.parentNode.insertBefore( script, prev );
2971 }
2972
2973 if ( document.readyState === 'loading' ) {
2974 document.addEventListener( 'DOMContentLoaded', jetpack_sharing_pocket_init );
2975 } else {
2976 jetpack_sharing_pocket_init();
2977 }
2978 document.body.addEventListener( 'is.post-load', jetpack_sharing_pocket_init );
2979 } )();
2980 </script>
2981 <?php
2982 else :
2983 $this->js_dialog(
2984 $this->shortname,
2985 array(
2986 'width' => 450,
2987 'height' => 450,
2988 )
2989 );
2990 endif;
2991 }
2992 }
2993
2994 /**
2995 * Telegram sharing service.
2996 */
2997 class Share_Telegram extends Sharing_Source {
2998 /**
2999 * Service short name.
3000 *
3001 * @var string
3002 */
3003 public $shortname = 'telegram';
3004
3005 /**
3006 * Constructor.
3007 *
3008 * @param int $id Sharing source ID.
3009 * @param array $settings Sharing settings.
3010 */
3011 public function __construct( $id, array $settings ) { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod.Found
3012 parent::__construct( $id, $settings );
3013 }
3014
3015 /**
3016 * Service name.
3017 *
3018 * @return string
3019 */
3020 public function get_name() {
3021 return __( 'Telegram', 'jetpack' );
3022 }
3023
3024 /**
3025 * Process sharing request. Add actions that need to happen when sharing here.
3026 *
3027 * @param WP_Post $post Post object.
3028 * @param array $post_data Array of information about the post we're sharing.
3029 *
3030 * @return void
3031 */
3032 public function process_request( $post, array $post_data ) {
3033 // Record stats
3034 parent::process_request( $post, $post_data );
3035
3036 $telegram_url = esc_url_raw( 'https://telegram.me/share/url?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&text=' . rawurlencode( $this->get_share_title( $post->ID ) ) );
3037
3038 parent::redirect_request( $telegram_url );
3039 }
3040
3041 /**
3042 * Get the markup of the sharing button.
3043 *
3044 * @param WP_Post $post Post object.
3045 *
3046 * @return string
3047 */
3048 public function get_display( $post ) {
3049 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Telegram', 'share to', 'jetpack' ), __( 'Click to share on Telegram', 'jetpack' ), 'share=telegram' );
3050 }
3051
3052 /**
3053 * AMP display for Telegram.
3054 *
3055 * @param \WP_Post $post The current post being viewed.
3056 */
3057 public function get_amp_display( $post ) {
3058 $attrs = array(
3059 'data-share-endpoint' => esc_url_raw( 'https://telegram.me/share/url?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&text=' . rawurlencode( $this->get_share_title( $post->ID ) ) ),
3060 );
3061
3062 return $this->build_amp_markup( $attrs );
3063 }
3064
3065 /**
3066 * Add content specific to a service in the footer.
3067 */
3068 public function display_footer() {
3069 $this->js_dialog(
3070 $this->shortname,
3071 array(
3072 'width' => 450,
3073 'height' => 450,
3074 )
3075 );
3076 }
3077 }
3078
3079 /**
3080 * WhatsApp sharing service.
3081 */
3082 class Jetpack_Share_WhatsApp extends Sharing_Source {
3083 /**
3084 * Service short name.
3085 *
3086 * @var string
3087 */
3088 public $shortname = 'jetpack-whatsapp';
3089
3090 /**
3091 * Constructor.
3092 *
3093 * @param int $id Sharing source ID.
3094 * @param array $settings Sharing settings.
3095 */
3096 public function __construct( $id, array $settings ) { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod.Found
3097 parent::__construct( $id, $settings );
3098 }
3099
3100 /**
3101 * Service name.
3102 *
3103 * @return string
3104 */
3105 public function get_name() {
3106 return __( 'WhatsApp', 'jetpack' );
3107 }
3108
3109 /**
3110 * Get the markup of the sharing button.
3111 *
3112 * @param WP_Post $post Post object.
3113 *
3114 * @return string
3115 */
3116 public function get_display( $post ) {
3117 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'WhatsApp', 'share to', 'jetpack' ), __( 'Click to share on WhatsApp', 'jetpack' ), 'share=jetpack-whatsapp' );
3118 }
3119
3120 /**
3121 * AMP display for Whatsapp.
3122 *
3123 * @param \WP_Post $post The current post being viewed.
3124 */
3125 public function get_amp_display( $post ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
3126 $attrs = array(
3127 'type' => 'whatsapp',
3128 );
3129
3130 return $this->build_amp_markup( $attrs );
3131 }
3132
3133 /**
3134 * Process sharing request. Add actions that need to happen when sharing here.
3135 *
3136 * @param WP_Post $post Post object.
3137 * @param array $post_data Array of information about the post we're sharing.
3138 *
3139 * @return void
3140 */
3141 public function process_request( $post, array $post_data ) {
3142 // Record stats
3143 parent::process_request( $post, $post_data );
3144
3145 // Firefox for desktop doesn't handle the "api.whatsapp.com" URL properly, so use "web.whatsapp.com"
3146 if ( User_Agent_Info::is_firefox_desktop() ) {
3147 $url = 'https://web.whatsapp.com/send?text=';
3148 } else {
3149 $url = 'https://api.whatsapp.com/send?text=';
3150 }
3151
3152 $url .= rawurlencode( $this->get_share_title( $post->ID ) . ' ' . $this->get_share_url( $post->ID ) );
3153
3154 parent::redirect_request( $url );
3155 }
3156 }
3157
3158 /**
3159 * Skype sharing service.
3160 */
3161 class Share_Skype extends Deprecated_Sharing_Source {
3162 /**
3163 * Service short name.
3164 *
3165 * @var string
3166 */
3167 public $shortname = 'skype';
3168
3169 /**
3170 * Service name.
3171 *
3172 * @return string
3173 */
3174 public function get_name() {
3175 return __( 'Skype', 'jetpack' );
3176 }
3177 }
3178
3179 /**
3180 * Mastodon sharing service.
3181 */
3182 class Share_Mastodon extends Sharing_Source {
3183 /**
3184 * Service short name.
3185 *
3186 * @var string
3187 */
3188 public $shortname = 'mastodon';
3189
3190 /**
3191 * Service icon font code.
3192 *
3193 * @var string
3194 */
3195 public $icon = '\f10a';
3196
3197 /**
3198 * Service name.
3199 *
3200 * @return string
3201 */
3202 public function get_name() {
3203 return __( 'Mastodon', 'jetpack' );
3204 }
3205
3206 /**
3207 * Get the markup of the sharing button.
3208 *
3209 * @param WP_Post $post Post object.
3210 *
3211 * @return string
3212 */
3213 public function get_display( $post ) {
3214 return $this->get_link(
3215 $this->get_process_request_url( $post->ID ),
3216 _x( 'Mastodon', 'share to', 'jetpack' ),
3217 __( 'Click to share on Mastodon', 'jetpack' ),
3218 'share=mastodon',
3219 'sharing-mastodon-' . $post->ID
3220 );
3221 }
3222
3223 /**
3224 * Process sharing request. Add actions that need to happen when sharing here.
3225 *
3226 * @param WP_Post $post Post object.
3227 * @param array $post_data Array of information about the post we're sharing.
3228 *
3229 * @return void
3230 */
3231 public function process_request( $post, array $post_data ) {
3232 if ( empty( $_POST['jetpack-mastodon-instance'] ) ) {
3233 require_once WP_SHARING_PLUGIN_DIR . 'services/class-jetpack-mastodon-modal.php';
3234 add_action( 'template_redirect', array( 'Jetpack_Mastodon_Modal', 'modal' ) );
3235 return;
3236 }
3237
3238 check_admin_referer( 'jetpack_share_mastodon_instance' );
3239
3240 $mastodon_instance = isset( $_POST['jetpack-mastodon-instance'] )
3241 ? trailingslashit( sanitize_text_field( wp_unslash( $_POST['jetpack-mastodon-instance'] ) ) )
3242 : null;
3243
3244 $post_title = $this->get_share_title( $post->ID );
3245 $post_link = $this->get_share_url( $post->ID );
3246 $post_tags = $this->get_share_tags( $post->ID );
3247
3248 /**
3249 * Allow filtering the default message that gets posted to Mastodon.
3250 *
3251 * @module sharedaddy
3252 * @since 11.9
3253 *
3254 * @param string $share_url The default message that gets posted to Mastodon.
3255 * @param WP_Post $post The post object.
3256 * @param array $post_data Array of information about the post we're sharing.
3257 */
3258 $shared_message = apply_filters(
3259 'jetpack_sharing_mastodon_default_message',
3260 $post_title . ' ' . $post_link . ' ' . $post_tags,
3261 $post,
3262 $post_data
3263 );
3264
3265 $share_url = sprintf(
3266 '%1$sshare?text=%2$s',
3267 $mastodon_instance,
3268 rawurlencode( $shared_message )
3269 );
3270
3271 // Record stats
3272 parent::process_request( $post, $post_data );
3273
3274 parent::redirect_request( $share_url );
3275 }
3276
3277 /**
3278 * Add content specific to a service in the footer.
3279 */
3280 public function display_footer() {
3281 $this->js_dialog(
3282 $this->shortname,
3283 array(
3284 'width' => 460,
3285 'height' => 400,
3286 )
3287 );
3288 }
3289 }
3290
3291 /**
3292 * Nextdoor sharing service.
3293 */
3294 class Share_Nextdoor extends Sharing_Source {
3295 /**
3296 * Service short name.
3297 *
3298 * @var string
3299 */
3300 public $shortname = 'nextdoor';
3301
3302 /**
3303 * Service icon font code.
3304 *
3305 * @var string
3306 */
3307 public $icon = '\f10c';
3308
3309 /**
3310 * Service name.
3311 *
3312 * @return string
3313 */
3314 public function get_name() {
3315 return __( 'Nextdoor', 'jetpack' );
3316 }
3317
3318 /**
3319 * Get the markup of the sharing button.
3320 *
3321 * @param WP_Post $post Post object.
3322 *
3323 * @return string
3324 */
3325 public function get_display( $post ) {
3326 return $this->get_link(
3327 $this->get_process_request_url( $post->ID ),
3328 _x( 'Nextdoor', 'share to', 'jetpack' ),
3329 __( 'Click to share on Nextdoor', 'jetpack' ),
3330 'share=nextdoor',
3331 'sharing-nextdoor-' . $post->ID
3332 );
3333 }
3334
3335 /**
3336 * Process sharing request. Add actions that need to happen when sharing here.
3337 *
3338 * @param WP_Post $post Post object.
3339 * @param array $post_data Array of information about the post we're sharing.
3340 *
3341 * @return void
3342 */
3343 public function process_request( $post, array $post_data ) {
3344 // Record stats
3345 parent::process_request( $post, $post_data );
3346
3347 $url = 'https://nextdoor.com/sharekit/?source=jetpack&body=';
3348 $url .= rawurlencode( $this->get_share_title( $post->ID ) . ' ' . $this->get_share_url( $post->ID ) );
3349
3350 parent::redirect_request( $url );
3351 }
3352 }
3353
3354 /**
3355 * Threads sharing service.
3356 */
3357 class Share_Threads extends Sharing_Source {
3358 /**
3359 * Service short name.
3360 *
3361 * @var string
3362 */
3363 public $shortname = 'threads';
3364
3365 /**
3366 * Service icon font code.
3367 *
3368 * @var string
3369 */
3370 public $icon = '\f10d';
3371
3372 /**
3373 * Service name.
3374 *
3375 * @return string
3376 */
3377 public function get_name() {
3378 return __( 'Threads', 'jetpack' );
3379 }
3380
3381 /**
3382 * Get the markup of the sharing button.
3383 *
3384 * @param WP_Post $post Post object.
3385 *
3386 * @return string
3387 */
3388 public function get_display( $post ) {
3389 return $this->get_link(
3390 $this->get_process_request_url( $post->ID ),
3391 _x( 'Threads', 'share to', 'jetpack' ),
3392 __( 'Click to share on Threads', 'jetpack' ),
3393 'share=threads',
3394 'sharing-threads-' . $post->ID
3395 );
3396 }
3397
3398 /**
3399 * Process sharing request. Add actions that need to happen when sharing here.
3400 *
3401 * @param WP_Post $post Post object.
3402 * @param array $post_data Array of information about the post we're sharing.
3403 *
3404 * @return void
3405 */
3406 public function process_request( $post, array $post_data ) {
3407 // Record stats
3408 parent::process_request( $post, $post_data );
3409
3410 $url = 'https://threads.net/intent/post?text=';
3411 $url .= rawurlencode( $this->get_share_title( $post->ID ) . ' ' . $this->get_share_url( $post->ID ) );
3412
3413 parent::redirect_request( $url );
3414 }
3415
3416 /**
3417 * Add content specific to a service in the footer.
3418 */
3419 public function display_footer() {
3420 $this->js_dialog( $this->shortname );
3421 }
3422 }
3423
3424 /**
3425 * Bluesky sharing service.
3426 */
3427 class Share_Bluesky extends Sharing_Source {
3428 /**
3429 * Service short name.
3430 *
3431 * @var string
3432 */
3433 public $shortname = 'bluesky';
3434
3435 /**
3436 * Service icon font code.
3437 *
3438 * @var string
3439 */
3440 public $icon = '\f10f';
3441
3442 /**
3443 * Service name.
3444 *
3445 * @return string
3446 */
3447 public function get_name() {
3448 return __( 'Bluesky', 'jetpack' );
3449 }
3450
3451 /**
3452 * Get the markup of the sharing button.
3453 *
3454 * @param WP_Post $post Post object.
3455 *
3456 * @return string
3457 */
3458 public function get_display( $post ) {
3459 return $this->get_link(
3460 $this->get_process_request_url( $post->ID ),
3461 _x( 'Bluesky', 'share to', 'jetpack' ),
3462 __( 'Click to share on Bluesky', 'jetpack' ),
3463 'share=bluesky',
3464 'sharing-bluesky-' . $post->ID
3465 );
3466 }
3467
3468 /**
3469 * Process sharing request. Add actions that need to happen when sharing here.
3470 *
3471 * @param WP_Post $post Post object.
3472 * @param array $post_data Array of information about the post we're sharing.
3473 *
3474 * @return void
3475 */
3476 public function process_request( $post, array $post_data ) {
3477 // Record stats
3478 parent::process_request( $post, $post_data );
3479
3480 $url = 'https://bsky.app/intent/compose?text=';
3481 $url .= rawurlencode( $this->get_share_title( $post->ID ) . ' ' . $this->get_share_url( $post->ID ) );
3482
3483 parent::redirect_request( $url );
3484 }
3485
3486 /**
3487 * Add content specific to a service in the footer.
3488 */
3489 public function display_footer() {
3490 $this->js_dialog( $this->shortname );
3491 }
3492 }
3493