REST API: Allow for the posts endpoint include/exclude terms query to include_children.

For example the `categories` or `categories_exclude` parameters can now optionally accept an object with a `terms` property that accepts the list of term ids and a new `include_children` property which controls the Tax Query `include_children` field.

Props jason_the_adams, jnylen0, birgire, dlh.
Fixes #39494.


git-svn-id: https://develop.svn.wordpress.org/trunk@50157 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Timothy Jacobs
2021-02-02 19:23:08 +00:00
parent 051c135c6e
commit 032e946633
3 changed files with 571 additions and 97 deletions

View File

@@ -280,35 +280,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
}
}
$taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) );
if ( ! empty( $request['tax_relation'] ) ) {
$args['tax_query'] = array( 'relation' => $request['tax_relation'] );
}
foreach ( $taxonomies as $taxonomy ) {
$base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
$tax_exclude = $base . '_exclude';
if ( ! empty( $request[ $base ] ) ) {
$args['tax_query'][] = array(
'taxonomy' => $taxonomy->name,
'field' => 'term_id',
'terms' => $request[ $base ],
'include_children' => false,
);
}
if ( ! empty( $request[ $tax_exclude ] ) ) {
$args['tax_query'][] = array(
'taxonomy' => $taxonomy->name,
'field' => 'term_id',
'terms' => $request[ $tax_exclude ],
'include_children' => false,
'operator' => 'NOT IN',
);
}
}
$args = $this->prepare_tax_query( $args, $request );
// Force the post_type argument, since it's not a user input variable.
$args['post_type'] = $this->post_type;
@@ -2799,39 +2771,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
'sanitize_callback' => array( $this, 'sanitize_post_statuses' ),
);
$taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) );
if ( ! empty( $taxonomies ) ) {
$query_params['tax_relation'] = array(
'description' => __( 'Limit result set based on relationship between multiple taxonomies.' ),
'type' => 'string',
'enum' => array( 'AND', 'OR' ),
);
}
foreach ( $taxonomies as $taxonomy ) {
$base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
$query_params[ $base ] = array(
/* translators: %s: Taxonomy name. */
'description' => sprintf( __( 'Limit result set to all items that have the specified term assigned in the %s taxonomy.' ), $base ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'default' => array(),
);
$query_params[ $base . '_exclude' ] = array(
/* translators: %s: Taxonomy name. */
'description' => sprintf( __( 'Limit result set to all items except those that have the specified term assigned in the %s taxonomy.' ), $base ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'default' => array(),
);
}
$query_params = $this->prepare_taxonomy_limit_schema( $query_params );
if ( 'post' === $this->post_type ) {
$query_params['sticky'] = array(
@@ -2899,4 +2839,168 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
return $statuses;
}
/**
* Prepares the 'tax_query' for a collection of posts.
*
* @since 5.7.0
*
* @param array $args WP_Query arguments.
* @param WP_REST_Request $request Full details about the request.
* @return array Updated query arguments.
*/
private function prepare_tax_query( array $args, WP_REST_Request $request ) {
$relation = $request['tax_relation'];
if ( $relation ) {
$args['tax_query'] = array( 'relation' => $relation );
}
$taxonomies = wp_list_filter(
get_object_taxonomies( $this->post_type, 'objects' ),
array( 'show_in_rest' => true )
);
foreach ( $taxonomies as $taxonomy ) {
$base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
$tax_include = $request[ $base ];
$tax_exclude = $request[ $base . '_exclude' ];
if ( $tax_include ) {
$terms = array();
$include_children = false;
if ( rest_is_array( $tax_include ) ) {
$terms = $tax_include;
} elseif ( rest_is_object( $tax_include ) ) {
$terms = empty( $tax_include['terms'] ) ? array() : $tax_include['terms'];
$include_children = ! empty( $tax_include['include_children'] );
}
if ( $terms ) {
$args['tax_query'][] = array(
'taxonomy' => $taxonomy->name,
'field' => 'term_id',
'terms' => $terms,
'include_children' => $include_children,
);
}
}
if ( $tax_exclude ) {
$terms = array();
$include_children = false;
if ( rest_is_array( $tax_exclude ) ) {
$terms = $tax_exclude;
} elseif ( rest_is_object( $tax_exclude ) ) {
$terms = empty( $tax_exclude['terms'] ) ? array() : $tax_exclude['terms'];
$include_children = ! empty( $tax_exclude['include_children'] );
}
if ( $terms ) {
$args['tax_query'][] = array(
'taxonomy' => $taxonomy->name,
'field' => 'term_id',
'terms' => $terms,
'include_children' => $include_children,
'operator' => 'NOT IN',
);
}
}
}
return $args;
}
/**
* Prepares the collection schema for including and excluding items by terms.
*
* @since 5.7.0
*
* @param array $query_params Collection schema.
* @return array Updated schema.
*/
private function prepare_taxonomy_limit_schema( array $query_params ) {
$taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) );
if ( ! $taxonomies ) {
return $query_params;
}
$query_params['tax_relation'] = array(
'description' => __( 'Limit result set based on relationship between multiple taxonomies.' ),
'type' => 'string',
'enum' => array( 'AND', 'OR' ),
);
$limit_schema = array(
'type' => array( 'object', 'array' ),
'oneOf' => array(
array(
'title' => __( 'Term ID List' ),
'description' => __( 'Match terms with the listed IDs.' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
),
array(
'title' => __( 'Term ID Taxonomy Query' ),
'description' => __( 'Perform an advanced term query.' ),
'type' => 'object',
'properties' => array(
'terms' => array(
'description' => __( 'Term IDs.' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'default' => array(),
),
'include_children' => array(
'description' => __( 'Whether to include child terms in the terms limiting the result set.' ),
'type' => 'boolean',
'default' => false,
),
),
'additionalProperties' => false,
),
),
);
$include_schema = array_merge(
array(
/* translators: %s: Taxonomy name. */
'description' => __( 'Limit result set to items with specific terms assigned in the %s taxonomy.' ),
),
$limit_schema
);
$exclude_schema = array_merge(
array(
/* translators: %s: Taxonomy name. */
'description' => __( 'Limit result set to items except those with specific terms assigned in the %s taxonomy.' ),
),
$limit_schema
);
foreach ( $taxonomies as $taxonomy ) {
$base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
$base_exclude = $base . '_exclude';
$query_params[ $base ] = $include_schema;
$query_params[ $base ]['description'] = sprintf( $query_params[ $base ]['description'], $base );
$query_params[ $base_exclude ] = $exclude_schema;
$query_params[ $base_exclude ]['description'] = sprintf( $query_params[ $base_exclude ]['description'], $base );
if ( ! $taxonomy->hierarchical ) {
unset( $query_params[ $base ]['oneOf'][1]['properties']['include_children'] );
unset( $query_params[ $base_exclude ]['oneOf'][1]['properties']['include_children'] );
}
}
return $query_params;
}
}