PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.6.15
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.6.15
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 2.6.4 2.6.3 2.5.23 All 138 releases
metasync / wp-mcp-server / tools / class-mcp-tool-wordpress-settings.php

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

581 lines 18.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MCP Tools for WordPress Core SEO Settings
4 *
5 * Provides MCP tools for managing WordPress core settings that affect SEO.
6 *
7 * @package MetaSync
8 * @subpackage MCP_Server/Tools
9 */
10
11 if (!defined('ABSPATH')) {
12 exit;
13 }
14
15 require_once plugin_dir_path(dirname(__FILE__)) . 'class-mcp-tool-base.php';
16
17 /**
18 * Get Site Info Tool
19 *
20 * Gets site title, tagline, description, and URL
21 */
22 class MCP_Tool_Get_Site_Info extends MCP_Tool_Base {
23
24 public function get_name() {
25 return 'wordpress_get_site_info';
26 }
27
28 public function get_description() {
29 return 'Get site information (title, tagline, description, URL)';
30 }
31
32 public function get_input_schema() {
33 return [
34 'type' => 'object',
35 'properties' => (object)[],
36 ];
37 }
38
39 public function execute($params) {
40 $this->validate_params($params);
41 $this->require_capability('manage_options');
42
43 return $this->success([
44 'site_title' => get_bloginfo('name'),
45 'site_tagline' => get_bloginfo('description'),
46 'site_url' => get_site_url(),
47 'home_url' => get_home_url(),
48 'admin_email' => get_option('admin_email'),
49 'language' => get_locale(),
50 'charset' => get_bloginfo('charset'),
51 'wordpress_version' => get_bloginfo('version'),
52 ]);
53 }
54 }
55
56 /**
57 * Update Site Info Tool
58 *
59 * Updates site title and tagline
60 */
61 class MCP_Tool_Update_Site_Info extends MCP_Tool_Base {
62
63 public function get_name() {
64 return 'wordpress_update_site_info';
65 }
66
67 public function get_description() {
68 return 'Update site title and tagline';
69 }
70
71 public function get_input_schema() {
72 return [
73 'type' => 'object',
74 'properties' => [
75 'site_title' => [
76 'type' => 'string',
77 'description' => 'Site title (optional)',
78 ],
79 'site_tagline' => [
80 'type' => 'string',
81 'description' => 'Site tagline/description (optional)',
82 ],
83 ],
84 ];
85 }
86
87 public function execute($params) {
88 $this->validate_params($params);
89 $this->require_capability('manage_options');
90
91 $updated = [];
92
93 // Elementor hooks into update_option_blogname/blogdescription to sync its
94 // Kit settings and runs current_user_can() inside that hook. Under API key
95 // auth there is no WP user session, so Elementor throws "Access denied."
96 // Temporarily remove third-party hooks on these options during the update.
97 $should_unhook = defined('METASYNC_MCP_API_KEY_AUTH') && METASYNC_MCP_API_KEY_AUTH;
98 $saved_filters = [];
99
100 if ($should_unhook) {
101 global $wp_filter;
102 foreach (['update_option_blogname', 'update_option_blogdescription'] as $hook) {
103 if (isset($wp_filter[$hook])) {
104 $saved_filters[$hook] = $wp_filter[$hook];
105 remove_all_actions($hook);
106 }
107 }
108 }
109
110 if (isset($params['site_title'])) {
111 update_option('blogname', sanitize_text_field($params['site_title']));
112 $updated[] = 'site_title';
113 }
114
115 if (isset($params['site_tagline'])) {
116 update_option('blogdescription', sanitize_text_field($params['site_tagline']));
117 $updated[] = 'site_tagline';
118 }
119
120 // Restore hooks
121 if ($should_unhook && !empty($saved_filters)) {
122 global $wp_filter;
123 foreach ($saved_filters as $hook => $filter_obj) {
124 $wp_filter[$hook] = $filter_obj;
125 }
126 }
127
128 if (empty($updated)) {
129 throw new Exception('No fields to update provided');
130 }
131
132 return $this->success([
133 'site_title' => get_bloginfo('name'),
134 'site_tagline' => get_bloginfo('description'),
135 'updated_fields' => $updated,
136 'message' => 'Site information updated successfully',
137 ]);
138 }
139 }
140
141 /**
142 * Get Permalink Structure Tool
143 *
144 * Gets permalink settings
145 */
146 class MCP_Tool_Get_Permalink_Structure extends MCP_Tool_Base {
147
148 public function get_name() {
149 return 'wordpress_get_permalink_structure';
150 }
151
152 public function get_description() {
153 return 'Get permalink structure settings';
154 }
155
156 public function get_input_schema() {
157 return [
158 'type' => 'object',
159 'properties' => (object)[],
160 ];
161 }
162
163 public function execute($params) {
164 $this->validate_params($params);
165 $this->require_capability('manage_options');
166
167 $permalink_structure = get_option('permalink_structure');
168
169 // Determine permalink type
170 $type = 'plain';
171 if ($permalink_structure === '/%year%/%monthnum%/%day%/%postname%/') {
172 $type = 'day_and_name';
173 } elseif ($permalink_structure === '/%year%/%monthnum%/%postname%/') {
174 $type = 'month_and_name';
175 } elseif ($permalink_structure === '/%postname%/') {
176 $type = 'post_name';
177 } elseif (!empty($permalink_structure)) {
178 $type = 'custom';
179 }
180
181 return $this->success([
182 'permalink_structure' => $permalink_structure ?: '',
183 'type' => $type,
184 'category_base' => get_option('category_base') ?: '',
185 'tag_base' => get_option('tag_base') ?: '',
186 ]);
187 }
188 }
189
190 /**
191 * Update Permalink Structure Tool
192 *
193 * Updates permalink settings
194 */
195 class MCP_Tool_Update_Permalink_Structure extends MCP_Tool_Base {
196
197 public function get_name() {
198 return 'wordpress_update_permalink_structure';
199 }
200
201 public function get_description() {
202 return 'Update permalink structure (automatically flushes rewrite rules)';
203 }
204
205 public function get_input_schema() {
206 return [
207 'type' => 'object',
208 'properties' => [
209 'structure' => [
210 'type' => 'string',
211 'description' => 'Permalink structure (e.g., "/%postname%/" or "/%year%/%monthnum%/%postname%/")',
212 ],
213 'category_base' => [
214 'type' => 'string',
215 'description' => 'Category base (optional)',
216 ],
217 'tag_base' => [
218 'type' => 'string',
219 'description' => 'Tag base (optional)',
220 ],
221 ],
222 'required' => ['structure'],
223 ];
224 }
225
226 public function execute($params) {
227 $this->validate_params($params);
228 $this->require_capability('manage_options');
229
230 $structure = sanitize_text_field($params['structure']);
231
232 // Validate structure
233 if (!empty($structure) && strpos($structure, '%') === false) {
234 throw new Exception('Invalid permalink structure. Must contain at least one tag (e.g., %postname%)');
235 }
236
237 // Update permalink structure
238 update_option('permalink_structure', $structure);
239
240 // Update category base if provided
241 if (isset($params['category_base'])) {
242 update_option('category_base', sanitize_title($params['category_base']));
243 }
244
245 // Update tag base if provided
246 if (isset($params['tag_base'])) {
247 update_option('tag_base', sanitize_title($params['tag_base']));
248 }
249
250 // Flush rewrite rules
251 flush_rewrite_rules();
252
253 return $this->success([
254 'permalink_structure' => get_option('permalink_structure'),
255 'category_base' => get_option('category_base') ?: '',
256 'tag_base' => get_option('tag_base') ?: '',
257 'message' => 'Permalink structure updated and rewrite rules flushed',
258 ]);
259 }
260 }
261
262 /**
263 * Get Reading Settings Tool
264 *
265 * Gets reading settings
266 */
267 class MCP_Tool_Get_Reading_Settings extends MCP_Tool_Base {
268
269 public function get_name() {
270 return 'wordpress_get_reading_settings';
271 }
272
273 public function get_description() {
274 return 'Get reading settings (posts per page, front page settings)';
275 }
276
277 public function get_input_schema() {
278 return [
279 'type' => 'object',
280 'properties' => (object)[],
281 ];
282 }
283
284 public function execute($params) {
285 $this->validate_params($params);
286 $this->require_capability('manage_options');
287
288 $show_on_front = get_option('show_on_front');
289 $page_on_front = get_option('page_on_front');
290 $page_for_posts = get_option('page_for_posts');
291
292 $result = [
293 'posts_per_page' => (int)get_option('posts_per_page'),
294 'show_on_front' => $show_on_front, // 'posts' or 'page'
295 ];
296
297 if ($show_on_front === 'page') {
298 $result['page_on_front'] = (int)$page_on_front;
299 $result['page_on_front_title'] = $page_on_front ? get_the_title($page_on_front) : null;
300 $result['page_for_posts'] = (int)$page_for_posts;
301 $result['page_for_posts_title'] = $page_for_posts ? get_the_title($page_for_posts) : null;
302 }
303
304 return $this->success($result);
305 }
306 }
307
308 /**
309 * Update Reading Settings Tool
310 *
311 * Updates reading settings
312 */
313 class MCP_Tool_Update_Reading_Settings extends MCP_Tool_Base {
314
315 public function get_name() {
316 return 'wordpress_update_reading_settings';
317 }
318
319 public function get_description() {
320 return 'Update reading settings (posts per page, front page)';
321 }
322
323 public function get_input_schema() {
324 return [
325 'type' => 'object',
326 'properties' => [
327 'posts_per_page' => [
328 'type' => 'integer',
329 'description' => 'Number of posts to show per page (optional)',
330 'minimum' => 1,
331 'maximum' => 100,
332 ],
333 'show_on_front' => [
334 'type' => 'string',
335 'enum' => ['posts', 'page'],
336 'description' => 'What to show on front page: posts or static page (optional)',
337 ],
338 'page_on_front' => [
339 'type' => 'integer',
340 'description' => 'Page ID to use as front page (required if show_on_front is "page")',
341 ],
342 'page_for_posts' => [
343 'type' => 'integer',
344 'description' => 'Page ID to use for blog posts (optional)',
345 ],
346 ],
347 ];
348 }
349
350 public function execute($params) {
351 $this->validate_params($params);
352 $this->require_capability('manage_options');
353
354 $updated = [];
355
356 if (isset($params['posts_per_page'])) {
357 $posts_per_page = intval($params['posts_per_page']);
358 if ($posts_per_page < 1 || $posts_per_page > 100) {
359 throw new Exception('posts_per_page must be between 1 and 100');
360 }
361 update_option('posts_per_page', $posts_per_page);
362 $updated[] = 'posts_per_page';
363 }
364
365 if (isset($params['show_on_front'])) {
366 $show_on_front = sanitize_text_field($params['show_on_front']);
367
368 if ($show_on_front === 'page' && !isset($params['page_on_front'])) {
369 throw new Exception('page_on_front is required when show_on_front is "page"');
370 }
371
372 update_option('show_on_front', $show_on_front);
373 $updated[] = 'show_on_front';
374 }
375
376 if (isset($params['page_on_front'])) {
377 $page_id = intval($params['page_on_front']);
378 $page = get_post($page_id);
379 if (!$page || $page->post_type !== 'page') {
380 throw new Exception(sprintf("Invalid page_on_front: %d", absint($page_id)));
381 }
382 update_option('page_on_front', $page_id);
383 $updated[] = 'page_on_front';
384 }
385
386 if (isset($params['page_for_posts'])) {
387 $page_id = intval($params['page_for_posts']);
388 if ($page_id > 0) {
389 $page = get_post($page_id);
390 if (!$page || $page->post_type !== 'page') {
391 throw new Exception(sprintf("Invalid page_for_posts: %d", absint($page_id)));
392 }
393 }
394 update_option('page_for_posts', $page_id);
395 $updated[] = 'page_for_posts';
396 }
397
398 if (empty($updated)) {
399 throw new Exception('No fields to update provided');
400 }
401
402 return $this->success([
403 'posts_per_page' => (int)get_option('posts_per_page'),
404 'show_on_front' => get_option('show_on_front'),
405 'updated_fields' => $updated,
406 'message' => 'Reading settings updated successfully',
407 ]);
408 }
409 }
410
411 /**
412 * Get Search Visibility Tool
413 *
414 * Gets search engine visibility setting
415 */
416 class MCP_Tool_Get_Search_Visibility extends MCP_Tool_Base {
417
418 public function get_name() {
419 return 'wordpress_get_search_visibility';
420 }
421
422 public function get_description() {
423 return 'Get search engine visibility setting (blog_public option)';
424 }
425
426 public function get_input_schema() {
427 return [
428 'type' => 'object',
429 'properties' => (object)[],
430 ];
431 }
432
433 public function execute($params) {
434 $this->validate_params($params);
435 $this->require_capability('manage_options');
436
437 $blog_public = (int)get_option('blog_public');
438
439 return $this->success([
440 'blog_public' => $blog_public,
441 'visible_to_search_engines' => $blog_public === 1,
442 'discourage_search_engines' => $blog_public === 0,
443 ]);
444 }
445 }
446
447 /**
448 * Update Search Visibility Tool
449 *
450 * Updates search engine visibility setting
451 */
452 class MCP_Tool_Update_Search_Visibility extends MCP_Tool_Base {
453
454 public function get_name() {
455 return 'wordpress_update_search_visibility';
456 }
457
458 public function get_description() {
459 return 'Update search engine visibility (requires confirm: true for safety)';
460 }
461
462 public function get_input_schema() {
463 return [
464 'type' => 'object',
465 'properties' => [
466 'visible_to_search_engines' => [
467 'type' => 'boolean',
468 'description' => 'True to allow search engines, false to discourage',
469 ],
470 'confirm' => [
471 'type' => 'boolean',
472 'description' => 'Must be true to confirm this change',
473 ],
474 ],
475 'required' => ['visible_to_search_engines', 'confirm'],
476 ];
477 }
478
479 public function execute($params) {
480 $this->validate_params($params);
481 $this->require_capability('manage_options');
482
483 // Require confirmation
484 if (!isset($params['confirm']) || $params['confirm'] !== true) {
485 throw new Exception('This action requires confirm: true parameter for safety');
486 }
487
488 $visible = (bool)$params['visible_to_search_engines'];
489 $blog_public = $visible ? 1 : 0;
490
491 update_option('blog_public', $blog_public);
492
493 return $this->success([
494 'blog_public' => $blog_public,
495 'visible_to_search_engines' => $visible,
496 'message' => $visible
497 ? 'Site is now visible to search engines'
498 : 'Site is now discouraged from search engine indexing',
499 ]);
500 }
501 }
502
503 /**
504 * Get Date Format Tool
505 *
506 * Gets date/time formats and timezone
507 */
508 class MCP_Tool_Get_Date_Format extends MCP_Tool_Base {
509
510 public function get_name() {
511 return 'wordpress_get_date_format';
512 }
513
514 public function get_description() {
515 return 'Get date/time format settings and timezone';
516 }
517
518 public function get_input_schema() {
519 return [
520 'type' => 'object',
521 'properties' => (object)[],
522 ];
523 }
524
525 public function execute($params) {
526 $this->validate_params($params);
527 $this->require_capability('manage_options');
528
529 return $this->success([
530 'date_format' => get_option('date_format'),
531 'time_format' => get_option('time_format'),
532 'timezone_string' => get_option('timezone_string'),
533 'gmt_offset' => get_option('gmt_offset'),
534 'week_starts_on' => (int)get_option('start_of_week'), // 0 = Sunday, 1 = Monday, etc.
535 'example_date' => date_i18n(get_option('date_format')),
536 'example_time' => date_i18n(get_option('time_format')),
537 ]);
538 }
539 }
540
541 /**
542 * Get Discussion Settings Tool
543 *
544 * Gets comment and discussion settings
545 */
546 class MCP_Tool_Get_Discussion_Settings extends MCP_Tool_Base {
547
548 public function get_name() {
549 return 'wordpress_get_discussion_settings';
550 }
551
552 public function get_description() {
553 return 'Get comment and discussion settings';
554 }
555
556 public function get_input_schema() {
557 return [
558 'type' => 'object',
559 'properties' => (object)[],
560 ];
561 }
562
563 public function execute($params) {
564 $this->validate_params($params);
565 $this->require_capability('manage_options');
566
567 return $this->success([
568 'default_comment_status' => get_option('default_comment_status'), // 'open' or 'closed'
569 'default_ping_status' => get_option('default_ping_status'), // 'open' or 'closed'
570 'comment_registration' => (bool)get_option('comment_registration'), // Must be registered to comment
571 'comment_moderation' => (bool)get_option('comment_moderation'), // Comments must be manually approved
572 'comment_whitelist' => (bool)get_option('comment_whitelist'), // Comment author must have previously approved comment
573 'comments_per_page' => (int)get_option('comments_per_page'),
574 'thread_comments' => (bool)get_option('thread_comments'), // Enable threaded comments
575 'thread_comments_depth' => (int)get_option('thread_comments_depth'),
576 'page_comments' => (bool)get_option('page_comments'), // Break comments into pages
577 'show_avatars' => (bool)get_option('show_avatars'),
578 ]);
579 }
580 }
581