[wp-trac] [WordPress Trac] #64926: REST API: GET requests fail object/array schema validation when params are JSON-serialized strings
WordPress Trac
noreply at wordpress.org
Thu Mar 26 13:57:28 UTC 2026
#64926: REST API: GET requests fail object/array schema validation when params are
JSON-serialized strings
-------------------------+-------------------------------------------------
Reporter: dsmy | Owner: (none)
Type: defect | Status: new
(bug) |
Priority: normal | Milestone: Awaiting Review
Component: REST API | Version:
Severity: normal | Resolution:
Keywords: needs-patch | Focuses: javascript, rest-api, php-
| compatibility
-------------------------+-------------------------------------------------
Comment (by dsmy):
@zieladam Sure thing!
This came up while building a structured MCP layer that exposes WordPress
site capabilities (theme tokens, block settings, animation configs, etc.)
to an AI agent via declared REST endpoints. Read-only abilities use GET by
design for the reasons you mentioned around caching and CORS, write
abilities use POST.
The problem surfaces when a read-only ability needs structured input. As
ability schemas get richer, params naturally become objects: filter
objects, block attribute matchers, config subsets. Declaring those as
type: object in the endpoint schema is the right call. Passing them from
the JS client via JSON.stringify() is the natural path, and it breaks on
GET.
The block attributes case is where the lossiness you raised was the most
annoying. Attributes like {"lock":{"move":false,"remove":true}} or
{"dropCap":false,"className":"hero"} contain booleans and nested objects
that don't survive bracket encoding intact. Boolean false and string
"false" are not equivalent when evaluating block state. JSON.stringify()
is the only lossless encoding path I naturally found that was already
existing in core, and it already works for POST bodies via
parse_json_params().
On your question about whether GET was intended for complex inputs: the
REST API's own schema system supports type: object and type: array for GET
params, which suggests the intent was there. The implementation just
didn't close the loop on the JSON string path side of things.
The closest historical ticket I was able to find was this one
https://core.trac.wordpress.org/ticket/42961
Hope this helps!
Replying to [comment:11 zieladam]:
> @dsmy would you be willing to share more information about your use-
case? While I don't have enough context off-hand to comment on possible
solutions, I'm thinking that it is weird there is no historical ticket for
this.
>
> I wonder whether the REST API was intended for handling complex inputs
via GET requests, or was the intention to always use POST. Is it just a
documentation issue? POST requests are not subject to HTTP caching, for
example, which wouldn't make sense for uniquely generated pages
parametrized by complex JSON structures. POST requests also behave
differently under CORS etc. etc. Knowing more about your project would be
a very helpful framing for this discussion.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/64926#comment:12>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list