[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
Tue Mar 24 13:30:34 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: trunk
Severity: normal | Resolution:
Keywords: needs-patch | Focuses: javascript, rest-api, php-
| compatibility
-------------------------+-------------------------------------------------
Description changed by westonruter:
Old description:
> == The problem
>
> When a REST endpoint declares a parameter with "type": "object" or
> "type": "array", GET requests cannot pass that parameter correctly.
> URLSearchParams has no native way to encode nested structures, so the
> only option is JSON.stringify(), producing ?input={"post_id":123}.
>
> PHP populates $_GET['input'] as a raw string.
> rest_validate_value_from_schema() receives a string where the schema
> expects object, and returns a WP_Error, the request is rejected before
> rest_sanitize_value_from_schema() can coerce it.
>
> rest_sanitize_value_from_schema() already handles this case correctly
> (calls json_decode() on strings before validating type). The fix is to
> apply the same coercion in rest_validate_value_from_schema(), or to add a
> pre-validation JSON-decode pass for GET params that match an object/array
> schema, mirroring what parse_json_params() does for application/json body
> requests.
>
> Affected file: wp-includes/rest-api.php —
> rest_validate_value_from_schema()
>
> Steps to reproduce:
>
> Register an endpoint with a param declared as "type": "object" Call it
> via GET with ?param{"key":"value"}
>
> Receive a 400: "param is not of type object"
>
> Workaround(see example below): Force POST method, or manually
> json_decode() the param in the endpoint callback before use.
>
> The closest historical ticket is
> [#42961](https://core.trac.wordpress.org/ticket/42961) ("REST API: Cannot
> pass empty object url encoded data", closed fixed in 2017) but that was
> about PHP bracket-notation encoding of empty arrays, not the
> `JSON.stringify` + `rest_validate_value_from_schema` ordering problem.
>
> == Workaround
>
> Until a core fix lands, the following filter coerces JSON-string GET
> params before validation runs:
>
> add_filter( 'rest_request_before_callbacks', function( $response,
> $handler, $request ) {
> if ( 'GET' !== $request->get_method() ) {
> return $response;
> }
> foreach ( $handler['args'] ?? array() as $key => $arg_schema ) {
> $type = $arg_schema['type'] ?? '';
> if ( in_array( $type, array( 'object', 'array' ), true ) ) {
> $value = $request->get_param( $key );
> if ( is_string( $value ) ) {
> $decoded = json_decode( $value, true );
> if ( null !== $decoded ) {
> $request->set_param( $key, $decoded );
> }
> }
> }
> }
> return $response;
> }, 10, 3 );
>
> The proper fix belongs in `rest_validate_value_from_schema()` in `wp-
> includes/rest-api.php`, mirroring the json_decode coercion already
> present in `rest_sanitize_value_from_schema()`.
New description:
== The problem
When a REST endpoint declares a parameter with "type": "object" or "type":
"array", GET requests cannot pass that parameter correctly.
URLSearchParams has no native way to encode nested structures, so the only
option is JSON.stringify(), producing ?input={"post_id":123}.
PHP populates $_GET['input'] as a raw string.
rest_validate_value_from_schema() receives a string where the schema
expects object, and returns a WP_Error, the request is rejected before
rest_sanitize_value_from_schema() can coerce it.
rest_sanitize_value_from_schema() already handles this case correctly
(calls json_decode() on strings before validating type). The fix is to
apply the same coercion in rest_validate_value_from_schema(), or to add a
pre-validation JSON-decode pass for GET params that match an object/array
schema, mirroring what parse_json_params() does for application/json body
requests.
Affected file: wp-includes/rest-api.php —
rest_validate_value_from_schema()
Steps to reproduce:
Register an endpoint with a param declared as "type": "object" Call it via
GET with ?param{"key":"value"}
Receive a 400: "param is not of type object"
Workaround(see example below): Force POST method, or manually
json_decode() the param in the endpoint callback before use.
The closest historical ticket is
[#42961](https://core.trac.wordpress.org/ticket/42961) ("REST API: Cannot
pass empty object url encoded data", closed fixed in 2017) but that was
about PHP bracket-notation encoding of empty arrays, not the
`JSON.stringify` + `rest_validate_value_from_schema` ordering problem.
== Workaround
Until a core fix lands, the following filter coerces JSON-string GET
params before validation runs:
{{{#!php
<?php
add_filter( 'rest_request_before_callbacks', function( $response,
$handler, $request ) {
if ( 'GET' !== $request->get_method() ) {
return $response;
}
foreach ( $handler['args'] ?? array() as $key => $arg_schema ) {
$type = $arg_schema['type'] ?? '';
if ( in_array( $type, array( 'object', 'array' ), true ) ) {
$value = $request->get_param( $key );
if ( is_string( $value ) ) {
$decoded = json_decode( $value, true );
if ( null !== $decoded ) {
$request->set_param( $key, $decoded );
}
}
}
}
return $response;
}, 10, 3 );
}}}
The proper fix belongs in `rest_validate_value_from_schema()` in `wp-
includes/rest-api.php`, mirroring the json_decode coercion already present
in `rest_sanitize_value_from_schema()`.
--
--
Ticket URL: <https://core.trac.wordpress.org/ticket/64926#comment:2>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list