Make WordPress Core

Ticket #38131: 38131.diff

File 38131.diff, 4.6 KB (added by kadamwhite, 8 years ago)

Initial patch based on PoC discussion w/ Ryan McCue

  • src/wp-includes/rest-api.php

    diff --git src/wp-includes/rest-api.php src/wp-includes/rest-api.php
    index 0eee75c..9bc5cbf 100644
    function rest_api_default_filters() { 
    115115        // Default serving.
    116116        add_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );
    117117        add_filter( 'rest_post_dispatch', 'rest_send_allow_header', 10, 3 );
     118        add_filter( 'rest_post_dispatch', 'rest_filter_response_fields', 10, 3 );
    118119
    119120        add_filter( 'rest_pre_dispatch', 'rest_handle_options_request', 10, 3 );
    120121}
    function rest_send_allow_header( $response, $server, $request ) { 
    484485}
    485486
    486487/**
     488 * Filter the API response to include only a whitelisted set of response object fields.
     489 *
     490 * @since 4.7.0
     491 *
     492 * @param WP_REST_Response $response Current response being served.
     493 * @param WP_REST_Server   $server   ResponseHandler instance (usually WP_REST_Server).
     494 * @param WP_REST_Request  $request  The request that was used to make current response.
     495 * @return WP_REST_Response Response to be served, trimmed down to contain a subset of fields.
     496 */
     497function rest_filter_response_fields( $response, $server, $request ) {
     498        if ( ! isset( $request['_fields'] ) || $response->is_error() ) {
     499                return $response;
     500        }
     501
     502        $data = $response->get_data();
     503
     504        $fields = (array) explode( ',', $request['_fields'] );
     505
     506        $fields_as_keyed = array_combine( $fields, array_fill( 0, count( $fields ), true ) );
     507
     508        if ( wp_is_numeric_array( $data ) ) {
     509                // $new_data = array_map( function ( $item ) use ( $fields_as_keyed ) {
     510                //      return array_intersect_key( $item, $fields_as_keyed );
     511                // }, $data );
     512                $new_data = array();
     513                foreach ( $data as $item ) {
     514                        $new_data[] = array_intersect_key( $item, $fields_as_keyed );
     515                }
     516        } else {
     517                $new_data = array_intersect_key( $data, $fields_as_keyed );
     518        }
     519
     520        $response->set_data( $new_data );
     521
     522        return $response;
     523}
     524
     525/**
    487526 * Adds the REST API URL to the WP RSD endpoint.
    488527 *
    489528 * @since 4.4.0
  • tests/phpunit/tests/rest-api.php

    diff --git tests/phpunit/tests/rest-api.php tests/phpunit/tests/rest-api.php
    index 6710a83..e543f3c 100644
    class Tests_REST_API extends WP_UnitTestCase { 
    268268        }
    269269
    270270        /**
     271         * Ensure that result fields are not whitelisted if no request['_fields'] is present.
     272         */
     273        public function test_rest_filter_response_fields_no_request_filter() {
     274                $response = new WP_REST_Response();
     275                $response->set_data( array( 'a' => true ) );
     276                $request = array();
     277
     278                $response = rest_filter_response_fields( $response, null, $request );
     279                $this->assertEquals( array( 'a' => true ), $response->get_data() );
     280        }
     281
     282        /**
     283         * Ensure that result fields are whitelisted if request['_fields'] is present.
     284         */
     285        public function test_rest_filter_response_fields_single_field_filter() {
     286                $response = new WP_REST_Response();
     287                $response->set_data( array(
     288                        'a' => 0,
     289                        'b' => 1,
     290                        'c' => 2,
     291                ) );
     292                $request = array(
     293                        '_fields' => 'b'
     294                );
     295
     296                $response = rest_filter_response_fields( $response, null, $request );
     297                $this->assertEquals( array( 'b' => 1 ), $response->get_data() );
     298        }
     299
     300        /**
     301         * Ensure that multiple comma-separated fields may be whitelisted with request['_fields'].
     302         */
     303        public function test_rest_filter_response_fields_multi_field_filter() {
     304                $response = new WP_REST_Response();
     305                $response->set_data( array(
     306                        'a' => 0,
     307                        'b' => 1,
     308                        'c' => 2,
     309                        'd' => 3,
     310                        'e' => 4,
     311                        'f' => 5,
     312                ) );
     313                $request = array(
     314                        '_fields' => 'b,c,e'
     315                );
     316
     317                $response = rest_filter_response_fields( $response, null, $request );
     318                $this->assertEquals( array(
     319                        'b' => 1,
     320                        'c' => 2,
     321                        'e' => 4,
     322                ), $response->get_data() );
     323        }
     324
     325        /**
     326         * Ensure that request['_fields'] whitelists apply to items in response collections.
     327         */
     328        public function test_rest_filter_response_fields_numeric_array() {
     329                $response = new WP_REST_Response();
     330                $response->set_data( array(
     331                        array(
     332                                'a' => 0,
     333                                'b' => 1,
     334                                'c' => 2,
     335                        ),
     336                        array(
     337                                'a' => 3,
     338                                'b' => 4,
     339                                'c' => 5,
     340                        ),
     341                        array(
     342                                'a' => 6,
     343                                'b' => 7,
     344                                'c' => 8,
     345                        ),
     346                ) );
     347                $request = array(
     348                        '_fields' => 'b,c'
     349                );
     350
     351                $response = rest_filter_response_fields( $response, null, $request );
     352                $this->assertEquals( array(
     353                        array(
     354                                'b' => 1,
     355                                'c' => 2,
     356                        ),
     357                        array(
     358                                'b' => 4,
     359                                'c' => 5,
     360                        ),
     361                        array(
     362                                'b' => 7,
     363                                'c' => 8,
     364                        ),
     365                ), $response->get_data() );
     366        }
     367
     368        /**
    271369         * The get_rest_url function should return a URL consistently terminated with a "/",
    272370         * whether the blog is configured with pretty permalink support or not.
    273371         */