diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-controller.php index d9d60d2ee9..b9c05eb894 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-controller.php @@ -451,7 +451,7 @@ abstract class WP_REST_Controller { continue; } - if ( ! in_array( $field_name, $requested_fields, true ) ) { + if ( ! rest_is_field_included( $field_name, $requested_fields ) ) { continue; } diff --git a/tests/phpunit/tests/rest-api.php b/tests/phpunit/tests/rest-api.php index c0eea9804f..97b79c8c88 100644 --- a/tests/phpunit/tests/rest-api.php +++ b/tests/phpunit/tests/rest-api.php @@ -560,6 +560,48 @@ class Tests_REST_API extends WP_UnitTestCase { ); } + /** + * Ensure inclusion of deeply nested fields may be controlled with request['_fields']. + * + * @ticket 49648 + */ + public function test_rest_filter_response_fields_deeply_nested_field_filter() { + $response = new WP_REST_Response(); + + $response->set_data( + array( + 'field' => array( + 'a' => array( + 'i' => 'value i', + 'ii' => 'value ii', + ), + 'b' => array( + 'iii' => 'value iii', + 'iv' => 'value iv', + ), + ), + ) + ); + $request = array( + '_fields' => 'field.a.i,field.b.iv', + ); + + $response = rest_filter_response_fields( $response, null, $request ); + $this->assertEquals( + array( + 'field' => array( + 'a' => array( + 'i' => 'value i', + ), + 'b' => array( + 'iv' => 'value iv', + ), + ), + ), + $response->get_data() + ); + } + /** * Ensure that specifying a single top-level key in _fields includes that field and all children. * diff --git a/tests/phpunit/tests/rest-api/rest-controller.php b/tests/phpunit/tests/rest-api/rest-controller.php index 0fa98078b5..499bc40929 100644 --- a/tests/phpunit/tests/rest-api/rest-controller.php +++ b/tests/phpunit/tests/rest-api/rest-controller.php @@ -48,6 +48,13 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase { ); } + public function tearDown() { + parent::tearDown(); + + global $wp_rest_additional_fields; + $wp_rest_additional_fields = array(); + } + public function test_validate_schema_type_integer() { $this->assertTrue( @@ -437,4 +444,125 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase { $this->assertTrue( $listener->get_call_count( $method ) > $first_call_count ); } + + /** + * @dataProvider data_filter_nested_registered_rest_fields + * @ticket 49648 + */ + public function test_filter_nested_registered_rest_fields( $filter, $expected ) { + $controller = new WP_REST_Test_Controller(); + + register_rest_field( + 'type', + 'field', + array( + 'schema' => array( + 'type' => 'object', + 'description' => 'A complex object', + 'context' => array( 'view', 'edit' ), + 'properties' => array( + 'a' => array( + 'i' => 'string', + 'ii' => 'string', + ), + 'b' => array( + 'iii' => 'string', + 'iv' => 'string', + ), + ), + ), + 'get_callback' => array( $this, 'register_nested_rest_field_get_callback' ), + ) + ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/testroute' ); + $request->set_param( '_fields', $filter ); + + $response = $controller->prepare_item_for_response( array(), $request ); + $response = rest_filter_response_fields( $response, rest_get_server(), $request ); + + $this->assertEquals( $expected, $response->get_data() ); + } + + public function register_nested_rest_field_get_callback() { + return array( + 'a' => array( + 'i' => 'value i', + 'ii' => 'value ii', + ), + 'b' => array( + 'iii' => 'value iii', + 'iv' => 'value iv', + ), + ); + } + + public function data_filter_nested_registered_rest_fields() { + return array( + array( + 'field', + array( + 'field' => array( + 'a' => array( + 'i' => 'value i', + 'ii' => 'value ii', + ), + 'b' => array( + 'iii' => 'value iii', + 'iv' => 'value iv', + ), + ), + ), + ), + array( + 'field.a', + array( + 'field' => array( + 'a' => array( + 'i' => 'value i', + 'ii' => 'value ii', + ), + ), + ), + ), + array( + 'field.b', + array( + 'field' => array( + 'b' => array( + 'iii' => 'value iii', + 'iv' => 'value iv', + ), + ), + ), + ), + array( + 'field.a.i,field.b.iv', + array( + 'field' => array( + 'a' => array( + 'i' => 'value i', + ), + 'b' => array( + 'iv' => 'value iv', + ), + ), + ), + ), + array( + 'field.a,field.b.iii', + array( + 'field' => array( + 'a' => array( + 'i' => 'value i', + 'ii' => 'value ii', + ), + 'b' => array( + 'iii' => 'value iii', + ), + ), + ), + ), + ); + } }