PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.5.23
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.5.23
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-plugin-settings.php

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

582 lines 20.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MCP Tool: Plugin Settings Management
4 *
5 * Provides tools for viewing and managing WordPress plugin settings.
6 * This allows AI agents to read and update all MetaSync plugin configuration.
7 *
8 * @package MetaSync
9 * @subpackage MCP_Server/Tools
10 */
11
12 if (!defined('ABSPATH')) {
13 exit;
14 }
15
16 /**
17 * Get Plugin Settings Tool
18 */
19 class MCP_Tool_Get_Plugin_Settings extends MCP_Tool_Base {
20
21 public function get_name() {
22 return 'wordpress_get_plugin_settings';
23 }
24
25 public function get_description() {
26 return 'Get all plugin settings or settings for a specific section. Returns the complete plugin configuration including features, SEO controls, API keys, and more.';
27 }
28
29 public function get_input_schema() {
30 return [
31 'type' => 'object',
32 'properties' => [
33 'section' => [
34 'type' => 'string',
35 'description' => 'Optional: specific settings section to retrieve (e.g., "general", "whitelabel", "seo"). If omitted, returns all settings.',
36 'enum' => [
37 'general',
38 'whitelabel',
39 'seo',
40 'social',
41 'advanced',
42 'features',
43 'api',
44 'all'
45 ]
46 ],
47 'keys' => [
48 'type' => 'array',
49 'description' => 'Optional: specific setting keys to retrieve. If provided, only these keys will be returned.',
50 'items' => [
51 'type' => 'string'
52 ]
53 ]
54 ],
55 'required' => []
56 ];
57 }
58
59 public function execute($params) {
60 // Validate and check permissions
61 $this->validate_params($params);
62 $this->require_capability('manage_options');
63
64 // Get all plugin options
65 $all_options = get_option(Metasync::option_name, []);
66
67 // If specific keys requested
68 if (!empty($params['keys']) && is_array($params['keys'])) {
69 $result = [];
70 foreach ($params['keys'] as $key) {
71 $key = $this->sanitize_string($key);
72 if (isset($all_options[$key])) {
73 $result[$key] = $all_options[$key];
74 }
75 }
76 return $this->success([
77 'settings' => $result,
78 'count' => count($result)
79 ]);
80 }
81
82 // If section specified (options are nested e.g. $all_options['general']['apikey'])
83 if (!empty($params['section']) && $params['section'] !== 'all') {
84 $section = $this->sanitize_string($params['section']);
85
86 if (isset($all_options[$section]) && is_array($all_options[$section])) {
87 $result = $all_options[$section];
88 } else {
89 // Fallback: map section to flat keys for legacy structure
90 $section_keys = $this->get_section_keys($section);
91 $result = [];
92 foreach ($section_keys as $key) {
93 if (isset($all_options[$key])) {
94 $result[$key] = $all_options[$key];
95 }
96 }
97 }
98
99 return $this->success([
100 'section' => $section,
101 'settings' => $result,
102 'count' => is_array($result) ? count($result) : 0
103 ]);
104 }
105
106 // Return all settings
107 return $this->success([
108 'settings' => $all_options,
109 'count' => count($all_options),
110 'available_sections' => [
111 'general' => 'API keys, integration settings',
112 'whitelabel' => 'Branding and white-label configuration',
113 'seo' => 'SEO controls and indexation settings',
114 'social' => 'Social media and OpenGraph settings',
115 'advanced' => 'Advanced plugin features',
116 'features' => 'Feature toggles and visibility',
117 'api' => 'API configuration and tokens'
118 ]
119 ]);
120 }
121
122 /**
123 * Get setting keys for a specific section
124 */
125 private function get_section_keys($section) {
126 $section_map = [
127 'general' => [
128 'searchatlas_api_key',
129 'apikey',
130 'permalink_structure',
131 'hide_dashboard_framework',
132 'show_admin_bar_status',
133 'enable_auto_updates'
134 ],
135 'whitelabel' => [
136 'white_label_plugin_name',
137 'whitelabel_otto_name',
138 'whitelabel_logo_url',
139 'whitelabel_domain_url',
140 'white_label_plugin_description',
141 'white_label_plugin_author',
142 'white_label_plugin_author_uri',
143 'white_label_plugin_uri',
144 'white_label_plugin_menu_slug',
145 'white_label_plugin_menu_icon',
146 'whitelabel_settings_password'
147 ],
148 'seo' => [
149 'index_date_archives',
150 'index_tag_archives',
151 'index_author_archives',
152 'index_format_archives',
153 'index_category_archives',
154 'override_robots_tags',
155 'enable_googleinstantindex',
156 'google_index_api_config'
157 ],
158 'social' => [
159 'otto_pixel_uuid',
160 'otto_disable_on_loggedin',
161 'otto_disable_preview_button',
162 'periodic_clear_ottopage_cache',
163 'periodic_clear_ottopost_cache',
164 'periodic_clear_otto_cache'
165 ],
166 'advanced' => [
167 'disable_common_robots_metabox',
168 'disable_advance_robots_metabox',
169 'disable_redirection_metabox',
170 'disable_canonical_metabox',
171 'disable_social_opengraph_metabox',
172 'disable_schema_markup_metabox'
173 ],
174 'features' => [
175 'enabled_elementor_plugin_css',
176 'enabled_elementor_plugin_css_color',
177 'import_external_data',
178 'content_genius_sync_roles'
179 ],
180 'api' => [
181 'searchatlas_api_key',
182 'apikey',
183 'google_index_api_config'
184 ]
185 ];
186
187 return $section_map[$section] ?? [];
188 }
189 }
190
191 /**
192 * Update Plugin Settings Tool
193 */
194 class MCP_Tool_Update_Plugin_Settings extends MCP_Tool_Base {
195
196 public function get_name() {
197 return 'wordpress_update_plugin_settings';
198 }
199
200 public function get_description() {
201 return 'Update one or more plugin settings. Allows modifying plugin configuration including features, SEO controls, API keys, whitelabel settings, and more.';
202 }
203
204 public function get_input_schema() {
205 return [
206 'type' => 'object',
207 'properties' => [
208 'settings' => [
209 'type' => 'object',
210 'description' => 'Key-value pairs of settings to update. Each key is a setting name and value is the new value.',
211 'additionalProperties' => true
212 ],
213 'merge' => [
214 'type' => 'boolean',
215 'description' => 'If true (default), merges with existing settings. If false, replaces all settings with provided values.',
216 'default' => true
217 ]
218 ],
219 'required' => ['settings']
220 ];
221 }
222
223 public function execute($params) {
224 // Validate and check permissions
225 $this->validate_params($params);
226 $this->require_capability('manage_options');
227
228 if (empty($params['settings']) || !is_array($params['settings'])) {
229 throw new Exception('Settings must be a non-empty object/array');
230 }
231
232 $merge = isset($params['merge']) ? (bool)$params['merge'] : true;
233
234 // Get current options
235 $current_options = get_option(Metasync::option_name, []);
236
237 if ($merge) {
238 // Merge with existing settings
239 $new_options = array_merge($current_options, $params['settings']);
240 } else {
241 // Replace all settings
242 $new_options = $params['settings'];
243 }
244
245 // Sanitize sensitive fields
246 $new_options = $this->sanitize_settings($new_options);
247
248 // Update the option
249 $updated = update_option(Metasync::option_name, $new_options);
250
251 if ($updated === false && $current_options !== $new_options) {
252 throw new Exception('Failed to update plugin settings');
253 }
254
255 // Clear any relevant caches
256 wp_cache_delete(Metasync::option_name, 'options');
257
258 return $this->success([
259 'message' => 'Plugin settings updated successfully',
260 'updated_keys' => array_keys($params['settings']),
261 'merge_mode' => $merge,
262 'total_settings' => count($new_options)
263 ]);
264 }
265
266 /**
267 * Sanitize settings before saving
268 */
269 private function sanitize_settings($settings) {
270 $sanitized = [];
271
272 foreach ($settings as $key => $value) {
273 $key = sanitize_key($key);
274
275 // Handle different types of values
276 if (is_array($value)) {
277 $sanitized[$key] = $this->sanitize_array($value);
278 } elseif (is_bool($value)) {
279 $sanitized[$key] = (bool)$value;
280 } elseif (is_numeric($value)) {
281 $sanitized[$key] = $value;
282 } elseif ($this->is_sensitive_field($key)) {
283 // Don't sanitize sensitive fields too aggressively
284 $sanitized[$key] = $value;
285 } elseif ($this->is_url_field($key)) {
286 $sanitized[$key] = esc_url_raw($value);
287 } else {
288 $sanitized[$key] = sanitize_text_field($value);
289 }
290 }
291
292 return $sanitized;
293 }
294
295 /**
296 * Sanitize array values recursively
297 */
298 private function sanitize_array($array) {
299 $sanitized = [];
300 foreach ($array as $key => $value) {
301 $key = sanitize_key($key);
302 if (is_array($value)) {
303 $sanitized[$key] = $this->sanitize_array($value);
304 } else {
305 $sanitized[$key] = sanitize_text_field($value);
306 }
307 }
308 return $sanitized;
309 }
310
311 /**
312 * Check if field is sensitive (API keys, tokens, passwords)
313 */
314 private function is_sensitive_field($key) {
315 $sensitive_patterns = ['api_key', 'apikey', 'token', 'password', 'secret'];
316 foreach ($sensitive_patterns as $pattern) {
317 if (stripos($key, $pattern) !== false) {
318 return true;
319 }
320 }
321 return false;
322 }
323
324 /**
325 * Check if field should be a URL
326 */
327 private function is_url_field($key) {
328 $url_patterns = ['url', 'uri', 'domain', 'logo', 'link'];
329 foreach ($url_patterns as $pattern) {
330 if (stripos($key, $pattern) !== false) {
331 return true;
332 }
333 }
334 return false;
335 }
336 }
337
338 /**
339 * List Available Settings Tool
340 */
341 class MCP_Tool_List_Plugin_Settings_Schema extends MCP_Tool_Base {
342
343 public function get_name() {
344 return 'wordpress_list_plugin_settings_schema';
345 }
346
347 public function get_description() {
348 return 'Get a schema of all available plugin settings with descriptions and expected types. Useful for understanding what settings can be configured.';
349 }
350
351 public function get_input_schema() {
352 return [
353 'type' => 'object',
354 'properties' => (object)[],
355 'required' => []
356 ];
357 }
358
359 public function execute($params) {
360 $this->validate_params($params);
361 $this->require_capability('manage_options');
362
363 $schema = [
364 'general' => [
365 'description' => 'General plugin configuration',
366 'settings' => [
367 'searchatlas_api_key' => [
368 'type' => 'string',
369 'description' => 'Search Atlas API key for integration',
370 'sensitive' => true
371 ],
372 'apikey' => [
373 'type' => 'string',
374 'description' => 'Plugin authentication token',
375 'sensitive' => true
376 ],
377 'hide_dashboard_framework' => [
378 'type' => 'boolean',
379 'description' => 'Hide the dashboard framework'
380 ],
381 'show_admin_bar_status' => [
382 'type' => 'boolean',
383 'description' => 'Show plugin status in admin bar'
384 ],
385 'enable_auto_updates' => [
386 'type' => 'boolean',
387 'description' => 'Enable automatic plugin updates'
388 ]
389 ]
390 ],
391 'whitelabel' => [
392 'description' => 'White-label branding configuration',
393 'settings' => [
394 'white_label_plugin_name' => [
395 'type' => 'string',
396 'description' => 'Custom plugin name'
397 ],
398 'whitelabel_otto_name' => [
399 'type' => 'string',
400 'description' => 'Custom Otto feature name'
401 ],
402 'whitelabel_logo_url' => [
403 'type' => 'string',
404 'description' => 'URL to custom logo image'
405 ],
406 'whitelabel_domain_url' => [
407 'type' => 'string',
408 'description' => 'Custom dashboard domain URL'
409 ],
410 'white_label_plugin_description' => [
411 'type' => 'string',
412 'description' => 'Custom plugin description'
413 ],
414 'white_label_plugin_author' => [
415 'type' => 'string',
416 'description' => 'Custom author name'
417 ],
418 'white_label_plugin_author_uri' => [
419 'type' => 'string',
420 'description' => 'Custom author URI'
421 ],
422 'white_label_plugin_uri' => [
423 'type' => 'string',
424 'description' => 'Custom plugin URI'
425 ]
426 ]
427 ],
428 'seo' => [
429 'description' => 'SEO controls and indexation settings',
430 'settings' => [
431 'index_date_archives' => [
432 'type' => 'boolean',
433 'description' => 'Disallow date archives from indexation'
434 ],
435 'index_tag_archives' => [
436 'type' => 'boolean',
437 'description' => 'Disallow tag archives from indexation'
438 ],
439 'index_author_archives' => [
440 'type' => 'boolean',
441 'description' => 'Disallow author archives from indexation'
442 ],
443 'index_format_archives' => [
444 'type' => 'boolean',
445 'description' => 'Disallow format archives from indexation'
446 ],
447 'index_category_archives' => [
448 'type' => 'boolean',
449 'description' => 'Disallow category archives from indexation'
450 ],
451 'override_robots_tags' => [
452 'type' => 'boolean',
453 'description' => 'Override robots tags from other plugins'
454 ],
455 'enable_googleinstantindex' => [
456 'type' => 'boolean',
457 'description' => 'Enable Google Instant Indexing'
458 ]
459 ]
460 ],
461 'social' => [
462 'description' => 'Social media and Otto settings',
463 'settings' => [
464 'otto_pixel_uuid' => [
465 'type' => 'string',
466 'description' => 'Otto Pixel UUID for tracking'
467 ],
468 'otto_disable_on_loggedin' => [
469 'type' => 'boolean',
470 'description' => 'Disable Otto for logged-in users'
471 ],
472 'otto_disable_preview_button' => [
473 'type' => 'boolean',
474 'description' => 'Disable Otto frontend toolbar'
475 ]
476 ]
477 ],
478 'advanced' => [
479 'description' => 'Advanced meta box visibility controls',
480 'settings' => [
481 'disable_common_robots_metabox' => [
482 'type' => 'boolean',
483 'description' => 'Disable common robots meta box in post editor'
484 ],
485 'disable_advance_robots_metabox' => [
486 'type' => 'boolean',
487 'description' => 'Disable advanced robots meta box in post editor'
488 ],
489 'disable_redirection_metabox' => [
490 'type' => 'boolean',
491 'description' => 'Disable redirection meta box in post editor'
492 ],
493 'disable_canonical_metabox' => [
494 'type' => 'boolean',
495 'description' => 'Disable canonical meta box in post editor'
496 ],
497 'disable_social_opengraph_metabox' => [
498 'type' => 'boolean',
499 'description' => 'Disable social/OpenGraph meta box in post editor'
500 ],
501 'disable_schema_markup_metabox' => [
502 'type' => 'boolean',
503 'description' => 'Disable schema markup meta box in post editor'
504 ]
505 ]
506 ],
507 'mcp' => [
508 'description' => 'MCP Server configuration',
509 'settings' => [
510 'metasync_mcp_enabled' => [
511 'type' => 'boolean',
512 'description' => 'Enable/disable the MCP server',
513 'stored_separately' => true,
514 'option_name' => 'metasync_mcp_enabled'
515 ],
516 'metasync_mcp_api_key' => [
517 'type' => 'string',
518 'description' => 'MCP server API key for authentication',
519 'sensitive' => true,
520 'stored_separately' => true,
521 'option_name' => 'metasync_mcp_api_key'
522 ]
523 ]
524 ]
525 ];
526
527 return $this->success([
528 'schema' => $schema,
529 'sections' => array_keys($schema),
530 'total_sections' => count($schema),
531 'note' => 'Some settings like MCP configuration are stored as separate options, not in the main metasync_options array'
532 ]);
533 }
534 }
535
536 /**
537 * Get MCP Server Settings Tool
538 */
539 class MCP_Tool_Get_MCP_Settings extends MCP_Tool_Base {
540
541 public function get_name() {
542 return 'wordpress_get_mcp_settings';
543 }
544
545 public function get_description() {
546 return 'Get MCP server-specific settings including authentication information and endpoint URLs.';
547 }
548
549 public function get_input_schema() {
550 return [
551 'type' => 'object',
552 'properties' => (object)[],
553 'required' => []
554 ];
555 }
556
557 public function execute($params) {
558 $this->validate_params($params);
559 $this->require_capability('manage_options');
560
561 $options = get_option('metasync_options', []);
562 $plugin_auth_token = isset($options['general']['apikey']) ? $options['general']['apikey'] : '';
563
564 return $this->success([
565 'mcp_enabled' => true, // MCP is always enabled
566 'authentication' => [
567 'type' => 'plugin_auth_token',
568 'header' => 'X-API-Key',
569 'token_set' => !empty($plugin_auth_token),
570 'token_length' => !empty($plugin_auth_token) ? strlen($plugin_auth_token) : 0,
571 'token_preview' => !empty($plugin_auth_token) ? substr($plugin_auth_token, 0, 8) . '...' : ''
572 ],
573 'endpoints' => [
574 'rest_endpoint' => rest_url('metasync/v1/mcp'),
575 'health_endpoint' => rest_url('metasync/v1/mcp/health')
576 ],
577 'version' => METASYNC_VERSION
578 ]);
579 }
580 }
581
582