diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php index c397bdc116..3e6f419f6b 100644 --- a/src/wp-includes/rest-api.php +++ b/src/wp-includes/rest-api.php @@ -743,8 +743,12 @@ function rest_filter_response_fields( $response, $server, $request ) { $parts = explode( '.', $field ); $ref = &$fields_as_keyed; while ( count( $parts ) > 1 ) { - $next = array_shift( $parts ); - $ref[ $next ] = array(); + $next = array_shift( $parts ); + if ( isset( $ref[ $next ] ) && true === $ref[ $next ] ) { + // Skip any sub-properties if their parent prop is already marked for inclusion. + break 2; + } + $ref[ $next ] = isset( $ref[ $next ] ) ? $ref[ $next ] : array(); $ref = &$ref[ $next ]; } $last = array_shift( $parts ); diff --git a/tests/phpunit/tests/rest-api.php b/tests/phpunit/tests/rest-api.php index 2b8310f168..1efb81a348 100644 --- a/tests/phpunit/tests/rest-api.php +++ b/tests/phpunit/tests/rest-api.php @@ -560,6 +560,102 @@ class Tests_REST_API extends WP_UnitTestCase { ); } + /** + * Ensure that specifying a single top-level key in _fields includes that field and all children. + * + * @ticket 48266 + */ + public function test_rest_filter_response_fields_top_level_key() { + $response = new WP_REST_Response(); + + $response->set_data( + array( + 'meta' => array( + 'key1' => 1, + 'key2' => 2, + ), + ) + ); + $request = array( + '_fields' => 'meta', + ); + + $response = rest_filter_response_fields( $response, null, $request ); + $this->assertEquals( + array( + 'meta' => array( + 'key1' => 1, + 'key2' => 2, + ), + ), + $response->get_data() + ); + } + + /** + * Ensure that a top-level key in _fields supersedes any specified children of that field. + * + * @ticket 48266 + */ + public function test_rest_filter_response_fields_child_after_parent() { + $response = new WP_REST_Response(); + + $response->set_data( + array( + 'meta' => array( + 'key1' => 1, + 'key2' => 2, + ), + ) + ); + $request = array( + '_fields' => 'meta,meta.key1', + ); + + $response = rest_filter_response_fields( $response, null, $request ); + $this->assertEquals( + array( + 'meta' => array( + 'key1' => 1, + 'key2' => 2, + ), + ), + $response->get_data() + ); + } + + /** + * Ensure that specifying two sibling properties in _fields causes both to be included. + * + * @ticket 48266 + */ + public function test_rest_filter_response_fields_include_all_specified_siblings() { + $response = new WP_REST_Response(); + + $response->set_data( + array( + 'meta' => array( + 'key1' => 1, + 'key2' => 2, + ), + ) + ); + $request = array( + '_fields' => 'meta.key1,meta.key2', + ); + + $response = rest_filter_response_fields( $response, null, $request ); + $this->assertEquals( + array( + 'meta' => array( + 'key1' => 1, + 'key2' => 2, + ), + ), + $response->get_data() + ); + } + /** * @ticket 42094 */