From 05754aa386b4a026433187b6124321e347a50600 Mon Sep 17 00:00:00 2001
From: Liam Sarsfield <43409125+LiamSarsfield@users.noreply.github.com>
Date: Thu, 6 Aug 2026 10:19:03 +0100
Subject: [PATCH] Boost: ask the host before linking concatenated assets from
the static cache
The 404 tester's verdict travels with the database in the
jetpack_boost_static_minification site option. A site migrated onto Atomic or
WP Cloud can arrive with its previous host's 1, and whether a missing
wp-content file 404s through WordPress there is a per-site platform setting
Boost cannot read. The concatenators now ask
jetpack_boost_minify_use_static_cache_urls(), which checks the host before the
option, so those sites emit the /_jb_static/?? fallback instead of static
cache URLs the web server may answer with a 404.
---
.../plugins/boost/app/admin/class-config.php | 4 +
.../app/lib/minify/class-concatenate-css.php | 2 +-
.../app/lib/minify/class-concatenate-js.php | 2 +-
.../app/lib/minify/functions-helpers.php | 41 ++++
...st-608-static-minification-after-migration | 4 +
projects/plugins/boost/phpunit.11.xml.dist | 2 +
projects/plugins/boost/phpunit.9.xml.dist | 2 +
.../Concatenate_Static_Cache_Urls_Test.php | 219 ++++++++++++++++++
8 files changed, 274 insertions(+), 2 deletions(-)
create mode 100644 projects/plugins/boost/changelog/fix-boost-608-static-minification-after-migration
create mode 100644 projects/plugins/boost/tests/php/lib/minify/Concatenate_Static_Cache_Urls_Test.php
diff --git a/projects/plugins/boost/app/admin/class-config.php b/projects/plugins/boost/app/admin/class-config.php
index 36d5d207c455..e580310276c3 100644
--- a/projects/plugins/boost/app/admin/class-config.php
+++ b/projects/plugins/boost/app/admin/class-config.php
@@ -97,6 +97,10 @@ private static function get_custom_post_types() {
* Retrieves the hosting provider.
* We're only interested in 'atomic' or 'woa' for now.
*
+ * A new value here also changes CSS and JS delivery:
+ * jetpack_boost_minify_host_handles_wp_content_404s() reads anything but 'other' as a host that
+ * answers wp-content 404s itself, and opts it out of static cache URLs for good.
+ *
* @since 3.10.0
*
* @return string The hosting provider.
diff --git a/projects/plugins/boost/app/lib/minify/class-concatenate-css.php b/projects/plugins/boost/app/lib/minify/class-concatenate-css.php
index 22b17bee3229..cf59d2594054 100644
--- a/projects/plugins/boost/app/lib/minify/class-concatenate-css.php
+++ b/projects/plugins/boost/app/lib/minify/class-concatenate-css.php
@@ -202,7 +202,7 @@ public function do_items( $handles = false, $group = false ) {
foreach ( $css_groups as $css_group ) {
$file_name = jetpack_boost_page_optimize_generate_concat_path( $css_group, $this->dependency_path_mapping );
- if ( get_site_option( 'jetpack_boost_static_minification' ) ) {
+ if ( jetpack_boost_minify_use_static_cache_urls() ) {
$href = jetpack_boost_get_minify_url( $file_name . '.min.css' );
} else {
$href = $siteurl . jetpack_boost_get_static_prefix() . '??' . $file_name;
diff --git a/projects/plugins/boost/app/lib/minify/class-concatenate-js.php b/projects/plugins/boost/app/lib/minify/class-concatenate-js.php
index e43c496ec0e3..48c2bdf23491 100644
--- a/projects/plugins/boost/app/lib/minify/class-concatenate-js.php
+++ b/projects/plugins/boost/app/lib/minify/class-concatenate-js.php
@@ -278,7 +278,7 @@ public function do_items( $handles = false, $group = false ) {
if ( isset( $js_array['paths'] ) && count( $js_array['paths'] ) > 1 ) {
$file_name = jetpack_boost_page_optimize_generate_concat_path( $js_array['paths'], $this->dependency_path_mapping );
- if ( get_site_option( 'jetpack_boost_static_minification' ) ) {
+ if ( jetpack_boost_minify_use_static_cache_urls() ) {
$href = jetpack_boost_get_minify_url( $file_name . '.min.js' );
} else {
$href = $siteurl . jetpack_boost_get_static_prefix() . '??' . $file_name;
diff --git a/projects/plugins/boost/app/lib/minify/functions-helpers.php b/projects/plugins/boost/app/lib/minify/functions-helpers.php
index 4b7ce146fb0b..aca634eae9d4 100644
--- a/projects/plugins/boost/app/lib/minify/functions-helpers.php
+++ b/projects/plugins/boost/app/lib/minify/functions-helpers.php
@@ -1,5 +1,6 @@
tests/php/lib/critical-css/Critical_CSS_Storage_Test.php
tests/php/modules/optimizations/critical-css/CSS_Proxy_Test.php
tests/php/Jetpack_Boost_Test.php
+ tests/php/lib/minify/Concatenate_Static_Cache_Urls_Test.php
tests/php/modules/optimizations/lcp/LCP_Optimize_Bg_Image_Test.php
tests/php/modules/optimizations/lcp/LCP_Optimize_Img_Tag_Test.php
tests/php/abilities/Boost_Abilities_Test.php
tests/php/Jetpack_Boost_Test.php
+ tests/php/lib/minify/Concatenate_Static_Cache_Urls_Test.php
tests/php/lib/critical-css/Display_Critical_CSS_Test.php
tests/php/lib/critical-css/Critical_CSS_Storage_Test.php
tests/php/modules/optimizations/critical-css/CSS_Proxy_Test.php
diff --git a/projects/plugins/boost/phpunit.9.xml.dist b/projects/plugins/boost/phpunit.9.xml.dist
index 30140ce16855..1b0ccf1d1c67 100644
--- a/projects/plugins/boost/phpunit.9.xml.dist
+++ b/projects/plugins/boost/phpunit.9.xml.dist
@@ -16,12 +16,14 @@
tests/php/lib/critical-css/Critical_CSS_Storage_Test.php
tests/php/modules/optimizations/critical-css/CSS_Proxy_Test.php
tests/php/Jetpack_Boost_Test.php
+ tests/php/lib/minify/Concatenate_Static_Cache_Urls_Test.php
tests/php/modules/optimizations/lcp/LCP_Optimize_Bg_Image_Test.php
tests/php/modules/optimizations/lcp/LCP_Optimize_Img_Tag_Test.php
tests/php/abilities/Boost_Abilities_Test.php
tests/php/Jetpack_Boost_Test.php
+ tests/php/lib/minify/Concatenate_Static_Cache_Urls_Test.php
tests/php/lib/critical-css/Display_Critical_CSS_Test.php
tests/php/lib/critical-css/Critical_CSS_Storage_Test.php
tests/php/modules/optimizations/critical-css/CSS_Proxy_Test.php
diff --git a/projects/plugins/boost/tests/php/lib/minify/Concatenate_Static_Cache_Urls_Test.php b/projects/plugins/boost/tests/php/lib/minify/Concatenate_Static_Cache_Urls_Test.php
new file mode 100644
index 000000000000..67e06d27f321
--- /dev/null
+++ b/projects/plugins/boost/tests/php/lib/minify/Concatenate_Static_Cache_Urls_Test.php
@@ -0,0 +1,219 @@
+asset_dir = WP_CONTENT_DIR . '/boost-concat-test';
+ if ( ! is_dir( $this->asset_dir ) ) {
+ mkdir( $this->asset_dir, 0755, true );
+ }
+
+ $this->asset_files = array();
+ foreach ( array(
+ 'a.css' => '.a{color:red}',
+ 'b.css' => '.b{color:blue}',
+ 'a.js' => 'var a = 1;',
+ 'b.js' => 'var b = 2;',
+ ) as $name => $contents ) {
+ $path = $this->asset_dir . '/' . $name;
+ file_put_contents( $path, $contents );
+ $this->asset_files[] = $path;
+ }
+
+ // Both classes derive the site URL from the base_url WordPress hands them, which points at
+ // wp-includes here. Pin it, or nothing resolves as internal and every asset is skipped.
+ $this->site_url_filter = function () {
+ return site_url();
+ };
+ add_filter( 'page_optimize_site_url', $this->site_url_filter );
+ }
+
+ public function tear_down() {
+ if ( $this->site_url_filter ) {
+ remove_filter( 'page_optimize_site_url', $this->site_url_filter );
+ }
+
+ // Remove exactly the files set_up() wrote, then the directory if that emptied it. Tracking
+ // paths rather than ownership means a part-way run cannot leave the fixture behind.
+ foreach ( $this->asset_files as $file ) {
+ if ( file_exists( $file ) ) {
+ unlink( $file );
+ }
+ }
+ if ( is_dir( $this->asset_dir ) ) {
+ @rmdir( $this->asset_dir ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- best effort; a non-empty directory holds something this test did not create.
+ }
+
+ Constants::clear_constants();
+ Status_Cache::clear();
+ delete_site_option( 'jetpack_boost_static_minification' );
+
+ parent::tear_down();
+ }
+
+ /**
+ * Put the site on WP Cloud, where the web server may answer wp-content 404s itself.
+ */
+ private function pretend_to_be_on_wp_cloud() {
+ Constants::set_constant( 'ATOMIC_SITE_ID', 1 );
+ Constants::set_constant( 'ATOMIC_CLIENT_ID', 1 );
+ Status_Cache::clear();
+ }
+
+ private function render_styles() {
+ $styles = new Concatenate_CSS( new WP_Styles() );
+ $styles->add( 'boost-test-a', '/wp-content/boost-concat-test/a.css', array(), null );
+ $styles->add( 'boost-test-b', '/wp-content/boost-concat-test/b.css', array(), null );
+ $styles->enqueue( array( 'boost-test-a', 'boost-test-b' ) );
+
+ // finally, so a throw inside do_items() surfaces as that failure rather than as a leaked
+ // buffer tripping beStrictAboutOutputDuringTests.
+ ob_start();
+ try {
+ $styles->do_items();
+ } finally {
+ $output = ob_get_clean();
+ }
+
+ return $output;
+ }
+
+ private function render_scripts() {
+ $scripts = new Concatenate_JS( new WP_Scripts() );
+ $scripts->add( 'boost-test-a', '/wp-content/boost-concat-test/a.js', array(), null );
+ $scripts->add( 'boost-test-b', '/wp-content/boost-concat-test/b.js', array(), null );
+ $scripts->enqueue( array( 'boost-test-a', 'boost-test-b' ) );
+
+ ob_start();
+ try {
+ $scripts->do_items();
+ } finally {
+ $output = ob_get_clean();
+ }
+
+ return $output;
+ }
+
+ /**
+ * The migrated database says the 404 tester passed, but it passed on the previous host.
+ */
+ public function test_css_falls_back_when_a_stale_verdict_arrives_on_wp_cloud() {
+ update_site_option( 'jetpack_boost_static_minification', 1 );
+ $this->pretend_to_be_on_wp_cloud();
+
+ $output = $this->render_styles();
+
+ $this->assertStringContainsString( '/_jb_static/??', $output );
+ $this->assertStringNotContainsString( '/boost-cache/static/', $output );
+ }
+
+ public function test_js_falls_back_when_a_stale_verdict_arrives_on_wp_cloud() {
+ update_site_option( 'jetpack_boost_static_minification', 1 );
+ $this->pretend_to_be_on_wp_cloud();
+
+ $output = $this->render_scripts();
+
+ $this->assertStringContainsString( '/_jb_static/??', $output );
+ $this->assertStringNotContainsString( '/boost-cache/static/', $output );
+ }
+
+ /**
+ * Hosts that can serve the static cache keep doing so. The guard only moves a site onto the
+ * fallback, never the other way.
+ */
+ public function test_css_uses_static_cache_urls_on_a_supported_host() {
+ update_site_option( 'jetpack_boost_static_minification', 1 );
+
+ $output = $this->render_styles();
+
+ $this->assertStringContainsString( '/boost-cache/static/', $output );
+ $this->assertStringContainsString( '.min.css', $output );
+ $this->assertStringNotContainsString( '/_jb_static/??', $output );
+ }
+
+ public function test_js_uses_static_cache_urls_on_a_supported_host() {
+ update_site_option( 'jetpack_boost_static_minification', 1 );
+
+ $output = $this->render_scripts();
+
+ $this->assertStringContainsString( '/boost-cache/static/', $output );
+ $this->assertStringContainsString( '.min.js', $output );
+ $this->assertStringNotContainsString( '/_jb_static/??', $output );
+ }
+
+ public function test_css_falls_back_on_a_supported_host_when_the_tester_failed() {
+ update_site_option( 'jetpack_boost_static_minification', 0 );
+
+ $output = $this->render_styles();
+
+ $this->assertStringContainsString( '/_jb_static/??', $output );
+ $this->assertStringNotContainsString( '/boost-cache/static/', $output );
+ }
+
+ public function test_js_falls_back_on_a_supported_host_when_the_tester_failed() {
+ update_site_option( 'jetpack_boost_static_minification', 0 );
+
+ $output = $this->render_scripts();
+
+ $this->assertStringContainsString( '/_jb_static/??', $output );
+ $this->assertStringNotContainsString( '/boost-cache/static/', $output );
+ }
+}