@@ -2182,6 +2182,7 @@ function rest_get_allowed_schema_keywords() {
21822182 * @return true|WP_Error
21832183 */
21842184function rest_validate_value_from_schema ( $ value , $ args , $ param = '' ) {
2185+
21852186 if ( isset ( $ args ['anyOf ' ] ) ) {
21862187 $ matching_schema = rest_find_any_matching_schema ( $ value , $ args , $ param );
21872188 if ( is_wp_error ( $ matching_schema ) ) {
@@ -2243,9 +2244,32 @@ function rest_validate_value_from_schema( $value, $args, $param = '' ) {
22432244 $ is_valid = rest_validate_boolean_value_from_schema ( $ value , $ param );
22442245 break ;
22452246 case 'object ' :
2247+ /*
2248+ * A JSON-encoded string (e.g. from a GET query parameter) should be
2249+ * decoded before validation, mirroring what parse_json_params() does
2250+ * for application/json request bodies.
2251+ */
2252+ if ( is_string ( $ value ) ) {
2253+ $ decoded = json_decode ( $ value , true );
2254+ if ( null !== $ decoded && JSON_ERROR_NONE === json_last_error () ) {
2255+ $ value = $ decoded ;
2256+ }
2257+ }
22462258 $ is_valid = rest_validate_object_value_from_schema ( $ value , $ args , $ param );
22472259 break ;
22482260 case 'array ' :
2261+ /*
2262+ * A JSON-encoded string (e.g. ?ids=[1,2,3]) should be decoded before
2263+ * validation. This takes priority over the comma-separated-value
2264+ * fallback in rest_is_array() / wp_parse_list(), which cannot
2265+ * preserve value types.
2266+ */
2267+ if ( is_string ( $ value ) && str_starts_with ( ltrim ( $ value ), '[ ' ) ) {
2268+ $ decoded = json_decode ( $ value , true );
2269+ if ( is_array ( $ decoded ) && JSON_ERROR_NONE === json_last_error () ) {
2270+ $ value = $ decoded ;
2271+ }
2272+ }
22492273 $ is_valid = rest_validate_array_value_from_schema ( $ value , $ args , $ param );
22502274 break ;
22512275 case 'number ' :
@@ -2780,6 +2804,7 @@ function rest_validate_integer_value_from_schema( $value, $args, $param ) {
27802804 * @return mixed|WP_Error The sanitized value or a WP_Error instance if the value cannot be safely sanitized.
27812805 */
27822806function rest_sanitize_value_from_schema ( $ value , $ args , $ param = '' ) {
2807+
27832808 if ( isset ( $ args ['anyOf ' ] ) ) {
27842809 $ matching_schema = rest_find_any_matching_schema ( $ value , $ args , $ param );
27852810 if ( is_wp_error ( $ matching_schema ) ) {
@@ -2833,6 +2858,19 @@ function rest_sanitize_value_from_schema( $value, $args, $param = '' ) {
28332858 }
28342859
28352860 if ( 'array ' === $ args ['type ' ] ) {
2861+ /*
2862+ * A JSON-encoded string (e.g. ?ids=[1,2,3]) should be decoded before
2863+ * sanitization. This takes priority over the comma-separated-value
2864+ * fallback in rest_sanitize_array() / wp_parse_list(), which cannot
2865+ * preserve value types.
2866+ */
2867+ if ( is_string ( $ value ) && str_starts_with ( ltrim ( $ value ), '[ ' ) ) {
2868+ $ decoded = json_decode ( $ value , true );
2869+ if ( is_array ( $ decoded ) && JSON_ERROR_NONE === json_last_error () ) {
2870+ $ value = $ decoded ;
2871+ }
2872+ }
2873+
28362874 $ value = rest_sanitize_array ( $ value );
28372875
28382876 if ( ! empty ( $ args ['items ' ] ) ) {
@@ -2850,6 +2888,18 @@ function rest_sanitize_value_from_schema( $value, $args, $param = '' ) {
28502888 }
28512889
28522890 if ( 'object ' === $ args ['type ' ] ) {
2891+ /*
2892+ * A JSON-encoded string (e.g. from a GET query parameter) should be
2893+ * decoded before sanitization, mirroring what parse_json_params() does
2894+ * for application/json request bodies.
2895+ */
2896+ if ( is_string ( $ value ) ) {
2897+ $ decoded = json_decode ( $ value , true );
2898+ if ( null !== $ decoded && JSON_ERROR_NONE === json_last_error () ) {
2899+ $ value = $ decoded ;
2900+ }
2901+ }
2902+
28532903 $ value = rest_sanitize_object ( $ value );
28542904
28552905 foreach ( $ value as $ property => $ v ) {
0 commit comments