Skip to content

Commit f57bee4

Browse files
REST API: Remove deprecated schema sanitization functions and integrate logic into WP_REST_Server
1 parent cfcc416 commit f57bee4

3 files changed

Lines changed: 39 additions & 130 deletions

File tree

src/wp-includes/rest-api.php

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -197,65 +197,6 @@ function register_rest_field( $object_type, $attribute, $args = array() ) {
197197
}
198198
}
199199

200-
/**
201-
* Sanitizes schema data ensuring empty properties arrays become objects for valid JSON Schema.
202-
*
203-
* The JSON Schema specification requires 'properties' to always be an object.
204-
* In PHP, empty associative arrays become empty arrays ([]) when JSON-encoded,
205-
* not empty objects ({}), which would make the schema invalid.
206-
*
207-
* This function only processes schema data from OPTIONS requests to avoid affecting
208-
* regular response data that may legitimately have a 'properties' field.
209-
*
210-
* @since 6.9.0
211-
*
212-
* @param array|object $data The response data to sanitize.
213-
* @param WP_REST_Server $server Server instance.
214-
* @param WP_REST_Request $request Request used to generate the response.
215-
* @return array|object The sanitized response data.
216-
*/
217-
function rest_sanitize_schema_properties( $data, $server, $request ) {
218-
if (
219-
$request->get_method() === 'OPTIONS' &&
220-
is_array( $data ) &&
221-
isset( $data['schema'] ) &&
222-
is_array( $data['schema'] )
223-
) {
224-
$data['schema'] = rest_sanitize_schema_properties_recursive( $data['schema'] );
225-
}
226-
227-
return $data;
228-
}
229-
230-
/**
231-
* Recursively sanitizes schema data ensuring empty properties arrays become objects.
232-
*
233-
* Helper function for rest_sanitize_schema_properties().
234-
*
235-
* @since 6.9.0
236-
*
237-
* @param array|object $data The schema data to sanitize.
238-
* @return array|object The sanitized schema data.
239-
*/
240-
function rest_sanitize_schema_properties_recursive( $data ) {
241-
$is_object = is_object( $data );
242-
$data_array = $is_object ? (array) $data : $data;
243-
244-
// Convert empty properties array to empty object.
245-
if ( isset( $data_array['properties'] ) && is_array( $data_array['properties'] ) && empty( $data_array['properties'] ) ) {
246-
$data_array['properties'] = (object) array();
247-
}
248-
249-
// Process nested elements recursively.
250-
foreach ( $data_array as $key => $value ) {
251-
if ( is_array( $value ) || is_object( $value ) ) {
252-
$data_array[ $key ] = rest_sanitize_schema_properties_recursive( $value );
253-
}
254-
}
255-
256-
return $is_object ? (object) $data_array : $data_array;
257-
}
258-
259200
/**
260201
* Registers rewrite rules for the REST API.
261202
*
@@ -269,9 +210,6 @@ function rest_api_init() {
269210

270211
global $wp;
271212
$wp->add_query_var( 'rest_route' );
272-
273-
// Ensure empty property arrays in schema are converted to objects.
274-
add_filter( 'rest_pre_echo_response', 'rest_sanitize_schema_properties', 10, 3 );
275213
}
276214

277215
/**

src/wp-includes/rest-api/class-wp-rest-server.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,14 @@ public function serve_request( $path = null ) {
523523
$embed = isset( $_GET['_embed'] ) ? rest_parse_embed_param( $_GET['_embed'] ) : false;
524524
$result = $this->response_to_data( $result, $embed );
525525

526+
if (
527+
$request->get_method() === 'OPTIONS' &&
528+
isset( $result['schema'] ) &&
529+
is_array( $result['schema'] )
530+
) {
531+
$result['schema'] = $this->sanitize_schema_properties_recursive( $result['schema'] );
532+
}
533+
526534
/**
527535
* Filters the REST API response.
528536
*
@@ -1346,6 +1354,37 @@ protected function get_json_last_error() {
13461354
return json_last_error_msg();
13471355
}
13481356

1357+
/**
1358+
* Recursively sanitizes schema data ensuring empty properties arrays become objects.
1359+
*
1360+
* The JSON Schema specification requires 'properties' to always be an object.
1361+
* In PHP, empty associative arrays become empty arrays ([]) when JSON-encoded,
1362+
* not empty objects ({}), which would make the schema invalid.
1363+
*
1364+
* @since 7.0.0
1365+
*
1366+
* @param array|object $data The schema data to sanitize.
1367+
* @return array|object The sanitized schema data.
1368+
*/
1369+
protected function sanitize_schema_properties_recursive( $data ) {
1370+
$is_object = is_object( $data );
1371+
$data_array = $is_object ? (array) $data : $data;
1372+
1373+
// Convert empty properties array to empty object.
1374+
if ( isset( $data_array['properties'] ) && is_array( $data_array['properties'] ) && empty( $data_array['properties'] ) ) {
1375+
$data_array['properties'] = (object) array();
1376+
}
1377+
1378+
// Process nested elements recursively.
1379+
foreach ( $data_array as $key => $value ) {
1380+
if ( is_array( $value ) || is_object( $value ) ) {
1381+
$data_array[ $key ] = $this->sanitize_schema_properties_recursive( $value );
1382+
}
1383+
}
1384+
1385+
return $is_object ? (object) $data_array : $data_array;
1386+
}
1387+
13491388
/**
13501389
* Retrieves the site index.
13511390
*

tests/phpunit/tests/rest-api/rest-schema-validation.php

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -2093,72 +2093,4 @@ public function data_combining_operation_error_message() {
20932093
),
20942094
);
20952095
}
2096-
2097-
/**
2098-
* Test that an empty properties array is sanitized to an empty object in schema responses.
2099-
*
2100-
* @ticket 63186
2101-
*/
2102-
public function test_empty_properties_array_sanitized_to_object() {
2103-
$data = array(
2104-
'schema' => array(
2105-
'type' => 'object',
2106-
'properties' => array(),
2107-
),
2108-
);
2109-
2110-
$request = new WP_REST_Request( 'OPTIONS', '/test' );
2111-
$server = rest_get_server();
2112-
2113-
$sanitized_data = apply_filters( 'rest_pre_echo_response', $data, $server, $request );
2114-
2115-
$this->assertIsObject( $sanitized_data['schema']['properties'], 'Empty properties array should be converted to an object.' );
2116-
$this->assertEmpty( (array) $sanitized_data['schema']['properties'] );
2117-
}
2118-
2119-
/**
2120-
* Test that a non-empty properties array remains unchanged.
2121-
*
2122-
* @ticket 63186
2123-
*/
2124-
public function test_non_empty_properties_array_remains_unchanged() {
2125-
$data = array(
2126-
'schema' => array(
2127-
'type' => 'object',
2128-
'properties' => array(
2129-
'field' => array( 'type' => 'string' ),
2130-
),
2131-
),
2132-
);
2133-
2134-
$request = new WP_REST_Request( 'OPTIONS', '/test' );
2135-
$server = rest_get_server();
2136-
2137-
$sanitized_data = apply_filters( 'rest_pre_echo_response', $data, $server, $request );
2138-
2139-
$this->assertNotEmpty( $sanitized_data['schema']['properties'] );
2140-
$this->assertIsArray( $sanitized_data['schema']['properties'], 'Non-empty properties should remain as an array.' );
2141-
$this->assertArrayHasKey( 'field', $sanitized_data['schema']['properties'] );
2142-
}
2143-
2144-
/**
2145-
* Test that regular response data with empty properties field is not affected.
2146-
*
2147-
* @ticket 63186
2148-
*/
2149-
public function test_regular_response_properties_not_affected() {
2150-
$data = array(
2151-
'id' => 123,
2152-
'title' => 'Test Post',
2153-
'properties' => array(),
2154-
);
2155-
2156-
$request = new WP_REST_Request( 'GET', '/test' );
2157-
$server = rest_get_server();
2158-
2159-
$result = apply_filters( 'rest_pre_echo_response', $data, $server, $request );
2160-
2161-
$this->assertIsArray( $result['properties'], 'Regular response data should not be affected.' );
2162-
$this->assertEmpty( $result['properties'] );
2163-
}
21642096
}

0 commit comments

Comments
 (0)