PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 15.9-a.7
Jetpack – WP Security, Backup, Speed, & Growth v15.9-a.7
15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / photon-cdn.php
jetpack / modules Last commit date
canonical-urls 2 months ago carousel 2 days ago comment-likes 6 months ago comments 1 week ago custom-post-types 3 months ago external-media 6 months ago google-fonts 4 months ago gravatar 5 years ago infinite-scroll 1 week ago likes 1 week ago markdown 1 week ago memberships 1 week ago photon-cdn 1 month ago plugin-search 4 weeks ago post-by-email 6 months ago related-posts 2 days ago scan 2 months ago seo-tools 1 week ago sharedaddy 1 week ago shortcodes 1 week ago shortlinks 1 week ago simple-payments 6 months ago site-icon 6 months ago sitemaps 1 week ago stats 5 months ago subscriptions 2 days ago theme-tools 2 weeks ago tiled-gallery 1 week ago verification-tools 2 weeks ago videopress 1 week ago widget-visibility 1 week ago widgets 2 days ago woocommerce-analytics 1 month ago wordads 1 month ago wpcom-tos 5 months ago account-protection.php 1 month ago blaze.php 6 months ago blocks.php 6 months ago canonical-urls.php 3 months ago carousel.php 6 months ago comment-likes.php 6 months ago comments.php 2 months ago contact-form.php 6 months ago copy-post.php 2 weeks ago custom-content-types.php 1 month ago google-fonts.php 1 month ago gravatar-hovercards.php 1 week ago infinite-scroll.php 6 months ago json-api.php 6 months ago latex.php 1 week ago likes.php 4 weeks ago markdown.php 6 months ago module-extras.php 6 months ago module-headings.php 1 week ago module-info.php 3 months ago monitor.php 2 days ago notes.php 5 months ago photon-cdn.php 6 months ago photon.php 6 months ago plugin-search.php 4 weeks ago post-by-email.php 1 month ago post-list.php 6 months ago protect.php 1 month ago publicize.php 6 months ago related-posts.php 2 weeks ago search.php 6 months ago seo-tools.php 6 months ago sharedaddy.php 3 months ago shortcodes.php 6 months ago shortlinks.php 2 weeks ago simple-payments.php 6 months ago sitemaps.php 6 months ago sso.php 6 months ago stats.php 1 week ago subscriptions.php 1 week ago theme-tools.php 6 months ago tiled-gallery.php 6 months ago vaultpress.php 6 months ago verification-tools.php 1 month ago videopress.php 6 months ago waf.php 6 months ago widget-visibility.php 6 months ago widgets.php 6 months ago woocommerce-analytics.php 6 months ago wordads.php 6 months ago wpcom-reader.php 3 months ago wpgroho.js 1 year ago
photon-cdn.php
352 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Module Name: Asset CDN
4 * Module Description: Serve static files like CSS and JS from Jetpack’s global CDN for faster load times.
5 * Sort Order: 26
6 * Recommendation Order: 1
7 * First Introduced: 6.6
8 * Requires Connection: No
9 * Auto Activate: No
10 * Module Tags: Photos and Videos, Appearance, Recommended
11 * Feature: Recommended, Appearance
12 * Additional Search Queries: site accelerator, accelerate, static, assets, javascript, css, files, performance, cdn, bandwidth, content delivery network, pagespeed, combine js, optimize css
13 *
14 * @package automattic/jetpack
15 */
16
17 use Automattic\Jetpack\Assets;
18
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit( 0 );
21 }
22
23 $GLOBALS['concatenate_scripts'] = false; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
24
25 Assets::add_resource_hint( '//c0.wp.com', 'preconnect' );
26
27 /**
28 * Asset CDN module main class file.
29 */
30 class Jetpack_Photon_Static_Assets_CDN {
31 const CDN = 'https://c0.wp.com/';
32
33 /**
34 * Sets up action handlers needed for Jetpack CDN.
35 */
36 public static function go() {
37 add_action( 'wp_print_scripts', array( __CLASS__, 'cdnize_assets' ) );
38 add_action( 'wp_print_styles', array( __CLASS__, 'cdnize_assets' ) );
39 add_action( 'admin_print_scripts', array( __CLASS__, 'cdnize_assets' ) );
40 add_action( 'admin_print_styles', array( __CLASS__, 'cdnize_assets' ) );
41 add_action( 'wp_footer', array( __CLASS__, 'cdnize_assets' ) );
42 add_filter( 'load_script_textdomain_relative_path', array( __CLASS__, 'fix_script_relative_path' ), 10, 2 );
43 add_filter( 'load_script_translation_file', array( __CLASS__, 'fix_local_script_translation_path' ), 10, 3 );
44 }
45
46 /**
47 * Sets up CDN URLs for assets that are enqueued by the WordPress Core.
48 */
49 public static function cdnize_assets() {
50 global $wp_scripts, $wp_styles, $wp_version;
51
52 /*
53 * Short-circuit if AMP since not relevant as custom JS is not allowed and CSS is inlined.
54 * Note that it is not suitable to use the jetpack_force_disable_site_accelerator filter for this
55 * because it will be applied before the wp action, which is the point at which the queried object
56 * is available and we know whether the response will be AMP or not. This is particularly important
57 * for AMP-first (native AMP) pages where there are no AMP-specific URLs.
58 */
59 if ( class_exists( Jetpack_AMP_Support::class ) && Jetpack_AMP_Support::is_amp_request() ) {
60 return;
61 }
62
63 /**
64 * Filters Jetpack CDN's Core version number and locale. Can be used to override the values
65 * that Jetpack uses to retrieve assets. Expects the values to be returned in an array.
66 *
67 * @module photon-cdn
68 *
69 * @since 6.6.0
70 *
71 * @param array $values array( $version = core assets version, i.e. 4.9.8, $locale = desired locale )
72 */
73 list( $version, $locale ) = apply_filters( // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
74 'jetpack_cdn_core_version_and_locale',
75 array( $wp_version, get_locale() )
76 );
77
78 if ( self::is_public_version( $version ) ) {
79 $site_url = trailingslashit( site_url() );
80 if ( $wp_scripts instanceof WP_Scripts && is_array( $wp_scripts->registered ) ) {
81 foreach ( $wp_scripts->registered as $handle => $thing ) {
82 if ( wp_startswith( $thing->src, self::CDN ) ) {
83 continue;
84 }
85 if ( ! is_string( $thing->src ) ) {
86 continue;
87 }
88 $src = ltrim( str_replace( $site_url, '', $thing->src ), '/' );
89 if ( self::is_js_or_css_file( $src ) && in_array( substr( $src, 0, 9 ), array( 'wp-admin/', 'wp-includ' ), true ) ) {
90 $wp_scripts->registered[ $handle ]->src = sprintf( self::CDN . 'c/%1$s/%2$s', $version, $src );
91 $wp_scripts->registered[ $handle ]->ver = null;
92 }
93 }
94 }
95 if ( $wp_styles instanceof WP_Styles && is_array( $wp_styles->registered ) ) {
96 foreach ( $wp_styles->registered as $handle => $thing ) {
97 if ( wp_startswith( $thing->src, self::CDN ) ) {
98 continue;
99 }
100 if ( ! is_string( $thing->src ) ) {
101 continue;
102 }
103 $src = ltrim( str_replace( $site_url, '', $thing->src ), '/' );
104 if ( self::is_js_or_css_file( $src ) && in_array( substr( $src, 0, 9 ), array( 'wp-admin/', 'wp-includ' ), true ) ) {
105 $wp_styles->registered[ $handle ]->src = sprintf( self::CDN . 'c/%1$s/%2$s', $version, $src );
106 $wp_styles->registered[ $handle ]->ver = null;
107 }
108 }
109 }
110 }
111
112 self::cdnize_plugin_assets( 'jetpack', JETPACK__VERSION );
113 if ( class_exists( 'WooCommerce' ) ) {
114 self::cdnize_plugin_assets( 'woocommerce', WC_VERSION );
115 }
116 }
117
118 /**
119 * Ensure use of the correct relative path when determining the JavaScript file names.
120 *
121 * @param string $relative The relative path of the script. False if it could not be determined.
122 * @param string $src The full source url of the script.
123 * @return string The expected relative path for the CDN-ed URL.
124 */
125 public static function fix_script_relative_path( $relative, $src ) {
126
127 // Note relevant in AMP responses. See note above.
128 if ( class_exists( Jetpack_AMP_Support::class ) && Jetpack_AMP_Support::is_amp_request() ) {
129 return $relative;
130 }
131
132 $strpos = strpos( $src, '/wp-includes/' );
133
134 // We only treat URLs that have wp-includes in them. Cases like language textdomains
135 // can also use this filter, they don't need to be touched because they are local paths.
136 if ( false !== $strpos ) {
137 return substr( $src, 1 + $strpos );
138 }
139
140 // Get the local path from a URL which was CDN'ed by cdnize_plugin_assets().
141 if ( preg_match( '#^' . preg_quote( self::CDN, '#' ) . 'p/[^/]+/[^/]+/(.*)$#', $src, $m ) ) {
142 return $m[1];
143 }
144
145 return $relative;
146 }
147
148 /**
149 * Ensure use of the correct local path when loading the JavaScript translation file for a CDN'ed asset.
150 *
151 * @param string|false $file Path to the translation file to load. False if there isn't one.
152 * @param string $handle The script handle.
153 * @param string $domain The text domain.
154 *
155 * @return string The transformed local languages path.
156 */
157 public static function fix_local_script_translation_path( $file, $handle, $domain ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
158 global $wp_scripts;
159
160 // This is a rewritten plugin URL, so load the language file from the plugins path.
161 if ( $file && isset( $wp_scripts->registered[ $handle ] ) && wp_startswith( $wp_scripts->registered[ $handle ]->src, self::CDN . 'p' ) ) {
162 return WP_LANG_DIR . '/plugins/' . basename( $file );
163 }
164
165 return $file;
166 }
167
168 /**
169 * Sets up CDN URLs for supported plugin assets.
170 *
171 * @param String $plugin_slug plugin slug string.
172 * @param String $current_version plugin version string.
173 * @return null|bool
174 */
175 public static function cdnize_plugin_assets( $plugin_slug, $current_version ) {
176 global $wp_scripts, $wp_styles;
177
178 /**
179 * Filters Jetpack CDN's plugin slug and version number. Can be used to override the values
180 * that Jetpack uses to retrieve assets. For example, when testing a development version of Jetpack
181 * the assets are not yet published, so you may need to override the version value to either
182 * trunk, or the latest available version. Expects the values to be returned in an array.
183 *
184 * @module photon-cdn
185 *
186 * @since 6.6.0
187 *
188 * @param array $values array( $slug = the plugin repository slug, i.e. jetpack, $version = the plugin version, i.e. 6.6 )
189 */
190 list( $plugin_slug, $current_version ) = apply_filters(
191 'jetpack_cdn_plugin_slug_and_version',
192 array( $plugin_slug, $current_version )
193 );
194
195 $assets = self::get_plugin_assets( $plugin_slug, $current_version );
196 $plugin_directory_url = plugins_url() . '/' . $plugin_slug . '/';
197
198 if ( is_wp_error( $assets ) || ! is_array( $assets ) ) {
199 return false;
200 }
201
202 if ( $wp_scripts instanceof WP_Scripts && is_array( $wp_scripts->registered ) ) {
203 foreach ( $wp_scripts->registered as $handle => $thing ) {
204 if ( wp_startswith( $thing->src, self::CDN ) ) {
205 continue;
206 }
207 if ( wp_startswith( $thing->src, $plugin_directory_url ) ) {
208 $local_path = substr( $thing->src, strlen( $plugin_directory_url ) );
209 if ( in_array( $local_path, $assets, true ) ) {
210 $wp_scripts->registered[ $handle ]->src = sprintf( self::CDN . 'p/%1$s/%2$s/%3$s', $plugin_slug, $current_version, $local_path );
211 $wp_scripts->registered[ $handle ]->ver = null;
212 }
213 }
214 }
215 }
216 if ( $wp_styles instanceof WP_Styles && is_array( $wp_styles->registered ) ) {
217 foreach ( $wp_styles->registered as $handle => $thing ) {
218 if ( wp_startswith( $thing->src, self::CDN ) ) {
219 continue;
220 }
221 if ( wp_startswith( $thing->src, $plugin_directory_url ) ) {
222 $local_path = substr( $thing->src, strlen( $plugin_directory_url ) );
223 if ( in_array( $local_path, $assets, true ) ) {
224 $wp_styles->registered[ $handle ]->src = sprintf( self::CDN . 'p/%1$s/%2$s/%3$s', $plugin_slug, $current_version, $local_path );
225 $wp_styles->registered[ $handle ]->ver = null;
226 }
227 }
228 }
229 }
230 }
231
232 /**
233 * Returns cdn-able assets for a given plugin.
234 *
235 * @param string $plugin plugin slug string.
236 * @param string $version plugin version number string.
237 * @return array|bool Will return false if not a public version.
238 */
239 public static function get_plugin_assets( $plugin, $version ) {
240 if ( 'jetpack' === $plugin && JETPACK__VERSION === $version ) {
241 if ( ! self::is_public_version( $version ) || ! file_exists( JETPACK__PLUGIN_DIR . 'modules/photon-cdn/jetpack-manifest.php' ) ) {
242 return false;
243 }
244
245 $assets = array(); // The variable will be redefined in the included file.
246
247 include JETPACK__PLUGIN_DIR . 'modules/photon-cdn/jetpack-manifest.php';
248 return $assets;
249 }
250
251 /**
252 * Used for other plugins to provide their bundled assets via filter to
253 * prevent the need of storing them in an option or an external api request
254 * to w.org.
255 *
256 * @module photon-cdn
257 *
258 * @since 6.6.0
259 *
260 * @param array $assets The assets array for the plugin.
261 * @param string $version The version of the plugin being requested.
262 */
263 $assets = apply_filters( "jetpack_cdn_plugin_assets-{$plugin}", null, $version ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
264 if ( is_array( $assets ) ) {
265 return $assets;
266 }
267
268 if ( ! self::is_public_version( $version ) ) {
269 return false;
270 }
271
272 $cache = Jetpack_Options::get_option( 'static_asset_cdn_files', array() );
273 if ( isset( $cache[ $plugin ][ $version ] ) ) {
274 if ( is_array( $cache[ $plugin ][ $version ] ) ) {
275 return $cache[ $plugin ][ $version ];
276 }
277 if ( is_numeric( $cache[ $plugin ][ $version ] ) ) {
278 // Cache an empty result for up to 24h.
279 if ( (int) $cache[ $plugin ][ $version ] + DAY_IN_SECONDS > time() ) {
280 return array();
281 }
282 }
283 }
284
285 $url = sprintf( 'http://downloads.wordpress.org/plugin-checksums/%s/%s.json', $plugin, $version );
286
287 if ( wp_http_supports( array( 'ssl' ) ) ) {
288 $url = set_url_scheme( $url, 'https' );
289 }
290
291 $response = wp_remote_get( $url );
292
293 $body = trim( wp_remote_retrieve_body( $response ) );
294 $body = json_decode( $body, true );
295
296 $return = time();
297 if ( is_array( $body ) && isset( $body['files'] ) && is_array( $body['files'] ) ) {
298 $return = array_filter(
299 array_keys( $body['files'] ),
300 array( __CLASS__, 'is_js_or_css_file' )
301 );
302 }
303
304 $cache[ $plugin ] = array();
305 $cache[ $plugin ][ $version ] = $return;
306 Jetpack_Options::update_option( 'static_asset_cdn_files', $cache, true );
307
308 return $return;
309 }
310
311 /**
312 * Checks a path whether it is a JS or CSS file.
313 *
314 * @param String $path file path.
315 * @return Boolean whether the file is a JS or CSS.
316 */
317 public static function is_js_or_css_file( $path ) {
318 return ( ! str_contains( $path, '?' ) ) && in_array( substr( $path, -3 ), array( 'css', '.js' ), true );
319 }
320
321 /**
322 * Checks whether the version string indicates a production version.
323 *
324 * @param String $version the version string.
325 * @param Boolean $include_beta_and_rc whether to count beta and RC versions as production.
326 * @return Boolean
327 */
328 public static function is_public_version( $version, $include_beta_and_rc = false ) {
329 if ( preg_match( '/^\d+(\.\d+)+$/', $version ) ) {
330 /** Example matches: `1`, `1.2`, `1.2.3`. */
331 return true;
332 } elseif ( $include_beta_and_rc && preg_match( '/^\d+(\.\d+)+(-(beta|rc|pressable)\d?)$/i', $version ) ) {
333 /** Example matches: `1.2.3`, `1.2.3-beta`, `1.2.3-pressable`, `1.2.3-beta1`, `1.2.3-rc`, `1.2.3-rc2`. */
334 return true;
335 }
336 // Unrecognized version.
337 return false;
338 }
339 }
340 /**
341 * Allow plugins to short-circuit the Asset CDN, even when the module is on.
342 *
343 * @module photon-cdn
344 *
345 * @since 6.7.0
346 *
347 * @param false bool Should the Asset CDN be blocked? False by default.
348 */
349 if ( true !== apply_filters( 'jetpack_force_disable_site_accelerator', false ) ) {
350 Jetpack_Photon_Static_Assets_CDN::go();
351 }
352