Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
9.20% covered (danger)
9.20%
15 / 163
35.29% covered (danger)
35.29%
6 / 17
CRAP
n/a
0 / 0
jetpack_deprecated_function
13.33% covered (danger)
13.33%
2 / 15
0.00% covered (danger)
0.00%
0 / 1
49.66
jetpack_deprecated_file
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
42
jetpack_get_future_removed_version
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
jetpack_is_atomic_site
n/a
0 / 0
n/a
0 / 0
1
jetpack_register_migration_post_type
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
jetpack_migration_post_exists
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
6
jetpack_store_migration_data
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
6
jetpack_get_migration_data
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
jetpack_render_tos_blurb
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
2
jetpack_theme_update
11.11% covered (danger)
11.11%
2 / 18
0.00% covered (danger)
0.00%
0 / 1
15.24
jetpack_upgrader_pre_download
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
jetpack_json_wrap
n/a
0 / 0
n/a
0 / 0
1
jetpack_mime_content_type
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
jetpack_is_file_supported_for_sideloading
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
12
jetpack_get_vary_headers
n/a
0 / 0
n/a
0 / 0
1
jetpack_is_frontend
n/a
0 / 0
n/a
0 / 0
1
jetpack_mastodon_get_instance_list
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
2
1<?php // phpcs:ignore WordPress.Files.FileName.NotHyphenatedLowercase
2/**
3 * This file is meant to be the home for any generic & reusable functions
4 * that can be accessed anywhere within Jetpack.
5 *
6 * This file is loaded whether Jetpack is active.
7 *
8 * Please namespace with jetpack_
9 *
10 * @package automattic/jetpack
11 */
12
13use Automattic\Jetpack\Connection\Client;
14use Automattic\Jetpack\Redirect;
15use Automattic\Jetpack\Status\Host;
16use Automattic\Jetpack\Status\Request;
17use Automattic\Jetpack\Sync\Functions;
18
19// Disable direct access.
20if ( ! defined( 'ABSPATH' ) ) {
21    exit( 0 );
22}
23
24require_once __DIR__ . '/functions.is-mobile.php';
25
26/**
27 * Hook into Core's _deprecated_function
28 * Add more details about when a deprecated function will be removed.
29 *
30 * @since 8.8.0
31 *
32 * @param string $function    The function that was called.
33 * @param string $replacement Optional. The function that should have been called. Default null.
34 * @param string $version     The version of Jetpack that deprecated the function.
35 */
36function jetpack_deprecated_function( $function, $replacement, $version ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
37    // Bail early for non-Jetpack deprecations.
38    if ( ! str_starts_with( $version, 'jetpack-' ) ) {
39        return;
40    }
41
42    // Look for when a function will be removed based on when it was deprecated.
43    $removed_version = jetpack_get_future_removed_version( $version );
44
45    // If we could find a version, let's log a message about when removal will happen.
46    if (
47        ! empty( $removed_version )
48        && ( defined( 'WP_DEBUG' ) && WP_DEBUG )
49        /** This filter is documented in core/src/wp-includes/functions.php */
50        && apply_filters( 'deprecated_function_trigger_error', true )
51    ) {
52        error_log( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
53            sprintf(
54                doing_action( 'after_setup_theme' ) || did_action( 'after_setup_theme' ) ?
55                    /* Translators: 1. Function name. 2. Jetpack version number. */
56                    __( 'The %1$s function will be removed from the Jetpack plugin in version %2$s.', 'jetpack' )
57                    : 'The %1$s function will be removed from the Jetpack plugin in version %2$s.',
58                $function,
59                $removed_version
60            )
61        );
62
63    }
64}
65add_action( 'deprecated_function_run', 'jetpack_deprecated_function', 10, 3 );
66
67/**
68 * Hook into Core's _deprecated_file
69 * Add more details about when a deprecated file will be removed.
70 *
71 * @since 8.8.0
72 *
73 * @param string $file        The file that was called.
74 * @param string $replacement The file that should have been included based on ABSPATH.
75 * @param string $version     The version of WordPress that deprecated the file.
76 * @param string $message     A message regarding the change.
77 */
78function jetpack_deprecated_file( $file, $replacement, $version, $message ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
79    // Bail early for non-Jetpack deprecations.
80    if ( ! str_starts_with( $version, 'jetpack-' ) ) {
81        return;
82    }
83
84    // Look for when a file will be removed based on when it was deprecated.
85    $removed_version = jetpack_get_future_removed_version( $version );
86
87    // If we could find a version, let's log a message about when removal will happen.
88    if (
89        ! empty( $removed_version )
90        && ( defined( 'WP_DEBUG' ) && WP_DEBUG )
91        /** This filter is documented in core/src/wp-includes/functions.php */
92        && apply_filters( 'deprecated_file_trigger_error', true )
93    ) {
94        error_log( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
95            sprintf(
96                /* Translators: 1. File name. 2. Jetpack version number. */
97                __( 'The %1$s file will be removed from the Jetpack plugin in version %2$s.', 'jetpack' ),
98                $file,
99                $removed_version
100            )
101        );
102
103    }
104}
105add_action( 'deprecated_file_included', 'jetpack_deprecated_file', 10, 4 );
106
107/**
108 * Get the major version number of Jetpack 6 months after provided version.
109 * Useful to indicate when a deprecated function will be removed from Jetpack.
110 *
111 * @since 8.8.0
112 *
113 * @param string $version The version of WordPress that deprecated the function.
114 *
115 * @return bool|float Return a Jetpack Major version number, or false.
116 */
117function jetpack_get_future_removed_version( $version ) {
118    /*
119     * Extract the version number from a deprecation notice.
120     * (let's only keep the first decimal, e.g. 8.8 and not 8.8.0)
121     */
122    preg_match( '#(([0-9]+\.([0-9]+))(?:\.[0-9]+)*)#', $version, $matches );
123
124    if ( isset( $matches[2] ) && isset( $matches[3] ) ) {
125        $deprecated_version = (float) $matches[2];
126        $deprecated_minor   = (float) $matches[3];
127
128        /*
129         * If the detected minor version number
130         * (e.g. "7" in "8.7")
131         * is higher than 9, we know the version number is malformed.
132         * Jetpack does not use semver yet.
133         * Bail.
134         */
135        if ( 10 <= $deprecated_minor ) {
136            return false;
137        }
138
139        // We'll remove the function from the code 6 months later, thus 6 major versions later.
140        $removed_version = $deprecated_version + 0.6;
141
142        return $removed_version;
143    }
144
145    return false;
146}
147
148/**
149 * Determine if this site is an WoA site or not by looking for presence of the wpcomsh plugin.
150 *
151 * @since 4.8.1
152 * @deprecated 10.3.0
153 *
154 * @return bool
155 */
156function jetpack_is_atomic_site() {
157    jetpack_deprecated_function( __FUNCTION__, 'Automattic/Jetpack/Status/Host::is_woa_site', 'jetpack-10.3.0' );
158    return ( new Host() )->is_woa_site();
159}
160
161/**
162 * Register post type for migration.
163 *
164 * @since 5.2
165 */
166function jetpack_register_migration_post_type() {
167    register_post_type(
168        'jetpack_migration',
169        array(
170            'supports'     => array(),
171            'taxonomies'   => array(),
172            'hierarchical' => false,
173            'public'       => false,
174            'has_archive'  => false,
175            'can_export'   => true,
176        )
177    );
178}
179
180/**
181 * Checks whether the Post DB threat currently exists on the site.
182 *
183 * @since 12.0
184 *
185 * @param string $option_name  Option name.
186 *
187 * @return WP_Post|bool
188 */
189function jetpack_migration_post_exists( $option_name ) {
190    $query = new WP_Query(
191        array(
192            'post_type'              => 'jetpack_migration',
193            'title'                  => $option_name,
194            'post_status'            => 'all',
195            'posts_per_page'         => 1,
196            'no_found_rows'          => true,
197            'ignore_sticky_posts'    => true,
198            'update_post_term_cache' => false,
199            'update_post_meta_cache' => false,
200            'orderby'                => 'post_date ID',
201            'order'                  => 'ASC',
202        )
203    );
204    if ( ! empty( $query->post ) ) {
205        return $query->post;
206    }
207
208    return false;
209}
210
211/**
212 * Stores migration data in the database.
213 *
214 * @since 5.2
215 *
216 * @param string $option_name  Option name.
217 * @param bool   $option_value Option value.
218 *
219 * @return int|WP_Error
220 */
221function jetpack_store_migration_data( $option_name, $option_value ) {
222    jetpack_register_migration_post_type();
223
224    $insert = array(
225        'post_title'            => $option_name,
226        'post_content_filtered' => $option_value,
227        'post_type'             => 'jetpack_migration',
228        'post_date'             => gmdate( 'Y-m-d H:i:s', time() ),
229    );
230
231    $migration_post = jetpack_migration_post_exists( $option_name );
232    if ( $migration_post ) {
233        $insert['ID'] = $migration_post->ID;
234    }
235
236    return wp_insert_post( $insert, true );
237}
238
239/**
240 * Retrieves legacy image widget data.
241 *
242 * @since 5.2
243 *
244 * @param string $option_name Option name.
245 *
246 * @return mixed|null
247 */
248function jetpack_get_migration_data( $option_name ) {
249    $post = jetpack_migration_post_exists( $option_name );
250
251    return null !== $post ? maybe_unserialize( $post->post_content_filtered ) : null;
252}
253
254/**
255 * Prints a TOS blurb used throughout the connection prompts.
256 *
257 * @since 5.3
258 *
259 * @echo string
260 */
261function jetpack_render_tos_blurb() {
262    printf(
263        wp_kses(
264            /* Translators: placeholders are links. */
265            __( 'By clicking <strong>Set up Jetpack</strong>, you agree to our <a href="%1$s" target="_blank" rel="noopener noreferrer">Terms of Service</a> and to <a href="%2$s" target="_blank" rel="noopener noreferrer">sync your site‘s data</a> with us.', 'jetpack' ),
266            array(
267                'a'      => array(
268                    'href'   => array(),
269                    'target' => array(),
270                    'rel'    => array(),
271                ),
272                'strong' => true,
273            )
274        ),
275        esc_url( Redirect::get_url( 'wpcom-tos' ) ),
276        esc_url( Redirect::get_url( 'jetpack-support-what-data-does-jetpack-sync' ) )
277    );
278}
279
280/**
281 * Intervene upgrade process so Jetpack themes are downloaded with credentials.
282 *
283 * @since 5.3
284 *
285 * @param bool   $preempt Whether to preempt an HTTP request's return value. Default false.
286 * @param array  $r       HTTP request arguments.
287 * @param string $url     The request URL.
288 *
289 * @return array|bool|WP_Error
290 */
291function jetpack_theme_update( $preempt, $r, $url ) {
292    if ( 0 === stripos( $url, JETPACK__WPCOM_JSON_API_BASE . '/rest/v1/themes/download' ) ) {
293        $file = $r['filename'];
294        if ( ! $file ) {
295            return new WP_Error( 'problem_creating_theme_file', esc_html__( 'Problem creating file for theme download', 'jetpack' ) );
296        }
297        $theme = pathinfo( wp_parse_url( $url, PHP_URL_PATH ), PATHINFO_FILENAME );
298
299        // Remove filter to avoid endless loop since wpcom_json_api_request_as_blog uses this too.
300        remove_filter( 'pre_http_request', 'jetpack_theme_update' );
301        $result = Client::wpcom_json_api_request_as_blog(
302            "themes/download/$theme.zip",
303            '1.1',
304            array(
305                'stream'   => true,
306                'filename' => $file,
307            )
308        );
309
310        if ( 200 !== wp_remote_retrieve_response_code( $result ) ) {
311            return new WP_Error( 'problem_fetching_theme', esc_html__( 'Problem downloading theme', 'jetpack' ) );
312        }
313        return $result;
314    }
315    return $preempt;
316}
317
318/**
319 * Add the filter when a upgrade is going to be downloaded.
320 *
321 * @since 5.3
322 *
323 * @param bool $reply Whether to bail without returning the package. Default false.
324 *
325 * @return bool
326 */
327function jetpack_upgrader_pre_download( $reply ) {
328    add_filter( 'pre_http_request', 'jetpack_theme_update', 10, 3 );
329    return $reply;
330}
331
332add_filter( 'upgrader_pre_download', 'jetpack_upgrader_pre_download' );
333
334/**
335 * Wraps data in a way so that we can distinguish between objects and array and also prevent object recursion.
336 *
337 * @since 6.1.0
338
339 * @deprecated Automattic\Jetpack\Sync\Functions::json_wrap
340 *
341 * @param mixed $any        Source data to be cleaned up.
342 * @param array $seen_nodes Built array of nodes.
343 *
344 * @return array
345 */
346function jetpack_json_wrap( &$any, $seen_nodes = array() ) {
347    _deprecated_function( __METHOD__, 'jetpack-9.5', 'Automattic\Jetpack\Sync\Functions' );
348
349    return Functions::json_wrap( $any, $seen_nodes );
350}
351
352/**
353 * Checks if the mime_content_type function is available and return it if so.
354 *
355 * The function mime_content_type is enabled by default in PHP, but can be disabled. We attempt to
356 * enforce this via composer.json, but that won't be checked in majority of cases where
357 * this would be happening.
358 *
359 * @since 7.8.0
360 *
361 * @param string $file File location.
362 *
363 * @return string|false MIME type or false if functionality is not available.
364 */
365function jetpack_mime_content_type( $file ) {
366    if ( function_exists( 'mime_content_type' ) ) {
367        return mime_content_type( $file );
368    }
369
370    return false;
371}
372
373/**
374 * Checks that the mime type of the specified file is among those in a filterable list of mime types.
375 *
376 * @since 7.8.0
377 *
378 * @param string $file Path to file to get its mime type.
379 *
380 * @return bool
381 */
382function jetpack_is_file_supported_for_sideloading( $file ) {
383    $type = jetpack_mime_content_type( $file );
384
385    if ( ! $type ) {
386        return false;
387    }
388
389    /**
390     * Filter the list of supported mime types for media sideloading.
391     *
392     * @since 4.0.0
393     *
394     * @module json-api
395     *
396     * @param array $supported_mime_types Array of the supported mime types for media sideloading.
397     */
398    $supported_mime_types = apply_filters(
399        'jetpack_supported_media_sideload_types',
400        array(
401            'image/png',
402            'image/jpeg',
403            'image/gif',
404            'image/bmp',
405            'image/webp',
406            'video/quicktime',
407            'video/mp4',
408            'video/mpeg',
409            'video/ogg',
410            'video/3gpp',
411            'video/3gpp2',
412            'video/h261',
413            'video/h262',
414            'video/h264',
415            'video/x-msvideo',
416            'video/x-ms-wmv',
417            'video/x-ms-asf',
418        )
419    );
420
421    // If the type returned was not an array as expected, then we know we don't have a match.
422    if ( ! is_array( $supported_mime_types ) ) {
423        return false;
424    }
425
426    return in_array( $type, $supported_mime_types, true );
427}
428
429/**
430 * Go through headers and get a list of Vary headers to add,
431 * including a Vary Accept header if necessary.
432 *
433 * @since 12.2
434 * @deprecated 14.8
435 *
436 * @param array $headers The headers to be sent.
437 *
438 * @return array $vary_header_parts Vary Headers to be sent.
439 */
440function jetpack_get_vary_headers( $headers = array() ) {
441    _deprecated_function( __FUNCTION__, '14.8', 'Automattic\Jetpack\Status\Request::get_vary_headers' );
442
443    return ( new Request() )->get_vary_headers( $headers );
444}
445
446/**
447 * Determine whether the current request is for accessing the frontend.
448 * Also update Vary headers to indicate that the response may vary by Accept header.
449 *
450 * @deprecated 14.8
451 *
452 * @return bool True if it's a frontend request, false otherwise.
453 */
454function jetpack_is_frontend() {
455    _deprecated_function( __FUNCTION__, '14.8', 'Automattic\Jetpack\Status\Request::is_frontend' );
456
457    return Request::is_frontend();
458}
459
460if ( ! function_exists( 'jetpack_mastodon_get_instance_list' ) ) {
461    /**
462     * Build a list of Mastodon instance hosts.
463     * That list can be extended via a filter.
464     *
465     * @todo This function is now replicated in the Classic Theme Helper package and can be
466     * removed here once Social Links are moved out of Jetpack.
467     *
468     * @since 11.8
469     *
470     * @return array
471     */
472    function jetpack_mastodon_get_instance_list() {
473        $mastodon_instance_list = array(
474            // Regex pattern to match any .tld for the mastodon host name.
475            '#https?:\/\/(www\.)?mastodon\.(\w+)(\.\w+)?#',
476            // Regex pattern to match any .tld for the mstdn host name.
477            '#https?:\/\/(www\.)?mstdn\.(\w+)(\.\w+)?#',
478            'counter.social',
479            'fosstodon.org',
480            'gc2.jp',
481            'hachyderm.io',
482            'infosec.exchange',
483            'mas.to',
484            'pawoo.net',
485        );
486
487        /**
488         * Filter the list of Mastodon instances.
489         *
490         * @since 11.8
491         *
492         * @module widgets, theme-tools
493         *
494         * @param array $mastodon_instance_list Array of Mastodon instances.
495         */
496        return (array) apply_filters( 'jetpack_mastodon_instance_list', $mastodon_instance_list );
497    }
498}