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