PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.0.2
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.0.2
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 / class-module.php

class-module.php in xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN 1.0.2, at includes/class-module.php

257 lines 7.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Module abstract base class.
4 *
5 * Every feature in xSpeed (Free or Pro) extends this class. The contract is
6 * documented in IMPLEMENTATION.md §1.1. A Module is a self-contained unit
7 * that declares its tier, settings schema, REST routes, UI panels, CLI
8 * commands, conflicts, and lifecycle hooks in one place — so moving a
9 * feature between Free and Pro is a `git mv` + flipping the TIER constant,
10 * with no call-site changes.
11 *
12 * Concrete modules MUST:
13 * - Set the SLUG class constant.
14 * - Set the TIER class constant (TIER_FREE or TIER_PRO).
15 * - Set the VERSION class constant.
16 *
17 * @package XSpeed
18 */
19
20 namespace XSpeed;
21
22 defined( 'ABSPATH' ) || exit;
23
24 abstract class Module {
25
26 public const TIER_FREE = 'free';
27 public const TIER_PRO = 'pro';
28
29 /**
30 * Concrete modules override these three constants.
31 */
32 public const SLUG = '';
33 public const TIER = self::TIER_FREE;
34 public const VERSION = '1.0.0';
35
36 /**
37 * Other module slugs this module needs at boot. Resolved by
38 * Module_Registry via topological sort; missing deps fail loudly.
39 *
40 * @return string[]
41 */
42 public function dependencies(): array {
43 return array();
44 }
45
46 /**
47 * Typed settings schema. See Settings_Manager::validate() for the
48 * supported `type` values (bool, int, string, enum, list, url). Each
49 * field declares `default` and optional `min` / `max` / `options` /
50 * `item_type`. Storage key is `xspeed_module_<slug>`.
51 *
52 * @return array<string,array>
53 */
54 public function settings_schema(): array {
55 return array();
56 }
57
58 /**
59 * Schema migrations keyed by target version. Each value is a callable
60 * that receives the stored options array and returns the migrated
61 * array. Migrations run in version order on first load after upgrade.
62 *
63 * @return array<string,callable>
64 */
65 public function migrations(): array {
66 return array();
67 }
68
69 /**
70 * REST routes the module owns. Paths are prefixed with
71 * `/xspeed/v1/<slug>/` by Rest_Manager; declare without the prefix.
72 * `permission_callback` is wrapped automatically with a final cap
73 * check + tier gate, so modules don't need to repeat that boilerplate
74 * — but they MUST still declare a sensible callback.
75 *
76 * Default impl returns the standard GET + POST pair for modules that
77 * declare a settings_schema. Modules that need extra endpoints can
78 * extend the array. Modules with truly custom REST should override
79 * entirely and skip parent::rest_routes().
80 *
81 * Per SETTINGS.md §5.1 every module's settings live at:
82 * GET /xspeed/v1/<slug>/ → current settings
83 * POST /xspeed/v1/<slug>/ → partial patch, returns updated settings
84 *
85 * @return array[]
86 */
87 public function rest_routes(): array {
88 if ( empty( $this->settings_schema() ) ) {
89 return array();
90 }
91 return array(
92 array(
93 'path' => '/',
94 'methods' => 'GET',
95 'callback' => array( $this, 'rest_get_settings' ),
96 ),
97 array(
98 'path' => '/',
99 'methods' => 'POST',
100 'callback' => array( $this, 'rest_update_settings' ),
101 'feature' => static::SLUG,
102 ),
103 );
104 }
105
106 /**
107 * Default GET handler — returns all settings (defaults + stored)
108 * coerced against the schema. Modules can override but rarely need
109 * to.
110 */
111 public function rest_get_settings( \WP_REST_Request $request ) {
112 return rest_ensure_response( $this->get_settings() );
113 }
114
115 /**
116 * Default POST handler — validates the JSON body against the
117 * schema, persists, returns the post-update settings. Unknown keys
118 * are stripped by Settings_Manager.
119 */
120 public function rest_update_settings( \WP_REST_Request $request ) {
121 $params = $request->get_json_params();
122 if ( ! is_array( $params ) ) {
123 $params = $request->get_params();
124 }
125 return rest_ensure_response( $this->update_settings( $params ) );
126 }
127
128 /**
129 * UI panel declarations consumed by the React dashboard via the
130 * bootstrap payload. Each entry: [
131 * 'section' => 'cache' | 'performance' | 'images' | ...,
132 * 'position' => int,
133 * 'component' => 'HealthCard' | 'TogglesList' | 'StatGrid' | 'Custom',
134 * 'props' => array,
135 * ]
136 *
137 * @return array[]
138 */
139 public function ui_panels(): array {
140 return array();
141 }
142
143 /**
144 * Sidebar / dashboard metadata. The React app uses these to render the
145 * module's nav entry. Override per module to set a friendly label and
146 * a lucide-react icon name (must be in the renderer's icon whitelist —
147 * see src/components/IconResolver.tsx).
148 *
149 * @return array{label:string,icon:string,description?:string,hidden?:bool}
150 */
151 public function ui_metadata(): array {
152 return array(
153 'label' => ucfirst( str_replace( '_', ' ', static::SLUG ) ),
154 'icon' => 'Square',
155 );
156 }
157
158 /**
159 * Dynamic in-panel notices (callouts) rendered above the schema form.
160 * Computed fresh on every dashboard load. Examples: nginx GZIP
161 * snippet when the server can't be auto-configured, "drop-in
162 * missing" warning when cache_enabled but no advanced-cache.php.
163 *
164 * Each entry: [
165 * 'tone' => 'info' | 'warn' | 'danger' | 'success',
166 * 'title' => 'Short heading.',
167 * 'body' => 'One- or two-sentence explanation.',
168 * 'snippet' => 'Optional verbatim code snippet rendered in a
169 * <pre> with a Copy button.',
170 * ]
171 *
172 * @return array[]
173 */
174 public function ui_notices(): array {
175 return array();
176 }
177
178 /**
179 * WP-CLI command definitions. Each entry: [
180 * 'name' => 'xspeed cache purge',
181 * 'callback' => callable,
182 * 'synopsis' => array, // wp-cli synopsis spec
183 * ]
184 *
185 * @return array[]
186 */
187 public function cli_commands(): array {
188 return array();
189 }
190
191 /**
192 * Conflict declarations for this module — which other plugins clash
193 * with which sub-feature. Each entry: [
194 * 'plugin' => 'wp-rocket/wp-rocket.php',
195 * 'feature' => 'page_cache',
196 * 'strategy' => 'refuse' | 'warn' | 'allow',
197 * 'reason' => 'human-readable why',
198 * ]
199 *
200 * @return array[]
201 */
202 public function conflicts(): array {
203 return array();
204 }
205
206 /**
207 * Register WP hooks. Called by Module_Registry::boot_all() after
208 * dependencies are resolved. Modules should NOT register hooks in
209 * their constructors — only in boot() — so the registry can control
210 * load order.
211 */
212 public function boot(): void {}
213
214 /**
215 * One-time setup at plugin activation. Idempotent. Examples: create
216 * a custom table, write a silence guard, register a cron schedule.
217 */
218 public function activate(): void {}
219
220 /**
221 * Tear down at plugin deactivation. Reversible counterpart to
222 * activate(). MUST leave the site in a clean state — no orphaned
223 * cron jobs, no leftover drop-ins.
224 */
225 public function deactivate(): void {}
226
227 /**
228 * Convenience accessors. Modules read/write their own settings
229 * through these so the storage detail (one option per module under
230 * `xspeed_module_<slug>`) stays encapsulated.
231 */
232 final public function get_setting( string $key, $default = null ) {
233 $opts = Settings_Manager::get( static::SLUG );
234 return array_key_exists( $key, $opts ) ? $opts[ $key ] : $default;
235 }
236
237 final public function get_settings(): array {
238 return Settings_Manager::get( static::SLUG );
239 }
240
241 final public function update_settings( array $input ): array {
242 return Settings_Manager::update( static::SLUG, $input );
243 }
244
245 final public function slug(): string {
246 return static::SLUG;
247 }
248
249 final public function tier(): string {
250 return static::TIER;
251 }
252
253 final public function version(): string {
254 return static::VERSION;
255 }
256 }
257