Changeset 50157
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
r50024 r50157 281 281 } 282 282 283 $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); 284 285 if ( ! empty( $request['tax_relation'] ) ) { 286 $args['tax_query'] = array( 'relation' => $request['tax_relation'] ); 287 } 288 289 foreach ( $taxonomies as $taxonomy ) { 290 $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; 291 $tax_exclude = $base . '_exclude'; 292 293 if ( ! empty( $request[ $base ] ) ) { 294 $args['tax_query'][] = array( 295 'taxonomy' => $taxonomy->name, 296 'field' => 'term_id', 297 'terms' => $request[ $base ], 298 'include_children' => false, 299 ); 300 } 301 302 if ( ! empty( $request[ $tax_exclude ] ) ) { 303 $args['tax_query'][] = array( 304 'taxonomy' => $taxonomy->name, 305 'field' => 'term_id', 306 'terms' => $request[ $tax_exclude ], 307 'include_children' => false, 308 'operator' => 'NOT IN', 309 ); 310 } 311 } 283 $args = $this->prepare_tax_query( $args, $request ); 312 284 313 285 // Force the post_type argument, since it's not a user input variable. … … 2800 2772 ); 2801 2773 2802 $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); 2803 2804 if ( ! empty( $taxonomies ) ) { 2805 $query_params['tax_relation'] = array( 2806 'description' => __( 'Limit result set based on relationship between multiple taxonomies.' ), 2807 'type' => 'string', 2808 'enum' => array( 'AND', 'OR' ), 2809 ); 2810 } 2811 2812 foreach ( $taxonomies as $taxonomy ) { 2813 $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; 2814 2815 $query_params[ $base ] = array( 2816 /* translators: %s: Taxonomy name. */ 2817 'description' => sprintf( __( 'Limit result set to all items that have the specified term assigned in the %s taxonomy.' ), $base ), 2818 'type' => 'array', 2819 'items' => array( 2820 'type' => 'integer', 2821 ), 2822 'default' => array(), 2823 ); 2824 2825 $query_params[ $base . '_exclude' ] = array( 2826 /* translators: %s: Taxonomy name. */ 2827 'description' => sprintf( __( 'Limit result set to all items except those that have the specified term assigned in the %s taxonomy.' ), $base ), 2828 'type' => 'array', 2829 'items' => array( 2830 'type' => 'integer', 2831 ), 2832 'default' => array(), 2833 ); 2834 } 2774 $query_params = $this->prepare_taxonomy_limit_schema( $query_params ); 2835 2775 2836 2776 if ( 'post' === $this->post_type ) { … … 2900 2840 return $statuses; 2901 2841 } 2842 2843 /** 2844 * Prepares the 'tax_query' for a collection of posts. 2845 * 2846 * @since 5.7.0 2847 * 2848 * @param array $args WP_Query arguments. 2849 * @param WP_REST_Request $request Full details about the request. 2850 * @return array Updated query arguments. 2851 */ 2852 private function prepare_tax_query( array $args, WP_REST_Request $request ) { 2853 $relation = $request['tax_relation']; 2854 2855 if ( $relation ) { 2856 $args['tax_query'] = array( 'relation' => $relation ); 2857 } 2858 2859 $taxonomies = wp_list_filter( 2860 get_object_taxonomies( $this->post_type, 'objects' ), 2861 array( 'show_in_rest' => true ) 2862 ); 2863 2864 foreach ( $taxonomies as $taxonomy ) { 2865 $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; 2866 2867 $tax_include = $request[ $base ]; 2868 $tax_exclude = $request[ $base . '_exclude' ]; 2869 2870 if ( $tax_include ) { 2871 $terms = array(); 2872 $include_children = false; 2873 2874 if ( rest_is_array( $tax_include ) ) { 2875 $terms = $tax_include; 2876 } elseif ( rest_is_object( $tax_include ) ) { 2877 $terms = empty( $tax_include['terms'] ) ? array() : $tax_include['terms']; 2878 $include_children = ! empty( $tax_include['include_children'] ); 2879 } 2880 2881 if ( $terms ) { 2882 $args['tax_query'][] = array( 2883 'taxonomy' => $taxonomy->name, 2884 'field' => 'term_id', 2885 'terms' => $terms, 2886 'include_children' => $include_children, 2887 ); 2888 } 2889 } 2890 2891 if ( $tax_exclude ) { 2892 $terms = array(); 2893 $include_children = false; 2894 2895 if ( rest_is_array( $tax_exclude ) ) { 2896 $terms = $tax_exclude; 2897 } elseif ( rest_is_object( $tax_exclude ) ) { 2898 $terms = empty( $tax_exclude['terms'] ) ? array() : $tax_exclude['terms']; 2899 $include_children = ! empty( $tax_exclude['include_children'] ); 2900 } 2901 2902 if ( $terms ) { 2903 $args['tax_query'][] = array( 2904 'taxonomy' => $taxonomy->name, 2905 'field' => 'term_id', 2906 'terms' => $terms, 2907 'include_children' => $include_children, 2908 'operator' => 'NOT IN', 2909 ); 2910 } 2911 } 2912 } 2913 2914 return $args; 2915 } 2916 2917 /** 2918 * Prepares the collection schema for including and excluding items by terms. 2919 * 2920 * @since 5.7.0 2921 * 2922 * @param array $query_params Collection schema. 2923 * @return array Updated schema. 2924 */ 2925 private function prepare_taxonomy_limit_schema( array $query_params ) { 2926 $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); 2927 2928 if ( ! $taxonomies ) { 2929 return $query_params; 2930 } 2931 2932 $query_params['tax_relation'] = array( 2933 'description' => __( 'Limit result set based on relationship between multiple taxonomies.' ), 2934 'type' => 'string', 2935 'enum' => array( 'AND', 'OR' ), 2936 ); 2937 2938 $limit_schema = array( 2939 'type' => array( 'object', 'array' ), 2940 'oneOf' => array( 2941 array( 2942 'title' => __( 'Term ID List' ), 2943 'description' => __( 'Match terms with the listed IDs.' ), 2944 'type' => 'array', 2945 'items' => array( 2946 'type' => 'integer', 2947 ), 2948 ), 2949 array( 2950 'title' => __( 'Term ID Taxonomy Query' ), 2951 'description' => __( 'Perform an advanced term query.' ), 2952 'type' => 'object', 2953 'properties' => array( 2954 'terms' => array( 2955 'description' => __( 'Term IDs.' ), 2956 'type' => 'array', 2957 'items' => array( 2958 'type' => 'integer', 2959 ), 2960 'default' => array(), 2961 ), 2962 'include_children' => array( 2963 'description' => __( 'Whether to include child terms in the terms limiting the result set.' ), 2964 'type' => 'boolean', 2965 'default' => false, 2966 ), 2967 ), 2968 'additionalProperties' => false, 2969 ), 2970 ), 2971 ); 2972 2973 $include_schema = array_merge( 2974 array( 2975 /* translators: %s: Taxonomy name. */ 2976 'description' => __( 'Limit result set to items with specific terms assigned in the %s taxonomy.' ), 2977 ), 2978 $limit_schema 2979 ); 2980 $exclude_schema = array_merge( 2981 array( 2982 /* translators: %s: Taxonomy name. */ 2983 'description' => __( 'Limit result set to items except those with specific terms assigned in the %s taxonomy.' ), 2984 ), 2985 $limit_schema 2986 ); 2987 2988 foreach ( $taxonomies as $taxonomy ) { 2989 $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; 2990 $base_exclude = $base . '_exclude'; 2991 2992 $query_params[ $base ] = $include_schema; 2993 $query_params[ $base ]['description'] = sprintf( $query_params[ $base ]['description'], $base ); 2994 2995 $query_params[ $base_exclude ] = $exclude_schema; 2996 $query_params[ $base_exclude ]['description'] = sprintf( $query_params[ $base_exclude ]['description'], $base ); 2997 2998 if ( ! $taxonomy->hierarchical ) { 2999 unset( $query_params[ $base ]['oneOf'][1]['properties']['include_children'] ); 3000 unset( $query_params[ $base_exclude ]['oneOf'][1]['properties']['include_children'] ); 3001 } 3002 } 3003 3004 return $query_params; 3005 } 2902 3006 } -
trunk/tests/phpunit/tests/rest-api/rest-posts-controller.php
r50024 r50157 1114 1114 $this->assertSame( $id2, $data[1]['id'] ); 1115 1115 $this->assertSame( $id1, $data[2]['id'] ); 1116 } 1117 1118 /** 1119 * @ticket 39494 1120 */ 1121 public function test_get_items_with_category_including_children() { 1122 $taxonomy = get_taxonomy( 'category' ); 1123 1124 $cat1 = static::factory()->term->create( array( 'taxonomy' => $taxonomy->name ) ); 1125 $cat2 = static::factory()->term->create( 1126 array( 1127 'taxonomy' => $taxonomy->name, 1128 'parent' => $cat1, 1129 ) 1130 ); 1131 1132 $post_ids = array( 1133 static::factory()->post->create( 1134 array( 1135 'post_status' => 'publish', 1136 'post_category' => array( $cat1 ), 1137 ) 1138 ), 1139 static::factory()->post->create( 1140 array( 1141 'post_status' => 'publish', 1142 'post_category' => array( $cat2 ), 1143 ) 1144 ), 1145 ); 1146 1147 $request = new WP_REST_Request( 'GET', '/wp/v2/posts' ); 1148 $request->set_param( 1149 $taxonomy->rest_base, 1150 array( 1151 'terms' => array( $cat1 ), 1152 'include_children' => true, 1153 ) 1154 ); 1155 $response = rest_get_server()->dispatch( $request ); 1156 $data = $response->get_data(); 1157 1158 $this->assertEqualSets( $post_ids, array_column( $data, 'id' ) ); 1159 } 1160 1161 /** 1162 * @ticket 39494 1163 */ 1164 public function test_get_items_with_category_excluding_children() { 1165 $taxonomy = get_taxonomy( 'category' ); 1166 1167 $cat1 = static::factory()->term->create( array( 'taxonomy' => $taxonomy->name ) ); 1168 $cat2 = static::factory()->term->create( 1169 array( 1170 'taxonomy' => $taxonomy->name, 1171 'parent' => $cat1, 1172 ) 1173 ); 1174 1175 $post_ids = array( 1176 static::factory()->post->create( 1177 array( 1178 'post_status' => 'publish', 1179 'post_category' => array( $cat1 ), 1180 ) 1181 ), 1182 static::factory()->post->create( 1183 array( 1184 'post_status' => 'publish', 1185 'post_category' => array( $cat2 ), 1186 ) 1187 ), 1188 ); 1189 1190 $request = new WP_REST_Request( 'GET', '/wp/v2/posts' ); 1191 $request->set_param( 1192 $taxonomy->rest_base, 1193 array( 1194 'terms' => array( $cat1 ), 1195 'include_children' => false, 1196 ) 1197 ); 1198 $response = rest_get_server()->dispatch( $request ); 1199 $data = $response->get_data(); 1200 1201 $this->assertCount( 1, $data ); 1202 $this->assertEquals( $post_ids[0], $data[0]['id'] ); 1203 } 1204 1205 /** 1206 * @ticket 39494 1207 */ 1208 public function test_get_items_without_category_or_its_children() { 1209 $taxonomy = get_taxonomy( 'category' ); 1210 1211 $cat1 = static::factory()->term->create( array( 'taxonomy' => $taxonomy->name ) ); 1212 $cat2 = static::factory()->term->create( 1213 array( 1214 'taxonomy' => $taxonomy->name, 1215 'parent' => $cat1, 1216 ) 1217 ); 1218 1219 $post_ids = array( 1220 static::factory()->post->create( 1221 array( 1222 'post_status' => 'publish', 1223 'post_category' => array( $cat1 ), 1224 ) 1225 ), 1226 static::factory()->post->create( 1227 array( 1228 'post_status' => 'publish', 1229 'post_category' => array( $cat2 ), 1230 ) 1231 ), 1232 ); 1233 1234 $request = new WP_REST_Request( 'GET', '/wp/v2/posts' ); 1235 $request->set_param( 1236 $taxonomy->rest_base . '_exclude', 1237 array( 1238 'terms' => array( $cat1 ), 1239 'include_children' => true, 1240 ) 1241 ); 1242 $response = rest_get_server()->dispatch( $request ); 1243 $data = $response->get_data(); 1244 1245 $this->assertEmpty( 1246 array_intersect( 1247 $post_ids, 1248 array_column( $data, 'id' ) 1249 ) 1250 ); 1251 } 1252 1253 /** 1254 * @ticket 39494 1255 */ 1256 public function test_get_items_without_category_but_allowing_its_children() { 1257 $taxonomy = get_taxonomy( 'category' ); 1258 1259 $cat1 = static::factory()->term->create( array( 'taxonomy' => $taxonomy->name ) ); 1260 $cat2 = static::factory()->term->create( 1261 array( 1262 'taxonomy' => $taxonomy->name, 1263 'parent' => $cat1, 1264 ) 1265 ); 1266 1267 $p1 = static::factory()->post->create( 1268 array( 1269 'post_status' => 'publish', 1270 'post_category' => array( $cat1 ), 1271 ) 1272 ); 1273 $p2 = static::factory()->post->create( 1274 array( 1275 'post_status' => 'publish', 1276 'post_category' => array( $cat2 ), 1277 ) 1278 ); 1279 1280 $request = new WP_REST_Request( 'GET', '/wp/v2/posts' ); 1281 $request->set_param( 1282 $taxonomy->rest_base . '_exclude', 1283 array( 1284 'terms' => array( $cat1 ), 1285 'include_children' => false, 1286 ) 1287 ); 1288 $response = rest_get_server()->dispatch( $request ); 1289 $data = $response->get_data(); 1290 1291 $found_ids = array_column( $data, 'id' ); 1292 1293 $this->assertNotContains( $p1, $found_ids ); 1294 $this->assertContains( $p2, $found_ids ); 1116 1295 } 1117 1296 -
trunk/tests/qunit/fixtures/wp-api-generated.js
r50072 r50157 428 428 }, 429 429 "categories": { 430 "description": "Limit result set to all items that have the specified term assigned in the categories taxonomy.", 431 "type": "array", 432 "items": { 433 "type": "integer" 434 }, 435 "default": [], 430 "description": "Limit result set to items with specific terms assigned in the categories taxonomy.", 431 "type": [ 432 "object", 433 "array" 434 ], 435 "oneOf": [ 436 { 437 "title": "Term ID List", 438 "description": "Match terms with the listed IDs.", 439 "type": "array", 440 "items": { 441 "type": "integer" 442 } 443 }, 444 { 445 "title": "Term ID Taxonomy Query", 446 "description": "Perform an advanced term query.", 447 "type": "object", 448 "properties": { 449 "terms": { 450 "description": "Term IDs.", 451 "type": "array", 452 "items": { 453 "type": "integer" 454 }, 455 "default": [] 456 }, 457 "include_children": { 458 "description": "Whether to include child terms in the terms limiting the result set.", 459 "type": "boolean", 460 "default": false 461 } 462 }, 463 "additionalProperties": false 464 } 465 ], 436 466 "required": false 437 467 }, 438 468 "categories_exclude": { 439 "description": "Limit result set to all items except those that have the specified term assigned in the categories taxonomy.", 440 "type": "array", 441 "items": { 442 "type": "integer" 443 }, 444 "default": [], 469 "description": "Limit result set to items except those with specific terms assigned in the categories taxonomy.", 470 "type": [ 471 "object", 472 "array" 473 ], 474 "oneOf": [ 475 { 476 "title": "Term ID List", 477 "description": "Match terms with the listed IDs.", 478 "type": "array", 479 "items": { 480 "type": "integer" 481 } 482 }, 483 { 484 "title": "Term ID Taxonomy Query", 485 "description": "Perform an advanced term query.", 486 "type": "object", 487 "properties": { 488 "terms": { 489 "description": "Term IDs.", 490 "type": "array", 491 "items": { 492 "type": "integer" 493 }, 494 "default": [] 495 }, 496 "include_children": { 497 "description": "Whether to include child terms in the terms limiting the result set.", 498 "type": "boolean", 499 "default": false 500 } 501 }, 502 "additionalProperties": false 503 } 504 ], 445 505 "required": false 446 506 }, 447 507 "tags": { 448 "description": "Limit result set to all items that have the specified term assigned in the tags taxonomy.", 449 "type": "array", 450 "items": { 451 "type": "integer" 452 }, 453 "default": [], 508 "description": "Limit result set to items with specific terms assigned in the tags taxonomy.", 509 "type": [ 510 "object", 511 "array" 512 ], 513 "oneOf": [ 514 { 515 "title": "Term ID List", 516 "description": "Match terms with the listed IDs.", 517 "type": "array", 518 "items": { 519 "type": "integer" 520 } 521 }, 522 { 523 "title": "Term ID Taxonomy Query", 524 "description": "Perform an advanced term query.", 525 "type": "object", 526 "properties": { 527 "terms": { 528 "description": "Term IDs.", 529 "type": "array", 530 "items": { 531 "type": "integer" 532 }, 533 "default": [] 534 } 535 }, 536 "additionalProperties": false 537 } 538 ], 454 539 "required": false 455 540 }, 456 541 "tags_exclude": { 457 "description": "Limit result set to all items except those that have the specified term assigned in the tags taxonomy.", 458 "type": "array", 459 "items": { 460 "type": "integer" 461 }, 462 "default": [], 542 "description": "Limit result set to items except those with specific terms assigned in the tags taxonomy.", 543 "type": [ 544 "object", 545 "array" 546 ], 547 "oneOf": [ 548 { 549 "title": "Term ID List", 550 "description": "Match terms with the listed IDs.", 551 "type": "array", 552 "items": { 553 "type": "integer" 554 } 555 }, 556 { 557 "title": "Term ID Taxonomy Query", 558 "description": "Perform an advanced term query.", 559 "type": "object", 560 "properties": { 561 "terms": { 562 "description": "Term IDs.", 563 "type": "array", 564 "items": { 565 "type": "integer" 566 }, 567 "default": [] 568 } 569 }, 570 "additionalProperties": false 571 } 572 ], 463 573 "required": false 464 574 }, … … 3129 3239 ], 3130 3240 "args": { 3241 "src": { 3242 "description": "URL to the edited image file.", 3243 "type": "string", 3244 "format": "uri", 3245 "required": true 3246 }, 3247 "modifiers": { 3248 "description": "Array of image edits.", 3249 "type": "array", 3250 "minItems": 1, 3251 "items": { 3252 "description": "Image edit.", 3253 "type": "object", 3254 "required": [ 3255 "type", 3256 "args" 3257 ], 3258 "oneOf": [ 3259 { 3260 "title": "Rotation", 3261 "properties": { 3262 "type": { 3263 "description": "Rotation type.", 3264 "type": "string", 3265 "enum": [ 3266 "rotate" 3267 ] 3268 }, 3269 "args": { 3270 "description": "Rotation arguments.", 3271 "type": "object", 3272 "required": [ 3273 "angle" 3274 ], 3275 "properties": { 3276 "angle": { 3277 "description": "Angle to rotate clockwise in degrees.", 3278 "type": "number" 3279 } 3280 } 3281 } 3282 } 3283 }, 3284 { 3285 "title": "Crop", 3286 "properties": { 3287 "type": { 3288 "description": "Crop type.", 3289 "type": "string", 3290 "enum": [ 3291 "crop" 3292 ] 3293 }, 3294 "args": { 3295 "description": "Crop arguments.", 3296 "type": "object", 3297 "required": [ 3298 "left", 3299 "top", 3300 "width", 3301 "height" 3302 ], 3303 "properties": { 3304 "left": { 3305 "description": "Horizontal position from the left to begin the crop as a percentage of the image width.", 3306 "type": "number" 3307 }, 3308 "top": { 3309 "description": "Vertical position from the top to begin the crop as a percentage of the image height.", 3310 "type": "number" 3311 }, 3312 "width": { 3313 "description": "Width of the crop as a percentage of the image width.", 3314 "type": "number" 3315 }, 3316 "height": { 3317 "description": "Height of the crop as a percentage of the image height.", 3318 "type": "number" 3319 } 3320 } 3321 } 3322 } 3323 } 3324 ] 3325 }, 3326 "required": false 3327 }, 3131 3328 "rotation": { 3132 "description": "The amount to rotate the image clockwise in degrees. ",3329 "description": "The amount to rotate the image clockwise in degrees. DEPRECATED: Use `modifiers` instead.", 3133 3330 "type": "integer", 3134 3331 "minimum": 0, … … 3139 3336 }, 3140 3337 "x": { 3141 "description": "As a percentage of the image, the x position to start the crop from. ",3338 "description": "As a percentage of the image, the x position to start the crop from. DEPRECATED: Use `modifiers` instead.", 3142 3339 "type": "number", 3143 3340 "minimum": 0, … … 3146 3343 }, 3147 3344 "y": { 3148 "description": "As a percentage of the image, the y position to start the crop from. ",3345 "description": "As a percentage of the image, the y position to start the crop from. DEPRECATED: Use `modifiers` instead.", 3149 3346 "type": "number", 3150 3347 "minimum": 0, … … 3153 3350 }, 3154 3351 "width": { 3155 "description": "As a percentage of the image, the width to crop the image to. ",3352 "description": "As a percentage of the image, the width to crop the image to. DEPRECATED: Use `modifiers` instead.", 3156 3353 "type": "number", 3157 3354 "minimum": 0, … … 3160 3357 }, 3161 3358 "height": { 3162 "description": "As a percentage of the image, the height to crop the image to. ",3359 "description": "As a percentage of the image, the height to crop the image to. DEPRECATED: Use `modifiers` instead.", 3163 3360 "type": "number", 3164 3361 "minimum": 0, 3165 3362 "maximum": 100, 3166 3363 "required": false 3167 },3168 "src": {3169 "description": "URL to the edited image file.",3170 "type": "string",3171 "format": "uri",3172 "required": true3173 3364 } 3174 3365 }
Note: See TracChangeset
for help on using the changeset viewer.