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 1d4f9c6817..ed5cdc8ae4 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 @@ -189,20 +189,23 @@ class WP_REST_Terms_Controller extends WP_REST_Controller { $prepared_args = apply_filters( "rest_{$this->taxonomy}_query", $prepared_args, $request ); if ( ! empty( $prepared_args['post'] ) ) { - $query_result = $this->get_terms_for_post( $prepared_args ); - $total_terms = $this->total_terms; + $query_result = wp_get_object_terms( $prepared_args['post'], $this->taxonomy, $prepared_args ); + + // Used when calling wp_count_terms() below. + $prepared_args['object_ids'] = $prepared_args['post']; } else { $query_result = get_terms( $this->taxonomy, $prepared_args ); - - $count_args = $prepared_args; - unset( $count_args['number'], $count_args['offset'] ); - $total_terms = wp_count_terms( $this->taxonomy, $count_args ); - - // wp_count_terms can return a falsy value when the term has no children - if ( ! $total_terms ) { - $total_terms = 0; - } } + + $count_args = $prepared_args; + unset( $count_args['number'], $count_args['offset'] ); + $total_terms = wp_count_terms( $this->taxonomy, $count_args ); + + // wp_count_terms can return a falsy value when the term has no children + if ( ! $total_terms ) { + $total_terms = 0; + } + $response = array(); foreach ( $query_result as $term ) { $data = $this->prepare_item_for_response( $term, $request ); @@ -237,77 +240,6 @@ class WP_REST_Terms_Controller extends WP_REST_Controller { return $response; } - /** - * Gets the terms attached to a post. - * - * This is an alternative to get_terms() that uses get_the_terms() - * instead, which hits the object cache. There are a few things not - * supported, notably `include`, `exclude`. In `self::get_items()` these - * are instead treated as a full query. - * - * @param array $prepared_args Arguments for get_terms(). - * @return array List of term objects. (Total count in `$this->total_terms`) - */ - protected function get_terms_for_post( $prepared_args ) { - $query_result = get_the_terms( $prepared_args['post'], $this->taxonomy ); - if ( empty( $query_result ) ) { - $this->total_terms = 0; - return array(); - } - - /* - * get_items() verifies that we don't have `include` set, and default - * ordering is by `name`. - */ - if ( ! in_array( $prepared_args['orderby'], array( 'name', 'none', 'include' ), true ) ) { - switch ( $prepared_args['orderby'] ) { - case 'id': - $this->sort_column = 'term_id'; - break; - - case 'slug': - case 'term_group': - case 'description': - case 'count': - $this->sort_column = $prepared_args['orderby']; - break; - } - usort( $query_result, array( $this, 'compare_terms' ) ); - } - if ( strtolower( $prepared_args['order'] ) !== 'asc' ) { - $query_result = array_reverse( $query_result ); - } - - // Pagination. - $this->total_terms = count( $query_result ); - $query_result = array_slice( $query_result, $prepared_args['offset'], $prepared_args['number'] ); - - return $query_result; - } - - /** - * Comparison function for sorting terms by a column. - * - * Uses `$this->sort_column` to determine field to sort by. - * - * @access protected - * - * @param stdClass $left Term object. - * @param stdClass $right Term object. - * @return int <0 if left is higher "priority" than right, 0 if equal, >0 if right is higher "priority" than left. - */ - protected function compare_terms( $left, $right ) { - $col = $this->sort_column; - $left_val = $left->$col; - $right_val = $right->$col; - - if ( is_int( $left_val ) && is_int( $right_val ) ) { - return $left_val - $right_val; - } - - return strcmp( $left_val, $right_val ); - } - /** * Checks if a request has access to read the specified term. * diff --git a/tests/phpunit/tests/rest-api/rest-tags-controller.php b/tests/phpunit/tests/rest-api/rest-tags-controller.php index f5296c057f..0bdae855ae 100644 --- a/tests/phpunit/tests/rest-api/rest-tags-controller.php +++ b/tests/phpunit/tests/rest-api/rest-tags-controller.php @@ -770,6 +770,34 @@ class WP_Test_REST_Tags_Controller extends WP_Test_REST_Controller_Testcase { $wp_rest_additional_fields = array(); } + /** + * @ticket 38504 + */ + public function test_object_term_queries_are_cached() { + global $wpdb; + + $tags = $this->factory->tag->create_many( 2 ); + $p = $this->factory->post->create(); + wp_set_object_terms( $p, $tags[0], 'post_tag' ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/tags' ); + $request->set_param( 'post', $p ); + $response = $this->server->dispatch( $request ); + $found_1 = wp_list_pluck( $response->data, 'id' ); + + unset( $request, $response ); + + $num_queries = $wpdb->num_queries; + + $request = new WP_REST_Request( 'GET', '/wp/v2/tags' ); + $request->set_param( 'post', $p ); + $response = $this->server->dispatch( $request ); + $found_2 = wp_list_pluck( $response->data, 'id' ); + + $this->assertEqualSets( $found_1, $found_2 ); + $this->assertSame( $num_queries, $wpdb->num_queries ); + } + public function additional_field_get_callback( $object, $request ) { return 123; }