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