Skip to content

Commit 1e26496

Browse files
committed
Initial Commit
0 parents  commit 1e26496

38 files changed

+26779
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/vendor/
2+
/node_modules/
3+
.DS_Store
4+
/build/

.phpcs.xml.dist

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?xml version="1.0"?>
2+
<ruleset name="WordPress Coding Standards based custom ruleset for your plugin">
3+
<description>Generally-applicable sniffs for WordPress plugins.</description>
4+
5+
<!-- What to scan -->
6+
<file>.</file>
7+
<exclude-pattern>/vendor/</exclude-pattern>
8+
<exclude-pattern>/node_modules/</exclude-pattern>
9+
10+
<!-- How to scan -->
11+
<!-- Usage instructions: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Usage -->
12+
<!-- Annotated ruleset: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml -->
13+
<arg value="sp"/> <!-- Show sniff and progress -->
14+
<arg name="basepath" value="./"/><!-- Strip the file paths down to the relevant bit -->
15+
<arg name="colors"/>
16+
<arg name="extensions" value="php"/>
17+
<arg name="parallel" value="8"/><!-- Enables parallel processing when available for faster results. -->
18+
19+
<!-- Rules: Check PHP version compatibility -->
20+
<!-- https://github.com/PHPCompatibility/PHPCompatibility#sniffing-your-code-for-compatibility-with-specific-php-versions -->
21+
<config name="testVersion" value="5.6-"/>
22+
<!-- https://github.com/PHPCompatibility/PHPCompatibilityWP -->
23+
<rule ref="PHPCompatibilityWP"/>
24+
25+
<!-- Rules: WordPress Coding Standards -->
26+
<!-- https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards -->
27+
<!-- https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/wiki/Customizable-sniff-properties -->
28+
<config name="minimum_supported_wp_version" value="4.6"/>
29+
<rule ref="WordPress"/>
30+
<rule ref="WordPress.NamingConventions.PrefixAllGlobals">
31+
<properties>
32+
<!-- Value: replace the function, class, and variable prefixes used. Separate multiple prefixes with a comma. -->
33+
<property name="prefixes" type="array" value="my-plugin"/>
34+
</properties>
35+
</rule>
36+
<rule ref="WordPress.WP.I18n">
37+
<properties>
38+
<!-- Value: replace the text domain used. -->
39+
<property name="text_domain" type="array" value="my-plugin"/>
40+
</properties>
41+
</rule>
42+
<rule ref="WordPress.WhiteSpace.ControlStructureSpacing">
43+
<properties>
44+
<property name="blank_line_check" value="true"/>
45+
</properties>
46+
</rule>
47+
</ruleset>

