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.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 1.2.0 All 28 releases
← All changes | includes/modules/BrowserCache/BrowserCacheModule.php +48 -22 1.0.41.3.2 View file →
@@ -13,9 +13,12 @@
13 13 declare(strict_types=1);
14 14
15 15 namespace XSpeed\Modules\BrowserCache;
16 16
17 +defined( 'ABSPATH' ) || exit;
18 +
17 19 use XSpeed\Browser_Cache;
20 +use XSpeed\Deep_Link;
18 21 use XSpeed\Module;
19 22 use XSpeed\Server;
20 23
21 24 final class BrowserCacheModule extends Module {
@@ -25,11 +28,11 @@
25 28 public const VERSION = '1.0.0';
26 29
27 30 public function ui_metadata(): array {
28 31 return array(
29 - 'label' => 'Browser Cache',
32 + 'label' => __( 'Browser Cache', 'xspeed' ),
30 33 'icon' => 'Clock',
31 - 'description' => 'Tell browsers (and intermediate CDNs) how long to cache static assets and HTML.',
34 + 'description' => __( 'Tell browsers (and intermediate CDNs) how long to cache static assets and HTML.', 'xspeed' ),
32 35 );
33 36 }
34 37
35 38 public function settings_schema(): array {
@@ -36,10 +39,10 @@
36 39 return array(
37 40 'enabled' => array(
38 41 'type' => 'bool',
39 42 'default' => false,
40 - 'label' => 'Enable browser cache headers',
41 - 'description' => 'On Apache/LiteSpeed this writes Cache-Control + Expires rules into .htaccess. On nginx it just stores the settings — you paste the snippet into your server block manually.',
43 + 'label' => __( 'Enable browser cache headers', 'xspeed' ),
44 + 'description' => __( 'On Apache/LiteSpeed this writes Cache-Control + Expires rules into .htaccess. On nginx it just stores the settings — you paste the snippet into your server block manually.', 'xspeed' ),
42 45 ),
43 46 'asset_ttl' => array(
44 47 'type' => 'int',
45 48 'default' => Browser_Cache::DEFAULT_ASSET_TTL,
@@ -44,10 +47,12 @@
44 47 'type' => 'int',
45 48 'default' => Browser_Cache::DEFAULT_ASSET_TTL,
46 49 'min' => 0,
47 50 'max' => 31536000,
48 - 'label' => 'Static asset TTL (seconds)',
49 - 'description' => 'Cache lifetime for CSS, JS, fonts, images. Defaults to 1 year + immutable (the industry-standard "fingerprinted assets never change" pattern).',
51 + 'label' => __( 'Static asset TTL (seconds)', 'xspeed' ),
52 + 'unit' => 'seconds',
53 + 'description' => __( 'Cache lifetime for CSS, JS, fonts, images. Defaults to 1 year + immutable (the industry-standard "fingerprinted assets never change" pattern).', 'xspeed' ),
54 + 'dependsOn' => array( 'field' => 'enabled' ),
50 55 ),
51 56 'html_ttl' => array(
52 57 'type' => 'int',
53 58 'default' => Browser_Cache::DEFAULT_HTML_TTL,
@@ -52,10 +57,12 @@
52 57 'type' => 'int',
53 58 'default' => Browser_Cache::DEFAULT_HTML_TTL,
54 59 'min' => 0,
55 60 'max' => 31536000,
56 - 'label' => 'HTML TTL (seconds)',
57 - 'description' => 'Cache lifetime for the HTML document itself. Keep short (default 1h) so post edits roll out same-day.',
61 + 'label' => __( 'HTML TTL (seconds)', 'xspeed' ),
62 + 'unit' => 'seconds',
63 + 'description' => __( 'Cache lifetime for the HTML document itself. Keep short (default 1h) so post edits roll out same-day.', 'xspeed' ),
64 + 'dependsOn' => array( 'field' => 'enabled' ),
58 65 ),
59 66 );
60 67 }
61 68
@@ -91,25 +98,42 @@
91 98 if ( empty( $opts['enabled'] ) ) {
92 99 return array();
93 100 }
94 101
95 - // Probe whether the snippet has actually been pasted + reloaded.
96 - // If the live HEAD shows Cache-Control: immutable on a known
97 - // static asset, the user is done — suppress the notice. Avoids
98 - // the false-alarm "do something" prompt we used to show forever.
99 - if ( Browser_Cache::probe_headers_present() ) {
102 + // Probe the live response for caching headers on a known static
103 + // asset. Suppress the notice unless the probe PROVES nothing is
104 + // being sent:
105 + //
106 + // true → headers present, from our snippet or from the host's own
107 + // vhost — either way the feature's job is done (issue #329)
108 + // null → the loopback never completed, so we know nothing; a
109 + // broken probe is not evidence of a broken server and must
110 + // not raise a warning the operator cannot act on (issue #18)
111 + // false → proven absent, fall through and show the notice
112 + if ( false !== Browser_Cache::probe_headers_present() ) {
100 113 return array();
101 114 }
102 115
103 - // nginx hosts can't auto-write Cache-Control / Expires headers.
104 - // The directives go into the unified server-block snippet on
105 - // the Cache panel — point users there instead of duplicating the
106 - // snippet here. Topology-aware wording lives in NginxServerBlock.
116 + // nginx hosts can't auto-write Cache-Control / Expires headers, and the
117 + // live probe just confirmed they are NOT being served — so the feature
118 + // reads "enabled" in the dashboard while doing nothing. That is a warning,
119 + // not a passive info note (a token that a user missed on this exact
120 + // account, issue #117): escalate the tone and say plainly that the config
121 + // is configured-but-not-live until the snippet is pasted + nginx reloaded.
122 + // The directives go into the unified server-block snippet on the Cache
123 + // panel — point users there instead of duplicating the snippet here.
107 124 return array(
108 125 array(
109 - 'tone' => 'info',
110 - 'title' => 'nginx server config required',
111 - 'body' => 'Browser-cache headers need to live in your nginx config. Your updated settings are included in the unified server-block snippet on the Cache panel — copy + paste it once into your nginx vhost (or container nginx config), and reload nginx.',
126 + 'tone' => 'warn',
127 + 'title' => __( 'Browser cache is enabled but not active on the server', 'xspeed' ),
128 + 'body' => __( 'Browser-cache headers need to live in your nginx config, and the live response shows they are not being sent yet — so this is on in settings but doing nothing. Your settings are included in the unified server-block snippet on the Cache panel: paste it once into your nginx vhost (or container nginx config) and reload nginx.', 'xspeed' ),
129 + // Lands on the snippet itself rather than on the Cache panel,
130 + // where it is one collapsed section among several (issue #49).
131 + 'action' => Deep_Link::action(
132 + __( 'Go to the snippet', 'xspeed' ),
133 + 'cache',
134 + 'nginx_snippet'
135 + ),
112 136 ),
113 137 );
114 138 }
115 139
@@ -122,8 +146,9 @@
122 146 array(
123 147 'name' => 'xspeed browser-cache',
124 148 'callback' => array( $this, 'cli_handler' ),
125 149 'shortdesc' => 'Print the Apache or nginx browser-cache snippet.',
150 + 'ai_hint' => 'Get the server config snippet that sets browser cache-control headers for static assets. Use when PageSpeed reports "serve static assets with an efficient cache policy", or when the user needs the rules to paste into Apache/nginx.',
126 151 'synopsis' => array(
127 152 array(
128 153 'type' => 'positional',
129 154 'name' => 'flavor',
@@ -147,10 +172,11 @@
147 172 }
148 173 }
149 174
150 175 /**
151 - * Cache-Control / Expires directives for the unified nginx
152 - * server-block snippet. Null when the module is disabled — no
176 + * Cache-Control directives for the unified nginx server-block
177 + * snippet. nginx sends no Expires — `expires off;` pins the block so
178 + * only the explicit `add_header` speaks (#259). Null when the module is disabled — no
153 179 * directives to install.
154 180 */
155 181 public function nginx_directives(): ?string {
156 182 $opts = $this->get_settings();