PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 8.9.4
Jetpack – WP Security, Backup, Speed, & Growth v8.9.4
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 All 500 releases
jetpack / modules / sharedaddy / sharing-sources.php
sharing-sources.php
1,985 lines 58.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use Automattic\Jetpack\Device_Detection\User_Agent_Info;
4
5 abstract class Sharing_Source {
6 public $button_style;
7 public $smart;
8 protected $open_link_in_new;
9 protected $id;
10
11 public function __construct( $id, array $settings ) {
12 $this->id = $id;
13 /**
14 * Filter the way sharing links open.
15 *
16 * By default, sharing links open in a new window.
17 *
18 * @module sharedaddy
19 *
20 * @since 3.4.0
21 *
22 * @param bool true Should Sharing links open in a new window. Default to true.
23 */
24 $this->open_link_in_new = apply_filters( 'jetpack_open_sharing_in_new_window', true );
25
26 if ( isset( $settings['button_style'] ) ) {
27 $this->button_style = $settings['button_style'];
28 }
29
30 if ( isset( $settings['smart'] ) ) {
31 $this->smart = $settings['smart'];
32 }
33 }
34
35 public function is_deprecated() {
36 return false;
37 }
38
39 public function http() {
40 return is_ssl() ? 'https' : 'http';
41 }
42
43 public function get_id() {
44 return $this->id;
45 }
46
47 public function get_class() {
48 return $this->id;
49 }
50
51 public function get_share_url( $post_id ) {
52 /**
53 * Filter the sharing permalink.
54 *
55 * @module sharedaddy
56 *
57 * @since 1.2.0
58 *
59 * @param string get_permalink( $post_id ) Post Permalink.
60 * @param int $post_id Post ID.
61 * @param int $this->id Sharing ID.
62 */
63 return apply_filters( 'sharing_permalink', get_permalink( $post_id ), $post_id, $this->id );
64 }
65
66 public function get_share_title( $post_id ) {
67 $post = get_post( $post_id );
68 /**
69 * Filter the sharing title.
70 *
71 * @module sharedaddy
72 *
73 * @since 2.8.0
74 *
75 * @param string $post->post_title Post Title.
76 * @param int $post_id Post ID.
77 * @param int $this->id Sharing ID.
78 */
79 $title = apply_filters( 'sharing_title', $post->post_title, $post_id, $this->id );
80
81 return html_entity_decode( wp_kses( $title, null ) );
82 }
83
84 public function has_custom_button_style() {
85 return false;
86 }
87
88 public function get_link( $url, $text, $title, $query = '', $id = false ) {
89 $args = func_get_args();
90 $klasses = array( 'share-' . $this->get_class(), 'sd-button' );
91
92 if ( 'icon' == $this->button_style || 'icon-text' == $this->button_style ) {
93 $klasses[] = 'share-icon';
94 }
95
96 if ( 'icon' == $this->button_style ) {
97 $text = $title;
98 $klasses[] = 'no-text';
99
100 if ( true == $this->open_link_in_new ) {
101 $text .= __( ' (Opens in new window)', 'jetpack' );
102 }
103 }
104
105 /**
106 * Filter the sharing display ID.
107 *
108 * @module sharedaddy
109 *
110 * @since 3.4.0
111 *
112 * @param int|false $id Sharing ID.
113 * @param object $this Sharing service properties.
114 * @param array $args Array of sharing service options.
115 */
116 $id = apply_filters( 'jetpack_sharing_display_id', $id, $this, $args );
117 /**
118 * Filter the sharing display link.
119 *
120 * @module sharedaddy
121 *
122 * @since 2.8.0
123 *
124 * @param string $url Post URL.
125 * @param object $this Sharing service properties.
126 * @param int|false $id Sharing ID.
127 * @param array $args Array of sharing service options.
128 */
129 $url = apply_filters( 'sharing_display_link', $url, $this, $id, $args ); // backwards compatibility
130 /**
131 * Filter the sharing display link.
132 *
133 * @module sharedaddy
134 *
135 * @since 2.8.0
136 *
137 * @param string $url Post URL.
138 * @param object $this Sharing service properties.
139 * @param int|false $id Sharing ID.
140 * @param array $args Array of sharing service options.
141 */
142 $url = apply_filters( 'jetpack_sharing_display_link', $url, $this, $id, $args );
143 /**
144 * Filter the sharing display query.
145 *
146 * @module sharedaddy
147 *
148 * @since 2.8.0
149 *
150 * @param string $query Sharing service URL parameter.
151 * @param object $this Sharing service properties.
152 * @param int|false $id Sharing ID.
153 * @param array $args Array of sharing service options.
154 */
155 $query = apply_filters( 'jetpack_sharing_display_query', $query, $this, $id, $args );
156
157 if ( ! empty( $query ) ) {
158 if ( false === stripos( $url, '?' ) ) {
159 $url .= '?' . $query;
160 } else {
161 $url .= '&amp;' . $query;
162 }
163 }
164
165 if ( 'text' == $this->button_style ) {
166 $klasses[] = 'no-icon';
167 }
168
169 /**
170 * Filter the sharing display classes.
171 *
172 * @module sharedaddy
173 *
174 * @since 3.4.0
175 *
176 * @param array $klasses Sharing service classes.
177 * @param object $this Sharing service properties.
178 * @param int|false $id Sharing ID.
179 * @param array $args Array of sharing service options.
180 */
181 $klasses = apply_filters( 'jetpack_sharing_display_classes', $klasses, $this, $id, $args );
182 /**
183 * Filter the sharing display title.
184 *
185 * @module sharedaddy
186 *
187 * @since 3.4.0
188 *
189 * @param string $title Sharing service title.
190 * @param object $this Sharing service properties.
191 * @param int|false $id Sharing ID.
192 * @param array $args Array of sharing service options.
193 */
194 $title = apply_filters( 'jetpack_sharing_display_title', $title, $this, $id, $args );
195 /**
196 * Filter the sharing display text.
197 *
198 * @module sharedaddy
199 *
200 * @since 3.4.0
201 *
202 * @param string $text Sharing service text.
203 * @param object $this Sharing service properties.
204 * @param int|false $id Sharing ID.
205 * @param array $args Array of sharing service options.
206 */
207 $text = apply_filters( 'jetpack_sharing_display_text', $text, $this, $id, $args );
208
209 return sprintf(
210 '<a rel="nofollow%s" data-shared="%s" class="%s" href="%s"%s title="%s"><span%s>%s</span></a>',
211 ( true == $this->open_link_in_new ) ? ' noopener noreferrer' : '',
212 ( $id ? esc_attr( $id ) : '' ),
213 implode( ' ', $klasses ),
214 $url,
215 ( true == $this->open_link_in_new ) ? ' target="_blank"' : '',
216 $title,
217 ( 'icon' == $this->button_style ) ? '></span><span class="sharing-screen-reader-text"' : '',
218 $text
219 );
220 }
221
222 /**
223 * Get an unfiltered post permalink to use when generating a sharing URL with get_link.
224 * Use instead of get_share_url for non-official styles as get_permalink ensures that process_request
225 * will be executed more reliably, in the case that the filtered URL uses a service that strips query parameters.
226 *
227 * @since 3.7.0
228 * @param int $post_id Post ID.
229 * @uses get_permalink
230 * @return string get_permalink( $post_id ) Post permalink.
231 */
232 public function get_process_request_url( $post_id ) {
233 return get_permalink( $post_id );
234 }
235
236 abstract public function get_name();
237 abstract public function get_display( $post );
238
239 public function display_header() {
240 }
241
242 public function display_footer() {
243 }
244
245 public function has_advanced_options() {
246 return false;
247 }
248
249 /**
250 * Get the AMP specific markup for a sharing button.
251 *
252 * @param \WP_Post $post The current post being viewed.
253 */
254 public function get_amp_display( $post ) {
255 // Only display markup if we're on a post.
256 if ( empty( $post ) ) {
257 return false;
258 }
259
260 return $this->build_amp_markup();
261 }
262
263 /**
264 * Generates and returns the markup for an AMP sharing button.
265 *
266 * @param array $attrs Custom attributes for rendering the social icon.
267 */
268 protected function build_amp_markup( $attrs = array() ) {
269
270 $title = sprintf(
271 /* translators: placeholder is a service name, such as "Twitter" or "Facebook". */
272 __( 'Click to share on %s', 'jetpack' ),
273 $this->get_name()
274 );
275
276 $attrs = array_merge(
277 array(
278 'type' => $this->get_id(),
279 'height' => '32px',
280 'width' => '32px',
281 'aria-label' => $title,
282 'title' => $title,
283 ),
284 $attrs
285 );
286 $sharing_link = '<amp-social-share';
287 foreach ( $attrs as $key => $value ) {
288 $sharing_link .= sprintf( ' %s="%s"', sanitize_key( $key ), esc_attr( $value ) );
289 }
290 $sharing_link .= '></amp-social-share>';
291 return $sharing_link;
292 }
293
294 public function display_preview( $echo = true, $force_smart = false, $button_style = null ) {
295 $text = '&nbsp;';
296 $button_style = ( ! empty( $button_style ) ) ? $button_style : $this->button_style;
297 if ( ! $this->smart && ! $force_smart ) {
298 if ( $button_style != 'icon' ) {
299 $text = $this->get_name();
300 }
301 }
302
303 $klasses = array( 'share-' . $this->get_class(), 'sd-button' );
304
305 if ( $button_style == 'icon' || $button_style == 'icon-text' ) {
306 $klasses[] = 'share-icon';
307 }
308
309 if ( $button_style == 'icon' ) {
310 $klasses[] = 'no-text';
311 }
312
313 if ( $button_style == 'text' ) {
314 $klasses[] = 'no-icon';
315 }
316
317 $is_deprecated = $this->is_deprecated();
318
319 $link = sprintf(
320 '<a rel="nofollow" class="%s" href="javascript:void(0)" title="%s"><span>%s</span></a>',
321 implode( ' ', $klasses ),
322 esc_attr(
323 $is_deprecated
324 /* translators: %1$s is the name of a deprecated Sharing Service like "Google+" */
325 ? sprintf( __( 'The %1$s service has shut down. This sharing button is not displayed to your visitors and should be removed.', 'jetpack' ), $this->get_name() )
326 : $this->get_name()
327 ),
328 esc_html(
329 $is_deprecated
330 /* translators: %1$s is the name of a deprecated Sharing Service like "Google+" */
331 ? sprintf( __( '%1$s has shut down', 'jetpack' ), $this->get_name() )
332 : $text
333 )
334 );
335
336 $smart = ( $this->smart || $force_smart ) ? 'on' : 'off';
337 $return = "<div class='option option-smart-$smart'>$link</div>";
338 if ( $echo ) {
339 echo $return;
340 }
341
342 return $return;
343 }
344
345 public function get_total( $post = false ) {
346 global $wpdb, $blog_id;
347
348 $name = strtolower( $this->get_id() );
349
350 if ( $post == false ) {
351 // get total number of shares for service
352 return (int) $wpdb->get_var( $wpdb->prepare( 'SELECT SUM( count ) FROM sharing_stats WHERE blog_id = %d AND share_service = %s', $blog_id, $name ) );
353 }
354
355 // get total shares for a post
356 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 ) );
357 }
358
359 public function get_posts_total() {
360 global $wpdb, $blog_id;
361
362 $totals = array();
363 $name = strtolower( $this->get_id() );
364
365 $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 ) );
366
367 if ( ! empty( $my_data ) ) {
368 foreach ( $my_data as $row ) {
369 $totals[] = new Sharing_Post_Total( $row->id, $row->total );
370 }
371 }
372
373 usort( $totals, array( 'Sharing_Post_Total', 'cmp' ) );
374
375 return $totals;
376 }
377
378 public function process_request( $post, array $post_data ) {
379 /**
380 * Fires when a post is shared via one of the sharing buttons.
381 *
382 * @module sharedaddy
383 *
384 * @since 1.1.0
385 *
386 * @param array $args Aray of information about the sharing service.
387 */
388 do_action( 'sharing_bump_stats', array( 'service' => $this, 'post' => $post ) );
389 }
390
391 public function js_dialog( $name, $params = array() ) {
392 if ( true !== $this->open_link_in_new ) {
393 return;
394 }
395
396 $defaults = array(
397 'menubar' => 1,
398 'resizable' => 1,
399 'width' => 600,
400 'height' => 400,
401 );
402 $params = array_merge( $defaults, $params );
403 $opts = array();
404 foreach ( $params as $key => $val ) {
405 $opts[] = "$key=$val";
406 }
407 $opts = implode( ',', $opts );
408
409 // Add JS after sharing-js has been enqueued.
410 wp_add_inline_script( 'sharing-js',
411 "var windowOpen;
412 jQuery( document.body ).on( 'click', 'a.share-$name', function() {
413 // If there's another sharing window open, close it.
414 if ( 'undefined' !== typeof windowOpen ) {
415 windowOpen.close();
416 }
417 windowOpen = window.open( jQuery( this ).attr( 'href' ), 'wpcom$name', '$opts' );
418 return false;
419 });"
420 );
421 }
422 }
423
424 abstract class Deprecated_Sharing_Source extends Sharing_Source {
425 public $button_style = 'text';
426 public $smart = false;
427 protected $open_link_in_new = false;
428 protected $id;
429 protected $deprecated = true;
430
431 final public function __construct( $id, array $settings ) {
432 $this->id = $id;
433
434 if ( isset( $settings['button_style'] ) ) {
435 $this->button_style = $settings['button_style'];
436 }
437 }
438
439 final public function is_deprecated() {
440 return true;
441 }
442
443 final public function get_share_url( $post_id ) {
444 return get_permalink( $post_id );
445 }
446
447 /**
448 * No AMP display for deprecated sources.
449 *
450 * @param \WP_Post $post The current post being viewed.
451 */
452 final public function get_amp_display( $post ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
453 return false;
454 }
455
456 final public function display_preview( $echo = true, $force_smart = false, $button_style = null ) {
457 return parent::display_preview( $echo, false, $button_style );
458 }
459
460 final public function get_total( $post = false ) {
461 return 0;
462 }
463
464 final public function get_posts_total() {
465 return 0;
466 }
467
468 final public function process_request( $post, array $post_data ) {
469 parent::process_request( $post, $post_data );
470 }
471
472 final public function get_display( $post ) {
473 if ( current_user_can( 'manage_options' ) ) {
474 return $this->display_deprecated( $post );
475 }
476
477 return '';
478 }
479
480 public function display_deprecated( $post ) {
481 return $this->get_link(
482 $this->get_share_url( $post->ID ),
483 /* translators: %1$s is the name of a deprecated Sharing Service like "Google+" */
484 sprintf( __( '%1$s has shut down', 'jetpack' ), $this->get_name() ),
485 /* translators: %1$s is the name of a deprecated Sharing Service like "Google+" */
486 sprintf( __( 'The %1$s service has shut down. This sharing button is not displayed to your visitors and should be removed.', 'jetpack' ), $this->get_name() )
487 );
488 }
489 }
490
491 abstract class Sharing_Advanced_Source extends Sharing_Source {
492 public function has_advanced_options() {
493 return true;
494 }
495
496 abstract public function display_options();
497 abstract public function update_options( array $data );
498 abstract public function get_options();
499 }
500
501 class Share_Email extends Sharing_Source {
502 public $shortname = 'email';
503 public $icon = '\f410';
504 public function __construct( $id, array $settings ) {
505 parent::__construct( $id, $settings );
506
507 if ( 'official' == $this->button_style ) {
508 $this->smart = true;
509 } else {
510 $this->smart = false;
511 }
512 }
513
514 public function get_name() {
515 return _x( 'Email', 'as sharing source', 'jetpack' );
516 }
517
518 // Default does nothing
519 public function process_request( $post, array $post_data ) {
520 $ajax = false;
521 if ( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) == 'xmlhttprequest' ) {
522 $ajax = true;
523 }
524
525 $source_email = $target_email = $source_name = false;
526
527 if ( isset( $post_data['source_email'] ) && is_email( $post_data['source_email'] ) ) {
528 $source_email = $post_data['source_email'];
529 }
530
531 if ( isset( $post_data['target_email'] ) && is_email( $post_data['target_email'] ) ) {
532 $target_email = $post_data['target_email'];
533 }
534
535 if ( isset( $post_data['source_name'] ) && strlen( $post_data['source_name'] ) < 200 ) {
536 $source_name = $post_data['source_name'];
537 } elseif ( isset( $post_data['source_name'] ) ) {
538 $source_name = substr( $post_data['source_name'], 0, 200 );
539 } else {
540 $source_name = '';
541 }
542
543 // Test email
544 $error = 1; // Failure in data
545 if ( empty( $post_data['source_f_name'] ) && $source_email && $target_email && $source_name ) {
546 /**
547 * Allow plugins to stop the email sharing button from running the shared message through Akismet.
548 *
549 * @module sharedaddy
550 *
551 * @since 1.1.0
552 *
553 * @param bool true Should we check if the message isn't spam?
554 * @param object $post Post information.
555 * @param array $post_data Information about the shared message.
556 */
557 if ( apply_filters( 'sharing_email_check', true, $post, $post_data ) ) {
558 $data = array(
559 'post' => $post,
560 'source' => $source_email,
561 'target' => $target_email,
562 'name' => $source_name,
563 'sharing_source' => $this,
564 );
565 // todo: implement an error message when email doesn't get sent.
566 /**
567 * Filter whether an email can be sent from the Email sharing button.
568 *
569 * @module sharedaddy
570 *
571 * @since 1.1.0
572 *
573 * @param array $data Array of information about the shared message.
574 */
575 if ( ( $data = apply_filters( 'sharing_email_can_send', $data ) ) !== false ) {
576 // Record stats
577 parent::process_request( $data['post'], $post_data );
578
579 /**
580 * Fires when an email is sent via the Email sharing button.
581 *
582 * @module sharedaddy
583 *
584 * @since 1.1.0
585 *
586 * @param array $data Array of information about the shared message.
587 */
588 do_action( 'sharing_email_send_post', $data );
589 }
590
591 // Return a positive regardless of whether the user is subscribed or not
592 if ( $ajax ) {
593 ?>
594 <div class="response">
595 <div class="response-title"><?php _e( 'This post has been shared!', 'jetpack' ); ?></div>
596 <div class="response-sub"><?php printf( __( 'You have shared this post with %s', 'jetpack' ), esc_html( $target_email ) ); ?></div>
597 <div class="response-close"><a href="#" class="sharing_cancel"><?php _e( 'Close', 'jetpack' ); ?></a></div>
598 </div>
599 <?php
600 } else {
601 wp_safe_redirect( get_permalink( $post->ID ) . '?shared=email' );
602 }
603
604 die();
605 } else {
606 $error = 2; // Email check failed
607 }
608 }
609
610 if ( $ajax ) {
611 echo $error;
612 } else {
613 wp_safe_redirect( get_permalink( $post->ID ) . '?shared=email&msg=fail' );
614 }
615
616 die();
617 }
618
619 public function get_display( $post ) {
620 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Email', 'share to', 'jetpack' ), __( 'Click to email this to a friend', 'jetpack' ), 'share=email' );
621 }
622
623 /**
624 * No AMP display for email.
625 *
626 * @param \WP_Post $post The current post being viewed.
627 */
628 public function get_amp_display( $post ) { // phpcs:ignore
629 return false;
630 }
631
632 /**
633 * Outputs the hidden email dialog
634 */
635 public function display_footer() {
636 global $current_user;
637
638 $visible = $status = false;
639 ?>
640 <div id="sharing_email" style="display: none;">
641 <form action="<?php echo esc_url( $_SERVER['REQUEST_URI'] ); ?>" method="post">
642 <label for="target_email"><?php _e( 'Send to Email Address', 'jetpack' ) ?></label>
643 <input type="email" name="target_email" id="target_email" value="" />
644
645 <?php if ( is_user_logged_in() ) : ?>
646 <input type="hidden" name="source_name" value="<?php echo esc_attr( $current_user->display_name ); ?>" />
647 <input type="hidden" name="source_email" value="<?php echo esc_attr( $current_user->user_email ); ?>" />
648 <?php else : ?>
649
650 <label for="source_name"><?php _e( 'Your Name', 'jetpack' ) ?></label>
651 <input type="text" name="source_name" id="source_name" value="" />
652
653 <label for="source_email"><?php _e( 'Your Email Address', 'jetpack' ) ?></label>
654 <input type="email" name="source_email" id="source_email" value="" />
655
656 <?php endif; ?>
657 <input type="text" id="jetpack-source_f_name" name="source_f_name" class="input" value="" size="25" autocomplete="off" title="<?php esc_attr_e( 'This field is for validation and should not be changed', 'jetpack' ); ?>" />
658 <?php
659 /**
660 * Fires when the Email sharing dialog is loaded.
661 *
662 * @module sharedaddy
663 *
664 * @since 1.1.0
665 *
666 * @param string jetpack Eail sharing source.
667 */
668 do_action( 'sharing_email_dialog', 'jetpack' );
669 ?>
670
671 <img style="float: right; display: none" class="loading" src="<?php
672 /** This filter is documented in modules/stats.php */
673 echo apply_filters( 'jetpack_static_url', plugin_dir_url( __FILE__ ) . 'images/loading.gif' ); ?>" alt="loading" width="16" height="16" />
674 <input type="submit" value="<?php esc_attr_e( 'Send Email', 'jetpack' ); ?>" class="sharing_send" />
675 <a rel="nofollow" href="#cancel" class="sharing_cancel" role="button"><?php _e( 'Cancel', 'jetpack' ); ?></a>
676
677 <div class="errors errors-1" style="display: none;">
678 <?php _e( 'Post was not sent - check your email addresses!', 'jetpack' ); ?>
679 </div>
680
681 <div class="errors errors-2" style="display: none;">
682 <?php _e( 'Email check failed, please try again', 'jetpack' ); ?>
683 </div>
684
685 <div class="errors errors-3" style="display: none;">
686 <?php _e( 'Sorry, your blog cannot share posts by email.', 'jetpack' ); ?>
687 </div>
688 </form>
689 </div>
690 <?php
691 }
692 }
693
694 class Share_Twitter extends Sharing_Source {
695 public $shortname = 'twitter';
696 public $icon = '\f202';
697 // 'https://dev.twitter.com/rest/reference/get/help/configuration' ( 2015/02/06 ) short_url_length is 22, short_url_length_https is 23
698 public $short_url_length = 24;
699
700 public function __construct( $id, array $settings ) {
701 parent::__construct( $id, $settings );
702
703 if ( 'official' == $this->button_style ) {
704 $this->smart = true;
705 } else {
706 $this->smart = false;
707 }
708 }
709
710 public function get_name() {
711 return __( 'Twitter', 'jetpack' );
712 }
713
714 /**
715 * Determine the Twitter 'via' value for a post.
716 *
717 * @param WP_Post|int $post Post object or post ID.
718 * @return string Twitter handle without the preceding @.
719 **/
720 public static function sharing_twitter_via( $post ) {
721 $post = get_post( $post );
722 /**
723 * Allow third-party plugins to customize the Twitter username used as "twitter:site" Twitter Card Meta Tag.
724 *
725 * @module sharedaddy
726 *
727 * @since 3.0.0
728 *
729 * @param string $string Twitter Username.
730 * @param array $args Array of Open Graph Meta Tags and Twitter Cards tags.
731 */
732 $twitter_site_tag_value = apply_filters(
733 'jetpack_twitter_cards_site_tag',
734 '',
735 /** This action is documented in modules/sharedaddy/sharing-sources.php */
736 array( 'twitter:creator' => apply_filters( 'jetpack_sharing_twitter_via', '', $post->ID ) )
737 );
738
739 /*
740 * Hack to remove the unwanted behavior of adding 'via @jetpack' which
741 * was introduced with the adding of the Twitter cards.
742 * This should be a temporary solution until a better method is setup.
743 */
744 if ( 'jetpack' == $twitter_site_tag_value ) {
745 $twitter_site_tag_value = '';
746 }
747
748 /**
749 * Filters the Twitter username used as "via" in the Twitter sharing button.
750 *
751 * @module sharedaddy
752 *
753 * @since 1.7.0
754 *
755 * @param string $twitter_site_tag_value Twitter Username.
756 * @param int $post->ID Post ID.
757 */
758 $twitter_site_tag_value = apply_filters( 'jetpack_sharing_twitter_via', $twitter_site_tag_value, $post->ID );
759
760 // Strip out anything other than a letter, number, or underscore.
761 // This will prevent the inadvertent inclusion of an extra @, as well as normalizing the handle.
762 return preg_replace( '/[^\da-z_]+/i', '', $twitter_site_tag_value );
763 }
764
765 /**
766 * Determine the 'related' Twitter accounts for a post.
767 *
768 * @param WP_Post|int $post Post object or post ID.
769 * @return string Comma-separated list of Twitter handles.
770 **/
771 public static function get_related_accounts( $post ) {
772 $post = get_post( $post );
773 /**
774 * Filter the list of related Twitter accounts added to the Twitter sharing button.
775 *
776 * @module sharedaddy
777 *
778 * @since 1.7.0
779 *
780 * @param array $args Array of Twitter usernames. Format is 'username' => 'Optional description'
781 * @param int $post->ID Post ID.
782 */
783 $related_accounts = apply_filters( 'jetpack_sharing_twitter_related', array(), $post->ID );
784
785 // Example related string: account1,account2:Account 2 description,account3
786 $related = array();
787
788 foreach ( $related_accounts as $related_account_username => $related_account_description ) {
789 // Join the description onto the end of the username
790 if ( $related_account_description ) {
791 $related_account_username .= ':' . $related_account_description;
792 }
793
794 $related[] = $related_account_username;
795 }
796
797 return implode( ',', $related );
798 }
799
800 public function get_display( $post ) {
801 $via = $this->sharing_twitter_via( $post );
802
803 if ( $via ) {
804 $via = 'data-via="' . esc_attr( $via ) . '"';
805 } else {
806 $via = '';
807 }
808
809 $related = $this->get_related_accounts( $post );
810 if ( ! empty( $related ) && $related !== $via ) {
811 $related = 'data-related="' . esc_attr( $related ) . '"';
812 } else {
813 $related = '';
814 }
815
816 if ( $this->smart ) {
817 $share_url = $this->get_share_url( $post->ID );
818 $post_title = $this->get_share_title( $post->ID );
819 return sprintf(
820 '<a href="https://twitter.com/share" class="twitter-share-button" data-url="%1$s" data-text="%2$s" %3$s %4$s>Tweet</a>',
821 esc_url( $share_url ),
822 esc_attr( $post_title ),
823 $via,
824 $related
825 );
826 } else {
827 if (
828 /**
829 * Allow plugins to disable sharing counts for specific sharing services.
830 *
831 * @module sharedaddy
832 *
833 * @since 3.0.0
834 *
835 * @param bool true Should sharing counts be enabled for this specific service. Default to true.
836 * @param int $post->ID Post ID.
837 * @param string $str Sharing service name.
838 */
839 apply_filters( 'jetpack_register_post_for_share_counts', true, $post->ID, 'twitter' )
840 ) {
841 sharing_register_post_for_share_counts( $post->ID );
842 }
843 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Twitter', 'share to', 'jetpack' ), __( 'Click to share on Twitter', 'jetpack' ), 'share=twitter', 'sharing-twitter-' . $post->ID );
844 }
845 }
846
847 public function process_request( $post, array $post_data ) {
848 $post_title = $this->get_share_title( $post->ID );
849 $post_link = $this->get_share_url( $post->ID );
850
851 if ( function_exists( 'mb_stripos' ) ) {
852 $strlen = 'mb_strlen';
853 $substr = 'mb_substr';
854 } else {
855 $strlen = 'strlen';
856 $substr = 'substr';
857 }
858
859 $via = $this->sharing_twitter_via( $post );
860 $related = $this->get_related_accounts( $post );
861 if ( $via ) {
862 $sig = " via @$via";
863 if ( $related === $via ) {
864 $related = false;
865 }
866 } else {
867 $via = false;
868 $sig = '';
869 }
870
871 $suffix_length = $this->short_url_length + $strlen( $sig );
872 // $sig is handled by twitter in their 'via' argument.
873 // $post_link is handled by twitter in their 'url' argument.
874 if ( 280 < $strlen( $post_title ) + $suffix_length ) {
875 // The -1 is for "\xE2\x80\xA6", a UTF-8 ellipsis.
876 $text = $substr( $post_title, 0, 280 - $suffix_length - 1 ) . "\xE2\x80\xA6";
877 } else {
878 $text = $post_title;
879 }
880
881 // Record stats
882 parent::process_request( $post, $post_data );
883
884 $url = $post_link;
885 $twitter_url = add_query_arg(
886 rawurlencode_deep( array_filter( compact( 'via', 'related', 'text', 'url' ) ) ),
887 'https://twitter.com/intent/tweet'
888 );
889
890 // Redirect to Twitter
891 wp_redirect( $twitter_url );
892 die();
893 }
894
895 public function has_custom_button_style() {
896 return $this->smart;
897 }
898
899 public function display_footer() {
900 if ( $this->smart ) {
901 ?>
902 <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>
903 <?php
904 } else {
905 $this->js_dialog( $this->shortname, array( 'height' => 350 ) );
906 }
907 }
908 }
909
910
911 class Share_Reddit extends Sharing_Source {
912 public $shortname = 'reddit';
913 public $icon = '\f222';
914 public function __construct( $id, array $settings ) {
915 parent::__construct( $id, $settings );
916
917 if ( 'official' == $this->button_style ) {
918 $this->smart = true;
919 } else {
920 $this->smart = false;
921 }
922 }
923
924 public function get_name() {
925 return __( 'Reddit', 'jetpack' );
926 }
927
928 public function get_display( $post ) {
929 if ( $this->smart ) {
930 return '<div class="reddit_button"><iframe src="' . $this->http() . '://www.reddit.com/static/button/button1.html?newwindow=true&width=120&amp;url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&amp;title=' . rawurlencode( $this->get_share_title( $post->ID ) ) . '" height="22" width="120" scrolling="no" frameborder="0"></iframe></div>';
931 } else {
932 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Reddit', 'share to', 'jetpack' ), __( 'Click to share on Reddit', 'jetpack' ), 'share=reddit' );
933 }
934 }
935
936 /**
937 * AMP display for Reddit.
938 *
939 * @param \WP_Post $post The current post being viewed.
940 */
941 public function get_amp_display( $post ) {
942 $attrs = array(
943 '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 ) ) ),
944 );
945
946 return $this->build_amp_markup( $attrs );
947 }
948
949 public function process_request( $post, array $post_data ) {
950 $reddit_url = $this->http() . '://reddit.com/submit?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $this->get_share_title( $post->ID ) );
951
952 // Record stats
953 parent::process_request( $post, $post_data );
954
955 // Redirect to Reddit
956 wp_redirect( $reddit_url );
957 die();
958 }
959 }
960
961 class Share_LinkedIn extends Sharing_Source {
962 public $shortname = 'linkedin';
963 public $icon = '\f207';
964 public function __construct( $id, array $settings ) {
965 parent::__construct( $id, $settings );
966
967 if ( 'official' == $this->button_style ) {
968 $this->smart = true;
969 } else {
970 $this->smart = false;
971 }
972 }
973
974 public function get_name() {
975 return __( 'LinkedIn', 'jetpack' );
976 }
977
978 public function has_custom_button_style() {
979 return $this->smart;
980 }
981
982 public function get_display( $post ) {
983 $display = '';
984
985 if ( $this->smart ) {
986 $share_url = $this->get_share_url( $post->ID );
987 $display .= sprintf( '<div class="linkedin_button"><script type="in/share" data-url="%s" data-counter="right"></script></div>', esc_url( $share_url ) );
988 } else {
989 $display = $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'LinkedIn', 'share to', 'jetpack' ), __( 'Click to share on LinkedIn', 'jetpack' ), 'share=linkedin', 'sharing-linkedin-' . $post->ID );
990 }
991
992 /** This filter is already documented in modules/sharedaddy/sharing-sources.php */
993 if ( apply_filters( 'jetpack_register_post_for_share_counts', true, $post->ID, 'linkedin' ) ) {
994 sharing_register_post_for_share_counts( $post->ID );
995 }
996
997 return $display;
998 }
999
1000 public function process_request( $post, array $post_data ) {
1001
1002 $post_link = $this->get_share_url( $post->ID );
1003
1004 // Using the same URL as the official button, which is *not* LinkedIn's documented sharing link
1005 // https://www.linkedin.com/cws/share?url={url}&token=&isFramed=false
1006 $linkedin_url = add_query_arg( array(
1007 'url' => rawurlencode( $post_link ),
1008 ), 'https://www.linkedin.com/cws/share?token=&isFramed=false' );
1009
1010 // Record stats
1011 parent::process_request( $post, $post_data );
1012
1013 // Redirect to LinkedIn
1014 wp_redirect( $linkedin_url );
1015 die();
1016 }
1017
1018 public function display_footer() {
1019 if ( ! $this->smart ) {
1020 $this->js_dialog( $this->shortname, array( 'width' => 580, 'height' => 450 ) );
1021 } else {
1022 ?><script type="text/javascript">
1023 jQuery( document ).ready( function() {
1024 jQuery.getScript( 'https://platform.linkedin.com/in.js?async=true', function success() {
1025 IN.init();
1026 });
1027 });
1028 jQuery( document.body ).on( 'post-load', function() {
1029 if ( typeof IN != 'undefined' )
1030 IN.parse();
1031 });
1032 </script><?php
1033 }
1034 }
1035 }
1036
1037 class Share_Facebook extends Sharing_Source {
1038 public $shortname = 'facebook';
1039 public $icon = '\f204';
1040 private $share_type = 'default';
1041
1042 public function __construct( $id, array $settings ) {
1043 parent::__construct( $id, $settings );
1044
1045 if ( isset( $settings['share_type'] ) ) {
1046 $this->share_type = $settings['share_type'];
1047 }
1048
1049 if ( 'official' == $this->button_style ) {
1050 $this->smart = true;
1051 } else {
1052 $this->smart = false;
1053 }
1054 }
1055
1056 public function get_name() {
1057 return __( 'Facebook', 'jetpack' );
1058 }
1059
1060 public function display_header() {
1061 }
1062
1063 function guess_locale_from_lang( $lang ) {
1064 if ( 'en' == $lang || 'en_US' == $lang || ! $lang ) {
1065 return 'en_US';
1066 }
1067
1068 if ( ! class_exists( 'GP_Locales' ) ) {
1069 if ( ! defined( 'JETPACK__GLOTPRESS_LOCALES_PATH' ) || ! file_exists( JETPACK__GLOTPRESS_LOCALES_PATH ) ) {
1070 return false;
1071 }
1072
1073 require JETPACK__GLOTPRESS_LOCALES_PATH;
1074 }
1075
1076 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
1077 // WP.com: get_locale() returns 'it'
1078 $locale = GP_Locales::by_slug( $lang );
1079 } else {
1080 // Jetpack: get_locale() returns 'it_IT';
1081 $locale = GP_Locales::by_field( 'wp_locale', $lang );
1082 }
1083
1084 if ( ! $locale ) {
1085 return false;
1086 }
1087
1088 if ( empty( $locale->facebook_locale ) ) {
1089 if ( empty( $locale->wp_locale ) ) {
1090 return false;
1091 } else {
1092 // Facebook SDK is smart enough to fall back to en_US if a
1093 // locale isn't supported. Since supported Facebook locales
1094 // can fall out of sync, we'll attempt to use the known
1095 // wp_locale value and rely on said fallback.
1096 return $locale->wp_locale;
1097 }
1098 }
1099
1100 return $locale->facebook_locale;
1101 }
1102
1103 public function get_display( $post ) {
1104 if ( $this->smart ) {
1105 $share_url = $this->get_share_url( $post->ID );
1106 $fb_share_html = '<div class="fb-share-button" data-href="' . esc_attr( $share_url ) . '" data-layout="button_count"></div>';
1107 /**
1108 * Filter the output of the Facebook Sharing button.
1109 *
1110 * @module sharedaddy
1111 *
1112 * @since 3.6.0
1113 *
1114 * @param string $fb_share_html Facebook Sharing button HTML.
1115 * @param string $share_url URL of the post to share.
1116 */
1117 return apply_filters( 'jetpack_sharing_facebook_official_button_output', $fb_share_html, $share_url );
1118 }
1119
1120 /** This filter is already documented in modules/sharedaddy/sharing-sources.php */
1121 if ( apply_filters( 'jetpack_register_post_for_share_counts', true, $post->ID, 'facebook' ) ) {
1122 sharing_register_post_for_share_counts( $post->ID );
1123 }
1124 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Facebook', 'share to', 'jetpack' ), __( 'Click to share on Facebook', 'jetpack' ), 'share=facebook', 'sharing-facebook-' . $post->ID );
1125 }
1126
1127 /**
1128 * AMP display for Facebook.
1129 *
1130 * @param \WP_Post $post The current post being viewed.
1131 */
1132 public function get_amp_display( $post ) {
1133 $attrs = array(
1134 /** This filter is documented in modules/sharedaddy/sharing-sources.php */
1135 'data-param-app_id' => apply_filters( 'jetpack_sharing_facebook_app_id', '249643311490' ),
1136 );
1137
1138 return $this->build_amp_markup( $attrs );
1139 }
1140
1141 public function process_request( $post, array $post_data ) {
1142 $fb_url = $this->http() . '://www.facebook.com/sharer.php?u=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&t=' . rawurlencode( $this->get_share_title( $post->ID ) );
1143
1144 // Record stats
1145 parent::process_request( $post, $post_data );
1146
1147 // Redirect to Facebook
1148 wp_redirect( $fb_url );
1149 die();
1150 }
1151
1152 public function display_footer() {
1153 $this->js_dialog( $this->shortname );
1154 if ( $this->smart ) {
1155 $locale = $this->guess_locale_from_lang( get_locale() );
1156 if ( ! $locale ) {
1157 $locale = 'en_US';
1158 }
1159 /**
1160 * Filter the App ID used in the official Facebook Share button.
1161 *
1162 * @since 3.8.0
1163 *
1164 * @param int $fb_app_id Facebook App ID. Default to 249643311490 (WordPress.com's App ID).
1165 */
1166 $fb_app_id = apply_filters( 'jetpack_sharing_facebook_app_id', '249643311490' );
1167 if ( is_numeric( $fb_app_id ) ) {
1168 $fb_app_id = '&appId=' . $fb_app_id;
1169 } else {
1170 $fb_app_id = '';
1171 }
1172 ?><div id="fb-root"></div>
1173 <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 $locale; ?>/sdk.js#xfbml=1<?php echo $fb_app_id; ?>&version=v2.3'; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk'));</script>
1174 <script>
1175 document.body.addEventListener( 'post-load', function() {
1176 if ( 'undefined' !== typeof FB ) {
1177 FB.XFBML.parse();
1178 }
1179 } );
1180 </script>
1181 <?php
1182 }
1183 }
1184 }
1185
1186 class Share_Print extends Sharing_Source {
1187 public $shortname = 'print';
1188 public $icon = '\f469';
1189 public function __construct( $id, array $settings ) {
1190 parent::__construct( $id, $settings );
1191
1192 if ( 'official' == $this->button_style ) {
1193 $this->smart = true;
1194 } else {
1195 $this->smart = false;
1196 }
1197 }
1198
1199 public function get_name() {
1200 return __( 'Print', 'jetpack' );
1201 }
1202
1203 public function get_display( $post ) {
1204 return $this->get_link( $this->get_process_request_url( $post->ID ) . ( ( is_single() || is_page() ) ? '#print': '' ), _x( 'Print', 'share to', 'jetpack' ), __( 'Click to print', 'jetpack' ) );
1205 }
1206
1207 /**
1208 * AMP display for Print.
1209 *
1210 * @param \WP_Post $post The current post being viewed.
1211 */
1212 public function get_amp_display( $post ) {
1213 if ( empty( $post ) ) {
1214 return false;
1215 }
1216
1217 return '<button class="amp-social-share print" on="tap:AMP.print">Print</button>';
1218 }
1219 }
1220
1221 class Share_PressThis extends Sharing_Source {
1222 public $shortname = 'pressthis';
1223 public $icon = '\f205';
1224 public function __construct( $id, array $settings ) {
1225 parent::__construct( $id, $settings );
1226
1227 if ( 'official' == $this->button_style ) {
1228 $this->smart = true;
1229 } else {
1230 $this->smart = false;
1231 }
1232 }
1233
1234 public function get_name() {
1235 return __( 'Press This', 'jetpack' );
1236 }
1237
1238 public function process_request( $post, array $post_data ) {
1239 global $current_user;
1240
1241 $primary_blog = (int) get_user_meta( $current_user->ID, 'primary_blog', true );
1242 if ( $primary_blog ) {
1243 $primary_blog_details = get_blog_details( $primary_blog );
1244 } else {
1245 $primary_blog_details = false;
1246 }
1247
1248 if ( $primary_blog_details ) {
1249 $blogs = array( $primary_blog_details );
1250 } elseif ( function_exists( 'get_active_blogs_for_user' ) ) {
1251 $blogs = get_active_blogs_for_user();
1252 if ( empty( $blogs ) ) {
1253 $blogs = get_blogs_of_user( $current_user->ID );
1254 }
1255 } else {
1256 $blogs = get_blogs_of_user( $current_user->ID );
1257 }
1258
1259 if ( empty( $blogs ) ) {
1260 wp_safe_redirect( get_permalink( $post->ID ) );
1261 die();
1262 }
1263
1264 $blog = current( $blogs );
1265
1266 $args = array(
1267 'u' => rawurlencode( $this->get_share_url( $post->ID ) ),
1268 );
1269
1270 $args[ 'url-scan-submit' ] = 'Scan';
1271 $args[ '_wpnonce' ] = wp_create_nonce( 'scan-site' );
1272
1273 $url = $blog->siteurl . '/wp-admin/press-this.php';
1274 $url = add_query_arg( $args, $url );
1275
1276 // Record stats
1277 parent::process_request( $post, $post_data );
1278
1279 // Redirect to Press This
1280 wp_redirect( $url );
1281 die();
1282 }
1283
1284 public function get_display( $post ) {
1285 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Press This', 'share to', 'jetpack' ), __( 'Click to Press This!', 'jetpack' ), 'share=press-this' );
1286 }
1287
1288 /**
1289 * No AMP display for PressThis.
1290 *
1291 * @param \WP_Post $post The current post being viewed.
1292 */
1293 public function get_amp_display( $post ) { // phpcs:ignore
1294 return false;
1295 }
1296 }
1297
1298 class Share_Custom extends Sharing_Advanced_Source {
1299 private $name;
1300 private $icon;
1301 private $url;
1302 public $smart = true;
1303 public $shortname;
1304
1305 public function get_class() {
1306 return 'custom share-custom-' . sanitize_html_class( strtolower( $this->name ) );
1307 }
1308
1309 public function __construct( $id, array $settings ) {
1310 parent::__construct( $id, $settings );
1311
1312 $opts = $this->get_options();
1313
1314 if ( isset( $settings['name'] ) ) {
1315 $this->name = $settings['name'];
1316 $this->shortname = preg_replace( '/[^a-z0-9]*/', '', $settings['name'] );
1317 }
1318
1319 if ( isset( $settings['icon'] ) ) {
1320 $this->icon = $settings['icon'];
1321
1322 $new_icon = esc_url_raw( wp_specialchars_decode( $this->icon, ENT_QUOTES ) );
1323 $i = 0;
1324 while ( $new_icon != $this->icon ) {
1325 if ( $i > 5 ) {
1326 $this->icon = false;
1327 break;
1328 } else {
1329 $this->icon = $new_icon;
1330 $new_icon = esc_url_raw( wp_specialchars_decode( $this->icon, ENT_QUOTES ) );
1331 }
1332 $i++;
1333 }
1334 }
1335
1336 if ( isset( $settings['url'] ) ) {
1337 $this->url = $settings['url'];
1338 }
1339 }
1340
1341 public function get_name() {
1342 return $this->name;
1343 }
1344
1345 public function get_display( $post ) {
1346 $str = $this->get_link( $this->get_process_request_url( $post->ID ), esc_html( $this->name ), sprintf( __( 'Click to share on %s', 'jetpack' ), esc_attr( $this->name ) ), 'share=' . $this->id );
1347 return str_replace( '<span>', '<span style="' . esc_attr( 'background-image:url("' . addcslashes( esc_url_raw( $this->icon ), '"' ) . '");' ) . '">', $str );
1348 }
1349
1350 /**
1351 * No AMP display for custom elements.
1352 *
1353 * @param \WP_Post $post The current post being viewed.
1354 */
1355 public function get_amp_display( $post ) { // phpcs:ignore
1356 return false;
1357 }
1358
1359 public function process_request( $post, array $post_data ) {
1360 $url = str_replace( '&amp;', '&', $this->url );
1361 $url = str_replace( '%post_id%', rawurlencode( $post->ID ), $url );
1362 $url = str_replace( '%post_url%', rawurlencode( $this->get_share_url( $post->ID ) ), $url );
1363 $url = str_replace( '%post_full_url%', rawurlencode( get_permalink( $post->ID ) ), $url );
1364 $url = str_replace( '%post_title%', rawurlencode( $this->get_share_title( $post->ID ) ), $url );
1365 $url = str_replace( '%home_url%', rawurlencode( home_url() ), $url );
1366 $url = str_replace( '%post_slug%', rawurlencode( $post->post_name ), $url );
1367
1368 if ( strpos( $url, '%post_tags%' ) !== false ) {
1369 $tags = get_the_tags( $post->ID );
1370 $tagged = '';
1371
1372 if ( $tags ) {
1373 $tagged_raw = array();
1374 foreach ( $tags as $tag ) {
1375 $tagged_raw[] = rawurlencode( $tag->name );
1376 }
1377
1378 $tagged = implode( ',', $tagged_raw );
1379 }
1380
1381 $url = str_replace( '%post_tags%', $tagged, $url );
1382 }
1383
1384 if ( strpos( $url, '%post_excerpt%' ) !== false ) {
1385 $url_excerpt = $post->post_excerpt;
1386 if ( empty( $url_excerpt ) ) {
1387 $url_excerpt = $post->post_content;
1388 }
1389
1390 $url_excerpt = strip_tags( strip_shortcodes( $url_excerpt ) );
1391 $url_excerpt = wp_html_excerpt( $url_excerpt, 100 );
1392 $url_excerpt = rtrim( preg_replace( '/[^ .]*$/', '', $url_excerpt ) );
1393 $url = str_replace( '%post_excerpt%', rawurlencode( $url_excerpt ), $url );
1394 }
1395
1396 // Record stats
1397 parent::process_request( $post, $post_data );
1398
1399 // Redirect
1400 wp_redirect( $url );
1401 die();
1402 }
1403
1404 public function display_options() {
1405 ?>
1406 <div class="input">
1407 <table class="form-table">
1408 <tbody>
1409 <tr>
1410 <th scope="row"><?php _e( 'Label', 'jetpack' ); ?></th>
1411 <td><input type="text" name="name" value="<?php echo esc_attr( $this->name ); ?>" /></td>
1412 </tr>
1413
1414 <tr>
1415 <th scope="row"><?php _e( 'URL', 'jetpack' ); ?></th>
1416 <td><input type="text" name="url" value="<?php echo esc_attr( $this->url ); ?>" /></td>
1417 </tr>
1418
1419 <tr>
1420 <th scope="row"><?php _e( 'Icon', 'jetpack' ); ?></th>
1421 <td><input type="text" name="icon" value="<?php echo esc_attr( $this->icon ); ?>" /></td>
1422 </tr>
1423
1424 <tr>
1425 <th scope="row"></th>
1426 <td>
1427 <input class="button-secondary" type="submit" value="<?php esc_attr_e( 'Save', 'jetpack' ); ?>" />
1428 <a href="#" class="remove"><small><?php _e( 'Remove Service', 'jetpack' ); ?></small></a>
1429 </td>
1430 </tr>
1431 </tbody>
1432 </table>
1433 </div>
1434 <?php
1435 }
1436
1437 public function update_options( array $data ) {
1438 $name = trim( wp_html_excerpt( wp_kses( stripslashes( $data['name'] ), array() ), 30 ) );
1439 $url = trim( esc_url_raw( $data['url'] ) );
1440 $icon = trim( esc_url_raw( $data['icon'] ) );
1441
1442 if ( $name ) {
1443 $this->name = $name;
1444 }
1445
1446 if ( $url ) {
1447 $this->url = $url;
1448 }
1449
1450 if ( $icon ) {
1451 $this->icon = $icon;
1452 }
1453 }
1454
1455 public function get_options() {
1456 return array(
1457 'name' => $this->name,
1458 'icon' => $this->icon,
1459 'url' => $this->url,
1460 );
1461 }
1462
1463 public function display_preview( $echo = true, $force_smart = false, $button_style = null ) {
1464 $opts = $this->get_options();
1465
1466 $text = '&nbsp;';
1467 if ( ! $this->smart ) {
1468 if ( $this->button_style != 'icon' ) {
1469 $text = $this->get_name();
1470 }
1471 }
1472
1473 $klasses = array( 'share-' . $this->shortname );
1474
1475 if ( $this->button_style == 'icon' || $this->button_style == 'icon-text' ) {
1476 $klasses[] = 'share-icon';
1477 }
1478
1479 if ( $this->button_style == 'icon' ) {
1480 $text = '';
1481 $klasses[] = 'no-text';
1482 }
1483
1484 if ( $this->button_style == 'text' ) {
1485 $klasses[] = 'no-icon';
1486 }
1487
1488 $link = sprintf(
1489 '<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>',
1490 implode( ' ', $klasses ),
1491 $this->get_name(),
1492 addcslashes( esc_url_raw( $opts['icon'] ), '"' ),
1493 $text
1494 );
1495 ?>
1496 <div class="option option-smart-off">
1497 <?php echo $link ; ?>
1498 </div><?php
1499 }
1500 }
1501
1502 class Share_Tumblr extends Sharing_Source {
1503 public $shortname = 'tumblr';
1504 public $icon = '\f214';
1505 public function __construct( $id, array $settings ) {
1506 parent::__construct( $id, $settings );
1507 if ( 'official' == $this->button_style ) {
1508 $this->smart = true;
1509 } else {
1510 $this->smart = false;
1511 }
1512 }
1513
1514 public function get_name() {
1515 return __( 'Tumblr', 'jetpack' );
1516 }
1517
1518 public function get_display( $post ) {
1519 if ( $this->smart ) {
1520 $target = '';
1521 if ( true == $this->open_link_in_new ) {
1522 $target = '_blank';
1523 }
1524
1525 /**
1526 * If we are looking at a single post, let Tumblr figure out the post type (text, photo, link, quote, chat, or video)
1527 * based on the content available on the page.
1528 * If we are not looking at a single post, content from other posts can appear on the page and Tumblr will pick that up.
1529 * 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.
1530 */
1531 if ( ! is_single() ) {
1532 $posttype = 'data-posttype="link"';
1533 } else {
1534 $posttype = '';
1535 }
1536
1537 // Documentation: https://www.tumblr.com/docs/en/share_button
1538 return sprintf(
1539 '<a class="tumblr-share-button" target="%1$s" href="%2$s" data-title="%3$s" data-content="%4$s" title="%5$s"%6$s>%5$s</a>',
1540 $target,
1541 'https://www.tumblr.com/share',
1542 $this->get_share_title( $post->ID ),
1543 $this->get_share_url( $post->ID ),
1544 __( 'Share on Tumblr', 'jetpack' ),
1545 $posttype
1546 );
1547 } else {
1548 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Tumblr', 'share to', 'jetpack' ), __( 'Click to share on Tumblr', 'jetpack' ), 'share=tumblr' );
1549 }
1550 }
1551
1552 public function process_request( $post, array $post_data ) {
1553 // Record stats
1554 parent::process_request( $post, $post_data );
1555
1556 // Redirect to Tumblr's sharing endpoint (a la their bookmarklet)
1557 $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=';
1558 wp_redirect( $url );
1559 die();
1560 }
1561
1562 public function display_footer() {
1563 if ( $this->smart ) {
1564 ?><script id="tumblr-js" type="text/javascript" src="https://assets.tumblr.com/share-button.js"></script><?php
1565 } else {
1566 $this->js_dialog( $this->shortname, array( 'width' => 450, 'height' => 450 ) );
1567 }
1568 }
1569 }
1570
1571 class Share_Pinterest extends Sharing_Source {
1572 public $shortname = 'pinterest';
1573 public $icon = '\f209';
1574
1575 public function __construct( $id, array $settings ) {
1576 parent::__construct( $id, $settings );
1577 if ( 'official' == $this->button_style ) {
1578 $this->smart = true;
1579 } else {
1580 $this->smart = false;
1581 }
1582 }
1583
1584 public function get_name() {
1585 return __( 'Pinterest', 'jetpack' );
1586 }
1587
1588 public function get_image( $post ) {
1589 if ( class_exists( 'Jetpack_PostImages' ) ) {
1590 $image = Jetpack_PostImages::get_image( $post->ID, array( 'fallback_to_avatars' => true ) );
1591 if ( ! empty( $image ) ) {
1592 return $image['src'];
1593 }
1594 }
1595
1596 /**
1597 * Filters the default image used by the Pinterest Pin It share button.
1598 *
1599 * @module sharedaddy
1600 *
1601 * @since 3.6.0
1602 *
1603 * @param string $url Default image URL.
1604 */
1605 return apply_filters( 'jetpack_sharing_pinterest_default_image', 'https://s0.wp.com/i/blank.jpg' );
1606 }
1607
1608 public function get_external_url( $post ) {
1609 $url = 'https://www.pinterest.com/pin/create/button/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&media=' . rawurlencode( $this->get_image( $post ) ) . '&description=' . rawurlencode( $post->post_title );
1610
1611 /**
1612 * Filters the Pinterest share URL used in sharing button output.
1613 *
1614 * @module sharedaddy
1615 *
1616 * @since 3.6.0
1617 *
1618 * @param string $url Pinterest share URL.
1619 */
1620 return apply_filters( 'jetpack_sharing_pinterest_share_url', $url );
1621 }
1622
1623 public function get_widget_type() {
1624 /**
1625 * Filters the Pinterest widget type.
1626 *
1627 * @see https://business.pinterest.com/en/widget-builder
1628 *
1629 * @module sharedaddy
1630 *
1631 * @since 3.6.0
1632 *
1633 * @param string $type Pinterest widget type. Default of 'buttonPin' for single-image selection. 'buttonBookmark' for multi-image modal.
1634 */
1635 return apply_filters( 'jetpack_sharing_pinterest_widget_type', 'buttonPin' );
1636 }
1637
1638 public function get_display( $post ) {
1639 $display = '';
1640
1641 if ( $this->smart ) {
1642 $display = sprintf(
1643 '<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>',
1644 esc_url( $this->get_external_url( $post ) ),
1645 esc_attr( $this->get_widget_type() )
1646 );
1647 } else {
1648 $display = $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Pinterest', 'share to', 'jetpack' ), __( 'Click to share on Pinterest', 'jetpack' ), 'share=pinterest', 'sharing-pinterest-' . $post->ID );
1649 }
1650
1651 /** This filter is already documented in modules/sharedaddy/sharing-sources.php */
1652 if ( apply_filters( 'jetpack_register_post_for_share_counts', true, $post->ID, 'linkedin' ) ) {
1653 sharing_register_post_for_share_counts( $post->ID );
1654 }
1655
1656 return $display;
1657 }
1658
1659 public function process_request( $post, array $post_data ) {
1660 // Record stats
1661 parent::process_request( $post, $post_data );
1662 // If we're triggering the multi-select panel, then we don't need to redirect to Pinterest
1663 if ( ! isset( $_GET['js_only'] ) ) {
1664 $pinterest_url = esc_url_raw( $this->get_external_url( $post ) );
1665 wp_redirect( $pinterest_url );
1666 } else {
1667 echo '// share count bumped';
1668 }
1669 die();
1670 }
1671
1672 public function display_footer() {
1673 /**
1674 * Filter the Pin it button appearing when hovering over images when using the official button style.
1675 *
1676 * @module sharedaddy
1677 *
1678 * @since 3.6.0
1679 *
1680 * @param bool $jetpack_pinit_over True by default, displays the Pin it button when hovering over images.
1681 */
1682 $jetpack_pinit_over = apply_filters( 'jetpack_pinit_over_button', true );
1683 ?>
1684 <?php if ( $this->smart ) : ?>
1685 <script type="text/javascript">
1686 // Pinterest shared resources
1687 var s = document.createElement("script");
1688 s.type = "text/javascript";
1689 s.async = true;
1690 <?php if ( $jetpack_pinit_over ) {
1691 echo "s.setAttribute('data-pin-hover', true);";
1692 } ?>
1693 s.src = window.location.protocol + "//assets.pinterest.com/js/pinit.js";
1694 var x = document.getElementsByTagName("script")[0];
1695 x.parentNode.insertBefore(s, x);
1696 // if 'Pin it' button has 'counts' make container wider
1697 jQuery(window).load( function(){ jQuery( 'li.share-pinterest a span:visible' ).closest( '.share-pinterest' ).width( '80px' ); } );
1698 </script>
1699 <?php elseif ( 'buttonPin' != $this->get_widget_type() ) : ?>
1700 <script type="text/javascript">
1701 jQuery(document).ready( function(){
1702 jQuery('body').on('click', 'a.share-pinterest', function(e){
1703 e.preventDefault();
1704 // Load Pinterest Bookmarklet code
1705 var s = document.createElement("script");
1706 s.type = "text/javascript";
1707 s.src = window.location.protocol + "//assets.pinterest.com/js/pinmarklet.js?r=" + ( Math.random() * 99999999 );
1708 var x = document.getElementsByTagName("script")[0];
1709 x.parentNode.insertBefore(s, x);
1710 // Trigger Stats
1711 var s = document.createElement("script");
1712 s.type = "text/javascript";
1713 s.src = this + ( this.toString().indexOf( '?' ) ? '&' : '?' ) + 'js_only=1';
1714 var x = document.getElementsByTagName("script")[0];
1715 x.parentNode.insertBefore(s, x);
1716 });
1717 });
1718 </script>
1719 <?php endif;
1720 }
1721 }
1722
1723 class Share_Pocket extends Sharing_Source {
1724 public $shortname = 'pocket';
1725 public $icon = '\f224';
1726
1727 public function __construct( $id, array $settings ) {
1728 parent::__construct( $id, $settings );
1729
1730 if ( 'official' == $this->button_style ) {
1731 $this->smart = true;
1732 } else {
1733 $this->smart = false;
1734 }
1735 }
1736
1737 public function get_name() {
1738 return __( 'Pocket', 'jetpack' );
1739 }
1740
1741 public function process_request( $post, array $post_data ) {
1742 // Record stats
1743 parent::process_request( $post, $post_data );
1744
1745 $pocket_url = esc_url_raw( 'https://getpocket.com/save/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $this->get_share_title( $post->ID ) ) );
1746 wp_redirect( $pocket_url );
1747 exit;
1748 }
1749
1750 public function get_display( $post ) {
1751 if ( $this->smart ) {
1752 $post_count = 'horizontal';
1753
1754 $button = '';
1755 $button .= '<div class="pocket_button">';
1756 $button .= sprintf( '<a href="https://getpocket.com/save" class="pocket-btn" data-lang="%s" data-save-url="%s" data-pocket-count="%s" >%s</a>', 'en', esc_attr( $this->get_share_url( $post->ID ) ), $post_count, esc_attr__( 'Pocket', 'jetpack' ) );
1757 $button .= '</div>';
1758
1759 return $button;
1760 } else {
1761 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Pocket', 'share to', 'jetpack' ), __( 'Click to share on Pocket', 'jetpack' ), 'share=pocket' );
1762 }
1763
1764 }
1765
1766 /**
1767 * AMP display for Pocket.
1768 *
1769 * @param \WP_Post $post The current post being viewed.
1770 */
1771 public function get_amp_display( $post ) {
1772 $attrs = array(
1773 'data-share-endpoint' => esc_url_raw( 'https://getpocket.com/save/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $this->get_share_title( $post->ID ) ) ),
1774 );
1775
1776 return $this->build_amp_markup( $attrs );
1777 }
1778
1779 function display_footer() {
1780 if ( $this->smart ) :
1781 ?>
1782 <script>
1783 // Don't use Pocket's default JS as it we need to force init new Pocket share buttons loaded via JS.
1784 function jetpack_sharing_pocket_init() {
1785 jQuery.getScript( 'https://widgets.getpocket.com/v1/j/btn.js?v=1' );
1786 }
1787 jQuery( document ).ready( jetpack_sharing_pocket_init );
1788 jQuery( document.body ).on( 'post-load', jetpack_sharing_pocket_init );
1789 </script>
1790 <?php
1791 else :
1792 $this->js_dialog( $this->shortname, array( 'width' => 450, 'height' => 450 ) );
1793 endif;
1794
1795 }
1796
1797 }
1798
1799 class Share_Telegram extends Sharing_Source {
1800 public $shortname = 'telegram';
1801
1802 public function __construct( $id, array $settings ) {
1803 parent::__construct( $id, $settings );
1804 }
1805
1806 public function get_name() {
1807 return __( 'Telegram', 'jetpack' );
1808 }
1809 public function process_request( $post, array $post_data ) {
1810 // Record stats
1811 parent::process_request( $post, $post_data );
1812 $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 ) ) );
1813 wp_redirect( $telegram_url );
1814 exit;
1815 }
1816
1817 public function get_display( $post ) {
1818 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'Telegram', 'share to', 'jetpack' ), __( 'Click to share on Telegram', 'jetpack' ), 'share=telegram' );
1819 }
1820
1821 /**
1822 * AMP display for Telegram.
1823 *
1824 * @param \WP_Post $post The current post being viewed.
1825 */
1826 public function get_amp_display( $post ) {
1827 $attrs = array(
1828 '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 ) ) ),
1829 );
1830
1831 return $this->build_amp_markup( $attrs );
1832 }
1833
1834 function display_footer() {
1835 $this->js_dialog( $this->shortname, array( 'width' => 450, 'height' => 450 ) );
1836 }
1837 }
1838
1839 class Jetpack_Share_WhatsApp extends Sharing_Source {
1840 public $shortname = 'jetpack-whatsapp';
1841
1842 public function __construct( $id, array $settings ) {
1843 parent::__construct( $id, $settings );
1844 }
1845
1846 public function get_name() {
1847 return __( 'WhatsApp', 'jetpack' );
1848 }
1849
1850 public function get_display( $post ) {
1851 return $this->get_link( $this->get_process_request_url( $post->ID ), _x( 'WhatsApp', 'share to', 'jetpack' ), __( 'Click to share on WhatsApp', 'jetpack' ), 'share=jetpack-whatsapp' );
1852 }
1853
1854 /**
1855 * AMP display for Whatsapp.
1856 *
1857 * @param \WP_Post $post The current post being viewed.
1858 */
1859 public function get_amp_display( $post ) {
1860 $attrs = array(
1861 'type' => 'whatsapp',
1862 );
1863
1864 return $this->build_amp_markup( $attrs );
1865 }
1866
1867 public function process_request( $post, array $post_data ) {
1868 // Record stats
1869 parent::process_request( $post, $post_data );
1870
1871 // Firefox for desktop doesn't handle the "api.whatsapp.com" URL properly, so use "web.whatsapp.com"
1872 if ( User_Agent_Info::is_firefox_desktop() ) {
1873 $url = 'https://web.whatsapp.com/send?text=';
1874 } else {
1875 $url = 'https://api.whatsapp.com/send?text=';
1876 }
1877
1878 $url .= rawurlencode( $this->get_share_title( $post->ID ) . ' ' . $this->get_share_url( $post->ID ) );
1879 wp_redirect( $url );
1880 exit;
1881 }
1882 }
1883
1884 class Share_Skype extends Sharing_Source {
1885 public $shortname = 'skype';
1886 public $icon = '\f220';
1887 private $share_type = 'default';
1888
1889 public function __construct( $id, array $settings ) {
1890 parent::__construct( $id, $settings );
1891
1892 if ( isset( $settings['share_type'] ) ) {
1893 $this->share_type = $settings['share_type'];
1894 }
1895
1896 if ( 'official' == $this->button_style ) {
1897 $this->smart = true;
1898 } else {
1899 $this->smart = false;
1900 }
1901
1902 }
1903
1904 public function get_name() {
1905 return __( 'Skype', 'jetpack' );
1906 }
1907
1908 public function get_display( $post ) {
1909 if ( $this->smart ) {
1910 $skype_share_html = sprintf(
1911 '<div class="skype-share" data-href="%1$s" data-lang="%2$s" data-style="small" data-source="jetpack" ></div>',
1912 esc_attr( $this->get_share_url( $post->ID ) ),
1913 'en-US'
1914 );
1915 return $skype_share_html;
1916 }
1917
1918 /** This filter is already documented in modules/sharedaddy/sharing-sources.php */
1919 if ( apply_filters( 'jetpack_register_post_for_share_counts', true, $post->ID, 'skype' ) ) {
1920 sharing_register_post_for_share_counts( $post->ID );
1921 }
1922 return $this->get_link(
1923 $this->get_process_request_url( $post->ID ), _x( 'Skype', 'share to', 'jetpack' ), __( 'Click to share on Skype', 'jetpack' ), 'share=skype', 'sharing-skype-' . $post->ID );
1924 }
1925
1926 /**
1927 * AMP display for Skype.
1928 *
1929 * @param \WP_Post $post The current post being viewed.
1930 */
1931 public function get_amp_display( $post ) {
1932 $attrs = array(
1933 'data-share-endpoint' => sprintf(
1934 'https://web.skype.com/share?url=%1$s&lang=%2$s=&source=jetpack',
1935 rawurlencode( $this->get_share_url( $post->ID ) ),
1936 'en-US'
1937 ),
1938 );
1939
1940 return $this->build_amp_markup( $attrs );
1941 }
1942
1943 public function process_request( $post, array $post_data ) {
1944 $skype_url = sprintf(
1945 'https://web.skype.com/share?url=%1$s&lang=%2$s=&source=jetpack',
1946 rawurlencode( $this->get_share_url( $post->ID ) ),
1947 'en-US'
1948 );
1949
1950 // Record stats
1951 parent::process_request( $post, $post_data );
1952
1953 // Redirect to Skype
1954 wp_redirect( $skype_url );
1955 die();
1956 }
1957
1958 public function display_footer() {
1959 if ( $this->smart ) :
1960 ?>
1961 <script>
1962 (function(r, d, s) {
1963 r.loadSkypeWebSdkAsync = r.loadSkypeWebSdkAsync || function(p) {
1964 var js, sjs = d.getElementsByTagName(s)[0];
1965 if (d.getElementById(p.id)) { return; }
1966 js = d.createElement(s);
1967 js.id = p.id;
1968 js.src = p.scriptToLoad;
1969 js.onload = p.callback
1970 sjs.parentNode.insertBefore(js, sjs);
1971 };
1972 var p = {
1973 scriptToLoad: 'https://swx.cdn.skype.com/shared/v/latest/skypewebsdk.js',
1974 id: 'skype_web_sdk'
1975 };
1976 r.loadSkypeWebSdkAsync(p);
1977 })(window, document, 'script');
1978 </script>
1979 <?php
1980 else :
1981 $this->js_dialog( $this->shortname, array( 'width' => 305, 'height' => 665 ) );
1982 endif;
1983 }
1984 }
1985