From a875f9dae7c10e313dda6b9bf5cc7bea53e493b9 Mon Sep 17 00:00:00 2001 From: "K. Adam White" Date: Wed, 31 Jul 2019 20:20:02 +0000 Subject: [PATCH] REST API: Skip processing fields which are not present in the selected context. In `WP_REST_Controller::get_fields_for_response()`, exclude fields which are not registered to appear in the request's context. In conjunction with r45705 this prevents the unnecessary computation of the sample permalink when making a request that is not context=edit. Props dlh. Fixes #45605. git-svn-id: https://develop.svn.wordpress.org/trunk@45706 602fd350-edb4-49c9-b593-d223f7449a82 --- .../endpoints/class-wp-rest-controller.php | 18 +++- .../tests/rest-api/rest-controller.php | 88 +++++++++++++++++++ 2 files changed, 103 insertions(+), 3 deletions(-) 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 6188bff380..cd976f3357 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 @@ -517,18 +517,30 @@ abstract class WP_REST_Controller { * @return array Fields to be included in the response. */ public function get_fields_for_response( $request ) { - $schema = $this->get_item_schema(); - $fields = isset( $schema['properties'] ) ? array_keys( $schema['properties'] ) : array(); + $schema = $this->get_item_schema(); + $properties = isset( $schema['properties'] ) ? $schema['properties'] : array(); $additional_fields = $this->get_additional_fields(); foreach ( $additional_fields as $field_name => $field_options ) { // For back-compat, include any field with an empty schema // because it won't be present in $this->get_item_schema(). if ( is_null( $field_options['schema'] ) ) { - $fields[] = $field_name; + $properties[ $field_name ] = $field_options; } } + // Exclude fields that specify a different context than the request context. + $context = $request['context']; + if ( $context ) { + foreach ( $properties as $name => $options ) { + if ( ! empty( $options['context'] ) && ! in_array( $context, $options['context'], true ) ) { + unset( $properties[ $name ] ); + } + } + } + + $fields = array_keys( $properties ); + if ( ! isset( $request['_fields'] ) ) { return $fields; } diff --git a/tests/phpunit/tests/rest-api/rest-controller.php b/tests/phpunit/tests/rest-api/rest-controller.php index 6301e64d9d..f130abc62d 100644 --- a/tests/phpunit/tests/rest-api/rest-controller.php +++ b/tests/phpunit/tests/rest-api/rest-controller.php @@ -255,6 +255,94 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase { ); } + public function test_get_fields_for_response_filters_by_context() { + $controller = new WP_REST_Test_Controller(); + + $request = new WP_REST_Request( 'GET', '/wp/v2/testroute' ); + $request->set_param( 'context', 'view' ); + + $schema = $controller->get_item_schema(); + $field = 'somefield'; + + $listener = new MockAction(); + $method = 'action'; + + register_rest_field( + $schema['title'], + $field, + array( + 'schema' => array( + 'type' => 'string', + 'context' => array( 'embed' ), + ), + 'get_callback' => array( $listener, $method ), + ) + ); + + $controller->prepare_item_for_response( array(), $request ); + + $this->assertSame( 0, $listener->get_call_count( $method ) ); + + $request->set_param( 'context', 'embed' ); + + $controller->prepare_item_for_response( array(), $request ); + + $this->assertGreaterThan( 0, $listener->get_call_count( $method ) ); + } + + public function test_filtering_fields_for_response_by_context_returns_fields_with_no_context() { + $controller = new WP_REST_Test_Controller(); + + $request = new WP_REST_Request( 'GET', '/wp/v2/testroute' ); + $request->set_param( 'context', 'view' ); + + $schema = $controller->get_item_schema(); + $field = 'somefield'; + + $listener = new MockAction(); + $method = 'action'; + + register_rest_field( + $schema['title'], + $field, + array( + 'schema' => array( + 'type' => 'string', + ), + 'get_callback' => array( $listener, $method ), + ) + ); + + $controller->prepare_item_for_response( array(), $request ); + + $this->assertGreaterThan( 0, $listener->get_call_count( $method ) ); + } + + public function test_filtering_fields_for_response_by_context_returns_fields_with_no_schema() { + $controller = new WP_REST_Test_Controller(); + + $request = new WP_REST_Request( 'GET', '/wp/v2/testroute' ); + $request->set_param( 'context', 'view' ); + + $schema = $controller->get_item_schema(); + $field = 'somefield'; + + $listener = new MockAction(); + $method = 'action'; + + register_rest_field( + $schema['title'], + $field, + array( + 'get_callback' => array( $listener, $method ), + ) + ); + + $controller->prepare_item_for_response( array(), $request ); + + $this->assertGreaterThan( 0, $listener->get_call_count( $method ) ); + } + public function test_add_additional_fields_to_object_respects_fields_param() { $controller = new WP_REST_Test_Controller(); $request = new WP_REST_Request( 'GET', '/wp/v2/testroute' );