From eb468c44466a7736bfd44d9e7b449aef8dfe88cd Mon Sep 17 00:00:00 2001 From: "K. Adam White" Date: Thu, 15 Aug 2019 21:08:05 +0000 Subject: [PATCH] REST API: Cache results of get_item_schema on controller instances for performance. Caches the output of get_item_schema() to avoid redundant recomputation of translatable strings and other computed values. This method is called many times per item in each REST request, and the results of the method should not vary between calls. Additional schema fields are not cached. Props kadamwhite, joehoyle, TimothyBlynJacobs. Fixes #47871. git-svn-id: https://develop.svn.wordpress.org/trunk@45811 602fd350-edb4-49c9-b593-d223f7449a82 --- .../endpoints/class-wp-rest-attachments-controller.php | 6 +++++- .../endpoints/class-wp-rest-autosaves-controller.php | 7 ++++++- .../endpoints/class-wp-rest-block-renderer-controller.php | 7 ++++++- .../endpoints/class-wp-rest-blocks-controller.php | 1 + .../endpoints/class-wp-rest-comments-controller.php | 7 ++++++- .../rest-api/endpoints/class-wp-rest-controller.php | 8 ++++++++ .../endpoints/class-wp-rest-post-statuses-controller.php | 7 ++++++- .../endpoints/class-wp-rest-post-types-controller.php | 8 +++++++- .../rest-api/endpoints/class-wp-rest-posts-controller.php | 6 +++++- .../endpoints/class-wp-rest-revisions-controller.php | 7 ++++++- .../endpoints/class-wp-rest-search-controller.php | 7 ++++++- .../endpoints/class-wp-rest-settings-controller.php | 7 ++++++- .../endpoints/class-wp-rest-taxonomies-controller.php | 8 +++++++- .../rest-api/endpoints/class-wp-rest-terms-controller.php | 7 ++++++- .../endpoints/class-wp-rest-themes-controller.php | 7 ++++++- .../rest-api/endpoints/class-wp-rest-users-controller.php | 7 ++++++- tests/phpunit/tests/rest-api/rest-posts-controller.php | 6 ++++++ tests/phpunit/tests/rest-api/rest-users-controller.php | 7 +++++++ 18 files changed, 106 insertions(+), 14 deletions(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php index fe7bd06ee0..bc1a280492 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php @@ -417,6 +417,9 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller { * @return array Item schema as an array. */ public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } $schema = parent::get_item_schema(); @@ -513,7 +516,8 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller { unset( $schema['properties']['password'] ); - return $schema; + $this->schema = $schema; + return $this->add_additional_fields_schema( $this->schema ); } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php index e55d3a3729..0d015519d3 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php @@ -296,6 +296,10 @@ class WP_REST_Autosaves_Controller extends WP_REST_Revisions_Controller { * @return array Item schema data. */ public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + $schema = $this->revisions_controller->get_item_schema(); $schema['properties']['preview_link'] = array( @@ -306,7 +310,8 @@ class WP_REST_Autosaves_Controller extends WP_REST_Revisions_Controller { 'readonly' => true, ); - return $schema; + $this->schema = $schema; + return $this->add_additional_fields_schema( $this->schema ); } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php index 681e519313..18fbe1e036 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php @@ -161,7 +161,11 @@ class WP_REST_Block_Renderer_Controller extends WP_REST_Controller { * @return array Item schema data. */ public function get_item_schema() { - return array( + if ( $this->schema ) { + return $this->schema; + } + + $this->schema = array( '$schema' => 'http://json-schema.org/schema#', 'title' => 'rendered-block', 'type' => 'object', @@ -174,5 +178,6 @@ class WP_REST_Block_Renderer_Controller extends WP_REST_Controller { ), ), ); + return $this->schema; } } diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php index a523764dc5..36d1573a9a 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php @@ -68,6 +68,7 @@ class WP_REST_Blocks_Controller extends WP_REST_Posts_Controller { * @return array Item schema data. */ public function get_item_schema() { + // Do not cache this schema because all properties are derived from parent controller. $schema = parent::get_item_schema(); /* diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php index b730844fde..8bce803ea9 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php @@ -1215,6 +1215,10 @@ class WP_REST_Comments_Controller extends WP_REST_Controller { * @return array */ public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'comment', @@ -1364,7 +1368,8 @@ class WP_REST_Comments_Controller extends WP_REST_Controller { $schema['properties']['meta'] = $this->meta->get_field_schema(); - return $this->add_additional_fields_schema( $schema ); + $this->schema = $schema; + return $this->add_additional_fields_schema( $this->schema ); } /** 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 e1ca0af6ce..735fee738a 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 @@ -30,6 +30,14 @@ abstract class WP_REST_Controller { */ protected $rest_base; + /** + * Cached results of get_item_schema. + * + * @since 5.3.0 + * @var array + */ + protected $schema; + /** * Registers the routes for the objects of the controller. * diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php index 699e8fd2ce..155c8aaa96 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php @@ -268,6 +268,10 @@ class WP_REST_Post_Statuses_Controller extends WP_REST_Controller { * @return array Item schema data. */ public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'status', @@ -318,7 +322,8 @@ class WP_REST_Post_Statuses_Controller extends WP_REST_Controller { ), ); - return $this->add_additional_fields_schema( $schema ); + $this->schema = $schema; + return $this->add_additional_fields_schema( $this->schema ); } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php index c718a3dfa6..99a3c77071 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php @@ -242,6 +242,10 @@ class WP_REST_Post_Types_Controller extends WP_REST_Controller { * @return array Item schema data. */ public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'type', @@ -312,7 +316,9 @@ class WP_REST_Post_Types_Controller extends WP_REST_Controller { ), ), ); - return $this->add_additional_fields_schema( $schema ); + + $this->schema = $schema; + return $this->add_additional_fields_schema( $this->schema ); } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php index 090ca2a5da..ad53ea6a1e 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php @@ -1870,6 +1870,9 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { * @return array Item schema data. */ public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', @@ -2229,7 +2232,8 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { $schema['links'] = $schema_links; } - return $this->add_additional_fields_schema( $schema ); + $this->schema = $schema; + return $this->add_additional_fields_schema( $this->schema ); } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php index 52df0f2206..1b34619130 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php @@ -606,6 +606,10 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller { * @return array Item schema data. */ public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => "{$this->parent_post_type}-revision", @@ -682,7 +686,8 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller { $schema['properties']['guid'] = $parent_schema['properties']['guid']; } - return $this->add_additional_fields_schema( $schema ); + $this->schema = $schema; + return $this->add_additional_fields_schema( $this->schema ); } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php index 299029b1c3..c464e0d1b4 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php @@ -211,6 +211,10 @@ class WP_REST_Search_Controller extends WP_REST_Controller { * @return array Item schema data. */ public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + $types = array(); $subtypes = array(); foreach ( $this->search_handlers as $search_handler ) { @@ -262,7 +266,8 @@ class WP_REST_Search_Controller extends WP_REST_Controller { ), ); - return $this->add_additional_fields_schema( $schema ); + $this->schema = $schema; + return $this->add_additional_fields_schema( $this->schema ); } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php index 95752f8236..b11e4fdca8 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php @@ -270,6 +270,10 @@ class WP_REST_Settings_Controller extends WP_REST_Controller { * @return array Item schema data. */ public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + $options = $this->get_registered_options(); $schema = array( @@ -286,7 +290,8 @@ class WP_REST_Settings_Controller extends WP_REST_Controller { ); } - return $this->add_additional_fields_schema( $schema ); + $this->schema = $schema; + return $this->add_additional_fields_schema( $this->schema ); } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php index 6dc78cb6d0..58ad748132 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php @@ -276,6 +276,10 @@ class WP_REST_Taxonomies_Controller extends WP_REST_Controller { * @return array Item schema data. */ public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'taxonomy', @@ -373,7 +377,9 @@ class WP_REST_Taxonomies_Controller extends WP_REST_Controller { ), ), ); - return $this->add_additional_fields_schema( $schema ); + + $this->schema = $schema; + return $this->add_additional_fields_schema( $this->schema ); } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php index 881afcd41f..52bc9d2b0a 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php @@ -856,6 +856,10 @@ class WP_REST_Terms_Controller extends WP_REST_Controller { * @return array Item schema data. */ public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'post_tag' === $this->taxonomy ? 'tag' : $this->taxonomy, @@ -924,7 +928,8 @@ class WP_REST_Terms_Controller extends WP_REST_Controller { $schema['properties']['meta'] = $this->meta->get_field_schema(); - return $this->add_additional_fields_schema( $schema ); + $this->schema = $schema; + return $this->add_additional_fields_schema( $this->schema ); } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php index dbfaa839cb..e04b23594d 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php @@ -147,6 +147,10 @@ class WP_REST_Themes_Controller extends WP_REST_Controller { * @return array Item schema data. */ public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'theme', @@ -177,7 +181,8 @@ class WP_REST_Themes_Controller extends WP_REST_Controller { ), ); - return $this->add_additional_fields_schema( $schema ); + $this->schema = $schema; + return $this->add_additional_fields_schema( $this->schema ); } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php index bd09b70b32..ec29c66974 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php @@ -1178,6 +1178,10 @@ class WP_REST_Users_Controller extends WP_REST_Controller { * @return array Item schema data. */ public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'user', @@ -1334,7 +1338,8 @@ class WP_REST_Users_Controller extends WP_REST_Controller { $schema['properties']['meta'] = $this->meta->get_field_schema(); - return $this->add_additional_fields_schema( $schema ); + $this->schema = $schema; + return $this->add_additional_fields_schema( $this->schema ); } /** diff --git a/tests/phpunit/tests/rest-api/rest-posts-controller.php b/tests/phpunit/tests/rest-api/rest-posts-controller.php index f03eee8e83..ba174c448e 100644 --- a/tests/phpunit/tests/rest-api/rest-posts-controller.php +++ b/tests/phpunit/tests/rest-api/rest-posts-controller.php @@ -3919,6 +3919,12 @@ class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te remove_post_type_support( 'post', 'author' ); + // Re-initialize the controller to cache-bust schemas from prior test runs. + $GLOBALS['wp_rest_server']->override_by_default = true; + $controller = new WP_REST_Posts_Controller( 'post' ); + $controller->register_routes(); + $GLOBALS['wp_rest_server']->override_by_default = false; + $response = rest_get_server()->dispatch( new WP_REST_Request( 'OPTIONS', '/wp/v2/posts' ) ); $data = $response->get_data(); $schema = $data['schema']; diff --git a/tests/phpunit/tests/rest-api/rest-users-controller.php b/tests/phpunit/tests/rest-api/rest-users-controller.php index 02ef87c04b..28755a97d1 100644 --- a/tests/phpunit/tests/rest-api/rest-users-controller.php +++ b/tests/phpunit/tests/rest-api/rest-users-controller.php @@ -2522,6 +2522,13 @@ class WP_Test_REST_Users_Controller extends WP_Test_REST_Controller_Testcase { public function test_get_item_schema_show_avatar() { update_option( 'show_avatars', false ); + + // Re-initialize the controller to cache-bust schemas from prior test runs. + $GLOBALS['wp_rest_server']->override_by_default = true; + $controller = new WP_REST_Users_Controller(); + $controller->register_routes(); + $GLOBALS['wp_rest_server']->override_by_default = false; + $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/users' ); $response = rest_get_server()->dispatch( $request ); $data = $response->get_data();