PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.3.2
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.3.2
1.3.3 1.3.2 1.3.1 1.3.0 1.2.4 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 All 29 releases
← All changes | includes/class-browser-cache.php +41 -7 1.2.41.3.2 View file →
@@ -1,9 +1,10 @@
1 1 <?php
2 2 /**
3 3 * Browser_Cache — writes/removes browser-cache directives in the site
4 4 * root .htaccess so static assets get long Cache-Control + Expires
5 - * headers, and serves an nginx snippet for non-Apache hosts.
5 + * headers, and serves an nginx snippet for non-Apache hosts (that one
6 + * sends Cache-Control only — see nginx_snippet()).
6 7 *
7 8 * Same shape as Gzip: marker block, insert_with_markers, snippet
8 9 * fallback. Independent toggle so users can enable browser caching
9 10 * without compression and vice versa.
@@ -93,12 +94,8 @@
93 94 );
94 95 }
95 96
96 97 /**
97 - * nginx snippet — uses `expires` directive (the canonical nginx way)
98 - * plus an `add_header` line for the immutable flag.
99 - */
100 - /**
101 98 * Probe whether long-lived caching headers are actually reaching the
102 99 * browser. Picks a recognisable static asset (anything in
103 100 * `wp-includes/css/` is always served on a WP install) and HEADs it.
104 101 * Cached in a transient so this never adds latency to the dashboard.
@@ -208,20 +205,57 @@
208 205 }
209 206 return false;
210 207 }
211 208
209 + /**
210 + * nginx snippet — one `add_header Cache-Control` per location, with
211 + * `expires off;` pinned in front of it.
212 + *
213 + * nginx's `expires Ns;` emits its own `Cache-Control: max-age=N` (plus
214 + * `Expires`), and `add_header` appends rather than replaces, so pairing
215 + * the two — as this block used to — put two Cache-Control fields on
216 + * every static asset it matched, WP core's own included (issue #259).
217 + * `expires` can't say `immutable` and `immutable` is the point, so
218 + * `add_header` is the one that stays.
219 + *
220 + * `off` rather than simply dropping the directive: `expires` is
221 + * inherited from `server {}`, so a host template that sets one there
222 + * would recreate the duplicate inside this location.
223 + *
224 + * Losing `Expires:` on nginx costs nothing — `max-age` outranks it in
225 + * any HTTP/1.1 cache, and Apache still emits both via mod_expires.
226 + *
227 + * Deliberately no `always`. Without it nginx applies `add_header` only
228 + * to the statuses its header filter treats as safe — 200, 201, 204,
229 + * 206, 301, 302, 303, 304, 307, 308 — which is the coverage we want,
230 + * and the same coverage Apache gives: `Header set` in apache_rules()
231 + * runs under the default `onsuccess` condition, so it is off on error
232 + * responses too. `always` would put `max-age=31536000, immutable` on a
233 + * 404, and minified asset URLs are deterministic (Minifier keys them on
234 + * path + mtime), so a file that 404s in the window after a purge comes
235 + * back at the URL a client has already cached the 404 for — for a year,
236 + * with no revalidation.
237 + */
212 238 public static function nginx_snippet( array $opts = array() ): string {
213 239 $asset = (int) ( $opts['asset_ttl'] ?? self::DEFAULT_ASSET_TTL );
214 240 $html = (int) ( $opts['html_ttl'] ?? self::DEFAULT_HTML_TTL );
241 + // Same guard as apache_rules(): a negative TTL would otherwise
242 + // reach the vhost as `max-age=-1`.
243 + if ( $asset < 0 ) {
244 + $asset = self::DEFAULT_ASSET_TTL;
245 + }
246 + if ( $html < 0 ) {
247 + $html = self::DEFAULT_HTML_TTL;
248 + }
215 249 return implode(
216 250 "\n",
217 251 array(
218 252 'location ~* \.(css|js|jpg|jpeg|png|gif|webp|avif|svg|ico|woff2|woff|ttf|otf|eot|mp4|webm|mp3|ogg)$ {',
219 - ' expires ' . $asset . 's;',
253 + ' expires off;',
220 254 ' add_header Cache-Control "public, max-age=' . $asset . ', immutable";',
221 255 '}',
222 256 'location ~* \.html$ {',
223 - ' expires ' . $html . 's;',
257 + ' expires off;',
224 258 ' add_header Cache-Control "public, max-age=' . $html . '";',
225 259 '}',
226 260 )
227 261 );