| 开发者 | fabiomontenegro1987 |
|---|---|
| 更新时间 | 2026年9月18日 11:52 |
| 捐献地址: | 去捐款 |
| PHP版本: | 8.0 及以上 |
| WordPress版本: | 7.1 |
| 版权: | GPLv2 or later |
| 版权网址: | 版权信息 |
registration_endpoint, /oauth/register refuses every request, and the claude.ai connector behaves exactly as before/oauth/register, gated by an administrator-managed callback allowlist, so clients that register themselves can connect through the same consent flowshow_in_rest and mcp.public metadatamanage_options only)manage_options)eval, exec, shell_exec, and more)wp_template and wp_template_part entries for the active theme, merging theme-file defaults with database overridesedit_theme_options)Yes. This plugin requires WordPress 6.9+ (which includes the Abilities API) and the MCP Adapter plugin to connect abilities with AI assistants like Claude.
Yes. On first activation, all abilities are enabled. You can disable any of them from Settings > WP Abilities.
Write abilities respect WordPress capabilities. For example, creating a post requires the publish_posts capability, and editing checks per-post permissions. The MCP user must have the appropriate WordPress role.
Yes. The plugin can be network-activated. Each site in the network has its own ability configuration, its own OAuth toggle, and its own connector URL — enabling MCP on one subsite never exposes the others. For subdirectory networks (site.com/blog-a, site.com/blog-b) the claude.ai OAuth connector needs the plugin network-activated (or active on the main site): OAuth clients resolve discovery documents against the domain root, which belongs to the main site, so the plugin bridges those requests to the owning subsite automatically.
Yes. The Custom Post Types section automatically detects WooCommerce products, orders, coupons, and any other registered post type. You can list, create, update, and delete items with full access to WooCommerce meta fields like _price, _sku, _stock_status, _regular_price, and more.
This plugin registers abilities using the standard wp_register_ability() API. You can register additional abilities in your own plugin using the wp_abilities_api_init hook.
Yes. Since 2.2, abilities registered by other plugins appear in the Abilities tab under their own "Third-party" section, grouped by plugin namespace, with the same toggles as this plugin's abilities. New third-party abilities start enabled; disabling one unregisters it before any MCP server can expose it — including this plugin's claude.ai OAuth connector and the other plugin's own MCP endpoint. Disabled abilities stay listed so you can re-enable them at any time.
In almost every reported case the OAuth flow is fine and the request never reaches WordPress: a security layer in front of your site is blocking Anthropic's backend, which connects with a non-browser User-Agent (python-httpx). Common culprits are hosting WAFs (cPGuard, Imunify360, ModSecurity rules like "generic HTTP client User-Agent") and Cloudflare's Bot Fight Mode or AI-crawler blocking. To diagnose, run curl -A "python-httpx/0.28.1" https://your-site.com/.well-known/oauth-authorization-server from an external machine — a 403 confirms the block. Ask your host to allow that User-Agent (or Anthropic's IP range 160.79.104.0/23) for /.well-known/oauth-*, /oauth/*, and /wp-json/mcp/*, or disable the relevant bot protection for the site.
Turn on the OAuth server on the Connection tab, then turn on ChatGPT & Other OAuth Connectors below it. Check the Allowed callback URLs box — it is prefilled with the callbacks ChatGPT is commonly seen to use, so confirm the exact one your connector screen shows and delete the rest. Save, then in ChatGPT turn on Developer mode (available on paid plans) and create a connector with the same MCP server URL. ChatGPT reads the discovery document, finds registration_endpoint, registers itself, and runs the normal login-and-consent flow. The callback allowlist is the security boundary: a self-registered client can only ever return a user to a URL you listed.
Yes — strict OAuth clients require a direct 200 on /.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource. This plugin already prevents WordPress's trailing-slash canonical redirect on those paths and serves the RFC 9728 path-suffixed variants. If they still return 404, your web server is intercepting .well-known/ before WordPress runs (common with Let's Encrypt auto-SSL configs) — see Tools → Site Health for the "MCP OAuth discovery documents" check and ask your host to route those two paths to WordPress.
topics is on it by default when Tutor LMS is active, so an assistant can finally build a course tree: course, topic, lesson. Every other non-public type is still rejected, WordPress built-ins remain unreachable, and all capability checks are unchanged. Site owners can add their own structural types with the new ewpa_manageable_private_post_types filter. Reported from a Tutor LMS site.ewpa/update-cpt-item accepts post_parent and menu_order, mirroring ewpa/create-cpt-item. A hierarchical item created in the wrong place, or a duplicate, can now be re-parented and reordered instead of being stuck. An item cannot be made its own parent, and a missing parent is refused.tests/cpt-abilities-test.php, 21 checks). Runs without WordPress: php tests/cpt-abilities-test.php.vendor/ as a dependency. Development builds of MCP Adapter check for a copy loaded before them; because this plugin loads first, they found that copy, showed "Another version of MCP Adapter is already loaded", and ran the bundled 0.5.0 instead of themselves. The MCP Adapter plugin you install is now the only copy this plugin provides. Reported by @donbowman.ewpa/get-code-snippets and ewpa/get-code-snippet (Code Snippets section, enabled by default) list the snippets stored by the Code Snippets plugin (without their code) and read one snippet by ID, including its code. Requires manage_options.ewpa/update-code-snippet (opt-in) changes a PHP snippet's name, description, code, scope, or tags, leaving every other field untouched. New code goes through the same syntax check and blocked-function list as ewpa/create-code-snippet; an active snippet whose code changes is deactivated so the new code is reviewed before it runs.ewpa/set-code-snippet-active (opt-in) deactivates a snippet immediately, but never activates one directly. Asking for activation files a request and returns a wp-admin link where an administrator reads the code and approves or rejects it. The approval form needs a WordPress login nonce, which MCP credentials cannot produce; the request is bound to a hash of the code, expires after 24 hours, and every check runs again at approval time. Pending requests are announced with an admin notice. Suggested by @torontotoph.ewpa/create-code-snippet stored snippets created with scope: frontend as global, because Code Snippets names that scope front-end and silently falls back to global for values it does not know, so a snippet meant for the front end also ran in wp-admin. Both spellings are now accepted and stored as front-end.ewpa/remove-menu-item, ewpa/assign-menu-location, and ewpa/delete-menu are now flagged opt-in too, matching their descriptions.tests/code-snippets-test.php, 33 checks). Runs without WordPress: php tests/code-snippets-test.php.ewpa/duplicate-post copied the internal translation-group taxonomies of Polylang and Linguator AI along with regular terms, so on a multilingual site the duplicate joined the original's translation group and its language switcher and translation links pointed at the original's translations. The duplicate now keeps the source language but gets its own group.ewpa/link-post-translation and ewpa/link-term-translation reported success on Polylang even when Polylang discarded the link because the translated post or term did not already carry the target language. They now assign that language first, as the WPML and Linguator AI backends already did, and return a translation_not_linked error if the link still does not persist.ewpa/list-languages returned term_id 0 for every Polylang language; it now returns each language's term ID.ewpa/create-post-translation (Multilanguage, enabled by default) creates the translation of a post or page in a target language and links it to the source. The AI supplies the translated title, content, and excerpt; the ability never calls a translation service. Taxonomies, custom fields, and the featured image are copied, with backslashes preserved so JSON meta such as Elementor's _elementor_data survives intact; on Linguator AI the plugin's own duplication engine is used. If a translation already exists in that language it is updated instead of duplicated. Contributed by @drbelt27.ewpa/create-term-translation (enabled by default) does the same for categories, tags, and custom taxonomy terms: translated name and description, term meta copied, and the parent remapped to its target-language counterpart. Updating an existing translation changes only the supplied fields. Contributed by @drbelt27.ewpa/list-languages, ewpa/set-term-language, ewpa/link-term-translation, and ewpa/get-term-translations (enabled by default) list the configured languages and manage term languages and translation groups. Contributed by @drbelt27.tests/multilanguage-backend-test.php, 42 cases), with test doubles that unslash like WordPress core and validate languages like Polylang. Runs without WordPress: php tests/multilanguage-backend-test.php./oauth/register, so ChatGPT and other self-registering clients connect through the same login-and-consent flow as the claude.ai connector. The security boundary is an administrator-managed callback allowlist, enforced at registration and re-checked on every authorization request, so removing a URL immediately blocks clients that registered while it was allowed. The same list gates which client metadata documents are fetched (wp_safe_remote_get, no redirects). Consent, code issuance, PKCE, token signing and refresh rotation stay in the bundled wp-media/mcp-oauth library; with the toggle off, the claude.ai connector is unchanged. Contributed by @keyvansolha.tests/oauth-connectors-test.php, 42 checks) covering redirect-URI smuggling — userinfo and backslash authorities, subdomain confusion, port and path-prefix mismatches, query strings and fragments through wildcards, protocol-relative and non-HTTP schemes — plus RFC 8252 loopback handling. Runs without WordPress: php tests/oauth-connectors-test.php.http://[::1]:port/…) were rejected, because PHP's parse_url() keeps the brackets around an IPv6 literal and the loopback check only knew ::1. It failed closed, so nothing was ever allowed that should not have been; native clients on IPv6 loopback can now connect. Found by the new regression suite.ewpa/assign-post-terms (Write section, enabled by default) — assigns a custom taxonomy's terms to a post or page. ewpa/assign-cpt-terms explicitly rejects built-in post types (post, page, attachment, and others) by design, since native categories/tags on posts are already covered by ewpa/update-post — but that left a real gap for a custom taxonomy registered on post/page by a companion plugin, with no assignment path through MCP at all. Mirrors ewpa/assign-cpt-terms's security checks exactly (edit_post, taxonomy_exists, taxonomy-post_type association, and the taxonomy's own assign_terms capability), so an admin-only taxonomy stays admin-only regardless of post type.ewpa/get-accessibility-snapshot (read, enabled by default) scans the media library for images missing alt text (WCAG 1.1.1 Non-text Content) and returns a paginated list, so they can be fixed via ewpa/update-post-meta (_wp_attachment_image_alt). Deliberately narrow scope: full WCAG scanning (color contrast, ARIA, keyboard navigation) is a rendered-page/browser concern already covered by browser-based tools such as Lighthouse, not duplicated here.ewpa/je-list-queries and ewpa/je-get-query (read, enabled by default) list and read Query Builder queries via JetEngine's own internal data layer (Jet_Engine\Query_Builder\Manager); ewpa/je-update-query (write, opt-in) updates an existing query's name, type, or arguments, converting query_args the same way JetEngine's own tools do. This is the missing counterpart to JetEngine's own native "Add Query" MCP tool — JetEngine ships its own separate, bundled MCP server with a tool to create a query but none to list, read, or edit one; these abilities close that gap through the standard WordPress Abilities API instead of JetEngine's internal tool registry. Requires JetEngine with the Query Builder module. Validated end-to-end on a live production site, including a real write to an in-use query with a non-trivial tax_query/post_type configuration that was confirmed intact after the update.ewpa/update-term (Custom Post Types section, enabled by default) — updates a taxonomy term's core fields (name, slug, description, parent term). Only the provided fields are modified. Complements ewpa/get-term-meta / ewpa/update-term-meta (v2.7.0), which only cover custom meta, not these core fields. Requested from a live JetEngine + Polylang site that needed to rename a mistranslated term.ewpa/get-term-meta and ewpa/update-term-meta (Custom Post Types section, enabled by default) — read and write taxonomy term meta by exact key, the term-level equivalent of ewpa/get-post-meta / ewpa/update-post-meta. get-term-meta returns every meta field for the term when meta_key is omitted. Both require the edit_term capability on the target term.ewpa/get-cpt-taxonomies threw an output-schema validation error ("not of type string") for taxonomies registered with 'label' => false — a pattern used by internal taxonomies some multilingual plugins (e.g. Polylang) attach to custom post types. The taxonomy slug is now used as a fallback label instead of the raw false value. Reported from a live JetEngine + Polylang site.ewpa/fse-list-templates and ewpa/fse-get-template (read, enabled by default) list and read wp_template / wp_template_part entries for the active theme via get_block_templates() / get_block_template(), merging theme-file defaults with database overrides; ewpa/fse-update-template (write, opt-in) writes new block markup, creating a database override when the target is still a theme default, and rejects content with unbalanced block-comment delimiters before saving. Guarded behind current_theme_supports('block-templates'). Requested by redsoulwarrior in a WordPress.org review.ewpa/create-code-snippet failed on every call with "Cannot instantiate Snippet class" on Code Snippets 3.10.0+ — its PSR-4 refactor moved the Snippet class from Code_Snippets\Snippet to Code_Snippets\Model\Snippet. Now checks both locations (plus the legacy global Snippet for 2.x), so it works across Code Snippets 2.x through 3.10+. Reported by redsoulwarrior with a confirmed version-downgrade repro.ewpa/search-replace matched against a sanitize_text_field()-cleaned copy of the search term instead of the raw text — a search containing HTML tags, line breaks, or repeated whitespace would silently never match post_content (which stores that raw). The search and replacement values are now used as-is.ewpa/search-replace rejected a search term of "0" as empty, because PHP's empty() treats the string "0" as falsy. Now uses a strict empty-string check.Stable tag in this readme was left at 2.5.0 after the 2.5.1 release, so WordPress.org never picked up 2.5.1 as current. Corrected to 2.5.2.ewpa/tutor-get-user-progress always returned enrollment_status: null — Tutor's EnrollmentModel::is_enrolled() doesn't select post_status in its query, so the field silently read as null. Now resolved via get_post().ewpa/duplicate-post — duplicates any post, page, or CPT item, copying all post meta (ACF fields, SEO data, featured image) and taxonomy terms. The copy is saved as a draft by default. Opt-in write ability.add_post_meta() to match WordPress's internal wp_unslash() contract — prevents backslash loss in serialized or JSON meta fields (e.g. _elementor_data) when duplicating.ewpa/duplicate-post to the enabled-abilities list on existing installs upgrading from earlier versions.ewpa/tutor-get-lesson-video and ewpa/tutor-update-lesson-video, both enabled by default. Requires Tutor LMS (tutor_utils()).ewpa/update-post-meta ability silently broke video playback — Tutor stores _video as a native PHP array, but update-post-meta always writes strings, and WordPress's own serialization safeguards (is_serialized()) prevent a plain or hand-serialized string from ever being reinterpreted as that array. ewpa/tutor-update-lesson-video calls tutor_utils()->update_video() directly — the same function Tutor's own editor uses — so the value is always stored correctly, including third-party sources registered via the tutor_preferred_video_sources filter (e.g. Bunny.net). Validated on a live Tutor LMS site with a Bunny.net-hosted lesson video.create-menu, list-menus, get-menu, add-menu-item (pages, posts, categories, tags, or custom URLs, with parent/position), and update-menu-item are enabled by default; remove-menu-item, assign-menu-location, and delete-menu are opt-in (destructive). All require edit_theme_options, the same capability WordPress demands for Appearance → Menus.ewpa/get-cpt-items ignored the requested post_type when the s (search) parameter was set, silently returning items from a different post type. Caused by suppress_filters => false on the internal get_posts() call, which left third-party pre_get_posts hooks free to rewrite the query once a search term was present (observed on a Tutor LMS site, where lesson is excluded from search and a search-integration plugin fell back to courses). Removed the override so the ability uses get_posts()'s own safe default (suppress_filters => true), matching every other CPT-listing ability in the plugin. Reported by a user testing the MCP connector against a live Tutor LMS site.wp_abilities_api_init, removing it from every MCP server on the site (this plugin's claude.ai OAuth connector, the default adapter server, and the third-party plugin's own MCP endpoint). New third-party abilities start enabled, and disabled ones stay listed for re-enabling — validated end-to-end against Fluent Forms' MCP tools.home_url() instead of assuming a root install./.well-known/oauth-* against the domain root, which belongs to the main site. With the plugin network-activated, the main site now resolves those requests to the owning subsite and relays its discovery document, making the claude.ai connector work for every subsite (validated against claude.ai on a production-style subdirectory multisite).Basic authorization header — copy-paste ready, no manual editing./.well-known/oauth-*) and /oauth/* endpoints no longer receive WordPress's trailing-slash 301 canonical redirect, which strict OAuth clients (claude.ai) reject as a failed metadata fetch./.well-known/oauth-protected-resource/<mcp-path>) are now served, matching the lookup order of Anthropic's OAuth client.python-httpx client.