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

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

165 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 defined( 'ABSPATH' ) || exit;
18
19 use XSpeed\Browser_Cache;
20 use XSpeed\Module;
21 use XSpeed\Server;
22
23 final class BrowserCacheModule extends Module {
24
25 public const SLUG = 'browser-cache';
26 public const TIER = self::TIER_FREE;
27 public const VERSION = '1.0.0';
28
29 public function ui_metadata(): array {
30 return array(
31 'label' => 'Browser Cache',
32 'icon' => 'Clock',
33 'description' => 'Tell browsers (and intermediate CDNs) how long to cache static assets and HTML.',
34 );
35 }
36
37 public function settings_schema(): array {
38 return array(
39 'enabled' => array(
40 'type' => 'bool',
41 'default' => false,
42 'label' => 'Enable browser cache headers',
43 '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.',
44 ),
45 'asset_ttl' => array(
46 'type' => 'int',
47 'default' => Browser_Cache::DEFAULT_ASSET_TTL,
48 'min' => 0,
49 'max' => 31536000,
50 'label' => 'Static asset TTL (seconds)',
51 'description' => 'Cache lifetime for CSS, JS, fonts, images. Defaults to 1 year + immutable (the industry-standard "fingerprinted assets never change" pattern).',
52 ),
53 'html_ttl' => array(
54 'type' => 'int',
55 'default' => Browser_Cache::DEFAULT_HTML_TTL,
56 'min' => 0,
57 'max' => 31536000,
58 'label' => 'HTML TTL (seconds)',
59 'description' => 'Cache lifetime for the HTML document itself. Keep short (default 1h) so post edits roll out same-day.',
60 ),
61 );
62 }
63
64 public function boot(): void {
65 add_action( 'update_option_xspeed_module_browser-cache', array( $this, 'on_settings_change' ), 10, 2 );
66 add_action( 'add_option_xspeed_module_browser-cache', array( $this, 'on_settings_added' ), 10, 2 );
67 }
68
69 public function on_settings_change( $old, $new ): void {
70 if ( ! is_array( $new ) ) {
71 return;
72 }
73 Browser_Cache::apply( ! empty( $new['enabled'] ), $new );
74 // Settings just changed — TTL values likely differ, so the
75 // currently-cached "probe says headers active" answer is stale.
76 // Clear the transient so the next dashboard load re-probes.
77 delete_transient( 'xspeed_browser_cache_probe' );
78 }
79
80 public function on_settings_added( $name, $value ): void {
81 if ( ! is_array( $value ) ) {
82 return;
83 }
84 Browser_Cache::apply( ! empty( $value['enabled'] ), $value );
85 delete_transient( 'xspeed_browser_cache_probe' );
86 }
87
88 public function ui_notices(): array {
89 if ( ! class_exists( '\\XSpeed\\Server' ) || Server::supports_htaccess() ) {
90 return array();
91 }
92 $opts = $this->get_settings();
93 if ( empty( $opts['enabled'] ) ) {
94 return array();
95 }
96
97 // Probe whether the snippet has actually been pasted + reloaded.
98 // If the live HEAD shows Cache-Control: immutable on a known
99 // static asset, the user is done — suppress the notice. Avoids
100 // the false-alarm "do something" prompt we used to show forever.
101 if ( Browser_Cache::probe_headers_present() ) {
102 return array();
103 }
104
105 // nginx hosts can't auto-write Cache-Control / Expires headers.
106 // The directives go into the unified server-block snippet on
107 // the Cache panel — point users there instead of duplicating the
108 // snippet here. Topology-aware wording lives in NginxServerBlock.
109 return array(
110 array(
111 'tone' => 'info',
112 'title' => 'nginx server config required',
113 '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.',
114 ),
115 );
116 }
117
118 public function deactivate(): void {
119 Browser_Cache::apply( false );
120 }
121
122 public function cli_commands(): array {
123 return array(
124 array(
125 'name' => 'xspeed browser-cache',
126 'callback' => array( $this, 'cli_handler' ),
127 'shortdesc' => 'Print the Apache or nginx browser-cache snippet.',
128 'synopsis' => array(
129 array(
130 'type' => 'positional',
131 'name' => 'flavor',
132 'options' => array( 'apache', 'nginx' ),
133 'optional' => true,
134 ),
135 ),
136 ),
137 );
138 }
139
140 public function cli_handler( array $args, array $assoc ): void {
141 $flavor = $args[0] ?? 'apache';
142 $opts = $this->get_settings();
143 if ( 'nginx' === $flavor ) {
144 \WP_CLI::log( Browser_Cache::nginx_snippet( $opts ) );
145 return;
146 }
147 foreach ( Browser_Cache::apache_rules( $opts ) as $line ) {
148 \WP_CLI::log( $line );
149 }
150 }
151
152 /**
153 * Cache-Control / Expires directives for the unified nginx
154 * server-block snippet. Null when the module is disabled — no
155 * directives to install.
156 */
157 public function nginx_directives(): ?string {
158 $opts = $this->get_settings();
159 if ( empty( $opts['enabled'] ) ) {
160 return null;
161 }
162 return Browser_Cache::nginx_snippet( $opts );
163 }
164 }
165