REST API: Use wp_get_object_terms() when fetching terms for a post object.

The WP-API plugin originally used a custom method for fetching object
terms in a way that supported the object cache and also accepted all
parameters for `get_terms()`. In [38667], the internals of
`wp_get_object_terms()` were modified to use `WP_Term_Query`, thus
delivering in a native fashion the features that the API had
previously achieved bespokely.

Fixes #38504.

git-svn-id: https://develop.svn.wordpress.org/trunk@38974 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Boone Gorges 2016-10-27 01:41:08 +00:00
parent 3e77cef88a
commit 5da7a1dccf
2 changed files with 42 additions and 82 deletions

View File

@ -189,10 +189,13 @@ 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'] );
@ -202,7 +205,7 @@ class WP_REST_Terms_Controller extends WP_REST_Controller {
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.
*

View File

@ -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;
}