PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.6.8
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.6.8
2.7.1 2.7.2 2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 All 141 releases
metasync / wp-mcp-server / tools / class-mcp-tool-redirects.php

class-mcp-tool-redirects.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.6.8, at wp-mcp-server/tools/class-mcp-tool-redirects.php

377 lines 12.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MCP Tool: Redirect Management
4 *
5 * Provides tools for managing WordPress redirects.
6 *
7 * @package MetaSync
8 * @subpackage MCP_Server/Tools
9 */
10
11 if (!defined('ABSPATH')) {
12 exit;
13 }
14
15 /**
16 * Create Redirect Tool
17 */
18 class MCP_Tool_Create_Redirect extends MCP_Tool_Base {
19
20 public function get_name() {
21 return 'wordpress_create_redirect';
22 }
23
24 public function get_description() {
25 return 'Create a 301 or 302 redirect from one URL to another';
26 }
27
28 public function get_input_schema() {
29 return [
30 'type' => 'object',
31 'properties' => [
32 'source' => [
33 'type' => 'string',
34 'description' => 'Source URL path (e.g., /old-page or https://example.com/old-page)'
35 ],
36 'destination' => [
37 'type' => 'string',
38 'description' => 'Destination URL (full URL or path)'
39 ],
40 'type' => [
41 'type' => 'integer',
42 'description' => 'Redirect HTTP code',
43 'enum' => [301, 302],
44 'default' => 301
45 ],
46 'description' => [
47 'type' => 'string',
48 'description' => 'Optional description of the redirect',
49 'default' => ''
50 ]
51 ],
52 'required' => ['source', 'destination']
53 ];
54 }
55
56 public function execute($params) {
57 $this->validate_params($params);
58 $this->require_capability('manage_options');
59
60 // Load database class
61 require_once plugin_dir_path(dirname(dirname(__FILE__))) . 'redirections/class-metasync-redirection-database.php';
62 $db = new Metasync_Redirection_Database();
63
64 $source = $this->sanitize_url($params['source']);
65 $destination = $this->sanitize_url($params['destination']);
66 $http_code = isset($params['type']) ? $this->sanitize_integer($params['type']) : 301;
67 $description = isset($params['description']) ? $this->sanitize_textarea($params['description']) : '';
68
69 if (!get_option('metasync_allow_external_redirects', 0) && !empty($destination) && wp_validate_redirect($destination, '') !== $destination) {
70 return [
71 'error' => 'external_destination',
72 'message' => 'Destination URL must be on this site. Enable "Allow External Redirects" in plugin settings to permit off-site redirects.',
73 ];
74 }
75
76 // Parse source to get path
77 $source_path = parse_url($source, PHP_URL_PATH) ?: $source;
78
79 // Loop detection — refuse to create a redirect whose chain resolves back to the source
80 require_once plugin_dir_path(dirname(dirname(__FILE__))) . 'redirections/class-metasync-redirection.php';
81 $db_ref = $db;
82 $redirection_helper = new Metasync_Redirection($db_ref);
83 $loop_chain = [];
84 if ($redirection_helper->would_create_loop($source_path, $destination, $loop_chain)) {
85 return [
86 'error' => 'loop_detected',
87 'chain' => $loop_chain,
88 ];
89 }
90
91 // Create redirect
92 $result = $db->add([
93 'sources_from' => [$source_path],
94 'url_redirect_to' => $destination,
95 'http_code' => $http_code,
96 'description' => $description,
97 'status' => 'active',
98 'pattern_type' => 'exact'
99 ]);
100
101 if ($result === false) {
102 throw new Exception('Failed to create redirect');
103 }
104
105 return $this->success([
106 'redirect_id' => $result,
107 'source' => $source_path,
108 'destination' => $destination,
109 'type' => $http_code,
110 'status' => 'active'
111 ], 'Redirect created successfully');
112 }
113 }
114
115 /**
116 * List Redirects Tool
117 */
118 class MCP_Tool_List_Redirects extends MCP_Tool_Base {
119
120 public function get_name() {
121 return 'wordpress_list_redirects';
122 }
123
124 public function get_description() {
125 return 'List all redirects with optional status filter';
126 }
127
128 public function get_input_schema() {
129 return [
130 'type' => 'object',
131 'properties' => [
132 'status' => [
133 'type' => 'string',
134 'description' => 'Filter by status',
135 'enum' => ['active', 'inactive', 'all'],
136 'default' => 'active'
137 ],
138 'limit' => [
139 'type' => 'integer',
140 'description' => 'Maximum number of results',
141 'default' => 50,
142 'minimum' => 1,
143 'maximum' => 200
144 ]
145 ],
146 'required' => []
147 ];
148 }
149
150 public function execute($params) {
151 $this->validate_params($params);
152 $this->require_capability('manage_options');
153
154 require_once plugin_dir_path(dirname(dirname(__FILE__))) . 'redirections/class-metasync-redirection-database.php';
155 $db = new Metasync_Redirection_Database();
156
157 $status = isset($params['status']) ? $params['status'] : 'active';
158
159 // Get redirects
160 if ($status === 'active') {
161 $redirects = $db->getAllActiveRecords();
162 } else {
163 $redirects = $db->getAllRecords();
164 }
165
166 // Filter by status if needed
167 if ($status !== 'all' && $status !== 'active') {
168 $redirects = array_filter($redirects, function($r) use ($status) {
169 return $r->status === $status;
170 });
171 }
172
173 // Limit results
174 $limit = isset($params['limit']) ? $this->sanitize_integer($params['limit']) : 50;
175 $redirects = array_slice($redirects, 0, $limit);
176
177 // Format results (sources_from may be JSON or legacy serialized in DB)
178 $result = array_map(function($redirect) {
179 $sources_raw = $redirect->sources_from;
180 $source = null;
181 if ( ! empty( $sources_raw ) ) {
182 // Try JSON first; fall back to unserialize for legacy DB records
183 $sources = json_decode( $sources_raw, true );
184 if ( $sources === null && $sources_raw !== 'null' ) {
185 $sources = unserialize( $sources_raw, ['allowed_classes' => false] ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize
186 }
187 if ( is_array( $sources ) && ! empty( $sources ) ) {
188 $keys = array_keys( $sources );
189 $source = is_int( $keys[0] ) ? $sources[ $keys[0] ] : $keys[0];
190 }
191 }
192 return [
193 'id' => $redirect->id,
194 'source' => $source,
195 'destination' => $redirect->url_redirect_to,
196 'type' => $redirect->http_code,
197 'hits' => $redirect->hits_count,
198 'status' => $redirect->status,
199 'pattern_type' => $redirect->pattern_type ?? 'exact',
200 'description' => $redirect->description ?? '',
201 'created_at' => $redirect->created_at ?? null
202 ];
203 }, $redirects);
204
205 return $this->success([
206 'redirects' => $result,
207 'total' => count($result)
208 ]);
209 }
210 }
211
212 /**
213 * Delete Redirect Tool
214 */
215 class MCP_Tool_Delete_Redirect extends MCP_Tool_Base {
216
217 public function get_name() {
218 return 'wordpress_delete_redirect';
219 }
220
221 public function get_description() {
222 return 'Delete a redirect by ID';
223 }
224
225 public function get_input_schema() {
226 return [
227 'type' => 'object',
228 'properties' => [
229 'redirect_id' => [
230 'type' => 'integer',
231 'description' => 'Redirect ID to delete',
232 'minimum' => 1
233 ]
234 ],
235 'required' => ['redirect_id']
236 ];
237 }
238
239 public function execute($params) {
240 $this->validate_params($params);
241 $this->require_capability('manage_options');
242
243 require_once plugin_dir_path(dirname(dirname(__FILE__))) . 'redirections/class-metasync-redirection-database.php';
244 $db = new Metasync_Redirection_Database();
245
246 $redirect_id = $this->sanitize_integer($params['redirect_id']);
247
248 // Verify redirect exists
249 $redirect = $db->find($redirect_id);
250 if (!$redirect) {
251 throw new Exception(sprintf("Redirect not found: %d", absint($redirect_id)));
252 }
253
254 // Delete redirect
255 $result = $db->delete([$redirect_id]);
256
257 if ($result === false) {
258 throw new Exception('Failed to delete redirect');
259 }
260
261 return $this->success([
262 'redirect_id' => $redirect_id,
263 'deleted' => true
264 ], 'Redirect deleted successfully');
265 }
266 }
267
268 /**
269 * Update Redirect Tool
270 */
271 class MCP_Tool_Update_Redirect extends MCP_Tool_Base {
272
273 public function get_name() {
274 return 'wordpress_update_redirect';
275 }
276
277 public function get_description() {
278 return 'Update an existing redirect';
279 }
280
281 public function get_input_schema() {
282 return [
283 'type' => 'object',
284 'properties' => [
285 'redirect_id' => [
286 'type' => 'integer',
287 'description' => 'Redirect ID to update',
288 'minimum' => 1
289 ],
290 'destination' => [
291 'type' => 'string',
292 'description' => 'New destination URL (optional)'
293 ],
294 'type' => [
295 'type' => 'integer',
296 'description' => 'New redirect HTTP code (optional)',
297 'enum' => [301, 302]
298 ],
299 'status' => [
300 'type' => 'string',
301 'description' => 'New status (optional)',
302 'enum' => ['active', 'inactive']
303 ]
304 ],
305 'required' => ['redirect_id']
306 ];
307 }
308
309 public function execute($params) {
310 $this->validate_params($params);
311 $this->require_capability('manage_options');
312
313 require_once plugin_dir_path(dirname(dirname(__FILE__))) . 'redirections/class-metasync-redirection-database.php';
314 $db = new Metasync_Redirection_Database();
315
316 $redirect_id = $this->sanitize_integer($params['redirect_id']);
317
318 // Verify redirect exists
319 $redirect = $db->find($redirect_id);
320 if (!$redirect) {
321 throw new Exception(sprintf("Redirect not found: %d", absint($redirect_id)));
322 }
323
324 // Build update args
325 $update_args = ['updated_at' => current_time('mysql')];
326
327 if (isset($params['destination'])) {
328 $destination = $this->sanitize_url($params['destination']);
329 if (!get_option('metasync_allow_external_redirects', 0) && !empty($destination) && wp_validate_redirect($destination, '') !== $destination) {
330 return [
331 'error' => 'external_destination',
332 'message' => 'Destination URL must be on this site. Enable "Allow External Redirects" in plugin settings to permit off-site redirects.',
333 ];
334 }
335 $update_args['url_redirect_to'] = $destination;
336 }
337
338 if (isset($params['type'])) {
339 $update_args['http_code'] = $this->sanitize_integer($params['type']);
340 }
341
342 if (isset($params['status'])) {
343 $update_args['status'] = $this->sanitize_string($params['status']);
344 }
345
346 // Update redirect
347 $result = $db->update($update_args, $redirect_id);
348
349 if ($result === false) {
350 throw new Exception('Failed to update redirect');
351 }
352
353 // Get updated redirect (sources_from may be JSON or legacy serialized in DB)
354 $updated = $db->find($redirect_id);
355 $source = null;
356 if ( ! empty( $updated->sources_from ) ) {
357 // Try JSON first; fall back to unserialize for legacy DB records
358 $sources = json_decode( $updated->sources_from, true );
359 if ( $sources === null && $updated->sources_from !== 'null' ) {
360 $sources = unserialize( $updated->sources_from, ['allowed_classes' => false] ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize
361 }
362 if ( is_array( $sources ) && ! empty( $sources ) ) {
363 $keys = array_keys( $sources );
364 $source = is_int( $keys[0] ) ? $sources[ $keys[0] ] : $keys[0];
365 }
366 }
367
368 return $this->success([
369 'redirect_id' => $redirect_id,
370 'source' => $source,
371 'destination' => $updated->url_redirect_to,
372 'type' => $updated->http_code,
373 'status' => $updated->status
374 ], 'Redirect updated successfully');
375 }
376 }
377