Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 314
0.00% covered (danger)
0.00%
0 / 55
CRAP
0.00% covered (danger)
0.00%
0 / 17
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 / 48
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 / 12
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 / 14
0.00% covered (danger)
0.00%
0 / 5
56
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 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 get_external_url
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 get_widget_type
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 process_request
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
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 Automattic\Jetpack\Post_Media\Images;
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 never
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            // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- It takes null, but its phpdoc only says int.
525            wp_send_json_success( null, null, JSON_UNESCAPED_SLASHES );
526        } else {
527            wp_safe_redirect( get_permalink( $post->ID ) . '?shared=email&msg=fail' );
528            exit( 0 );
529        }
530    }
531}
532
533/**
534 * Facebook sharing button.
535 */
536class Share_Facebook_Block extends Sharing_Source_Block {
537    /**
538     * Service short name.
539     *
540     * @var string
541     */
542    public $shortname = 'facebook';
543
544    /**
545     * Sharing type.
546     *
547     * @var string
548     */
549    private $share_type = 'default';
550
551    /**
552     * Service name.
553     *
554     * @return string
555     */
556    public function get_name() {
557        return __( 'Facebook', 'jetpack' );
558    }
559
560    /**
561     * Process sharing request. Add actions that need to happen when sharing here.
562     *
563     * @param WP_Post $post Post object.
564     * @param array   $post_data Array of information about the post we're sharing.
565     *
566     * @return void
567     */
568    public function process_request( $post, array $post_data ) {
569        $post_id = $post instanceof WP_Post ? $post->ID : 0;
570        $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 ) );
571
572        // Record stats
573        parent::process_request( $post, $post_data );
574
575        parent::redirect_request( $fb_url );
576    }
577}
578
579/**
580 * Print button.
581 */
582class Share_Print_Block extends Sharing_Source_Block {
583    /**
584     * Service short name.
585     *
586     * @var string
587     */
588    public $shortname = 'print';
589
590    /**
591     * Service name.
592     *
593     * @return string
594     */
595    public function get_name() {
596        return __( 'Print', 'jetpack' );
597    }
598}
599
600/**
601 * Native Share button (relying on the Web Share API).
602 */
603class Share_Native_Block extends Sharing_Source_Block {
604    /**
605     * Service short name.
606     *
607     * @var string
608     */
609    public $shortname = 'native';
610
611    /**
612     * Service name.
613     *
614     * @return string
615     */
616    public function get_name() {
617        return __( 'Web Share', 'jetpack' );
618    }
619}
620
621/**
622 * Tumblr sharing service.
623 */
624class Share_Tumblr_Block extends Sharing_Source_Block {
625    /**
626     * Service short name.
627     *
628     * @var string
629     */
630    public $shortname = 'tumblr';
631
632    /**
633     * Service name.
634     *
635     * @return string
636     */
637    public function get_name() {
638        return __( 'Tumblr', 'jetpack' );
639    }
640
641    /**
642     * Process sharing request. Add actions that need to happen when sharing here.
643     *
644     * @param WP_Post $post Post object.
645     * @param array   $post_data Array of information about the post we're sharing.
646     *
647     * @return void
648     */
649    public function process_request( $post, array $post_data ) {
650        // Record stats
651        parent::process_request( $post, $post_data );
652
653        // Redirect to Tumblr's sharing endpoint (a la their bookmarklet)
654        $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=';
655
656        parent::redirect_request( $url );
657    }
658}
659
660/**
661 * Pinterest sharing service.
662 */
663class Share_Pinterest_Block extends Sharing_Source_Block {
664    /**
665     * Service short name.
666     *
667     * @var string
668     */
669    public $shortname = 'pinterest';
670
671    /**
672     * Service name.
673     *
674     * @return string
675     */
676    public function get_name() {
677        return __( 'Pinterest', 'jetpack' );
678    }
679
680    /**
681     * Get image representative of the post to pass on to Pinterest.
682     *
683     * @param WP_Post $post Post object.
684     *
685     * @return string
686     */
687    public function get_image( $post ) {
688        $image = Images::get_image( $post->ID, array( 'fallback_to_avatars' => true ) );
689        if ( ! empty( $image ) ) {
690            return $image['src'];
691        }
692
693        /**
694         * Filters the default image used by the Pinterest Pin It share button.
695         *
696         * @module sharedaddy
697         *
698         * @since 3.6.0
699         *
700         * @param string $url Default image URL.
701         */
702        return apply_filters( 'jetpack_sharing_pinterest_default_image', 'https://s0.wp.com/i/blank.jpg' );
703    }
704
705    /**
706     * Get Pinterest external sharing URL.
707     *
708     * @param WP_Post $post Post object.
709     *
710     * @return string
711     */
712    public function get_external_url( $post ) {
713        $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 );
714
715        /**
716         * Filters the Pinterest share URL used in sharing button output.
717         *
718         * @module sharedaddy
719         *
720         * @since 3.6.0
721         *
722         * @param string $url Pinterest share URL.
723         */
724        return apply_filters( 'jetpack_sharing_pinterest_share_url', $url );
725    }
726
727    /**
728     * Get Pinterest widget type.
729     *
730     * @return string
731     */
732    public function get_widget_type() {
733        /**
734         * Filters the Pinterest widget type.
735         *
736         * @see https://business.pinterest.com/en/widget-builder
737         *
738         * @module sharedaddy
739         *
740         * @since 3.6.0
741         *
742         * @param string $type Pinterest widget type. Default of 'buttonPin' for single-image selection. 'buttonBookmark' for multi-image modal.
743         */
744        return apply_filters( 'jetpack_sharing_pinterest_widget_type', 'buttonPin' );
745    }
746
747    /**
748     * Process sharing request. Add actions that need to happen when sharing here.
749     *
750     * @param WP_Post $post Post object.
751     * @param array   $post_data Array of information about the post we're sharing.
752     *
753     * @return void
754     */
755    public function process_request( $post, array $post_data ) {
756        // Record stats
757        parent::process_request( $post, $post_data );
758        // If we're triggering the multi-select panel, then we don't need to redirect to Pinterest
759        if ( ! isset( $_GET['js_only'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
760            $pinterest_url = esc_url_raw( $this->get_external_url( $post ) );
761            parent::redirect_request( $pinterest_url );
762        } else {
763            echo '// share count bumped';
764            die( 0 );
765        }
766    }
767}
768
769/**
770 * Telegram sharing service.
771 */
772class Share_Telegram_Block extends Sharing_Source_Block {
773    /**
774     * Service short name.
775     *
776     * @var string
777     */
778    public $shortname = 'telegram';
779
780    /**
781     * Service name.
782     *
783     * @return string
784     */
785    public function get_name() {
786        return __( 'Telegram', 'jetpack' );
787    }
788
789    /**
790     * Process sharing request. Add actions that need to happen when sharing here.
791     *
792     * @param WP_Post $post Post object.
793     * @param array   $post_data Array of information about the post we're sharing.
794     *
795     * @return void
796     */
797    public function process_request( $post, array $post_data ) {
798        // Record stats
799        parent::process_request( $post, $post_data );
800
801        $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 ) ) );
802
803        parent::redirect_request( $telegram_url );
804    }
805}
806
807/**
808 * WhatsApp sharing service.
809 */
810class Jetpack_Share_WhatsApp_Block extends Sharing_Source_Block {
811    /**
812     * Service short name.
813     *
814     * @var string
815     */
816    public $shortname = 'jetpack-whatsapp';
817
818    /**
819     * Service name.
820     *
821     * @return string
822     */
823    public function get_name() {
824        return __( 'WhatsApp', 'jetpack' );
825    }
826
827    /**
828     * Process sharing request. Add actions that need to happen when sharing here.
829     *
830     * @param WP_Post $post Post object.
831     * @param array   $post_data Array of information about the post we're sharing.
832     *
833     * @return void
834     */
835    public function process_request( $post, array $post_data ) {
836        // Record stats
837        parent::process_request( $post, $post_data );
838
839        // Firefox for desktop doesn't handle the "api.whatsapp.com" URL properly, so use "web.whatsapp.com"
840        if ( User_Agent_Info::is_firefox_desktop() ) {
841            $url = 'https://web.whatsapp.com/send?text=';
842        } else {
843            $url = 'https://api.whatsapp.com/send?text=';
844        }
845
846        $url .= rawurlencode( $this->get_share_title( $post->ID ) . ' ' . $this->get_share_url( $post->ID ) );
847
848        parent::redirect_request( $url );
849    }
850}
851
852/**
853 * Mastodon sharing service.
854 */
855class Share_Mastodon_Block extends Sharing_Source_Block {
856    /**
857     * Service short name.
858     *
859     * @var string
860     */
861    public $shortname = 'mastodon';
862
863    /**
864     * Service name.
865     *
866     * @return string
867     */
868    public function get_name() {
869        return __( 'Mastodon', 'jetpack' );
870    }
871
872    /**
873     * Process sharing request. Add actions that need to happen when sharing here.
874     *
875     * @param WP_Post $post Post object.
876     * @param array   $post_data Array of information about the post we're sharing.
877     *
878     * @return void
879     */
880    public function process_request( $post, array $post_data ) {
881        if ( empty( $_POST['jetpack-mastodon-instance'] ) ) {
882            require_once __DIR__ . '/components/class-jetpack-mastodon-modal.php';
883            add_action( 'template_redirect', array( Jetpack_Mastodon_Modal::class, 'modal' ) );
884            return;
885        }
886
887        check_admin_referer( 'jetpack_share_mastodon_instance' );
888
889        $mastodon_instance = isset( $_POST['jetpack-mastodon-instance'] )
890            ? trailingslashit( sanitize_text_field( wp_unslash( $_POST['jetpack-mastodon-instance'] ) ) )
891            : null;
892
893        $post_title = $this->get_share_title( $post->ID );
894        $post_link  = $this->get_share_url( $post->ID );
895        $post_tags  = $this->get_share_tags( $post->ID );
896
897        /**
898         * Allow filtering the default message that gets posted to Mastodon.
899         *
900         * @module sharedaddy
901         * @since 11.9
902         *
903         * @param string  $share_url The default message that gets posted to Mastodon.
904         * @param WP_Post $post      The post object.
905         * @param array   $post_data Array of information about the post we're sharing.
906         */
907        $shared_message = apply_filters(
908            'jetpack_sharing_mastodon_default_message',
909            $post_title . ' ' . $post_link . ' ' . $post_tags,
910            $post,
911            $post_data
912        );
913
914        $share_url = sprintf(
915            '%1$sshare?text=%2$s',
916            $mastodon_instance,
917            rawurlencode( $shared_message )
918        );
919
920            // Record stats
921        parent::process_request( $post, $post_data );
922
923        parent::redirect_request( $share_url );
924    }
925}
926
927/**
928 * Nextdoor sharing service.
929 */
930class Share_Nextdoor_Block extends Sharing_Source_Block {
931    /**
932     * Service short name.
933     *
934     * @var string
935     */
936    public $shortname = 'nextdoor';
937
938    /**
939     * Service name.
940     *
941     * @return string
942     */
943    public function get_name() {
944        return __( 'Nextdoor', 'jetpack' );
945    }
946
947    /**
948     * Process sharing request. Add actions that need to happen when sharing here.
949     *
950     * @param WP_Post $post Post object.
951     * @param array   $post_data Array of information about the post we're sharing.
952     *
953     * @return void
954     */
955    public function process_request( $post, array $post_data ) {
956        // Record stats
957        parent::process_request( $post, $post_data );
958
959        $url  = 'https://nextdoor.com/sharekit/?source=jetpack&body=';
960        $url .= rawurlencode( $this->get_share_title( $post->ID ) . ' ' . $this->get_share_url( $post->ID ) );
961
962        parent::redirect_request( $url );
963    }
964}
965
966/**
967 * Bluesky sharing button.
968 */
969class Share_Bluesky_Block extends Sharing_Source_Block {
970    /**
971     * Service short name.
972     *
973     * @var string
974     */
975    public $shortname = 'bluesky';
976
977    /**
978     * Service name.
979     *
980     * @return string
981     */
982    public function get_name() {
983        return __( 'Bluesky', 'jetpack' );
984    }
985
986    /**
987     * Process sharing request. Add actions that need to happen when sharing here.
988     *
989     * @param WP_Post $post Post object.
990     * @param array   $post_data Array of information about the post we're sharing.
991     *
992     * @return void
993     */
994    public function process_request( $post, array $post_data ) {
995        // Record stats
996        parent::process_request( $post, $post_data );
997
998        $url  = 'https://bsky.app/intent/compose?text=';
999        $url .= rawurlencode( $this->get_share_title( $post->ID ) . ' ' . $this->get_share_url( $post->ID ) );
1000
1001        parent::redirect_request( $url );
1002    }
1003}
1004
1005/**
1006 * X sharing button.
1007 *
1008 * While the old Twitter button had an official button,
1009 * this new X button does not, since there is no official X button yet.
1010 */
1011class Share_X_Block extends Sharing_Source_Block {
1012    /**
1013     * Service short name.
1014     *
1015     * @var string
1016     */
1017    public $shortname = 'x';
1018
1019    /**
1020     * Length of a URL on X.
1021     * https://developer.twitter.com/en/docs/tco
1022     *
1023     * @var int
1024     */
1025    public $short_url_length = 24;
1026
1027    /**
1028     * Service name.
1029     *
1030     * @return string
1031     */
1032    public function get_name() {
1033        return __( 'X', 'jetpack' );
1034    }
1035
1036    /**
1037     * Determine the X 'via' value for a post.
1038     *
1039     * @param  WP_Post|int $post Post object or post ID.
1040     * @return string X handle without the preceding @.
1041     **/
1042    public static function sharing_x_via( $post ) {
1043        $post = get_post( $post );
1044        /** This filter is documented in modules/sharedaddy/sharing-sources.php */
1045        $twitter_site_tag_value = apply_filters(
1046            'jetpack_twitter_cards_site_tag',
1047            '',
1048            /** This action is documented in modules/sharedaddy/sharing-sources.php */
1049            array( 'twitter:creator' => apply_filters( 'jetpack_sharing_twitter_via', '', $post->ID ) )
1050        );
1051
1052        /*
1053         * Hack to remove the unwanted behavior of adding 'via @jetpack' which
1054         * was introduced with the adding of the Twitter cards.
1055         * This should be a temporary solution until a better method is setup.
1056         */
1057        if ( 'jetpack' === $twitter_site_tag_value ) {
1058            $twitter_site_tag_value = '';
1059        }
1060
1061        /** This filter is documented in modules/sharedaddy/sharing-sources.php */
1062        $twitter_site_tag_value = apply_filters( 'jetpack_sharing_twitter_via', $twitter_site_tag_value, $post->ID );
1063
1064        // Strip out anything other than a letter, number, or underscore.
1065        // This will prevent the inadvertent inclusion of an extra @, as well as normalizing the handle.
1066        return preg_replace( '/[^\da-z_]+/i', '', $twitter_site_tag_value );
1067    }
1068
1069    /**
1070     * Determine the 'related' X accounts for a post.
1071     *
1072     * @param  WP_Post|int $post Post object or post ID.
1073     * @return string Comma-separated list of X handles.
1074     **/
1075    public static function get_related_accounts( $post ) {
1076        $post = get_post( $post );
1077        /** This filter is documented in modules/sharedaddy/sharing-sources.php */
1078        $related_accounts = apply_filters( 'jetpack_sharing_twitter_related', array(), $post->ID );
1079
1080        // Example related string: account1,account2:Account 2 description,account3
1081        $related = array();
1082
1083        foreach ( $related_accounts as $related_account_username => $related_account_description ) {
1084            // Join the description onto the end of the username
1085            if ( $related_account_description ) {
1086                $related_account_username .= ':' . $related_account_description;
1087            }
1088
1089            $related[] = $related_account_username;
1090        }
1091
1092        return implode( ',', $related );
1093    }
1094
1095    /**
1096     * Process sharing request. Add actions that need to happen when sharing here.
1097     *
1098     * @param WP_Post $post Post object.
1099     * @param array   $post_data Array of information about the post we're sharing.
1100     *
1101     * @return void
1102     */
1103    public function process_request( $post, array $post_data ) {
1104        $post_title = $this->get_share_title( $post->ID );
1105        $post_link  = $this->get_share_url( $post->ID );
1106
1107        if ( function_exists( 'mb_stripos' ) ) {
1108            $strlen = 'mb_strlen';
1109            $substr = 'mb_substr';
1110        } else {
1111            $strlen = 'strlen';
1112            $substr = 'substr';
1113        }
1114
1115        $via     = static::sharing_x_via( $post );
1116        $related = static::get_related_accounts( $post );
1117        if ( $via ) {
1118            $sig = " via @$via";
1119            if ( $related === $via ) {
1120                $related = false;
1121            }
1122        } else {
1123            $via = false;
1124            $sig = '';
1125        }
1126
1127        $suffix_length = $this->short_url_length + $strlen( $sig );
1128        // $sig is handled by twitter in their 'via' argument.
1129        // $post_link is handled by twitter in their 'url' argument.
1130        if ( 280 < $strlen( $post_title ) + $suffix_length ) {
1131            // The -1 is for "\xE2\x80\xA6", a UTF-8 ellipsis.
1132            $text = $substr( $post_title, 0, 280 - $suffix_length - 1 ) . "\xE2\x80\xA6";
1133        } else {
1134            $text = $post_title;
1135        }
1136
1137        // Record stats
1138        parent::process_request( $post, $post_data );
1139
1140        $url         = $post_link;
1141        $twitter_url = add_query_arg(
1142            rawurlencode_deep( array_filter( compact( 'via', 'related', 'text', 'url' ) ) ),
1143            'https://x.com/intent/tweet'
1144        );
1145
1146        parent::redirect_request( $twitter_url );
1147    }
1148}
1149
1150/**
1151 * Twitter sharing button.
1152 */
1153class Share_Twitter_Block extends Sharing_Source_Block {
1154    /**
1155     * Service short name.
1156     *
1157     * @var string
1158     */
1159    public $shortname = 'twitter';
1160
1161    /**
1162     * Length of a URL on Twitter.
1163     * 'https://dev.twitter.com/rest/reference/get/help/configuration'
1164     * ( 2015/02/06 ) short_url_length is 22, short_url_length_https is 23
1165     *
1166     * @var int
1167     */
1168    public $short_url_length = 24;
1169
1170    /**
1171     * Service name.
1172     *
1173     * @return string
1174     */
1175    public function get_name() {
1176        return __( 'X', 'jetpack' );
1177    }
1178
1179    /**
1180     * Determine the Twitter 'via' value for a post.
1181     *
1182     * @param  WP_Post|int $post Post object or post ID.
1183     * @return string Twitter handle without the preceding @.
1184     **/
1185    public static function sharing_twitter_via( $post ) {
1186        $post = get_post( $post );
1187        /**
1188         * Allow third-party plugins to customize the Twitter username used as "twitter:site" Twitter Card Meta Tag.
1189         *
1190         * @module sharedaddy
1191         *
1192         * @since 3.0.0
1193         *
1194         * @param string $string Twitter Username.
1195         * @param array $args Array of Open Graph Meta Tags and Twitter Cards tags.
1196         */
1197        $twitter_site_tag_value = apply_filters(
1198            'jetpack_twitter_cards_site_tag',
1199            '',
1200            /** This action is documented in modules/sharedaddy/sharing-sources.php */
1201            array( 'twitter:creator' => apply_filters( 'jetpack_sharing_twitter_via', '', $post->ID ) )
1202        );
1203
1204        /*
1205         * Hack to remove the unwanted behavior of adding 'via @jetpack' which
1206         * was introduced with the adding of the Twitter cards.
1207         * This should be a temporary solution until a better method is setup.
1208         */
1209        if ( 'jetpack' === $twitter_site_tag_value ) {
1210            $twitter_site_tag_value = '';
1211        }
1212
1213        /**
1214         * Filters the Twitter username used as "via" in the Twitter sharing button.
1215         *
1216         * @module sharedaddy
1217         *
1218         * @since 1.7.0
1219         *
1220         * @param string $twitter_site_tag_value Twitter Username.
1221         * @param int $post->ID Post ID.
1222         */
1223        $twitter_site_tag_value = apply_filters( 'jetpack_sharing_twitter_via', $twitter_site_tag_value, $post->ID );
1224
1225        // Strip out anything other than a letter, number, or underscore.
1226        // This will prevent the inadvertent inclusion of an extra @, as well as normalizing the handle.
1227        return preg_replace( '/[^\da-z_]+/i', '', $twitter_site_tag_value );
1228    }
1229
1230    /**
1231     * Determine the 'related' Twitter accounts for a post.
1232     *
1233     * @param  WP_Post|int $post Post object or post ID.
1234     * @return string Comma-separated list of Twitter handles.
1235     **/
1236    public static function get_related_accounts( $post ) {
1237        $post = get_post( $post );
1238        /**
1239         * Filter the list of related Twitter accounts added to the Twitter sharing button.
1240         *
1241         * @module sharedaddy
1242         *
1243         * @since 1.7.0
1244         *
1245         * @param array $args Array of Twitter usernames. Format is 'username' => 'Optional description'
1246         * @param int $post->ID Post ID.
1247         */
1248        $related_accounts = apply_filters( 'jetpack_sharing_twitter_related', array(), $post->ID );
1249
1250        // Example related string: account1,account2:Account 2 description,account3
1251        $related = array();
1252
1253        foreach ( $related_accounts as $related_account_username => $related_account_description ) {
1254            // Join the description onto the end of the username
1255            if ( $related_account_description ) {
1256                $related_account_username .= ':' . $related_account_description;
1257            }
1258
1259            $related[] = $related_account_username;
1260        }
1261
1262        return implode( ',', $related );
1263    }
1264
1265    /**
1266     * Process sharing request. Add actions that need to happen when sharing here.
1267     *
1268     * @param WP_Post $post Post object.
1269     * @param array   $post_data Array of information about the post we're sharing.
1270     *
1271     * @return void
1272     */
1273    public function process_request( $post, array $post_data ) {
1274        $post_title = $this->get_share_title( $post->ID );
1275        $post_link  = $this->get_share_url( $post->ID );
1276
1277        if ( function_exists( 'mb_stripos' ) ) {
1278            $strlen = 'mb_strlen';
1279            $substr = 'mb_substr';
1280        } else {
1281            $strlen = 'strlen';
1282            $substr = 'substr';
1283        }
1284
1285        $via     = static::sharing_twitter_via( $post );
1286        $related = static::get_related_accounts( $post );
1287        if ( $via ) {
1288            $sig = " via @$via";
1289            if ( $related === $via ) {
1290                $related = false;
1291            }
1292        } else {
1293            $via = false;
1294            $sig = '';
1295        }
1296
1297        $suffix_length = $this->short_url_length + $strlen( $sig );
1298        // $sig is handled by twitter in their 'via' argument.
1299        // $post_link is handled by twitter in their 'url' argument.
1300        if ( 280 < $strlen( $post_title ) + $suffix_length ) {
1301            // The -1 is for "\xE2\x80\xA6", a UTF-8 ellipsis.
1302            $text = $substr( $post_title, 0, 280 - $suffix_length - 1 ) . "\xE2\x80\xA6";
1303        } else {
1304            $text = $post_title;
1305        }
1306
1307        // Record stats
1308        parent::process_request( $post, $post_data );
1309
1310        $url         = $post_link;
1311        $twitter_url = add_query_arg(
1312            rawurlencode_deep( array_filter( compact( 'via', 'related', 'text', 'url' ) ) ),
1313            'https://x.com/intent/tweet'
1314        );
1315
1316        parent::redirect_request( $twitter_url );
1317    }
1318}
1319
1320/**
1321 * Reddit sharing button.
1322 */
1323class Share_Reddit_Block extends Sharing_Source_Block {
1324    /**
1325     * Service short name.
1326     *
1327     * @var string
1328     */
1329    public $shortname = 'reddit';
1330
1331    /**
1332     * Service name.
1333     *
1334     * @return string
1335     */
1336    public function get_name() {
1337        return __( 'Reddit', 'jetpack' );
1338    }
1339
1340    /**
1341     * Process sharing request. Add actions that need to happen when sharing here.
1342     *
1343     * @param WP_Post $post Post object.
1344     * @param array   $post_data Array of information about the post we're sharing.
1345     *
1346     * @return void
1347     */
1348    public function process_request( $post, array $post_data ) {
1349        $reddit_url = $this->http() . '://reddit.com/submit?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $this->get_share_title( $post->ID ) );
1350
1351        // Record stats
1352        parent::process_request( $post, $post_data );
1353
1354        parent::redirect_request( $reddit_url );
1355    }
1356}
1357
1358/**
1359 * LinkedIn sharing button.
1360 */
1361class Share_LinkedIn_Block extends Sharing_Source_Block {
1362    /**
1363     * Service short name.
1364     *
1365     * @var string
1366     */
1367    public $shortname = 'linkedin';
1368
1369    /**
1370     * Service name.
1371     *
1372     * @return string
1373     */
1374    public function get_name() {
1375        return __( 'LinkedIn', 'jetpack' );
1376    }
1377
1378    /**
1379     * Process sharing request. Add actions that need to happen when sharing here.
1380     *
1381     * @param WP_Post $post Post object.
1382     * @param array   $post_data Array of information about the post we're sharing.
1383     *
1384     * @return void
1385     */
1386    public function process_request( $post, array $post_data ) {
1387
1388        $post_link = $this->get_share_url( $post->ID );
1389
1390        $linkedin_url = add_query_arg(
1391            array(
1392                'url' => rawurlencode( $post_link ),
1393            ),
1394            'https://www.linkedin.com/sharing/share-offsite/'
1395        );
1396
1397        // Record stats
1398        parent::process_request( $post, $post_data );
1399
1400        parent::redirect_request( $linkedin_url );
1401    }
1402}
1403
1404/**
1405 * Threads sharing button.
1406 */
1407class Share_Threads_Block extends Sharing_Source_Block {
1408    /**
1409     * Service short name.
1410     *
1411     * @var string
1412     */
1413    public $shortname = 'threads';
1414
1415    /**
1416     * Service name.
1417     *
1418     * @return string
1419     */
1420    public function get_name() {
1421        return __( 'Threads', 'jetpack' );
1422    }
1423
1424    /**
1425     * Process sharing request. Add actions that need to happen when sharing here.
1426     *
1427     * @param WP_Post $post Post object.
1428     * @param array   $post_data Array of information about the post we're sharing.
1429     *
1430     * @return void
1431     */
1432    public function process_request( $post, array $post_data ) {
1433        // Record stats
1434        parent::process_request( $post, $post_data );
1435
1436        $url  = 'https://www.threads.net/intent/post/?text=';
1437        $url .= rawurlencode( $this->get_share_title( $post->ID ) . ' ' . $this->get_share_url( $post->ID ) );
1438
1439        parent::redirect_request( $url );
1440    }
1441}