PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.3.0
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.3.0
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 / Database / DatabaseModule.php

DatabaseModule.php in xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN 1.3.0, at includes/modules/Database/DatabaseModule.php

194 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Database cleanup module — read-first scan + selective cleanup +
4 * OPTIMIZE TABLE + optional auto-cleanup schedule.
5 *
6 * Tier: Free per FEATURES.md Database §1–11. (DB-side activity log
7 * Database §12 stays Pro.)
8 *
9 * @package XSpeed
10 */
11
12 declare(strict_types=1);
13
14 namespace XSpeed\Modules\Database;
15
16 defined( 'ABSPATH' ) || exit;
17
18 use XSpeed\Database_Cleaner;
19 use XSpeed\Module;
20 use XSpeed\Settings_Manager;
21
22 final class DatabaseModule extends Module {
23
24 public const SLUG = 'database';
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' => __( 'Database', 'xspeed' ),
31 'icon' => 'Trash2',
32 'description' => __( 'Scan + clean WordPress bloat (revisions, spam, transients, orphan meta) and optimize tables.', 'xspeed' ),
33 'custom_panel' => 'DatabaseCleanerPanel',
34 );
35 }
36
37 public function settings_schema(): array {
38 return array(
39 'schedule' => array(
40 'type' => 'enum',
41 'default' => 'manual',
42 'options' => array( 'manual', 'hourly', 'daily', 'weekly' ),
43 'option_labels' => array(
44 'manual' => 'Manual',
45 'hourly' => 'Hourly',
46 'daily' => 'Daily',
47 'weekly' => 'Weekly',
48 ),
49 'label' => __( 'Auto-Cleanup Schedule', 'xspeed' ),
50 'description' => __( 'How often to run cleanup automatically. Manual means cleanup only runs when you press the button.', 'xspeed' ),
51 ),
52 'included_types' => array(
53 'type' => 'list',
54 'default' => array(),
55 'item_type' => 'string',
56 'label' => __( 'Auto-Cleanup Types', 'xspeed' ),
57 'description' => __( 'Which cleanup categories run on the schedule above. Leave empty to keep auto-cleanup disabled even if a schedule is set.', 'xspeed' ),
58 ),
59 );
60 }
61
62 public function rest_routes(): array {
63 // Schema POST/GET come from the base; we add three custom routes.
64 $default = parent::rest_routes();
65 return array_merge(
66 $default,
67 array(
68 array(
69 'path' => '/scan',
70 'methods' => 'GET',
71 'callback' => array( $this, 'rest_scan' ),
72 ),
73 array(
74 'path' => '/clean',
75 'methods' => 'POST',
76 'callback' => array( $this, 'rest_clean' ),
77 ),
78 array(
79 'path' => '/optimize',
80 'methods' => 'POST',
81 'callback' => array( $this, 'rest_optimize' ),
82 ),
83 )
84 );
85 }
86
87 public function cli_commands(): array {
88 return array(
89 array(
90 'name' => 'xspeed db',
91 'callback' => array( $this, 'cli_handler' ),
92 'shortdesc' => 'Scan or clean WordPress bloat. Use --types=a,b to clean specific categories.',
93 'ai_hint' => 'Find and remove database bloat (post revisions, spam comments, expired transients, orphaned metadata). Always `scan` first to see what would go; `clean` is destructive and requires confirmation.',
94 'synopsis' => array(
95 array(
96 'type' => 'positional',
97 'name' => 'action',
98 'options' => array( 'scan', 'clean', 'optimize' ),
99 'optional' => false,
100 ),
101 array(
102 'type' => 'assoc',
103 'name' => 'types',
104 'optional' => true,
105 ),
106 ),
107 ),
108 );
109 }
110
111 public function boot(): void {
112 add_action( Database_Cleaner::CRON_HOOK, array( Database_Cleaner::class, 'cron_tick' ) );
113 add_action( 'update_option_xspeed_module_database', array( $this, 'on_settings_change' ), 10, 2 );
114 add_action( 'add_option_xspeed_module_database', array( $this, 'on_settings_added' ), 10, 2 );
115 }
116
117 public function deactivate(): void {
118 wp_clear_scheduled_hook( Database_Cleaner::CRON_HOOK );
119 }
120
121 public function on_settings_change( $old, $new ): void {
122 $schedule = is_array( $new ) ? (string) ( $new['schedule'] ?? 'manual' ) : 'manual';
123 $types = is_array( $new ) && isset( $new['included_types'] ) && is_array( $new['included_types'] ) ? $new['included_types'] : array();
124 Database_Cleaner::apply_schedule( $schedule, $types );
125 }
126
127 public function on_settings_added( $name, $value ): void {
128 $schedule = is_array( $value ) ? (string) ( $value['schedule'] ?? 'manual' ) : 'manual';
129 $types = is_array( $value ) && isset( $value['included_types'] ) && is_array( $value['included_types'] ) ? $value['included_types'] : array();
130 Database_Cleaner::apply_schedule( $schedule, $types );
131 }
132
133 public function rest_scan( \WP_REST_Request $request ) {
134 return rest_ensure_response(
135 array(
136 'scan' => Database_Cleaner::scan(),
137 'labels' => Database_Cleaner::type_labels(),
138 )
139 );
140 }
141
142 public function rest_clean( \WP_REST_Request $request ) {
143 $params = $request->get_json_params();
144 if ( ! is_array( $params ) ) {
145 $params = $request->get_params();
146 }
147 $types = isset( $params['types'] ) && is_array( $params['types'] ) ? $params['types'] : array();
148 if ( empty( $types ) ) {
149 return new \WP_Error( 'xspeed_db_no_types', __( 'Provide at least one cleanup type.', 'xspeed' ), array( 'status' => 400 ) );
150 }
151 return rest_ensure_response( Database_Cleaner::clean( $types ) );
152 }
153
154 public function rest_optimize( \WP_REST_Request $request ) {
155 return rest_ensure_response(
156 array(
157 'optimized' => Database_Cleaner::optimize_tables(),
158 )
159 );
160 }
161
162 public function cli_handler( array $args, array $assoc ): void {
163 $action = $args[0] ?? 'scan';
164
165 switch ( $action ) {
166 case 'scan':
167 foreach ( Database_Cleaner::scan() as $key => $row ) {
168 \WP_CLI::log( sprintf( '%-22s %s — %d rows', $key, $row['label'], $row['count'] ) );
169 }
170 return;
171
172 case 'clean':
173 $types = isset( $assoc['types'] ) ? array_filter( array_map( 'trim', explode( ',', (string) $assoc['types'] ) ) ) : array_keys( Database_Cleaner::type_labels() );
174 $res = Database_Cleaner::clean( $types );
175 foreach ( $res['cleaned'] as $key => $affected ) {
176 \WP_CLI::log( sprintf( '%-22s %d removed', $key, $affected ) );
177 }
178 \WP_CLI::success( 'Cleanup complete.' );
179 return;
180
181 case 'optimize':
182 $res = Database_Cleaner::optimize_tables();
183 foreach ( $res as $table => $ok ) {
184 \WP_CLI::log( sprintf( '%-40s %s', $table, $ok ? 'ok' : 'failed' ) );
185 }
186 \WP_CLI::success( 'Tables optimized.' );
187 return;
188
189 default:
190 \WP_CLI::error( "Unknown action: $action" );
191 }
192 }
193 }
194