Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 320
0.00% covered (danger)
0.00%
0 / 57
CRAP
0.00% covered (danger)
0.00%
0 / 18
Sharing_Source_Block
0.00% covered (danger)
0.00%
0 / 86
0.00% covered (danger)
0.00%
0 / 16
506
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 http
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_id
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_class
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 / 18
0.00% covered (danger)
0.00%
0 / 1
6
 get_share_url
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_share_title
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 get_share_tags
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
6
 get_link
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 get_url
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 js_dialog
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_data_attributes
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
6
 get_process_request_url
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
 process_request
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 redirect_request
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
Share_Email_Block
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 4
156
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_email_share_nonce_action
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 get_link
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
6
 process_request
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
56
Share_Facebook_Block
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 2
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
 process_request
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
Share_Print_Block
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
 get_name
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
Share_Native_Block
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
 get_name
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
Share_Tumblr_Block
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 2
6
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
 process_request
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
Share_Pinterest_Block
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 5
72
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_image
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 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
 process_request
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
Share_Pocket_Block
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 2
6
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
 process_request
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
Share_Telegram_Block
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 2
6
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
 process_request
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
Jetpack_Share_WhatsApp_Block
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 2
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
 process_request
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
Share_Mastodon_Block
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 2
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
 process_request
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
12
Share_Nextdoor_Block
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 2
6
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
 process_request
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
Share_Bluesky_Block
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 2
6
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
 process_request
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
Share_X_Block
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 4
132
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
 sharing_x_via
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 get_related_accounts
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 process_request
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
30
Share_Twitter_Block
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 4
132
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
 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
 process_request
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
30
Share_Reddit_Block
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 2
6
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
 process_request
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
Share_LinkedIn_Block
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 2
6
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
 process_request
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
Share_Threads_Block
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 2
6
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
 process_request
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Define all sharing sources.
4 *
5 * @since 13.0
6 *
7 * @package automattic/jetpack
8 *
9 * phpcs:disable Generic.Files.OneObjectStructurePerFile.MultipleFound
10 */
11
12namespace Automattic\Jetpack\Extensions\Sharing_Button_Block;
13
14use Automattic\Jetpack\Device_Detection\User_Agent_Info;
15use Jetpack_PostImages;
16use WP_Post;
17
18/**
19 * Base class for sharing sources.
20 * See individual sharing classes below for the implementation of this class.
21 */
22abstract class Sharing_Source_Block {
23    /**
24     * Sharing unique ID.
25     *
26     * @var int
27     */
28    protected $id;
29
30    /**
31     * Constructor.
32     *
33     * @param int $id       Sharing source ID.
34     */
35    public function __construct( $id ) {
36        $this->id = $id;
37    }
38
39    /**
40     * Get the protocol to use for a sharing service, based on the site settings.
41     *
42     * @return string
43     */
44    public function http() {
45        return 'https';
46    }
47
48    /**
49     * Get unique sharing ID.
50     *
51     * @return int
52     */
53    public function get_id() {
54        return $this->id;
55    }
56
57    /**
58     * Get unique sharing ID. Similar to get_id().
59     *
60     * @return int
61     */
62    public function get_class() {
63        return $this->id;
64    }
65
66    /**
67     * Get stats for a site, a post, or a sharing service.
68     * Soon to come to a .org plugin near you!
69     *
70     * @param WP_Post|bool $post Post object.
71     *
72     * @return int
73     */
74    public function get_total( $post = false ) {
75        global $wpdb, $blog_id;
76
77        $name = strtolower( (string) $this->get_id() );
78
79        if ( $post === false ) {
80            // get total number of shares for service
81            return (int) $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
82                $wpdb->prepare(
83                    'SELECT SUM( count ) FROM sharing_stats WHERE blog_id = %d AND share_service = %s',
84                    $blog_id,
85                    $name
86                )
87            );
88        }
89
90        // get total shares for a post
91        return (int) $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
92            $wpdb->prepare(
93                'SELECT count FROM sharing_stats WHERE blog_id = %d AND post_id = %d AND share_service = %s',
94                $blog_id,
95                $post->ID,
96                $name
97            )
98        );
99    }
100
101    /**
102     * Get a post's permalink to use for sharing.
103     *
104     * @param int $post_id Post ID.
105     *
106     * @return string
107     */
108    public function get_share_url( $post_id ) {
109        /**
110         * Filter the sharing permalink.
111         *
112         * @module sharedaddy
113         *
114         * @since 1.2.0
115         *
116         * @param string get_permalink( $post_id ) Post Permalink.
117         * @param int $post_id Post ID.
118         * @param int $this->id Sharing ID.
119         */
120        return apply_filters( 'sharing_permalink', get_permalink( $post_id ), $post_id, $this->id );
121    }
122
123    /**
124     * Get a post's title to use for sharing.
125     *
126     * @param int $post_id Post ID.
127     *
128     * @return string
129     */
130    public function get_share_title( $post_id ) {
131        $post = get_post( $post_id );
132        /**
133         * Filter the sharing title.
134         *
135         * @module sharedaddy
136         *
137         * @since 2.8.0
138         *
139         * @param string $post->post_title Post Title.
140         * @param int $post_id Post ID.
141         * @param int $this->id Sharing ID.
142         */
143        $title = $post instanceof WP_Post ? apply_filters( 'sharing_title', $post->post_title, $post_id, $this->id ) : '';
144        return html_entity_decode( wp_kses( $title, '' ), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
145    }
146
147    /**
148     * Get a comma-separated list of the post's tags to use for sharing.
149     * Prepends a '#' to each tag.
150     *
151     * @param int $post_id Post ID.
152     *
153     * @return string
154     */
155    public function get_share_tags( $post_id ) {
156        $tags = get_the_tags( $post_id );
157        if ( ! $tags ) {
158            return '';
159        }
160
161        $tags = array_map(
162            function ( $tag ) {
163                // Camel case the tag name and remove spaces as well as apostrophes.
164                $tag = preg_replace( '/\s+|\'/', '', ucwords( $tag->name ) );
165
166                // Return with a '#' prepended.
167                return '#' . $tag;
168            },
169            $tags
170        );
171
172        /**
173         * Allow customizing how the list of tags is displayed.
174         *
175         * @module sharedaddy
176         * @since 11.9
177         *
178         * @param string $tags     Comma-separated list of tags.
179         * @param int    $post_id  Post ID.
180         * @param int    $this->id Sharing ID.
181         */
182        $tag_list = (string) apply_filters( 'jetpack_sharing_tag_list', implode( ', ', $tags ), $post_id, $this->id );
183
184        return html_entity_decode( wp_kses( $tag_list, '' ), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
185    }
186
187    /**
188     * Get the URL for the link.
189     *
190     * @param int         $post_id         Post ID.
191     * @param string      $query           Additional query arguments to add to the link. They should be in 'foo=bar&baz=1' format.
192     * @param bool|string $id              Sharing ID to include in the data-shared attribute.
193     * @param array       $data_attributes The keys are used as additional attribute names with 'data-' prefix.
194     *                                     The values are used as the attribute values.
195     * @return object Link related data (url and data_attributes);
196     */
197    public function get_link( $post_id, $query = '', $id = false, $data_attributes = array() ) {
198        $url             = $this->get_url( $this->get_process_request_url( $post_id ), $query, $id );
199        $data_attributes = $this->get_data_attributes( $id, $data_attributes );
200
201        return array(
202            'url'             => $url,
203            'data_attributes' => $data_attributes,
204        );
205    }
206
207    /**
208     * Get the URL for the link.
209     *
210     * @param string      $url             Post URL to share.
211     * @param string      $query           Additional query arguments to add to the link. They should be in 'foo=bar&baz=1' format.
212     * @param bool|string $id              Sharing ID to include in the data-shared attribute.
213     *
214     * @return string The link URL.
215     */
216    public function get_url( $url, $query = '', $id = false ) {
217        $args = func_get_args();
218
219        /**
220         * Filter the sharing display ID.
221         *
222         * @module sharedaddy
223         *
224         * @since 3.4.0
225         *
226         * @param string|false $id Sharing ID.
227         * @param object $this Sharing service properties.
228         * @param array $args Array of sharing service options.
229         */
230        $id = apply_filters( 'jetpack_sharing_display_id', $id, $this, $args );
231        /**
232         * Filter the sharing display link.
233         *
234         * @module sharedaddy
235         *
236         * @since 2.8.0
237         *
238         * @param string $url Post URL.
239         * @param object $this Sharing service properties.
240         * @param string|false $id Sharing ID.
241         * @param array $args Array of sharing service options.
242         */
243        $url = apply_filters( 'sharing_display_link', $url, $this, $id, $args ); // backwards compatibility
244        /**
245         * Filter the sharing display link.
246         *
247         * @module sharedaddy
248         *
249         * @since 2.8.0
250         *
251         * @param string $url Post URL.
252         * @param object $this Sharing service properties.
253         * @param string|false $id Sharing ID.
254         * @param array $args Array of sharing service options.
255         */
256        $url = apply_filters( 'jetpack_sharing_display_link', $url, $this, $id, $args );
257        /**
258         * Filter the sharing display query.
259         *
260         * @module sharedaddy
261         *
262         * @since 2.8.0
263         *
264         * @param string $query Sharing service URL parameter.
265         * @param object $this Sharing service properties.
266         * @param string|false $id Sharing ID.
267         * @param array $args Array of sharing service options.
268         */
269        $query = apply_filters( 'jetpack_sharing_display_query', $query, $this, $id, $args );
270
271        if ( ! empty( $query ) ) {
272            if ( false === stripos( $url, '?' ) ) {
273                $url .= '?' . $query;
274            } else {
275                $url .= '&amp;' . $query;
276            }
277        }
278
279        return $url;
280    }
281
282    /**
283     * Add extra JavaScript to a sharing service.
284     *
285     * @param array $params Array of sharing options.
286     *
287     * @return void
288     */
289    public function js_dialog( $params = array() ) {
290    }
291
292    /**
293     * Get custom data attributes for the link.
294     *
295     * @param bool|string $id              Sharing ID to include in the data-shared attribute.
296     * @param array       $data_attributes The keys are used as additional attribute names with 'data-' prefix.
297     *                                     The values are used as the attribute values.
298     *
299     * @return string Encoded data attributes.
300     */
301    public function get_data_attributes( $id = false, $data_attributes = array() ) {
302        $args = func_get_args();
303
304        /**
305         * Filter the sharing data attributes.
306         *
307         * @module sharedaddy
308         *
309         * @since 11.0
310         *
311         * @param array $data_attributes Attributes supplied from the sharing source.
312         *                               Note that 'data-' will be prepended to all keys.
313         * @param Sharing_Source $this Sharing source instance.
314         * @param string|false $id Sharing ID.
315         * @param array $args Array of sharing service options.
316         */
317        $data_attributes = apply_filters( 'jetpack_sharing_data_attributes', (array) $data_attributes, $this, $id, $args );
318
319        $encoded_data_attributes = '';
320        if ( ! empty( $data_attributes ) ) {
321            $encoded_data_attributes = implode(
322                ' ',
323                array_map(
324                    /** Format attributes */
325                    function ( $data_key, $data_value ) {
326                        return sprintf(
327                            'data-%s="%s"',
328                            esc_attr( str_replace( array( ' ', '"' ), '', $data_key ) ),
329                            esc_attr( $data_value )
330                        );
331                    },
332                    array_keys( $data_attributes ),
333                    array_values( $data_attributes )
334                )
335            );
336        }
337        return $encoded_data_attributes;
338    }
339
340    /**
341     * Get an unfiltered post permalink to use when generating a sharing URL with get_link.
342     * Use instead of get_share_url for non-official styles as get_permalink ensures that process_request
343     * will be executed more reliably, in the case that the filtered URL uses a service that strips query parameters.
344     *
345     * @since 3.7.0
346     * @param int $post_id Post ID.
347     *
348     * @uses get_permalink
349     *
350     * @return string get_permalink( $post_id ) Post permalink.
351     */
352    public function get_process_request_url( $post_id ) {
353        return get_permalink( $post_id );
354    }
355
356    /**
357     * Does the service have advanced options.
358     *
359     * @return bool
360     */
361    public function has_advanced_options() {
362        return false;
363    }
364
365    /**
366     * Process sharing request. Add actions that need to happen when sharing here.
367     *
368     * @param WP_Post $post Post object.
369     * @param array   $post_data Array of information about the post we're sharing.
370     *
371     * @return void
372     */
373    public function process_request( $post, array $post_data ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
374        /**
375         * Fires when a post is shared via one of the sharing buttons.
376         *
377         * @module sharedaddy
378         *
379         * @since 1.1.0
380         *
381         * @param array $args Aray of information about the sharing service.
382         */
383        do_action(
384            'sharing_bump_stats',
385            array(
386                'service' => $this,
387                'post'    => $post,
388            )
389        );
390    }
391
392    /**
393     * Redirect to an external social network site to finish sharing.
394     *
395     * @param string $url Sharing URL for a given service.
396     * @return never
397     */
398    public function redirect_request( $url ) {
399        wp_redirect( $url ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- We allow external redirects here; we define them ourselves.
400
401        // We set up this custom header to indicate to search engines not to index this page.
402        header( 'X-Robots-Tag: noindex, nofollow' );
403        die( 0 );
404    }
405}
406
407/**
408 * Handle the display of the email sharing button.
409 */
410class Share_Email_Block extends Sharing_Source_Block {
411    /**
412     * Service short name.
413     *
414     * @var string
415     */
416    public $shortname = 'email';
417
418    /**
419     * Service name.
420     *
421     * @return string
422     */
423    public function get_name() {
424        return _x( 'Email', 'as sharing source', 'jetpack' );
425    }
426
427    /**
428     * Helper function to return a nonce action based on the current post.
429     *
430     * @param int $post_id The current post id if it is defined.
431     * @return string The nonce action name.
432     */
433    protected function get_email_share_nonce_action( $post_id ) {
434        if ( ! empty( $post_id ) ) {
435            return 'jetpack-email-share-' . $post_id;
436        }
437
438        return 'jetpack-email-share';
439    }
440
441    /**
442     * Get the URL for the link.
443     *
444     * @param int         $post_id         Post ID.
445     * @param string      $query           Additional query arguments to add to the link. They should be in 'foo=bar&baz=1' format.
446     * @param bool|string $id              Sharing ID to include in the data-shared attribute.
447     * @param array       $data_attributes The keys are used as additional attribute names with 'data-' prefix.
448     *                                     The values are used as the attribute values.
449     * @return object Link related data (url and data_attributes);
450     */
451    public function get_link( $post_id, $query = '', $id = false, $data_attributes = array() ) {
452        // We don't need to open new window, so we set it to false.
453        $id           = false;
454        $tracking_url = $this->get_process_request_url( $post_id );
455        if ( false === stripos( $tracking_url, '?' ) ) {
456            $tracking_url .= '?';
457        } else {
458            $tracking_url .= '&';
459        }
460        $tracking_url .= 'share=email';
461
462        $data_attributes = array(
463            'email-share-error-title' => __( 'Do you have email set up?', 'jetpack' ),
464            'email-share-error-text'  => __(
465                "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.",
466                'jetpack'
467            ),
468            'email-share-nonce'       => wp_create_nonce( $this->get_email_share_nonce_action( $post_id ) ),
469            'email-share-track-url'   => $tracking_url,
470        );
471
472        $post_title = $this->get_share_title( $post_id );
473        $post_url   = $this->get_share_url( $post_id );
474
475        /** This filter is documented in plugins/jetpack/modules/sharedaddy/sharedaddy.php */
476        $email_subject = apply_filters(
477            'wp_sharing_email_send_post_subject',
478            sprintf( '[%s] %s', __( 'Shared Post', 'jetpack' ), $post_title )
479        );
480
481        $mailto_query = sprintf(
482            'subject=%s&body=%s&share=email',
483            rawurlencode( $email_subject ),
484            rawurlencode( $post_url )
485        );
486
487        $url             = $this->get_url( 'mailto:', $mailto_query, $id );
488        $data_attributes = $this->get_data_attributes( $id, $data_attributes );
489
490        return array(
491            'url'             => $url,
492            'data_attributes' => $data_attributes,
493        );
494    }
495
496    /**
497     * Process sharing request. Add actions that need to happen when sharing here.
498     *
499     * @param WP_Post $post Post object.
500     * @param array   $post_data Array of information about the post we're sharing.
501     *
502     * @return void
503     */
504    public function process_request( $post, array $post_data ) {
505        $is_ajax = false;
506        if (
507            isset( $_SERVER['HTTP_X_REQUESTED_WITH'] )
508            && strtolower( sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_REQUESTED_WITH'] ) ) ) === 'xmlhttprequest'
509        ) {
510            $is_ajax = true;
511        }
512
513        // Require an AJAX-driven submit and a valid nonce to process the request
514        if (
515            $is_ajax
516            && isset( $post_data['email-share-nonce'] )
517            && wp_verify_nonce( $post_data['email-share-nonce'], $this->get_email_share_nonce_action( $post ) )
518        ) {
519            // Ensure that we bump stats
520            parent::process_request( $post, $post_data );
521        }
522
523        if ( $is_ajax ) {
524            wp_send_json_success();
525        } else {
526            wp_safe_redirect( get_permalink( $post->ID ) . '?shared=email&msg=fail' );
527            exit( 0 );
528        }
529
530        wp_die();
531    }
532}
533
534/**
535 * Facebook sharing button.
536 */
537class Share_Facebook_Block extends Sharing_Source_Block {
538    /**
539     * Service short name.
540     *
541     * @var string
542     */
543    public $shortname = 'facebook';
544
545    /**
546     * Sharing type.
547     *
548     * @var string
549     */
550    private $share_type = 'default';
551
552    /**
553     * Service name.
554     *
555     * @return string
556     */
557    public function get_name() {
558        return __( 'Facebook', 'jetpack' );
559    }
560
561    /**
562     * Process sharing request. Add actions that need to happen when sharing here.
563     *
564     * @param WP_Post $post Post object.
565     * @param array   $post_data Array of information about the post we're sharing.
566     *
567     * @return void
568     */
569    public function process_request( $post, array $post_data ) {
570        $post_id = $post instanceof WP_Post ? $post->ID : 0;
571        $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 ) );
572
573        // Record stats
574        parent::process_request( $post, $post_data );
575
576        parent::redirect_request( $fb_url );
577    }
578}
579
580/**
581 * Print button.
582 */
583class Share_Print_Block extends Sharing_Source_Block {
584    /**
585     * Service short name.
586     *
587     * @var string
588     */
589    public $shortname = 'print';
590
591    /**
592     * Service name.
593     *
594     * @return string
595     */
596    public function get_name() {
597        return __( 'Print', 'jetpack' );
598    }
599}
600
601/**
602 * Native Share button (relying on the Web Share API).
603 */
604class Share_Native_Block extends Sharing_Source_Block {
605    /**
606     * Service short name.
607     *
608     * @var string
609     */
610    public $shortname = 'native';
611
612    /**
613     * Service name.
614     *
615     * @return string
616     */
617    public function get_name() {
618        return __( 'Web Share', 'jetpack' );
619    }
620}
621
622/**
623 * Tumblr sharing service.
624 */
625class Share_Tumblr_Block extends Sharing_Source_Block {
626    /**
627     * Service short name.
628     *
629     * @var string
630     */
631    public $shortname = 'tumblr';
632
633    /**
634     * Service name.
635     *
636     * @return string
637     */
638    public function get_name() {
639        return __( 'Tumblr', 'jetpack' );
640    }
641
642    /**
643     * Process sharing request. Add actions that need to happen when sharing here.
644     *
645     * @param WP_Post $post Post object.
646     * @param array   $post_data Array of information about the post we're sharing.
647     *
648     * @return void
649     */
650    public function process_request( $post, array $post_data ) {
651        // Record stats
652        parent::process_request( $post, $post_data );
653
654        // Redirect to Tumblr's sharing endpoint (a la their bookmarklet)
655        $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=';
656
657        parent::redirect_request( $url );
658    }
659}
660
661/**
662 * Pinterest sharing service.
663 */
664class Share_Pinterest_Block extends Sharing_Source_Block {
665    /**
666     * Service short name.
667     *
668     * @var string
669     */
670    public $shortname = 'pinterest';
671
672    /**
673     * Service name.
674     *
675     * @return string
676     */
677    public function get_name() {
678        return __( 'Pinterest', 'jetpack' );
679    }
680
681    /**
682     * Get image representative of the post to pass on to Pinterest.
683     *
684     * @param WP_Post $post Post object.
685     *
686     * @return string
687     */
688    public function get_image( $post ) {
689        if ( class_exists( 'Jetpack_PostImages' ) ) {
690            $image = Jetpack_PostImages::get_image( $post->ID, array( 'fallback_to_avatars' => true ) );
691            if ( ! empty( $image ) ) {
692                return $image['src'];
693            }
694        }
695
696        /**
697         * Filters the default image used by the Pinterest Pin It share button.
698         *
699         * @module sharedaddy
700         *
701         * @since 3.6.0
702         *
703         * @param string $url Default image URL.
704         */
705        return apply_filters( 'jetpack_sharing_pinterest_default_image', 'https://s0.wp.com/i/blank.jpg' );
706    }
707
708    /**
709     * Get Pinterest external sharing URL.
710     *
711     * @param WP_Post $post Post object.
712     *
713     * @return string
714     */
715    public function get_external_url( $post ) {
716        $url = 'https://www.pinterest.com/pin/create/button/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&media=' . rawurlencode( $this->get_image( $post ) ) . '&description=' . rawurlencode( $post->post_title );
717
718        /**
719         * Filters the Pinterest share URL used in sharing button output.
720         *
721         * @module sharedaddy
722         *
723         * @since 3.6.0
724         *
725         * @param string $url Pinterest share URL.
726         */
727        return apply_filters( 'jetpack_sharing_pinterest_share_url', $url );
728    }
729
730    /**
731     * Get Pinterest widget type.
732     *
733     * @return string
734     */
735    public function get_widget_type() {
736        /**
737         * Filters the Pinterest widget type.
738         *
739         * @see https://business.pinterest.com/en/widget-builder
740         *
741         * @module sharedaddy
742         *
743         * @since 3.6.0
744         *
745         * @param string $type Pinterest widget type. Default of 'buttonPin' for single-image selection. 'buttonBookmark' for multi-image modal.
746         */
747        return apply_filters( 'jetpack_sharing_pinterest_widget_type', 'buttonPin' );
748    }
749
750    /**
751     * Process sharing request. Add actions that need to happen when sharing here.
752     *
753     * @param WP_Post $post Post object.
754     * @param array   $post_data Array of information about the post we're sharing.
755     *
756     * @return void
757     */
758    public function process_request( $post, array $post_data ) {
759        // Record stats
760        parent::process_request( $post, $post_data );
761        // If we're triggering the multi-select panel, then we don't need to redirect to Pinterest
762        if ( ! isset( $_GET['js_only'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
763            $pinterest_url = esc_url_raw( $this->get_external_url( $post ) );
764            parent::redirect_request( $pinterest_url );
765        } else {
766            echo '// share count bumped';
767            die( 0 );
768        }
769    }
770}
771
772/**
773 * Pocket sharing service.
774 */
775class Share_Pocket_Block extends Sharing_Source_Block {
776    /**
777     * Service short name.
778     *
779     * @var string
780     */
781    public $shortname = 'pocket';
782
783    /**
784     * Service name.
785     *
786     * @return string
787     */
788    public function get_name() {
789        return __( 'Pocket', 'jetpack' );
790    }
791
792    /**
793     * Process sharing request. Add actions that need to happen when sharing here.
794     *
795     * @param WP_Post $post Post object.
796     * @param array   $post_data Array of information about the post we're sharing.
797     *
798     * @return void
799     */
800    public function process_request( $post, array $post_data ) {
801        // Record stats
802        parent::process_request( $post, $post_data );
803
804        $pocket_url = esc_url_raw( 'https://getpocket.com/save/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $this->get_share_title( $post->ID ) ) );
805
806        parent::redirect_request( $pocket_url );
807    }
808}
809
810/**
811 * Telegram sharing service.
812 */
813class Share_Telegram_Block extends Sharing_Source_Block {
814    /**
815     * Service short name.
816     *
817     * @var string
818     */
819    public $shortname = 'telegram';
820
821    /**
822     * Service name.
823     *
824     * @return string
825     */
826    public function get_name() {
827        return __( 'Telegram', 'jetpack' );
828    }
829
830    /**
831     * Process sharing request. Add actions that need to happen when sharing here.
832     *
833     * @param WP_Post $post Post object.
834     * @param array   $post_data Array of information about the post we're sharing.
835     *
836     * @return void
837     */
838    public function process_request( $post, array $post_data ) {
839        // Record stats
840        parent::process_request( $post, $post_data );
841
842        $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 ) ) );
843
844        parent::redirect_request( $telegram_url );
845    }
846}
847
848/**
849 * WhatsApp sharing service.
850 */
851class Jetpack_Share_WhatsApp_Block extends Sharing_Source_Block {
852    /**
853     * Service short name.
854     *
855     * @var string
856     */
857    public $shortname = 'jetpack-whatsapp';
858
859    /**
860     * Service name.
861     *
862     * @return string
863     */
864    public function get_name() {
865        return __( 'WhatsApp', 'jetpack' );
866    }
867
868    /**
869     * Process sharing request. Add actions that need to happen when sharing here.
870     *
871     * @param WP_Post $post Post object.
872     * @param array   $post_data Array of information about the post we're sharing.
873     *
874     * @return void
875     */
876    public function process_request( $post, array $post_data ) {
877        // Record stats
878        parent::process_request( $post, $post_data );
879
880        // Firefox for desktop doesn't handle the "api.whatsapp.com" URL properly, so use "web.whatsapp.com"
881        if ( User_Agent_Info::is_firefox_desktop() ) {
882            $url = 'https://web.whatsapp.com/send?text=';
883        } else {
884            $url = 'https://api.whatsapp.com/send?text=';
885        }
886
887        $url .= rawurlencode( $this->get_share_title( $post->ID ) . ' ' . $this->get_share_url( $post->ID ) );
888
889        parent::redirect_request( $url );
890    }
891}
892
893/**
894 * Mastodon sharing service.
895 */
896class Share_Mastodon_Block extends Sharing_Source_Block {
897    /**
898     * Service short name.
899     *
900     * @var string
901     */
902    public $shortname = 'mastodon';
903
904    /**
905     * Service name.
906     *
907     * @return string
908     */
909    public function get_name() {
910        return __( 'Mastodon', 'jetpack' );
911    }
912
913    /**
914     * Process sharing request. Add actions that need to happen when sharing here.
915     *
916     * @param WP_Post $post Post object.
917     * @param array   $post_data Array of information about the post we're sharing.
918     *
919     * @return void
920     */
921    public function process_request( $post, array $post_data ) {
922        if ( empty( $_POST['jetpack-mastodon-instance'] ) ) {
923            require_once __DIR__ . '/components/class-jetpack-mastodon-modal.php';
924            add_action( 'template_redirect', array( Jetpack_Mastodon_Modal::class, 'modal' ) );
925            return;
926        }
927
928        check_admin_referer( 'jetpack_share_mastodon_instance' );
929
930        $mastodon_instance = isset( $_POST['jetpack-mastodon-instance'] )
931            ? trailingslashit( sanitize_text_field( wp_unslash( $_POST['jetpack-mastodon-instance'] ) ) )
932            : null;
933
934        $post_title = $this->get_share_title( $post->ID );
935        $post_link  = $this->get_share_url( $post->ID );
936        $post_tags  = $this->get_share_tags( $post->ID );
937
938        /**
939         * Allow filtering the default message that gets posted to Mastodon.
940         *
941         * @module sharedaddy
942         * @since 11.9
943         *
944         * @param string  $share_url The default message that gets posted to Mastodon.
945         * @param WP_Post $post      The post object.
946         * @param array   $post_data Array of information about the post we're sharing.
947         */
948        $shared_message = apply_filters(
949            'jetpack_sharing_mastodon_default_message',
950            $post_title . ' ' . $post_link . ' ' . $post_tags,
951            $post,
952            $post_data
953        );
954
955        $share_url = sprintf(
956            '%1$sshare?text=%2$s',
957            $mastodon_instance,
958            rawurlencode( $shared_message )
959        );
960
961            // Record stats
962        parent::process_request( $post, $post_data );
963
964        parent::redirect_request( $share_url );
965    }
966}
967
968/**
969 * Nextdoor sharing service.
970 */
971class Share_Nextdoor_Block extends Sharing_Source_Block {
972    /**
973     * Service short name.
974     *
975     * @var string
976     */
977    public $shortname = 'nextdoor';
978
979    /**
980     * Service name.
981     *
982     * @return string
983     */
984    public function get_name() {
985        return __( 'Nextdoor', 'jetpack' );
986    }
987
988    /**
989     * Process sharing request. Add actions that need to happen when sharing here.
990     *
991     * @param WP_Post $post Post object.
992     * @param array   $post_data Array of information about the post we're sharing.
993     *
994     * @return void
995     */
996    public function process_request( $post, array $post_data ) {
997        // Record stats
998        parent::process_request( $post, $post_data );
999
1000        $url  = 'https://nextdoor.com/sharekit/?source=jetpack&body=';
1001        $url .= rawurlencode( $this->get_share_title( $post->ID ) . ' ' . $this->get_share_url( $post->ID ) );
1002
1003        parent::redirect_request( $url );
1004    }
1005}
1006
1007/**
1008 * Bluesky sharing button.
1009 */
1010class Share_Bluesky_Block extends Sharing_Source_Block {
1011    /**
1012     * Service short name.
1013     *
1014     * @var string
1015     */
1016    public $shortname = 'bluesky';
1017
1018    /**
1019     * Service name.
1020     *
1021     * @return string
1022     */
1023    public function get_name() {
1024        return __( 'Bluesky', 'jetpack' );
1025    }
1026
1027    /**
1028     * Process sharing request. Add actions that need to happen when sharing here.
1029     *
1030     * @param WP_Post $post Post object.
1031     * @param array   $post_data Array of information about the post we're sharing.
1032     *
1033     * @return void
1034     */
1035    public function process_request( $post, array $post_data ) {
1036        // Record stats
1037        parent::process_request( $post, $post_data );
1038
1039        $url  = 'https://bsky.app/intent/compose?text=';
1040        $url .= rawurlencode( $this->get_share_title( $post->ID ) . ' ' . $this->get_share_url( $post->ID ) );
1041
1042        parent::redirect_request( $url );
1043    }
1044}
1045
1046/**
1047 * X sharing button.
1048 *
1049 * While the old Twitter button had an official button,
1050 * this new X button does not, since there is no official X button yet.
1051 */
1052class Share_X_Block extends Sharing_Source_Block {
1053    /**
1054     * Service short name.
1055     *
1056     * @var string
1057     */
1058    public $shortname = 'x';
1059
1060    /**
1061     * Length of a URL on X.
1062     * https://developer.twitter.com/en/docs/tco
1063     *
1064     * @var int
1065     */
1066    public $short_url_length = 24;
1067
1068    /**
1069     * Service name.
1070     *
1071     * @return string
1072     */
1073    public function get_name() {
1074        return __( 'X', 'jetpack' );
1075    }
1076
1077    /**
1078     * Determine the X 'via' value for a post.
1079     *
1080     * @param  WP_Post|int $post Post object or post ID.
1081     * @return string X handle without the preceding @.
1082     **/
1083    public static function sharing_x_via( $post ) {
1084        $post = get_post( $post );
1085        /** This filter is documented in modules/sharedaddy/sharing-sources.php */
1086        $twitter_site_tag_value = apply_filters(
1087            'jetpack_twitter_cards_site_tag',
1088            '',
1089            /** This action is documented in modules/sharedaddy/sharing-sources.php */
1090            array( 'twitter:creator' => apply_filters( 'jetpack_sharing_twitter_via', '', $post->ID ) )
1091        );
1092
1093        /*
1094         * Hack to remove the unwanted behavior of adding 'via @jetpack' which
1095         * was introduced with the adding of the Twitter cards.
1096         * This should be a temporary solution until a better method is setup.
1097         */
1098        if ( 'jetpack' === $twitter_site_tag_value ) {
1099            $twitter_site_tag_value = '';
1100        }
1101
1102        /** This filter is documented in modules/sharedaddy/sharing-sources.php */
1103        $twitter_site_tag_value = apply_filters( 'jetpack_sharing_twitter_via', $twitter_site_tag_value, $post->ID );
1104
1105        // Strip out anything other than a letter, number, or underscore.
1106        // This will prevent the inadvertent inclusion of an extra @, as well as normalizing the handle.
1107        return preg_replace( '/[^\da-z_]+/i', '', $twitter_site_tag_value );
1108    }
1109
1110    /**
1111     * Determine the 'related' X accounts for a post.
1112     *
1113     * @param  WP_Post|int $post Post object or post ID.
1114     * @return string Comma-separated list of X handles.
1115     **/
1116    public static function get_related_accounts( $post ) {
1117        $post = get_post( $post );
1118        /** This filter is documented in modules/sharedaddy/sharing-sources.php */
1119        $related_accounts = apply_filters( 'jetpack_sharing_twitter_related', array(), $post->ID );
1120
1121        // Example related string: account1,account2:Account 2 description,account3
1122        $related = array();
1123
1124        foreach ( $related_accounts as $related_account_username => $related_account_description ) {
1125            // Join the description onto the end of the username
1126            if ( $related_account_description ) {
1127                $related_account_username .= ':' . $related_account_description;
1128            }
1129
1130            $related[] = $related_account_username;
1131        }
1132
1133        return implode( ',', $related );
1134    }
1135
1136    /**
1137     * Process sharing request. Add actions that need to happen when sharing here.
1138     *
1139     * @param WP_Post $post Post object.
1140     * @param array   $post_data Array of information about the post we're sharing.
1141     *
1142     * @return void
1143     */
1144    public function process_request( $post, array $post_data ) {
1145        $post_title = $this->get_share_title( $post->ID );
1146        $post_link  = $this->get_share_url( $post->ID );
1147
1148        if ( function_exists( 'mb_stripos' ) ) {
1149            $strlen = 'mb_strlen';
1150            $substr = 'mb_substr';
1151        } else {
1152            $strlen = 'strlen';
1153            $substr = 'substr';
1154        }
1155
1156        $via     = static::sharing_x_via( $post );
1157        $related = static::get_related_accounts( $post );
1158        if ( $via ) {
1159            $sig = " via @$via";
1160            if ( $related === $via ) {
1161                $related = false;
1162            }
1163        } else {
1164            $via = false;
1165            $sig = '';
1166        }
1167
1168        $suffix_length = $this->short_url_length + $strlen( $sig );
1169        // $sig is handled by twitter in their 'via' argument.
1170        // $post_link is handled by twitter in their 'url' argument.
1171        if ( 280 < $strlen( $post_title ) + $suffix_length ) {
1172            // The -1 is for "\xE2\x80\xA6", a UTF-8 ellipsis.
1173            $text = $substr( $post_title, 0, 280 - $suffix_length - 1 ) . "\xE2\x80\xA6";
1174        } else {
1175            $text = $post_title;
1176        }
1177
1178        // Record stats
1179        parent::process_request( $post, $post_data );
1180
1181        $url         = $post_link;
1182        $twitter_url = add_query_arg(
1183            rawurlencode_deep( array_filter( compact( 'via', 'related', 'text', 'url' ) ) ),
1184            'https://x.com/intent/tweet'
1185        );
1186
1187        parent::redirect_request( $twitter_url );
1188    }
1189}
1190
1191/**
1192 * Twitter sharing button.
1193 */
1194class Share_Twitter_Block extends Sharing_Source_Block {
1195    /**
1196     * Service short name.
1197     *
1198     * @var string
1199     */
1200    public $shortname = 'twitter';
1201
1202    /**
1203     * Length of a URL on Twitter.
1204     * 'https://dev.twitter.com/rest/reference/get/help/configuration'
1205     * ( 2015/02/06 ) short_url_length is 22, short_url_length_https is 23
1206     *
1207     * @var int
1208     */
1209    public $short_url_length = 24;
1210
1211    /**
1212     * Service name.
1213     *
1214     * @return string
1215     */
1216    public function get_name() {
1217        return __( 'X', 'jetpack' );
1218    }
1219
1220    /**
1221     * Determine the Twitter 'via' value for a post.
1222     *
1223     * @param  WP_Post|int $post Post object or post ID.
1224     * @return string Twitter handle without the preceding @.
1225     **/
1226    public static function sharing_twitter_via( $post ) {
1227        $post = get_post( $post );
1228        /**
1229         * Allow third-party plugins to customize the Twitter username used as "twitter:site" Twitter Card Meta Tag.
1230         *
1231         * @module sharedaddy
1232         *
1233         * @since 3.0.0
1234         *
1235         * @param string $string Twitter Username.
1236         * @param array $args Array of Open Graph Meta Tags and Twitter Cards tags.
1237         */
1238        $twitter_site_tag_value = apply_filters(
1239            'jetpack_twitter_cards_site_tag',
1240            '',
1241            /** This action is documented in modules/sharedaddy/sharing-sources.php */
1242            array( 'twitter:creator' => apply_filters( 'jetpack_sharing_twitter_via', '', $post->ID ) )
1243        );
1244
1245        /*
1246         * Hack to remove the unwanted behavior of adding 'via @jetpack' which
1247         * was introduced with the adding of the Twitter cards.
1248         * This should be a temporary solution until a better method is setup.
1249         */
1250        if ( 'jetpack' === $twitter_site_tag_value ) {
1251            $twitter_site_tag_value = '';
1252        }
1253
1254        /**
1255         * Filters the Twitter username used as "via" in the Twitter sharing button.
1256         *
1257         * @module sharedaddy
1258         *
1259         * @since 1.7.0
1260         *
1261         * @param string $twitter_site_tag_value Twitter Username.
1262         * @param int $post->ID Post ID.
1263         */
1264        $twitter_site_tag_value = apply_filters( 'jetpack_sharing_twitter_via', $twitter_site_tag_value, $post->ID );
1265
1266        // Strip out anything other than a letter, number, or underscore.
1267        // This will prevent the inadvertent inclusion of an extra @, as well as normalizing the handle.
1268        return preg_replace( '/[^\da-z_]+/i', '', $twitter_site_tag_value );
1269    }
1270
1271    /**
1272     * Determine the 'related' Twitter accounts for a post.
1273     *
1274     * @param  WP_Post|int $post Post object or post ID.
1275     * @return string Comma-separated list of Twitter handles.
1276     **/
1277    public static function get_related_accounts( $post ) {
1278        $post = get_post( $post );
1279        /**
1280         * Filter the list of related Twitter accounts added to the Twitter sharing button.
1281         *
1282         * @module sharedaddy
1283         *
1284         * @since 1.7.0
1285         *
1286         * @param array $args Array of Twitter usernames. Format is 'username' => 'Optional description'
1287         * @param int $post->ID Post ID.
1288         */
1289        $related_accounts = apply_filters( 'jetpack_sharing_twitter_related', array(), $post->ID );
1290
1291        // Example related string: account1,account2:Account 2 description,account3
1292        $related = array();
1293
1294        foreach ( $related_accounts as $related_account_username => $related_account_description ) {
1295            // Join the description onto the end of the username
1296            if ( $related_account_description ) {
1297                $related_account_username .= ':' . $related_account_description;
1298            }
1299
1300            $related[] = $related_account_username;
1301        }
1302
1303        return implode( ',', $related );
1304    }
1305
1306    /**
1307     * Process sharing request. Add actions that need to happen when sharing here.
1308     *
1309     * @param WP_Post $post Post object.
1310     * @param array   $post_data Array of information about the post we're sharing.
1311     *
1312     * @return void
1313     */
1314    public function process_request( $post, array $post_data ) {
1315        $post_title = $this->get_share_title( $post->ID );
1316        $post_link  = $this->get_share_url( $post->ID );
1317
1318        if ( function_exists( 'mb_stripos' ) ) {
1319            $strlen = 'mb_strlen';
1320            $substr = 'mb_substr';
1321        } else {
1322            $strlen = 'strlen';
1323            $substr = 'substr';
1324        }
1325
1326        $via     = static::sharing_twitter_via( $post );
1327        $related = static::get_related_accounts( $post );
1328        if ( $via ) {
1329            $sig = " via @$via";
1330            if ( $related === $via ) {
1331                $related = false;
1332            }
1333        } else {
1334            $via = false;
1335            $sig = '';
1336        }
1337
1338        $suffix_length = $this->short_url_length + $strlen( $sig );
1339        // $sig is handled by twitter in their 'via' argument.
1340        // $post_link is handled by twitter in their 'url' argument.
1341        if ( 280 < $strlen( $post_title ) + $suffix_length ) {
1342            // The -1 is for "\xE2\x80\xA6", a UTF-8 ellipsis.
1343            $text = $substr( $post_title, 0, 280 - $suffix_length - 1 ) . "\xE2\x80\xA6";
1344        } else {
1345            $text = $post_title;
1346        }
1347
1348        // Record stats
1349        parent::process_request( $post, $post_data );
1350
1351        $url         = $post_link;
1352        $twitter_url = add_query_arg(
1353            rawurlencode_deep( array_filter( compact( 'via', 'related', 'text', 'url' ) ) ),
1354            'https://x.com/intent/tweet'
1355        );
1356
1357        parent::redirect_request( $twitter_url );
1358    }
1359}
1360
1361/**
1362 * Reddit sharing button.
1363 */
1364class Share_Reddit_Block extends Sharing_Source_Block {
1365    /**
1366     * Service short name.
1367     *
1368     * @var string
1369     */
1370    public $shortname = 'reddit';
1371
1372    /**
1373     * Service name.
1374     *
1375     * @return string
1376     */
1377    public function get_name() {
1378        return __( 'Reddit', 'jetpack' );
1379    }
1380
1381    /**
1382     * Process sharing request. Add actions that need to happen when sharing here.
1383     *
1384     * @param WP_Post $post Post object.
1385     * @param array   $post_data Array of information about the post we're sharing.
1386     *
1387     * @return void
1388     */
1389    public function process_request( $post, array $post_data ) {
1390        $reddit_url = $this->http() . '://reddit.com/submit?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $this->get_share_title( $post->ID ) );
1391
1392        // Record stats
1393        parent::process_request( $post, $post_data );
1394
1395        parent::redirect_request( $reddit_url );
1396    }
1397}
1398
1399/**
1400 * LinkedIn sharing button.
1401 */
1402class Share_LinkedIn_Block extends Sharing_Source_Block {
1403    /**
1404     * Service short name.
1405     *
1406     * @var string
1407     */
1408    public $shortname = 'linkedin';
1409
1410    /**
1411     * Service name.
1412     *
1413     * @return string
1414     */
1415    public function get_name() {
1416        return __( 'LinkedIn', 'jetpack' );
1417    }
1418
1419    /**
1420     * Process sharing request. Add actions that need to happen when sharing here.
1421     *
1422     * @param WP_Post $post Post object.
1423     * @param array   $post_data Array of information about the post we're sharing.
1424     *
1425     * @return void
1426     */
1427    public function process_request( $post, array $post_data ) {
1428
1429        $post_link = $this->get_share_url( $post->ID );
1430
1431        // Using the same URL as the official button, which is *not* LinkedIn's documented sharing link
1432        // https://www.linkedin.com/cws/share?url={url}&token=&isFramed=false
1433        $linkedin_url = add_query_arg(
1434            array(
1435                'url' => rawurlencode( $post_link ),
1436            ),
1437            'https://www.linkedin.com/cws/share?token=&isFramed=false'
1438        );
1439
1440        // Record stats
1441        parent::process_request( $post, $post_data );
1442
1443        parent::redirect_request( $linkedin_url );
1444    }
1445}
1446
1447/**
1448 * Threads sharing button.
1449 */
1450class Share_Threads_Block extends Sharing_Source_Block {
1451    /**
1452     * Service short name.
1453     *
1454     * @var string
1455     */
1456    public $shortname = 'threads';
1457
1458    /**
1459     * Service name.
1460     *
1461     * @return string
1462     */
1463    public function get_name() {
1464        return __( 'Threads', 'jetpack' );
1465    }
1466
1467    /**
1468     * Process sharing request. Add actions that need to happen when sharing here.
1469     *
1470     * @param WP_Post $post Post object.
1471     * @param array   $post_data Array of information about the post we're sharing.
1472     *
1473     * @return void
1474     */
1475    public function process_request( $post, array $post_data ) {
1476        // Record stats
1477        parent::process_request( $post, $post_data );
1478
1479        $url  = 'https://www.threads.net/intent/post/?text=';
1480        $url .= rawurlencode( $this->get_share_title( $post->ID ) . ' ' . $this->get_share_url( $post->ID ) );
1481
1482        parent::redirect_request( $url );
1483    }
1484}