PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.0.4
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.0.4
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
xspeed / includes / modules / BrowserCache / BrowserCacheModule.php

BrowserCacheModule.php in xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN 1.0.4, at includes/modules/BrowserCache/BrowserCacheModule.php

163 lines 5.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Browser cache headers module — writes Cache-Control + Expires
4 * directives to .htaccess (Apache/LiteSpeed) or surfaces an nginx
5 * snippet for manual paste on other servers.
6 *
7 * Tier: Free per FEATURES.md (LiteSpeed parity — Browser Cache
8 * settings are all in LS free).
9 *
10 * @package XSpeed
11 */
12
13 declare(strict_types=1);
14
15 namespace XSpeed\Modules\BrowserCache;
16
17 use XSpeed\Browser_Cache;
18 use XSpeed\Module;
19 use XSpeed\Server;
20
21 final class BrowserCacheModule extends Module {
22
23 public const SLUG = 'browser-cache';
24 public const TIER = self::TIER_FREE;
25 public const VERSION = '1.0.0';
26
27 public function ui_metadata(): array {
28 return array(
29 'label' => 'Browser Cache',
30 'icon' => 'Clock',
31 'description' => 'Tell browsers (and intermediate CDNs) how long to cache static assets and HTML.',
32 );
33 }
34
35 public function settings_schema(): array {
36 return array(
37 'enabled' => array(
38 'type' => 'bool',
39 '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.',
42 ),
43 'asset_ttl' => array(
44 'type' => 'int',
45 'default' => Browser_Cache::DEFAULT_ASSET_TTL,
46 'min' => 0,
47 '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).',
50 ),
51 'html_ttl' => array(
52 'type' => 'int',
53 'default' => Browser_Cache::DEFAULT_HTML_TTL,
54 'min' => 0,
55 '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.',
58 ),
59 );
60 }
61
62 public function boot(): void {
63 add_action( 'update_option_xspeed_module_browser-cache', array( $this, 'on_settings_change' ), 10, 2 );
64 add_action( 'add_option_xspeed_module_browser-cache', array( $this, 'on_settings_added' ), 10, 2 );
65 }
66
67 public function on_settings_change( $old, $new ): void {
68 if ( ! is_array( $new ) ) {
69 return;
70 }
71 Browser_Cache::apply( ! empty( $new['enabled'] ), $new );
72 // Settings just changed — TTL values likely differ, so the
73 // currently-cached "probe says headers active" answer is stale.
74 // Clear the transient so the next dashboard load re-probes.
75 delete_transient( 'xspeed_browser_cache_probe' );
76 }
77
78 public function on_settings_added( $name, $value ): void {
79 if ( ! is_array( $value ) ) {
80 return;
81 }
82 Browser_Cache::apply( ! empty( $value['enabled'] ), $value );
83 delete_transient( 'xspeed_browser_cache_probe' );
84 }
85
86 public function ui_notices(): array {
87 if ( ! class_exists( '\\XSpeed\\Server' ) || Server::supports_htaccess() ) {
88 return array();
89 }
90 $opts = $this->get_settings();
91 if ( empty( $opts['enabled'] ) ) {
92 return array();
93 }
94
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() ) {
100 return array();
101 }
102
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.
107 return array(
108 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.',
112 ),
113 );
114 }
115
116 public function deactivate(): void {
117 Browser_Cache::apply( false );
118 }
119
120 public function cli_commands(): array {
121 return array(
122 array(
123 'name' => 'xspeed browser-cache',
124 'callback' => array( $this, 'cli_handler' ),
125 'shortdesc' => 'Print the Apache or nginx browser-cache snippet.',
126 'synopsis' => array(
127 array(
128 'type' => 'positional',
129 'name' => 'flavor',
130 'options' => array( 'apache', 'nginx' ),
131 'optional' => true,
132 ),
133 ),
134 ),
135 );
136 }
137
138 public function cli_handler( array $args, array $assoc ): void {
139 $flavor = $args[0] ?? 'apache';
140 $opts = $this->get_settings();
141 if ( 'nginx' === $flavor ) {
142 \WP_CLI::log( Browser_Cache::nginx_snippet( $opts ) );
143 return;
144 }
145 foreach ( Browser_Cache::apache_rules( $opts ) as $line ) {
146 \WP_CLI::log( $line );
147 }
148 }
149
150 /**
151 * Cache-Control / Expires directives for the unified nginx
152 * server-block snippet. Null when the module is disabled — no
153 * directives to install.
154 */
155 public function nginx_directives(): ?string {
156 $opts = $this->get_settings();
157 if ( empty( $opts['enabled'] ) ) {
158 return null;
159 }
160 return Browser_Cache::nginx_snippet( $opts );
161 }
162 }
163