Ticket #38131: 38131.3.diff
File 38131.3.diff, 15.8 KB (added by , 7 years ago) |
---|
-
src/wp-includes/rest-api/endpoints/class-wp-rest-controller.php
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-controller.php index e04193a..b6a3746 100644
a b abstract class WP_REST_Controller { 255 255 } 256 256 257 257 /** 258 * Filters a response based on the fields requested. 259 * 260 * @since 4.9.0 261 * 262 * @param array $data Response data to filter. 263 * @param array $fields Fields to include. Can specify nested objects using array dot notation. 264 * 265 * @return array 266 */ 267 public function filter_response_by_fields( $data, $fields ) { 268 269 if ( empty( $fields ) ) { 270 return $data; 271 } 272 273 $flipped = array_flip( $fields ); 274 $filtered = array(); 275 276 foreach ( $data as $key => $value ) { 277 $key_requested = isset( $flipped[ $key ] ); 278 279 if ( is_array( $value ) ) { 280 $nested_fields = $this->_get_nested_fields( $fields, $key ); 281 282 if ( $nested_fields ) { 283 $filtered[ $key ] = $this->filter_response_by_fields( $value, $nested_fields ); 284 } elseif ( $key_requested ) { 285 $filtered[ $key ] = $value; 286 } 287 } elseif ( $key_requested ) { 288 $filtered[ $key ] = $value; 289 } 290 } 291 292 return $filtered; 293 } 294 295 /** 296 * Filter the fields list to only include fields that are an array dot child of a given $key. 297 * 298 * @param array $fields All fields. 299 * @param string $key The key to look for. 300 * 301 * @return array The filtered list of fields. 302 */ 303 private function _get_nested_fields( $fields, $key ) { 304 305 $nested = array(); 306 307 foreach ( $fields as $field ) { 308 $sub = substr( $field, 0,strlen( $key ) + 1 ); 309 310 if ( $sub === $key . '.' ) { 311 $nested[] = substr( $field, strlen( $key ) + 1 ); 312 } 313 } 314 315 return $nested; 316 } 317 318 /** 258 319 * Retrieves the item's schema, conforming to JSON Schema. 259 320 * 260 321 * @since 4.7.0 … … abstract class WP_REST_Controller { 360 421 } 361 422 362 423 /** 424 * Retrieves the fields param. 425 * 426 * @since 4.9.0 427 * 428 * @param array $args 429 * 430 * @return array 431 */ 432 public function get_fields_param( $args = array() ) { 433 434 $param_details = array( 435 'description' => __( 'Limit the fields to include in the response.' ), 436 'type' => 'string', 437 'sanitize_callback' => 'sanitize_key', 438 'validate_callback' => 'rest_validate_request_arg', 439 ); 440 441 $fields = $this->get_all_field_keys( $this->get_item_schema() ); 442 443 if ( $fields ) { 444 $param_details['enum'] = $fields; 445 } 446 447 return array_merge( $param_details, $args ); 448 } 449 450 /** 451 * Recursively retrieve all the keys for fields in array dot notation. 452 * 453 * @param array $schema 454 * @param string $parent_field 455 * 456 * @return array 457 */ 458 private function get_all_field_keys( $schema, $parent_field = '' ) { 459 460 $fields = array(); 461 462 if ( $parent_field ) { 463 $fields[] = $parent_field; 464 } 465 466 $type = (array) $schema['type']; 467 468 if ( ! in_array( 'object', $type, true ) || empty( $schema['properties'] ) ) { 469 return $fields; 470 } 471 472 foreach ( $schema['properties'] as $property => $prop_schema ) { 473 $prop_field = $parent_field ? "{$parent_field}.{$property}" : $property; 474 $fields = array_merge( $fields, $this->get_all_field_keys( $prop_schema, $prop_field ) ); 475 } 476 477 return $fields; 478 } 479 480 /** 363 481 * Adds the values from additional fields to a data object. 364 482 * 365 483 * @since 4.7.0 -
src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php index f9de736..d68ffa6 100644
a b class WP_REST_Posts_Controller extends WP_REST_Controller { 1531 1531 $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; 1532 1532 $data = $this->add_additional_fields_to_object( $data, $request ); 1533 1533 $data = $this->filter_response_by_context( $data, $context ); 1534 $data = $this->filter_response_by_fields( $data, $request['_fields'] ); 1534 1535 1535 1536 // Wrap the data in a response object. 1536 1537 $response = rest_ensure_response( $data ); … … class WP_REST_Posts_Controller extends WP_REST_Controller { 2023 2024 $query_params = parent::get_collection_params(); 2024 2025 2025 2026 $query_params['context']['default'] = 'view'; 2027 $query_params['_fields'] = $this->get_fields_param(); 2026 2028 2027 2029 $query_params['after'] = array( 2028 2030 'description' => __( 'Limit response to posts published after a given ISO8601 compliant date.' ), -
src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php index 0723022..7ef7f42 100644
a b class WP_REST_Terms_Controller extends WP_REST_Controller { 712 712 $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; 713 713 $data = $this->add_additional_fields_to_object( $data, $request ); 714 714 $data = $this->filter_response_by_context( $data, $context ); 715 $data = $this->filter_response_by_fields( $data, $request['_fields'] ); 715 716 716 717 $response = rest_ensure_response( $data ); 717 718 -
tests/phpunit/tests/rest-api/rest-attachments-controller.php
diff --git a/tests/phpunit/tests/rest-api/rest-attachments-controller.php b/tests/phpunit/tests/rest-api/rest-attachments-controller.php index 98a079b..1d40e6f 100644
a b class WP_Test_REST_Attachments_Controller extends WP_Test_REST_Post_Type_Control 140 140 $keys = array_keys( $data['endpoints'][0]['args'] ); 141 141 sort( $keys ); 142 142 $this->assertEquals( array( 143 '_fields', 143 144 'after', 144 145 'author', 145 146 'author_exclude', -
tests/phpunit/tests/rest-api/rest-pages-controller.php
diff --git a/tests/phpunit/tests/rest-api/rest-pages-controller.php b/tests/phpunit/tests/rest-api/rest-pages-controller.php index ee24f7a..bed80f8 100644
a b class WP_Test_REST_Pages_Controller extends WP_Test_REST_Post_Type_Controller_Te 65 65 $keys = array_keys( $data['endpoints'][0]['args'] ); 66 66 sort( $keys ); 67 67 $this->assertEquals( array( 68 '_fields', 68 69 'after', 69 70 'author', 70 71 'author_exclude', -
tests/phpunit/tests/rest-api/rest-posts-controller.php
diff --git a/tests/phpunit/tests/rest-api/rest-posts-controller.php b/tests/phpunit/tests/rest-api/rest-posts-controller.php index c86879c..c5d736c 100644
a b class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te 120 120 $this->assertEquals( array( 'view', 'embed', 'edit' ), $data['endpoints'][0]['args']['context']['enum'] ); 121 121 } 122 122 123 public function test_fields_param() { 124 125 $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts' ); 126 $response = $this->server->dispatch( $request ); 127 $data = $response->get_data(); 128 129 $fields = $data['endpoints'][0]['args']['_fields']['enum']; 130 $expected = array( 131 'title', 132 'title.raw', 133 'title.rendered', 134 'content', 135 'content.raw', 136 'content.rendered', 137 'content.protected', 138 'date', 139 'date_gmt' 140 ); 141 142 foreach ( $expected as $field ) { 143 $this->assertContains( $field, $fields ); 144 } 145 } 146 123 147 public function test_registered_query_params() { 124 148 $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts' ); 125 149 $response = $this->server->dispatch( $request ); … … class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te 127 151 $keys = array_keys( $data['endpoints'][0]['args'] ); 128 152 sort( $keys ); 129 153 $this->assertEquals( array( 154 '_fields', 130 155 'after', 131 156 'author', 132 157 'author_exclude', … … class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te 3080 3105 $this->assertEquals( $expected_keys, $keys ); 3081 3106 } 3082 3107 3108 public function test_get_post_fields() { 3109 wp_set_current_user( self::$editor_id ); 3110 3111 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', self::$post_id ) ); 3112 $request->set_param( 'context', 'edit' ); 3113 $request->set_param( '_fields', array( 'title.raw', 'content', 'date', 'fake.prop.nested' ) ); 3114 $response = $this->server->dispatch( $request ); 3115 $data = $response->get_data(); 3116 3117 $this->assertArrayHasKey( 'title', $data ); 3118 $this->assertArrayHasKey( 'raw', $data['title'] ); 3119 $this->assertArrayNotHasKey( 'rendered', $data['title'] ); 3120 3121 $this->assertArrayHasKey( 'content', $data ); 3122 $this->assertArrayHasKey( 'raw', $data['content'] ); 3123 $this->assertArrayHasKey( 'rendered', $data['content'] ); 3124 $this->assertArrayHasKey( 'protected', $data['content'] ); 3125 3126 $this->assertArrayHasKey( 'date', $data ); 3127 $this->assertArrayNotHasKey( 'date_gmt', $data ); 3128 } 3129 3083 3130 public function test_status_array_enum_args() { 3084 3131 $request = new WP_REST_Request( 'GET', '/wp/v2' ); 3085 3132 $response = $this->server->dispatch( $request ); -
tests/qunit/fixtures/wp-api-generated.js
diff --git a/tests/qunit/fixtures/wp-api-generated.js b/tests/qunit/fixtures/wp-api-generated.js index 679d024..a522a27 100644
a b mockedApiResponse.Schema = { 211 211 "description": "Limit results to those matching a string.", 212 212 "type": "string" 213 213 }, 214 "_fields": { 215 "required": false, 216 "enum": [ 217 "date", 218 "date_gmt", 219 "guid", 220 "guid.raw", 221 "guid.rendered", 222 "id", 223 "link", 224 "modified", 225 "modified_gmt", 226 "slug", 227 "status", 228 "type", 229 "password", 230 "title", 231 "title.raw", 232 "title.rendered", 233 "content", 234 "content.raw", 235 "content.rendered", 236 "content.protected", 237 "author", 238 "excerpt", 239 "excerpt.raw", 240 "excerpt.rendered", 241 "excerpt.protected", 242 "featured_media", 243 "comment_status", 244 "ping_status", 245 "format", 246 "meta", 247 "sticky", 248 "template", 249 "categories", 250 "tags" 251 ], 252 "description": "Limit the fields to include in the response.", 253 "type": "string" 254 }, 214 255 "after": { 215 256 "required": false, 216 257 "description": "Limit response to posts published after a given ISO8601 compliant date.", … … mockedApiResponse.Schema = { 827 868 "description": "Limit results to those matching a string.", 828 869 "type": "string" 829 870 }, 871 "_fields": { 872 "required": false, 873 "enum": [ 874 "date", 875 "date_gmt", 876 "guid", 877 "guid.raw", 878 "guid.rendered", 879 "id", 880 "link", 881 "modified", 882 "modified_gmt", 883 "slug", 884 "status", 885 "type", 886 "password", 887 "parent", 888 "title", 889 "title.raw", 890 "title.rendered", 891 "content", 892 "content.raw", 893 "content.rendered", 894 "content.protected", 895 "author", 896 "excerpt", 897 "excerpt.raw", 898 "excerpt.rendered", 899 "excerpt.protected", 900 "featured_media", 901 "comment_status", 902 "ping_status", 903 "menu_order", 904 "meta", 905 "template" 906 ], 907 "description": "Limit the fields to include in the response.", 908 "type": "string" 909 }, 830 910 "after": { 831 911 "required": false, 832 912 "description": "Limit response to posts published after a given ISO8601 compliant date.", … … mockedApiResponse.Schema = { 1370 1450 "description": "Limit results to those matching a string.", 1371 1451 "type": "string" 1372 1452 }, 1453 "_fields": { 1454 "required": false, 1455 "enum": [ 1456 "date", 1457 "date_gmt", 1458 "guid", 1459 "guid.raw", 1460 "guid.rendered", 1461 "id", 1462 "link", 1463 "modified", 1464 "modified_gmt", 1465 "slug", 1466 "status", 1467 "type", 1468 "title", 1469 "title.raw", 1470 "title.rendered", 1471 "author", 1472 "comment_status", 1473 "ping_status", 1474 "meta", 1475 "template", 1476 "alt_text", 1477 "caption", 1478 "caption.raw", 1479 "caption.rendered", 1480 "description", 1481 "description.raw", 1482 "description.rendered", 1483 "media_type", 1484 "mime_type", 1485 "media_details", 1486 "post", 1487 "source_url" 1488 ], 1489 "description": "Limit the fields to include in the response.", 1490 "type": "string" 1491 }, 1373 1492 "after": { 1374 1493 "required": false, 1375 1494 "description": "Limit response to posts published after a given ISO8601 compliant date.",