WordPress.org

Make WordPress Core

Ticket #41287: 41287.diff

File 41287.diff, 11.2 KB (added by earnjam, 18 months ago)
  • src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php

    diff --git src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
    index b7b2dd79f6..1a322849cf 100644
    class WP_REST_Posts_Controller extends WP_REST_Controller { 
    267267
    268268                $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) );
    269269
     270                if ( ! empty( $request['relation'] ) ) {
     271                        $query_args['tax_query'] = array( 'relation' => $request['relation'] );
     272                }
     273
    270274                foreach ( $taxonomies as $taxonomy ) {
    271275                        $base        = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
    272276                        $tax_exclude = $base . '_exclude';
     277                        $tax_and     = $base . '_and';
    273278
    274279                        if ( ! empty( $request[ $base ] ) ) {
    275280                                $query_args['tax_query'][] = array(
    class WP_REST_Posts_Controller extends WP_REST_Controller { 
    289294                                        'operator'         => 'NOT IN',
    290295                                );
    291296                        }
     297
     298                        if ( ! empty( $request[ $tax_and ] ) ) {
     299                                $query_args['tax_query'][] = array(
     300                                        'taxonomy'         => $taxonomy->name,
     301                                        'field'            => 'term_id',
     302                                        'terms'            => $request[ $tax_and ],
     303                                        'include_children' => false,
     304                                        'operator'         => 'AND',
     305                                );
     306                        }
    292307                }
    293308
    294309                $posts_query  = new WP_Query();
    class WP_REST_Posts_Controller extends WP_REST_Controller { 
    22172232
    22182233                $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) );
    22192234
     2235                if ( ! empty( $taxonomies ) ) {
     2236                        $query_params['relation'] = array(
     2237                                'description' => __( 'Limit result set based on relationship between multiple taxonomies.' ),
     2238                                'type'        => 'string',
     2239                                'enum'        => array( 'AND', 'OR' ),
     2240                        );
     2241                }
     2242
    22202243                foreach ( $taxonomies as $taxonomy ) {
    22212244                        $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
    22222245
    class WP_REST_Posts_Controller extends WP_REST_Controller { 
    22392262                                ),
    22402263                                'default'     => array(),
    22412264                        );
     2265
     2266                        $query_params[ $base . '_and' ] = array(
     2267                                /* translators: %s: taxonomy name */
     2268                                'description' => sprintf( __( 'Limit result set to all items that have all the specified terms assigned in the %s taxonomy.' ), $base ),
     2269                                'type'        => 'array',
     2270                                'items'       => array(
     2271                                        'type' => 'integer',
     2272                                ),
     2273                                'default'     => array(),
     2274                        );
    22422275                }
    22432276
    22442277                if ( 'post' === $this->post_type ) {
  • tests/phpunit/tests/rest-api/rest-posts-controller.php

    diff --git tests/phpunit/tests/rest-api/rest-posts-controller.php tests/phpunit/tests/rest-api/rest-posts-controller.php
    index 721b08292a..1d0fac01c5 100644
    class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te 
    146146                                'author_exclude',
    147147                                'before',
    148148                                'categories',
     149                                'categories_and',
    149150                                'categories_exclude',
    150151                                'context',
    151152                                'exclude',
    class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te 
    155156                                'orderby',
    156157                                'page',
    157158                                'per_page',
     159                                'relation',
    158160                                'search',
    159161                                'slug',
    160162                                'status',
    161163                                'sticky',
    162164                                'tags',
     165                                'tags_and',
    163166                                'tags_exclude',
    164167                        ), $keys
    165168                );
    class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te 
    865868                $this->assertEquals( $id1, $data[0]['id'] );
    866869        }
    867870
     871        public function test_get_items_tags_and_query() {
     872                $id1 = self::$post_id;
     873                $id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     874                $id3 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     875                $tag1 = wp_insert_term( 'Tag1', 'post_tag' );
     876                $tag2 = wp_insert_term( 'Tag2', 'post_tag' );
     877
     878                wp_set_object_terms( $id1, array( $tag1['term_id'] ), 'post_tag' );
     879                wp_set_object_terms( $id2, array( $tag2['term_id'] ), 'post_tag' );
     880                wp_set_object_terms( $id3, array( $tag1['term_id'], $tag2['term_id'] ), 'post_tag' );
     881                $request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
     882                $request->set_param( 'tags_and', array( $tag1['term_id'], $tag2['term_id'] ) );
     883
     884                $response = rest_get_server()->dispatch( $request );
     885                $data     = $response->get_data();
     886                $this->assertCount( 1, $data );
     887                $this->assertEquals( $id3, $data[0]['id'] );
     888        }
     889
    868890        public function test_get_items_tags_exclude_query() {
    869891                $id1 = self::$post_id;
    870892                $id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
    class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te 
    908930                $this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
    909931        }
    910932
     933        public function test_get_items_tags_or_categories_query() {
     934                $id1      = self::$post_id;
     935                $id2      = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     936                $id3      = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     937                $id4      = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     938                $tag      = wp_insert_term( 'My Tag', 'post_tag' );
     939                $category = wp_insert_term( 'My Category', 'category' );
     940
     941                wp_set_object_terms( $id1, array( $tag['term_id'] ), 'post_tag' );
     942                wp_set_object_terms( $id2, array( $category['term_id'] ), 'category' );
     943
     944                $request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
     945                $request->set_param( 'relation', 'OR' );
     946                $request->set_param( 'tags', array( $tag['term_id'] ) );
     947                $request->set_param( 'categories', array( $category['term_id'] ) );
     948
     949                $response = rest_get_server()->dispatch( $request );
     950                $data     = $response->get_data();
     951                $this->assertCount( 2, $data );
     952                $this->assertEquals( $id2, $data[0]['id'] );
     953                $this->assertEquals( $id1, $data[1]['id'] );
     954        }
     955
    911956        public function test_get_items_tags_and_categories_exclude_query() {
    912957                $id1      = self::$post_id;
    913958                $id2      = $this->factory->post->create( array( 'post_status' => 'publish' ) );
    class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te 
    934979                $this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
    935980        }
    936981
     982        public function test_get_items_tags_or_categories_exclude_query() {
     983                $id1      = self::$post_id;
     984                $id2      = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     985                $id3      = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     986                $id4      = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     987                $tag      = wp_insert_term( 'My Tag', 'post_tag' );
     988                $category = wp_insert_term( 'My Category', 'category' );
     989
     990                wp_set_object_terms( $id1, array( $tag['term_id'] ), 'post_tag' );
     991                wp_set_object_terms( $id2, array( $tag['term_id'] ), 'post_tag' );
     992                wp_set_object_terms( $id2, array( $category['term_id'] ), 'category' );
     993                wp_set_object_terms( $id3, array( $category['term_id'] ), 'category' );
     994
     995                $request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
     996                $request->set_param( 'tags', array( $tag['term_id'] ) );
     997                $request->set_param( 'categories_exclude', array( $category['term_id'] ) );
     998                $request->set_param( 'relation', 'OR' );
     999
     1000                $response = rest_get_server()->dispatch( $request );
     1001                $data     = $response->get_data();
     1002                $this->assertCount( 3, $data );
     1003                $this->assertEquals( $id2, $data[0]['id'] );
     1004                $this->assertEquals( $id4, $data[1]['id'] );
     1005                $this->assertEquals( $id1, $data[2]['id'] );
     1006        }
     1007
     1008        public function test_get_items_tags_and_and_categories_query() {
     1009                $id1      = self::$post_id;
     1010                $id2      = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     1011                $id3      = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     1012                $id4      = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     1013                $tag1     = wp_insert_term( 'Tag1', 'post_tag' );
     1014                $tag2     = wp_insert_term( 'Tag2', 'post_tag' );
     1015                $category = wp_insert_term( 'My Category', 'category' );
     1016
     1017                wp_set_object_terms( $id1, array( $tag1['term_id'], $tag2['term_id'] ), 'post_tag' );
     1018                wp_set_object_terms( $id1, array( $category['term_id'] ), 'category' );
     1019                wp_set_object_terms( $id2, array( $tag1['term_id'] ), 'post_tag' );
     1020                wp_set_object_terms( $id2, array( $category['term_id'] ), 'category' );
     1021                wp_set_object_terms( $id3, array( $category['term_id'] ), 'category' );
     1022
     1023                $request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
     1024                $request->set_param( 'tags_and', array( $tag1['term_id'], $tag2['term_id'] ) );
     1025                $request->set_param( 'categories', array( $category['term_id'] ) );
     1026
     1027                $response = rest_get_server()->dispatch( $request );
     1028                $data     = $response->get_data();
     1029                $this->assertCount( 1, $data );
     1030                $this->assertEquals( $id1, $data[0]['id'] );
     1031        }
     1032
    9371033        public function test_get_items_sticky() {
    9381034                $id1 = self::$post_id;
    9391035                $id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
  • tests/qunit/fixtures/wp-api-generated.js

    diff --git tests/qunit/fixtures/wp-api-generated.js tests/qunit/fixtures/wp-api-generated.js
    index fd20726c9d..0da906e4c8 100644
    mockedApiResponse.Schema = { 
    322322                                "type": "string"
    323323                            }
    324324                        },
     325                        "relation": {
     326                            "required": false,
     327                            "enum": [
     328                                "AND",
     329                                "OR"
     330                            ],
     331                            "description": "Limit result set based on relationship between multiple taxonomies.",
     332                            "type": "string"
     333                        },
    325334                        "categories": {
    326335                            "required": false,
    327336                            "default": [],
    mockedApiResponse.Schema = { 
    340349                                "type": "integer"
    341350                            }
    342351                        },
     352                        "categories_and": {
     353                            "required": false,
     354                            "default": [],
     355                            "description": "Limit result set to all items that have all the specified terms assigned in the categories taxonomy.",
     356                            "type": "array",
     357                            "items": {
     358                                "type": "integer"
     359                            }
     360                        },
    343361                        "tags": {
    344362                            "required": false,
    345363                            "default": [],
    mockedApiResponse.Schema = { 
    358376                                "type": "integer"
    359377                            }
    360378                        },
     379                        "tags_and": {
     380                            "required": false,
     381                            "default": [],
     382                            "description": "Limit result set to all items that have all the specified terms assigned in the tags taxonomy.",
     383                            "type": "array",
     384                            "items": {
     385                                "type": "integer"
     386                            }
     387                        },
    361388                        "sticky": {
    362389                            "required": false,
    363390                            "description": "Limit result set to items that are sticky.",