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 / ObjectCache / ObjectCacheModule.php

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

279 lines 8.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Object Cache module — status, settings, wp-config snippet, flush.
4 *
5 * Tier: Free per FEATURES.md "Object Cache" §1-11 (LiteSpeed parity).
6 *
7 * We don't ship our own object-cache.php drop-in in this Free release
8 * (see Object_Cache class docblock for rationale). The settings here
9 * are surfaced via the wp-config snippet; advanced consumers (Pro,
10 * external drop-ins like Redis Object Cache) can read them too.
11 *
12 * @package XSpeed
13 */
14
15 declare(strict_types=1);
16
17 namespace XSpeed\Modules\ObjectCache;
18
19 use XSpeed\Module;
20 use XSpeed\Object_Cache;
21
22 final class ObjectCacheModule extends Module {
23
24 public const SLUG = 'object-cache';
25 public const TIER = self::TIER_FREE;
26 public const VERSION = '1.0.0';
27
28 public function ui_metadata(): array {
29 return array(
30 'label' => 'Object Cache',
31 'icon' => 'Server',
32 'description' => 'Configure a persistent object cache (Redis / Memcached) and generate a paste-ready wp-config.php snippet.',
33 'custom_panel' => 'ObjectCachePanel',
34 );
35 }
36
37 public function settings_schema(): array {
38 return array(
39 'backend' => array(
40 'type' => 'enum',
41 'default' => 'redis',
42 'options' => array( 'redis', 'memcached' ),
43 'option_labels' => array(
44 'redis' => 'Redis',
45 'memcached' => 'Memcached',
46 ),
47 'label' => 'Backend',
48 'description' => 'Which cache server you intend to use. Affects the generated wp-config snippet.',
49 ),
50 'redis_host' => array(
51 'type' => 'string',
52 'default' => '127.0.0.1',
53 'label' => 'Redis Host',
54 'description' => 'Hostname or IP of the Redis server. Use 127.0.0.1 for a local socket on the same machine as PHP.',
55 ),
56 'redis_port' => array(
57 'type' => 'int',
58 'default' => 6379,
59 'min' => 1,
60 'max' => 65535,
61 'label' => 'Redis Port',
62 'description' => 'Default Redis port is 6379.',
63 ),
64 'redis_password' => array(
65 'type' => 'string',
66 'default' => '',
67 'label' => 'Redis Password',
68 'description' => 'Leave blank if your Redis server runs without auth.',
69 ),
70 'redis_database' => array(
71 'type' => 'int',
72 'default' => 0,
73 'min' => 0,
74 'max' => 15,
75 'label' => 'Redis Database',
76 'description' => 'Redis logical DB number (0-15). Use a dedicated DB per site if Redis is shared.',
77 ),
78 'memcached_host' => array(
79 'type' => 'string',
80 'default' => '127.0.0.1',
81 'label' => 'Memcached Host',
82 'description' => 'Used when Backend = Memcached.',
83 ),
84 'memcached_port' => array(
85 'type' => 'int',
86 'default' => 11211,
87 'min' => 1,
88 'max' => 65535,
89 'label' => 'Memcached Port',
90 'description' => 'Default Memcached port is 11211.',
91 ),
92 'key_prefix' => array(
93 'type' => 'string',
94 'default' => '',
95 'label' => 'Cache Key Prefix',
96 'description' => 'Unique salt for this site\'s cache keys. Critical when multiple WP sites share one Redis/Memcached server.',
97 ),
98 'connection_timeout' => array(
99 'type' => 'int',
100 'default' => 1,
101 'min' => 0,
102 'max' => 60,
103 'label' => 'Connection Timeout (seconds)',
104 'description' => 'How long to wait for a connection. Keep low (1-2s) so a misconfigured cache never stalls the page.',
105 ),
106 'persistent' => array(
107 'type' => 'bool',
108 'default' => true,
109 'label' => 'Persistent Connections',
110 'description' => 'Reuse the connection across PHP requests when supported. Generally a win unless the cache server complains about idle connections.',
111 ),
112 );
113 }
114
115 public function rest_routes(): array {
116 $default = parent::rest_routes();
117 return array_merge(
118 $default,
119 array(
120 array(
121 'path' => '/detect',
122 'methods' => 'GET',
123 'callback' => array( $this, 'rest_detect' ),
124 ),
125 array(
126 'path' => '/flush',
127 'methods' => 'POST',
128 'callback' => array( $this, 'rest_flush' ),
129 ),
130 array(
131 'path' => '/snippet',
132 'methods' => 'GET',
133 'callback' => array( $this, 'rest_snippet' ),
134 ),
135 array(
136 'path' => '/test-connection',
137 'methods' => 'POST',
138 'callback' => array( $this, 'rest_test_connection' ),
139 ),
140 array(
141 'path' => '/enable',
142 'methods' => 'POST',
143 'callback' => array( $this, 'rest_enable' ),
144 ),
145 array(
146 'path' => '/disable',
147 'methods' => 'POST',
148 'callback' => array( $this, 'rest_disable' ),
149 ),
150 )
151 );
152 }
153
154 public function rest_detect( \WP_REST_Request $request ) {
155 return rest_ensure_response( Object_Cache::detect() );
156 }
157
158 public function rest_flush( \WP_REST_Request $request ) {
159 $ok = Object_Cache::flush();
160 if ( $ok && class_exists( '\\XSpeed\\Activity_Log' ) ) {
161 \XSpeed\Activity_Log::record(
162 'object_cache_flushed',
163 'Object cache flushed.',
164 \XSpeed\Activity_Log::INFO
165 );
166 }
167 return rest_ensure_response( array( 'ok' => $ok ) );
168 }
169
170 public function rest_snippet( \WP_REST_Request $request ) {
171 return rest_ensure_response(
172 array( 'snippet' => Object_Cache::render_config_snippet( $this->get_settings() ) )
173 );
174 }
175
176 /**
177 * Merge any settings sent in the request body over the saved settings, so
178 * the UI can "Test connection" with unsaved values. Only known keys pass.
179 */
180 private function settings_with_overrides( \WP_REST_Request $request ): array {
181 $settings = $this->get_settings();
182 $body = $request->get_json_params();
183 if ( is_array( $body ) ) {
184 foreach ( $settings as $key => $value ) {
185 if ( array_key_exists( $key, $body ) ) {
186 $settings[ $key ] = $body[ $key ];
187 }
188 }
189 }
190 return $settings;
191 }
192
193 public function rest_test_connection( \WP_REST_Request $request ) {
194 return rest_ensure_response( Object_Cache::test_connection( $this->settings_with_overrides( $request ) ) );
195 }
196
197 public function rest_enable( \WP_REST_Request $request ) {
198 // Persist any settings sent with the enable call first, then act on them.
199 $body = $request->get_json_params();
200 if ( is_array( $body ) && ! empty( $body ) ) {
201 \XSpeed\Settings_Manager::update( self::SLUG, $body );
202 }
203 $result = Object_Cache::enable( $this->get_settings() );
204
205 if ( $result['ok'] && class_exists( '\\XSpeed\\Activity_Log' ) ) {
206 \XSpeed\Activity_Log::record(
207 'object_cache_enabled',
208 'Object cache enabled (' . ( $result['test']['backend'] ?? '' ) . ').',
209 \XSpeed\Activity_Log::INFO
210 );
211 }
212 return rest_ensure_response( $result );
213 }
214
215 public function rest_disable( \WP_REST_Request $request ) {
216 $result = Object_Cache::disable();
217 if ( $result['ok'] && class_exists( '\\XSpeed\\Activity_Log' ) ) {
218 \XSpeed\Activity_Log::record(
219 'object_cache_disabled',
220 'Object cache disabled.',
221 \XSpeed\Activity_Log::INFO
222 );
223 }
224 return rest_ensure_response( $result );
225 }
226
227 public function cli_commands(): array {
228 return array(
229 array(
230 'name' => 'xspeed objcache',
231 'callback' => array( $this, 'cli_handler' ),
232 'shortdesc' => 'Show object cache status, flush, or print the wp-config snippet.',
233 'synopsis' => array(
234 array(
235 'type' => 'positional',
236 'name' => 'action',
237 'options' => array( 'status', 'flush', 'snippet', 'enable', 'disable', 'test' ),
238 'optional' => true,
239 ),
240 ),
241 ),
242 );
243 }
244
245 public function cli_handler( array $args, array $assoc ): void {
246 $action = $args[0] ?? 'status';
247 switch ( $action ) {
248 case 'status':
249 $d = Object_Cache::detect();
250 \WP_CLI::log( 'drop-in installed: ' . ( $d['drop_in_installed'] ? 'yes' : 'no' ) );
251 \WP_CLI::log( 'label: ' . $d['drop_in_label'] );
252 \WP_CLI::log( 'backend: ' . $d['backend'] );
253 \WP_CLI::log( 'ext object cache: ' . ( $d['wp_cache_active'] ? 'yes' : 'no' ) );
254 return;
255 case 'flush':
256 $ok = Object_Cache::flush();
257 $ok ? \WP_CLI::success( 'Flushed.' ) : \WP_CLI::error( 'Flush failed.' );
258 return;
259 case 'snippet':
260 \WP_CLI::log( Object_Cache::render_config_snippet( $this->get_settings() ) );
261 return;
262 case 'test':
263 $t = Object_Cache::test_connection( $this->get_settings() );
264 $t['ok'] ? \WP_CLI::success( $t['message'] ) : \WP_CLI::error( $t['message'] );
265 return;
266 case 'enable':
267 $r = Object_Cache::enable( $this->get_settings() );
268 $r['ok'] ? \WP_CLI::success( $r['message'] ) : \WP_CLI::error( $r['message'] );
269 return;
270 case 'disable':
271 $r = Object_Cache::disable();
272 $r['ok'] ? \WP_CLI::success( $r['message'] ) : \WP_CLI::error( $r['message'] );
273 return;
274 default:
275 \WP_CLI::error( "Unknown action: $action" );
276 }
277 }
278 }
279