Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
53.85% covered (warning)
53.85%
14 / 26
40.00% covered (danger)
40.00%
2 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Jetpack_Script_Data
53.85% covered (warning)
53.85%
14 / 26
40.00% covered (danger)
40.00%
2 / 5
29.62
0.00% covered (danger)
0.00%
0 / 1
 configure
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 set_admin_script_data
72.73% covered (warning)
72.73%
8 / 11
0.00% covered (danger)
0.00%
0 / 1
3.18
 theme_supports_infinite_scroll
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
30
 is_settings_consolidation_enabled
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 should_skip_photon_domain
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3 * Jetpack_Script_Data.
4 *
5 * Adds Jetpack-plugin-specific data to the consolidated JetpackScriptData object.
6 *
7 * @package automattic/jetpack
8 */
9
10namespace Automattic\Jetpack\Plugin;
11
12use Automattic\Jetpack\Current_Plan as Jetpack_Plan;
13use Automattic\Jetpack\My_Jetpack\Initializer as My_Jetpack_Initializer;
14
15/**
16 * Jetpack_Script_Data class.
17 */
18class Jetpack_Script_Data {
19
20    /**
21     * Configure script data.
22     */
23    public static function configure() {
24        add_filter( 'jetpack_admin_js_script_data', array( __CLASS__, 'set_admin_script_data' ), 10, 1 );
25    }
26
27    /**
28     * Add Jetpack-plugin-specific data to the consolidated JetpackScriptData object.
29     *
30     * @since 15.6
31     *
32     * @param array $data The script data.
33     * @return array
34     */
35    public static function set_admin_script_data( $data ) {
36        /**
37         * Whether to show the Jetpack branding in editor panels (e.g., SEO, AI Assistant).
38         *
39         * @since 15.6
40         *
41         * @param bool $show Whether to show the Jetpack editor panel branding. Defaults to true.
42         */
43        $data['jetpack'] = array(
44            'flags' => array(
45                'showJetpackBranding' => (bool) apply_filters( 'jetpack_show_editor_panel_branding', true ),
46                'skipPhotonDomain'    => self::should_skip_photon_domain( $data ),
47            ),
48        );
49
50        // Only the settings panel in My Jetpack reads it, so skip the theme folder scan elsewhere.
51        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Only selects which data to print.
52        if ( 'my-jetpack' === sanitize_key( wp_unslash( $_GET['page'] ?? '' ) ) && self::is_settings_consolidation_enabled() ) {
53            $data['jetpack']['themeSupports'] = array(
54                'infiniteScroll' => self::theme_supports_infinite_scroll(),
55            );
56        }
57
58        return $data;
59    }
60
61    /**
62     * Whether the current theme supports Infinite Scroll, by itself or through a file Jetpack ships for it.
63     *
64     * @since $$next-version$$
65     *
66     * @return bool
67     */
68    public static function theme_supports_infinite_scroll() {
69        if ( current_theme_supports( 'infinite-scroll' ) ) {
70            return true;
71        }
72
73        $stylesheet = wp_get_theme()->get_stylesheet();
74        foreach ( \Jetpack::glob_php( JETPACK__PLUGIN_DIR . 'modules/infinite-scroll/themes' ) as $path ) {
75            if ( basename( $path, '.php' ) === $stylesheet && is_readable( $path ) ) {
76                return true;
77            }
78        }
79
80        return false;
81    }
82
83    /**
84     * Whether settings move to My Jetpack. False with a My Jetpack too old to know the flag.
85     *
86     * @return bool
87     */
88    private static function is_settings_consolidation_enabled() {
89        return method_exists( My_Jetpack_Initializer::class, 'is_settings_consolidation_enabled' )
90            && My_Jetpack_Initializer::is_settings_consolidation_enabled();
91    }
92
93    /**
94     * Whether image-serving blocks should skip the external Photon domain (i0.wp.com) and build
95     * URLs on the site's own Photon-like host instead.
96     *
97     * VIP sites serve images from a host of their own, and images routed through the public Photon
98     * domain are not reachable there.
99     *
100     * This is read by the Tiled Gallery block's skipPhotonDomain(), which runs inside the block's
101     * save() output — including when the editor regenerates that output to validate saved content.
102     * That regeneration happens while the post is being parsed, before any editor store holds
103     * settings, so the value has to travel in the script data rather than in editor settings.
104     *
105     * The signal is the plan slug rather than Host::is_vip_site(): it is what the block's previous
106     * isVIP() check used, and switching to the WPCOM_IS_VIP_ENV constant would change which sites get
107     * site-host URLs — and so which existing galleries need a deprecation to stay valid.
108     *
109     * @since 16.2
110     *
111     * @param array $data The script data, which may already carry the site plan.
112     * @return bool
113     */
114    private static function should_skip_photon_domain( $data ) {
115        // Another package may have put the plan in the payload already (see Publicize_Script_Data);
116        // only look it up when it hasn't.
117        $product_slug = $data['site']['plan']['product_slug'] ?? '';
118        if ( '' === $product_slug ) {
119            $jetpack_plan = Jetpack_Plan::get();
120            $product_slug = $jetpack_plan['product_slug'];
121        }
122
123        /**
124         * Filter whether the Tiled Gallery and Image Compare blocks should skip the external
125         * Photon (i0.wp.com) domain and build image URLs on the site's own host instead.
126         *
127         * Defaults to true on VIP sites only, and false everywhere else.
128         *
129         * Changing this changes the markup Tiled Gallery saves, because it bakes the image URLs into its
130         * save() output. Galleries saved under the previous value stay valid — the block ships a
131         * deprecation for each image host, so flipping this either way is safe — and they are
132         * re-serialized with the new URLs the next time they are saved.
133         *
134         * Image Compare only uses this for its editor previews; its save() writes the attachment URLs
135         * through untouched, so its saved markup does not depend on this value.
136         *
137         * @module tiled-gallery
138         *
139         * @since 16.2
140         *
141         * @param bool $skip_photon_domain Whether to skip the external Photon domain.
142         */
143        return (bool) apply_filters( 'jetpack_skip_photon_domain', 'vip' === $product_slug );
144    }
145}