diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php index e9a5799b60..c18c63ec2a 100644 --- a/src/wp-includes/rest-api.php +++ b/src/wp-includes/rest-api.php @@ -2052,15 +2052,28 @@ function rest_filter_response_by_context( $data, $schema, $context ) { return $data; } + $is_array_type = 'array' === $type || ( is_array( $type ) && in_array( 'array', $type, true ) ); + $is_object_type = 'object' === $type || ( is_array( $type ) && in_array( 'object', $type, true ) ); + + if ( $is_array_type && $is_object_type ) { + if ( rest_is_array( $data ) ) { + $is_object_type = false; + } else { + $is_array_type = false; + } + } + + $has_additional_properties = $is_object_type && isset( $schema['additionalProperties'] ) && is_array( $schema['additionalProperties'] ); + foreach ( $data as $key => $value ) { $check = array(); - if ( 'array' === $type || ( is_array( $type ) && in_array( 'array', $type, true ) ) ) { + if ( $is_array_type ) { $check = isset( $schema['items'] ) ? $schema['items'] : array(); - } elseif ( 'object' === $type || ( is_array( $type ) && in_array( 'object', $type, true ) ) ) { + } elseif ( $is_object_type ) { if ( isset( $schema['properties'][ $key ] ) ) { $check = $schema['properties'][ $key ]; - } elseif ( isset( $schema['additionalProperties'] ) && is_array( $schema['additionalProperties'] ) ) { + } elseif ( $has_additional_properties ) { $check = $schema['additionalProperties']; } } @@ -2070,6 +2083,12 @@ function rest_filter_response_by_context( $data, $schema, $context ) { } if ( ! in_array( $context, $check['context'], true ) ) { + if ( $is_array_type ) { + // All array items share schema, so there's no need to check each one. + $data = array(); + break; + } + if ( is_object( $data ) ) { unset( $data->$key ); } else { diff --git a/tests/phpunit/tests/rest-api.php b/tests/phpunit/tests/rest-api.php index 123e872f07..e9d9b50c5d 100644 --- a/tests/phpunit/tests/rest-api.php +++ b/tests/phpunit/tests/rest-api.php @@ -1085,7 +1085,7 @@ class Tests_REST_API extends WP_UnitTestCase { public function _dp_rest_filter_response_by_context() { return array( - 'default' => array( + 'default' => array( array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'type' => 'object', @@ -1106,7 +1106,7 @@ class Tests_REST_API extends WP_UnitTestCase { ), array( 'first' => 'a' ), ), - 'keeps missing context' => array( + 'keeps missing context' => array( array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'type' => 'object', @@ -1129,7 +1129,7 @@ class Tests_REST_API extends WP_UnitTestCase { 'second' => 'b', ), ), - 'removes empty context' => array( + 'removes empty context' => array( array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'type' => 'object', @@ -1150,7 +1150,7 @@ class Tests_REST_API extends WP_UnitTestCase { ), array( 'first' => 'a' ), ), - 'nested properties' => array( + 'nested properties' => array( array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'type' => 'object', @@ -1179,7 +1179,7 @@ class Tests_REST_API extends WP_UnitTestCase { ), array( 'parent' => array( 'child' => 'hi' ) ), ), - 'grand child properties' => array( + 'grand child properties' => array( array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'type' => 'object', @@ -1215,7 +1215,7 @@ class Tests_REST_API extends WP_UnitTestCase { ), array( 'parent' => array( 'child' => array( 'grand' => 'hi' ) ) ), ), - 'array' => array( + 'array' => array( array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'type' => 'object', @@ -1250,7 +1250,7 @@ class Tests_REST_API extends WP_UnitTestCase { ), array( 'arr' => array( array( 'visible' => 'hi' ) ) ), ), - 'additional properties' => array( + 'additional properties' => array( array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'type' => 'object', @@ -1284,7 +1284,7 @@ class Tests_REST_API extends WP_UnitTestCase { ), array( 'additional' => array( 'a' => '1' ) ), ), - 'multiple types object' => array( + 'multiple types object' => array( array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'type' => 'object', @@ -1313,7 +1313,7 @@ class Tests_REST_API extends WP_UnitTestCase { ), array( 'multi' => array( 'a' => '1' ) ), ), - 'multiple types array' => array( + 'multiple types array' => array( array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'type' => 'object', @@ -1348,7 +1348,7 @@ class Tests_REST_API extends WP_UnitTestCase { ), array( 'multi' => array( array( 'visible' => '1' ) ) ), ), - 'grand child properties does not traverses missing context' => array( + 'does not traverse missing context' => array( array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'type' => 'object', @@ -1391,6 +1391,126 @@ class Tests_REST_API extends WP_UnitTestCase { ), ), ), + 'object with no matching properties' => array( + array( + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'type' => 'object', + 'properties' => array( + 'a' => array( + 'type' => 'string', + 'context' => array( 'edit' ), + ), + 'b' => array( + 'type' => 'string', + 'context' => array( 'edit' ), + ), + ), + ), + array( + 'a' => 'hi', + 'b' => 'hello', + ), + array(), + ), + 'array whose type does not match' => array( + array( + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'type' => 'object', + 'properties' => array( + 'arr' => array( + 'type' => 'array', + 'context' => array( 'view' ), + 'items' => array( + 'type' => 'string', + 'context' => array( 'edit' ), + ), + ), + ), + ), + array( + 'arr' => array( 'foo', 'bar', 'baz' ), + ), + array( 'arr' => array() ), + ), + 'array and object type passed object' => array( + array( + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'type' => array( 'array', 'object' ), + 'properties' => array( + 'a' => array( + 'type' => 'string', + 'context' => array( 'view' ), + ), + 'b' => array( + 'type' => 'string', + 'context' => array( 'view' ), + ), + ), + 'items' => array( + 'type' => 'object', + 'context' => array( 'edit' ), + 'properties' => array( + 'a' => array( + 'type' => 'string', + 'context' => array( 'view' ), + ), + 'b' => array( + 'type' => 'string', + 'context' => array( 'view' ), + ), + ), + ), + ), + array( + 'a' => 'foo', + 'b' => 'bar', + ), + array( + 'a' => 'foo', + 'b' => 'bar', + ), + ), + 'array and object type passed array' => array( + array( + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'type' => array( 'array', 'object' ), + 'properties' => array( + 'a' => array( + 'type' => 'string', + 'context' => array( 'view' ), + ), + 'b' => array( + 'type' => 'string', + 'context' => array( 'view' ), + ), + ), + 'items' => array( + 'type' => 'object', + 'context' => array( 'edit' ), + 'properties' => array( + 'a' => array( + 'type' => 'string', + 'context' => array( 'view' ), + ), + 'b' => array( + 'type' => 'string', + 'context' => array( 'view' ), + ), + ), + ), + ), + array( + array( + 'a' => 'foo', + 'b' => 'bar', + ), + array( + 'a' => 'foo', + 'b' => 'bar', + ), + ), + array(), + ), ); }