feat(content): warn when WordPress silently drops unregistered meta keys#17
Open
kleintech wants to merge 1 commit into
Open
feat(content): warn when WordPress silently drops unregistered meta keys#17kleintech wants to merge 1 commit into
kleintech wants to merge 1 commit into
Conversation
WordPress core silently drops any meta key sent via /wp/v2/{type}/{id}
unless the key was registered with show_in_rest. SEO plugin keys
(Yoast _yoast_wpseo_*, Rank Math rank_math_*, AIOSEO _aioseo_*) are
not registered, so writes returned success while the values never
persisted. The MCP tool result hid this from the LLM caller.
This change diffs the meta keys sent vs the keys echoed in the WP
response and prepends a Warning content block listing every key WP
dropped, on create_content, update_content, and the two update branches
of find_content_by_url. It does not change which keys WP accepts —
that requires a WordPress companion plugin (scoped separately).
Includes scripts/manual-test-meta-warning.mjs which exercises the
warning end-to-end against a live WP install. The repo has no test
harness yet, so this is the agreed manual verification step.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced May 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
WordPress core silently drops any meta key sent via
/wp/v2/{type}/{id}unless the key was registered viaregister_post_meta(..., ['show_in_rest' => true]). The big SEO plugins (Yoast SEO, Rank Math, AIOSEO) deliberately do not register their_yoast_wpseo_*/rank_math_*/_aioseo_*keys for core REST exposure — they ship their own routes (e.g. Yoast's/yoast/v1/*indexable endpoints).As a result, calling
update_content(orcreate_content, orfind_content_by_urlwithupdate_fields.meta) with SEO meta keys returns 200 OK while the values silently never land. The MCP tool result echoed the API response back to the LLM with no indication anything had gone wrong, so callers reported success.This PR adds a defensive diff: after each successful write, the handler compares the
metakeys sent in the request to themetakeys echoed in the WP response. If any are missing, it prepends aWarning:content block to thetoolResultlisting every dropped key with a short explanation. It does not change which keys WP will accept — that requires a small WordPress companion plugin (being scoped separately atmcp-wp-seo-bridge).Root cause / diagnosis
Reproduced against a live Yoast-active install:
show_in_rest?_genesis_layout_test_made_up_key_yoast_wpseo_focuskwSingle POST request, one key kept, two dropped, no error. This is core WP behavior and not something the MCP server can fix — but it can at least stop hiding the failure.
Changes
src/tools/unified-content.ts:detectDroppedMetaKeys(sent, responseData)— returns the keys present insentbut missing fromresponseData.meta. Pure function, no I/O. Treats unexpected response shapes (nometa, ormetaas an array) as "all dropped" — conservative.buildDroppedMetaWarning(keys)— builds the warning text, including a pointer to the README "Meta field limitations" section (added in a follow-up doc PR).meta:create_contentupdate_contentfind_content_by_url(both the priority-types-matched and all-types-fallback update branches)scripts/manual-test-meta-warning.mjs— end-to-end check against a real WP install (this repo currently has no automated test harness; the script is the agreed manual verification step).The warning is added as a separate
textcontent block prepended totoolResult.content. The WP response JSON is untouched so anything downstream that parses the response keeps working.What was tested
node scripts/manual-test-meta-warning.mjsagainst a Yoast-active install. Creates a draft post, callsupdate_contentwith three_yoast_wpseo_*keys, asserts the warning block appears and lists each sent key, deletes the post. Passes.npm run build. Two pre-existing TS errors inserver.tsandmedia.tsare unrelated to this change (present onmainbefore this PR).Security considerations
metato WordPress exactly as before — WP's existingregister_post_meta/auth_callbackenforcement is the only gate on what actually persists.Keys that still won't work after this PR
All of them. This PR doesn't make any new keys writable — it just stops pretending the writes worked when they didn't. The follow-up companion plugin (
mcp-wp-seo-bridge, separate repo) will register the actual SEO keys withshow_in_rest.Test plan
npm run build(warnings on pre-existing TS errors in server.ts and media.ts are unrelated)node scripts/manual-test-meta-warning.mjsagainst a Yoast-active install — expects PASS lines and exit 0update_contenton a post withmeta: {_yoast_wpseo_metadesc: "test"}. Tool output should include both a Warning block and the JSON response._genesis_layout: "content-sidebar"on a Genesis site) — no warning block expected.🤖 Generated with Claude Code