PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.0.6
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.0.6
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 / ObjectCache / ObjectCacheModule.php

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

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