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