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