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