Readme.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# WordPress MCP
2+
3+
A WordPress plugin that implements the Model Context Protocol (MCP) to expose WordPress functionality through a standardized interface. This plugin enables AI models and other applications to interact with WordPress sites in a structured and secure way.
4+
5+
## Features
6+
7+
- 🔒 Secure and standardized interface for WordPress interactions
8+
- 🤖 AI-friendly API endpoints
9+
- 🏗️ Extensible architecture for custom tools, resources and prompts
10+
- ⚡ High-performance implementation
11+
12+
## Installation
13+
14+
1. Download the plugin files
15+
2. Upload the plugin files to the `/wp-content/plugins/wordpress-mcp` directory
16+
3. Activate the plugin through the 'Plugins' menu in WordPress
17+
4. Navigate to `Settings > WordPress MCP` and enable MCP functionality
18+
19+
## Usage
20+
21+
This plugin is designed to work with [wp-wordpress-remote-proxy](https://github.com/galatanovidiu/wp-wordpress-remote-proxy), which provides the client-side implementation for interacting with the MCP interface.
22+
23+
## Development
24+
25+
### Extending the Plugin
26+
27+
You can extend the plugin's functionality by adding new components:
28+
29+
#### Adding New Tools
30+
31+
Check the tools defined on `wp-content/plugins/wordpress-mcp/includes/Tools/` for examples
32+
33+
#### Adding Resources
34+
35+
Check the resources define on `wp-content/plugins/wordpress-mcp/includes/Resources/` for examples
36+
37+
#### Adding Prompts
38+
39+
Check the prompts defined on `wp-content/plugins/wordpress-mcp/includes/Prompts/` for axamples
40+
41+
## Contributing
42+
43+
We welcome contributions!
44+
45+
## Support
46+
47+
For support, please:
48+
49+
- Open an issue on GitHub
50+
- Check the [documentation](docs/)
51+
- Contact the maintainers

includes/Admin/Settings.php

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
<?php //phpcs:ignore
2+
declare(strict_types=1);
3+
4+
namespace Automattic\WordpressMcp\Admin;
5+
6+
/**
7+
* Class Settings
8+
* Handles the MCP settings page in WordPress admin.
9+
*/
10+
class Settings {
11+
/**
12+
* The option name in the WordPress options table.
13+
*/
14+
const OPTION_NAME = 'wordpress_mcp_settings';
15+
16+
/**
17+
* Initialize the settings page.
18+
*/
19+
public function __construct() {
20+
add_action( 'admin_menu', array( $this, 'add_settings_page' ) );
21+
add_action( 'admin_init', array( $this, 'register_settings' ) );
22+
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
23+
add_action( 'wp_ajax_wordpress_mcp_save_settings', array( $this, 'ajax_save_settings' ) );
24+
}
25+
26+
/**
27+
* Add the settings page to the WordPress admin menu.
28+
*/
29+
public function add_settings_page(): void {
30+
add_options_page(
31+
__( 'MCP Settings', 'wordpress-mcp' ),
32+
__( 'MCP Settings', 'wordpress-mcp' ),
33+
'manage_options',
34+
'wordpress-mcp-settings',
35+
array( $this, 'render_settings_page' )
36+
);
37+
}
38+
39+
/**
40+
* Register the settings and their sanitization callbacks.
41+
*/
42+
public function register_settings(): void {
43+
register_setting(
44+
'wordpress_mcp_settings',
45+
self::OPTION_NAME,
46+
array(
47+
'type' => 'array',
48+
'sanitize_callback' => array( $this, 'sanitize_settings' ),
49+
)
50+
);
51+
}
52+
53+
/**
54+
* Enqueue scripts and styles for the React app.
55+
*
56+
* @param string $hook The current admin page.
57+
*/
58+
public function enqueue_scripts( string $hook ): void {
59+
if ( 'settings_page_wordpress-mcp-settings' !== $hook ) {
60+
return;
61+
}
62+
63+
$asset_file = include WORDPRESS_MCP_PATH . 'build/index.asset.php';
64+
65+
// Enqueue our React app.
66+
wp_enqueue_script(
67+
'wordpress-mcp-settings',
68+
WORDPRESS_MCP_URL . 'build/index.js',
69+
$asset_file['dependencies'],
70+
$asset_file['version'],
71+
true
72+
);
73+
74+
// Enqueue the WordPress components styles CSS.
75+
wp_enqueue_style(
76+
'wp-components',
77+
includes_url( 'css/dist/components/style.css' ),
78+
array(),
79+
$asset_file['version'],
80+
);
81+
82+
// Enqueue the WordPress MCP settings CSS.
83+
wp_enqueue_style(
84+
'wp-mcp-settings',
85+
WORDPRESS_MCP_URL . 'build/style-index.css',
86+
array(),
87+
$asset_file['version'],
88+
);
89+
90+
// Localize the script with data needed by the React app.
91+
wp_localize_script(
92+
'wordpress-mcp-settings',
93+
'wordpressMcpSettings',
94+
array(
95+
'apiUrl' => rest_url( 'wordpress-mcp/v1/settings' ),
96+
'nonce' => wp_create_nonce( 'wordpress_mcp_settings' ),
97+
'settings' => get_option( self::OPTION_NAME, array() ),
98+
'strings' => array(
99+
'enableMcp' => __( 'Enable MCP functionality', 'wordpress-mcp' ),
100+
'enableMcpDescription' => __( 'Toggle to enable or disable the MCP plugin functionality.', 'wordpress-mcp' ),
101+
'enableFeaturesAdapter' => __( 'Enable WordPress Features Adapter', 'wordpress-mcp' ),
102+
'enableFeaturesAdapterDescription' => __( 'Enable or disable the WordPress Features Adapter. This option only works when MCP is enabled.', 'wordpress-mcp' ),
103+
'saveSettings' => __( 'Save Settings', 'wordpress-mcp' ),
104+
'settingsSaved' => __( 'Settings saved successfully!', 'wordpress-mcp' ),
105+
'settingsError' => __( 'Error saving settings. Please try again.', 'wordpress-mcp' ),
106+
),
107+
)
108+
);
109+
}
110+
111+
/**
112+
* AJAX handler for saving settings.
113+
*/
114+
public function ajax_save_settings(): void {
115+
if ( ! current_user_can( 'manage_options' ) ) {
116+
wp_send_json_error( array( 'message' => __( 'You do not have permission to perform this action.', 'wordpress-mcp' ) ) );
117+
}
118+
119+
$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
120+
if ( ! wp_verify_nonce( $nonce, 'wordpress_mcp_settings' ) ) {
121+
wp_send_json_error( array( 'message' => __( 'Invalid nonce. Please refresh the page and try again.', 'wordpress-mcp' ) ) );
122+
}
123+
124+
// Sanitize the settings input.
125+
$settings_raw = isset( $_POST['settings'] ) ? sanitize_text_field( wp_unslash( $_POST['settings'] ) ) : '{}';
126+
$settings = $this->sanitize_settings( json_decode( $settings_raw, true ) );
127+
update_option( self::OPTION_NAME, $settings );
128+
129+
wp_send_json_success( array( 'message' => __( 'Settings saved successfully!', 'wordpress-mcp' ) ) );
130+
}
131+
132+
/**
133+
* Sanitize the settings before saving.
134+
*
135+
* @param array $input The input array.
136+
* @return array The sanitized input array.
137+
*/
138+
public function sanitize_settings( array $input ): array {
139+
$sanitized = array();
140+
141+
if ( isset( $input['enabled'] ) ) {
142+
$sanitized['enabled'] = (bool) $input['enabled'];
143+
} else {
144+
$sanitized['enabled'] = false;
145+
}
146+
147+
if ( isset( $input['features_adapter_enabled'] ) ) {
148+
$sanitized['features_adapter_enabled'] = (bool) $input['features_adapter_enabled'];
149+
} else {
150+
$sanitized['features_adapter_enabled'] = false;
151+
}
152+
153+
return $sanitized;
154+
}
155+
156+
/**
157+
* Render the settings page.
158+
*/
159+
public function render_settings_page(): void {
160+
if ( ! current_user_can( 'manage_options' ) ) {
161+
return;
162+
}
163+
?>
164+
<div class="wrap">
165+
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
166+
<div id="wordpress-mcp-settings-app"></div>
167+
</div>
168+
<?php
169+
}
170+
}

0 commit comments

Comments
 (0)