Make WordPress Core

Ticket #39494: 39494.diff

File 39494.diff, 9.4 KB (added by dlh, 4 years 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 a0752c2534..8fdc9b766a 100644
    class WP_REST_Posts_Controller extends WP_REST_Controller { 
    269269                }
    270270
    271271                foreach ( $taxonomies as $taxonomy ) {
    272                         $base        = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
    273                         $tax_exclude = $base . '_exclude';
    274 
    275                         if ( ! empty( $request[ $base ] ) ) {
    276                                 $args['tax_query'][] = array(
    277                                         'taxonomy'         => $taxonomy->name,
    278                                         'field'            => 'term_id',
    279                                         'terms'            => $request[ $base ],
    280                                         'include_children' => false,
    281                                 );
     272                        $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
     273
     274                        $tax_include = $request[ $base ];
     275                        $tax_exclude = $request[ $base . '_exclude' ];
     276
     277                        if ( $tax_include ) {
     278                                $terms            = array();
     279                                $include_children = false;
     280
     281                                if ( rest_is_array( $tax_include ) ) {
     282                                        $terms = $tax_include;
     283                                } elseif ( rest_is_object( $tax_include ) ) {
     284                                        $terms            = empty( $tax_include['terms'] ) ? array() : $tax_include['terms'];
     285                                        $include_children = ! empty( $tax_include['include_children'] );
     286                                }
     287
     288                                if ( $terms ) {
     289                                        $args['tax_query'][] = array(
     290                                                'taxonomy'         => $taxonomy->name,
     291                                                'field'            => 'term_id',
     292                                                'terms'            => $terms,
     293                                                'include_children' => $include_children,
     294                                        );
     295                                }
    282296                        }
    283297
    284                         if ( ! empty( $request[ $tax_exclude ] ) ) {
    285                                 $args['tax_query'][] = array(
    286                                         'taxonomy'         => $taxonomy->name,
    287                                         'field'            => 'term_id',
    288                                         'terms'            => $request[ $tax_exclude ],
    289                                         'include_children' => false,
    290                                         'operator'         => 'NOT IN',
    291                                 );
     298                        if ( $tax_exclude ) {
     299                                $terms            = array();
     300                                $include_children = false;
     301
     302                                if ( rest_is_array( $tax_exclude ) ) {
     303                                        $terms = $tax_exclude;
     304                                } elseif ( rest_is_object( $tax_exclude ) ) {
     305                                        $terms            = empty( $tax_exclude['terms'] ) ? array() : $tax_exclude['terms'];
     306                                        $include_children = ! empty( $tax_exclude['include_children'] );
     307                                }
     308
     309                                if ( $terms ) {
     310                                        $args['tax_query'][] = array(
     311                                                'taxonomy'         => $taxonomy->name,
     312                                                'field'            => 'term_id',
     313                                                'terms'            => $terms,
     314                                                'include_children' => $include_children,
     315                                                'operator'         => 'NOT IN',
     316                                        );
     317                                }
    292318                        }
    293319                }
    294320
    class WP_REST_Posts_Controller extends WP_REST_Controller { 
    27832809                        $query_params[ $base ] = array(
    27842810                                /* translators: %s: Taxonomy name. */
    27852811                                'description' => sprintf( __( 'Limit result set to all items that have the specified term assigned in the %s taxonomy.' ), $base ),
    2786                                 'type'        => 'array',
    2787                                 'items'       => array(
    2788                                         'type' => 'integer',
     2812                                'type'        => array( 'object', 'array' ),
     2813                                'oneOf'       => array(
     2814                                        array(
     2815                                                'type'    => 'array',
     2816                                                'items'   => array(
     2817                                                        'type' => 'integer',
     2818                                                ),
     2819                                                'default' => array(),
     2820                                        ),
     2821                                        array(
     2822                                                'type'                 => 'object',
     2823                                                'properties'           => array(
     2824                                                        'terms'            => array(
     2825                                                                'type'    => 'array',
     2826                                                                'items'   => array(
     2827                                                                        'type' => 'integer',
     2828                                                                ),
     2829                                                                'default' => array(),
     2830                                                        ),
     2831                                                        'include_children' => array(
     2832                                                                'type'    => 'boolean',
     2833                                                                'default' => false,
     2834                                                        ),
     2835                                                ),
     2836                                                'additionalProperties' => false,
     2837                                        ),
    27892838                                ),
    2790                                 'default'     => array(),
    27912839                        );
    27922840
    27932841                        $query_params[ $base . '_exclude' ] = array(
    27942842                                /* translators: %s: Taxonomy name. */
    27952843                                'description' => sprintf( __( 'Limit result set to all items except those that have the specified term assigned in the %s taxonomy.' ), $base ),
    2796                                 'type'        => 'array',
    2797                                 'items'       => array(
    2798                                         'type' => 'integer',
     2844                                'type'        => array( 'object', 'array' ),
     2845                                'oneOf'       => array(
     2846                                        array(
     2847                                                'type'    => 'array',
     2848                                                'items'   => array(
     2849                                                        'type' => 'integer',
     2850                                                ),
     2851                                                'default' => array(),
     2852                                        ),
     2853                                        array(
     2854                                                'type'                 => 'object',
     2855                                                'properties'           => array(
     2856                                                        'terms'            => array(
     2857                                                                'type'    => 'array',
     2858                                                                'items'   => array(
     2859                                                                        'type' => 'integer',
     2860                                                                ),
     2861                                                                'default' => array(),
     2862                                                        ),
     2863                                                        'include_children' => array(
     2864                                                                'type'    => 'boolean',
     2865                                                                'default' => false,
     2866                                                        ),
     2867                                                ),
     2868                                                'additionalProperties' => false,
     2869                                        ),
    27992870                                ),
    2800                                 'default'     => array(),
    28012871                        );
    28022872                }
    28032873
  • 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 d07347f973..cea5ef7961 100644
    class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te 
    11131113                $this->assertSame( $id1, $data[2]['id'] );
    11141114        }
    11151115
     1116        /**
     1117         * @ticket 39494
     1118         */
     1119        public function test_get_items_with_category_including_children() {
     1120                $taxonomy = get_taxonomy( 'category' );
     1121
     1122                $cat1 = static::factory()->term->create( array( 'taxonomy' => $taxonomy->name ) );
     1123                $cat2 = static::factory()->term->create(
     1124                        array(
     1125                                'taxonomy' => $taxonomy->name,
     1126                                'parent'   => $cat1,
     1127                        )
     1128                );
     1129
     1130                $post_ids = array(
     1131                        static::factory()->post->create(
     1132                                array(
     1133                                        'post_status'   => 'publish',
     1134                                        'post_category' => array( $cat1 ),
     1135                                )
     1136                        ),
     1137                        static::factory()->post->create(
     1138                                array(
     1139                                        'post_status'   => 'publish',
     1140                                        'post_category' => array( $cat2 ),
     1141                                )
     1142                        ),
     1143                );
     1144
     1145                $request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
     1146                $request->set_param(
     1147                        $taxonomy->rest_base,
     1148                        array(
     1149                                'terms'            => array( $cat1 ),
     1150                                'include_children' => true,
     1151                        )
     1152                );
     1153                $response = rest_get_server()->dispatch( $request );
     1154                $data     = $response->get_data();
     1155
     1156                $this->assertSame( $post_ids, array_column( $data, 'id' ) );
     1157        }
     1158
     1159        /**
     1160         * @ticket 39494
     1161         */
     1162        public function test_get_items_with_category_excluding_children() {
     1163                $taxonomy = get_taxonomy( 'category' );
     1164
     1165                $cat1 = static::factory()->term->create( array( 'taxonomy' => $taxonomy->name ) );
     1166                $cat2 = static::factory()->term->create(
     1167                        array(
     1168                                'taxonomy' => $taxonomy->name,
     1169                                'parent'   => $cat1,
     1170                        )
     1171                );
     1172
     1173                $post_ids = array(
     1174                        static::factory()->post->create(
     1175                                array(
     1176                                        'post_status'   => 'publish',
     1177                                        'post_category' => array( $cat1 ),
     1178                                )
     1179                        ),
     1180                        static::factory()->post->create(
     1181                                array(
     1182                                        'post_status'   => 'publish',
     1183                                        'post_category' => array( $cat2 ),
     1184                                )
     1185                        ),
     1186                );
     1187
     1188                $request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
     1189                $request->set_param(
     1190                        $taxonomy->rest_base,
     1191                        array(
     1192                                'terms'            => array( $cat1 ),
     1193                                'include_children' => false,
     1194                        )
     1195                );
     1196                $response = rest_get_server()->dispatch( $request );
     1197                $data     = $response->get_data();
     1198
     1199                $this->assertCount( 1, $data );
     1200                $this->assertEquals( $post_ids[0], $data[0]['id'] );
     1201        }
     1202
     1203        /**
     1204         * @ticket 39494
     1205         */
     1206        public function test_get_items_without_category_or_its_children() {
     1207                $taxonomy = get_taxonomy( 'category' );
     1208
     1209                $cat1 = static::factory()->term->create( array( 'taxonomy' => $taxonomy->name ) );
     1210                $cat2 = static::factory()->term->create(
     1211                        array(
     1212                                'taxonomy' => $taxonomy->name,
     1213                                'parent'   => $cat1,
     1214                        )
     1215                );
     1216
     1217                $post_ids = array(
     1218                        static::factory()->post->create(
     1219                                array(
     1220                                        'post_status'   => 'publish',
     1221                                        'post_category' => array( $cat1 ),
     1222                                )
     1223                        ),
     1224                        static::factory()->post->create(
     1225                                array(
     1226                                        'post_status'   => 'publish',
     1227                                        'post_category' => array( $cat2 ),
     1228                                )
     1229                        ),
     1230                );
     1231
     1232                $request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
     1233                $request->set_param(
     1234                        $taxonomy->rest_base . '_exclude',
     1235                        array(
     1236                                'terms'            => array( $cat1 ),
     1237                                'include_children' => true,
     1238                        )
     1239                );
     1240                $response = rest_get_server()->dispatch( $request );
     1241                $data     = $response->get_data();
     1242
     1243                $this->assertEmpty(
     1244                        array_intersect(
     1245                                $post_ids,
     1246                                array_column( $data, 'id' )
     1247                        )
     1248                );
     1249        }
     1250
     1251        /**
     1252         * @ticket 39494
     1253         */
     1254        public function test_get_items_without_category_but_allowing_its_children() {
     1255                $taxonomy = get_taxonomy( 'category' );
     1256
     1257                $cat1 = static::factory()->term->create( array( 'taxonomy' => $taxonomy->name ) );
     1258                $cat2 = static::factory()->term->create(
     1259                        array(
     1260                                'taxonomy' => $taxonomy->name,
     1261                                'parent'   => $cat1,
     1262                        )
     1263                );
     1264
     1265                $p1 = static::factory()->post->create(
     1266                        array(
     1267                                'post_status'   => 'publish',
     1268                                'post_category' => array( $cat1 ),
     1269                        )
     1270                );
     1271                $p2 = static::factory()->post->create(
     1272                        array(
     1273                                'post_status'   => 'publish',
     1274                                'post_category' => array( $cat2 ),
     1275                        )
     1276                );
     1277
     1278                $request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
     1279                $request->set_param(
     1280                        $taxonomy->rest_base . '_exclude',
     1281                        array(
     1282                                'terms'            => array( $cat1 ),
     1283                                'include_children' => false,
     1284                        )
     1285                );
     1286                $response = rest_get_server()->dispatch( $request );
     1287                $data     = $response->get_data();
     1288
     1289                $found_ids = array_column( $data, 'id' );
     1290
     1291                $this->assertNotContains( $p1, $found_ids );
     1292                $this->assertContains( $p2, $found_ids );
     1293        }
     1294
    11161295        /**
    11171296         * @ticket 44326
    11181297         */