Make WordPress Core

Ticket #38531: 38531.8.diff

File 38531.8.diff, 12.4 KB (added by joehoyle, 7 years ago)
  • src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php

     
    8484                        $response[ $name ] = $value;
    8585                }
    8686
    87                 return (object) $response;
     87                return $response;
    8888        }
    8989
    9090        /**
     
    133133                         */
    134134                        if ( is_null( $request[ $name ] ) ) {
    135135                                $result = $this->delete_meta_value( $object_id, $name );
    136                         } elseif ( $args['single'] ) {
    137                                 $result = $this->update_meta_value( $object_id, $name, $request[ $name ] );
     136                                if ( is_wp_error( $result ) ) {
     137                                        return $result;
     138                                }
     139                                continue;
     140                        }
     141
     142                        $is_valid = rest_validate_value_from_schema( $request[ $name ], $args['schema'], 'meta.' . $name );
     143                        if ( is_wp_error( $is_valid ) ) {
     144                                $is_valid->add_data( array( 'status' => 400 ) );
     145                                return $is_valid;
     146                        }
     147
     148                        $value = rest_sanitize_value_from_schema( $request[ $name ], $args['schema'] );
     149
     150                        if ( $args['single'] ) {
     151                                $result = $this->update_meta_value( $object_id, $name, $value );
    138152                        } else {
    139                                 $result = $this->update_multi_meta_value( $object_id, $name, $request[ $name ] );
     153                                $result = $this->update_multi_meta_value( $object_id, $name, $value );
    140154                        }
    141155
    142156                        if ( is_wp_error( $result ) ) {
     
    319333                        $default_args = array(
    320334                                'name'             => $name,
    321335                                'single'           => $args['single'],
     336                                'type'             => ! empty( $args['type'] ) ? $args['type'] : null,
    322337                                'schema'           => array(),
    323338                                'prepare_callback' => array( $this, 'prepare_value' ),
    324339                        );
     
    332347                        $rest_args = array_merge( $default_args, $rest_args );
    333348                        $rest_args['schema'] = array_merge( $default_schema, $rest_args['schema'] );
    334349
     350                        $type = ! empty( $rest_args['type'] ) ? $rest_args['type'] : null;
     351                        $type = ! empty( $rest_args['schema']['type'] ) ? $rest_args['schema']['type'] : $type;
     352
     353                        if ( ! in_array( $type, array( 'string', 'boolean', 'integer', 'number' ) ) ) {
     354                                continue;
     355                        }
     356
    335357                        if ( empty( $rest_args['schema']['type'] ) ) {
    336358                                // Skip over meta fields that don't have a defined type.
    337359                                if ( empty( $args['type'] ) ) {
  • src/wp-includes/rest-api.php

     
    998998                if ( ! is_array( $value ) ) {
    999999                        $value = preg_split( '/[\s,]+/', $value );
    10001000                }
     1001                if ( ! wp_is_numeric_array( $value ) ) {
     1002                        return new WP_Error( 'rest_invalid_param', sprintf( /* translators: 1: parameter, 2: type name */ __( '%1$s is not of type %2$s.' ), $param, 'array' ) );
     1003                }
    10011004                foreach ( $value as $index => $v ) {
    10021005                        $is_valid = rest_validate_value_from_schema( $v, $args['items'], $param . '[' . $index . ']' );
    10031006                        if ( is_wp_error( $is_valid ) ) {
     
    11071110                foreach ( $value as $index => $v ) {
    11081111                        $value[ $index ] = rest_sanitize_value_from_schema( $v, $args['items'] );
    11091112                }
     1113                // Normalize to numeric array so nothing unexpected
     1114                // is in the keys.
     1115                $value = array_values( $value );
    11101116                return $value;
    11111117        }
    11121118        if ( 'integer' === $args['type'] ) {
     
    11401146                }
    11411147        }
    11421148
     1149        if ( 'string' === $args['type'] ) {
     1150                return strval( $value );
     1151        }
     1152
    11431153        return $value;
    11441154}
  • tests/phpunit/tests/rest-api/rest-post-meta-fields.php

     
    2626                register_meta( 'post', 'test_single', array(
    2727                        'show_in_rest' => true,
    2828                        'single' => true,
     29                        'type' => 'string',
    2930                ));
    3031                register_meta( 'post', 'test_multi', array(
    3132                        'show_in_rest' => true,
    3233                        'single' => false,
     34                        'type' => 'string',
    3335                ));
    3436                register_meta( 'post', 'test_bad_auth', array(
    3537                        'show_in_rest' => true,
    3638                        'single' => true,
    3739                        'auth_callback' => '__return_false',
     40                        'type' => 'string',
    3841                ));
    3942                register_meta( 'post', 'test_bad_auth_multi', array(
    4043                        'show_in_rest' => true,
    4144                        'single' => false,
    4245                        'auth_callback' => '__return_false',
     46                        'type' => 'string',
    4347                ));
    4448                register_meta( 'post', 'test_no_rest', array() );
    4549                register_meta( 'post', 'test_rest_disabled', array(
    4650                        'show_in_rest' => false,
     51                        'type' => 'string',
    4752                ));
    4853                register_meta( 'post', 'test_custom_schema', array(
    4954                        'single' => true,
     
    5661                ));
    5762                register_meta( 'post', 'test_invalid_type', array(
    5863                        'single' => true,
    59                         'type' => false,
     64                        'type' => 'lalala',
     65                        'show_in_rest' => true,
     66                ));
     67                register_meta( 'post', 'test_no_type', array(
     68                        'single' => true,
     69                        'type' => null,
    6070                        'show_in_rest' => true,
    6171                ));
    6272
     
    240250                $this->assertEquals( 'test_value', $meta['test_single'] );
    241251        }
    242252
     253
     254
    243255        /**
    244256         * @depends test_get_value
    245257         */
     
    341353                $wpdb->show_errors = true;
    342354        }
    343355
     356        public function test_set_value_invalid_type() {
     357                $values = get_post_meta( self::$post_id, 'test_invalid_type', false );
     358                $this->assertEmpty( $values );
     359
     360                $this->grant_write_permission();
     361
     362                $data = array(
     363                        'meta' => array(
     364                                'test_invalid_type' => 'test_value',
     365                        ),
     366                );
     367                $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
     368                $request->set_body_params( $data );
     369
     370                $response = $this->server->dispatch( $request );
     371                $this->assertEmpty( get_post_meta( self::$post_id, 'test_invalid_type', false ) );
     372        }
     373
    344374        public function test_set_value_multiple() {
    345375                // Ensure no data exists currently.
    346376                $values = get_post_meta( self::$post_id, 'test_multi', false );
     
    435465                $this->assertEmpty( $meta );
    436466        }
    437467
     468        public function test_set_value_invalid_value() {
     469                register_meta( 'post', 'my_meta_key', array(
     470                        'show_in_rest' => true,
     471                        'single' => true,
     472                        'type' => 'string',
     473                ));
     474
     475                $this->grant_write_permission();
     476
     477                $data = array(
     478                        'meta' => array(
     479                                'my_meta_key' => array( 'c', 'n' ),
     480                        ),
     481                );
     482                $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
     483                $request->set_body_params( $data );
     484
     485                $response = $this->server->dispatch( $request );
     486                $this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
     487        }
     488
     489        public function test_set_value_invalid_value_multiple() {
     490                register_meta( 'post', 'my_meta_key', array(
     491                        'show_in_rest' => true,
     492                        'single' => false,
     493                        'type' => 'string',
     494                ));
     495
     496                $this->grant_write_permission();
     497
     498                $data = array(
     499                        'meta' => array(
     500                                'my_meta_key' => array( array( 'a' ) ),
     501                        ),
     502                );
     503                $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
     504                $request->set_body_params( $data );
     505
     506                $response = $this->server->dispatch( $request );
     507                $this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
     508        }
     509
     510        public function test_set_value_sanitized() {
     511                register_meta( 'post', 'my_meta_key', array(
     512                        'show_in_rest' => true,
     513                        'single' => true,
     514                        'type' => 'integer',
     515                ));
     516
     517                $this->grant_write_permission();
     518
     519                $data = array(
     520                        'meta' => array(
     521                                'my_meta_key' => '1', // Set to a string.
     522                        ),
     523                );
     524                $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
     525                $request->set_body_params( $data );
     526
     527                $response = $this->server->dispatch( $request );
     528                $data = $response->get_data();
     529                $this->assertEquals( 1, $data['meta']['my_meta_key'] );
     530        }
     531
     532        public function test_set_value_csv() {
     533                register_meta( 'post', 'my_meta_key', array(
     534                        'show_in_rest' => true,
     535                        'single' => false,
     536                        'type' => 'integer',
     537                ));
     538
     539                $this->grant_write_permission();
     540
     541                $data = array(
     542                        'meta' => array(
     543                                'my_meta_key' => '1,2,3', // Set to a string.
     544                        ),
     545                );
     546                $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
     547                $request->set_body_params( $data );
     548
     549                $response = $this->server->dispatch( $request );
     550                $data = $response->get_data();
     551                $this->assertEquals( array( 1, 2, 3 ), $data['meta']['my_meta_key'] );
     552        }
     553
    438554        /**
    439555         * @depends test_set_value_multiple
    440556         */
     
    515631                $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 );
    516632        }
    517633
     634
    518635        public function test_delete_value() {
    519636                add_post_meta( self::$post_id, 'test_single', 'val1' );
    520637                $current = get_post_meta( self::$post_id, 'test_single', true );
     
    618735                $this->assertArrayNotHasKey( 'test_no_rest', $meta_schema );
    619736                $this->assertArrayNotHasKey( 'test_rest_disabled', $meta_schema );
    620737                $this->assertArrayNotHasKey( 'test_invalid_type', $meta_schema );
     738                $this->assertArrayNotHasKey( 'test_no_type', $meta_schema );
    621739        }
    622740
    623741        /**
  • tests/phpunit/tests/rest-api/rest-schema-sanitization.php

     
    7676                $this->assertEquals( array( 1 ), rest_sanitize_value_from_schema( array( '1' ), $schema ) );
    7777        }
    7878
     79        public function test_type_array_nested() {
     80                $schema = array(
     81                        'type' => 'array',
     82                        'items' => array(
     83                                'type' => 'array',
     84                                'items' => array(
     85                                        'type' => 'number',
     86                                ),
     87                        ),
     88                );
     89                $this->assertEquals( array( array( 1 ), array( 2 ) ), rest_sanitize_value_from_schema( array( array( 1 ), array( 2 ) ), $schema ) );
     90                $this->assertEquals( array( array( 1 ), array( 2 ) ), rest_sanitize_value_from_schema( array( array( '1' ), array( '2' ) ), $schema ) );
     91        }
     92
    7993        public function test_type_array_as_csv() {
    8094                $schema = array(
    8195                        'type' => 'array',
     
    110124                $this->assertEquals( array( 'ribs', 'chicken' ), rest_sanitize_value_from_schema( 'ribs,chicken', $schema ) );
    111125                $this->assertEquals( array( 'chicken', 'coleslaw' ), rest_sanitize_value_from_schema( 'chicken,coleslaw', $schema ) );
    112126        }
     127
     128        public function test_type_array_is_associative() {
     129                $schema = array(
     130                        'type' => 'array',
     131                        'items' => array(
     132                                'type' => 'string',
     133                        ),
     134                );
     135                $this->assertEquals( array( '1', '2' ), rest_sanitize_value_from_schema( array( 'first' => '1', 'second' => '2' ), $schema ) );
     136        }
     137
     138        public function test_type_unknown() {
     139                $schema = array(
     140                        'type' => 'lalala',
     141                );
     142                $this->assertEquals( 'Best lyrics', rest_sanitize_value_from_schema( 'Best lyrics', $schema ) );
     143                $this->assertEquals( 1.10, rest_sanitize_value_from_schema( 1.10, $schema ) );
     144                $this->assertEquals( 1, rest_sanitize_value_from_schema( 1, $schema ) );
     145        }
     146
     147        public function test_no_type() {
     148                $schema = array(
     149                        'type' => null,
     150                );
     151                $this->assertEquals( 'Nothing', rest_sanitize_value_from_schema( 'Nothing', $schema ) );
     152                $this->assertEquals( 1.10, rest_sanitize_value_from_schema( 1.10, $schema ) );
     153                $this->assertEquals( 1, rest_sanitize_value_from_schema( 1, $schema ) );
     154        }
    113155}
  • tests/phpunit/tests/rest-api/rest-schema-validation.php

     
    104104                $this->assertWPError( rest_validate_value_from_schema( array( true ), $schema ) );
    105105        }
    106106
     107        public function test_type_array_nested() {
     108                $schema = array(
     109                        'type' => 'array',
     110                        'items' => array(
     111                                'type' => 'array',
     112                                'items' => array(
     113                                        'type' => 'number',
     114                                ),
     115                        ),
     116                );
     117                $this->assertTrue( rest_validate_value_from_schema( array( array( 1 ), array( 2 ) ), $schema ) );
     118        }
     119
    107120        public function test_type_array_as_csv() {
    108121                $schema = array(
    109122                        'type' => 'array',
     
    139152                $this->assertTrue( rest_validate_value_from_schema( 'ribs,chicken', $schema ) );
    140153                $this->assertWPError( rest_validate_value_from_schema( 'chicken,coleslaw', $schema ) );
    141154        }
     155
     156        public function test_type_array_is_associative() {
     157                $schema = array(
     158                        'type'  => 'array',
     159                        'items' => array(
     160                                'type' => 'string',
     161                        ),
     162                );
     163                $this->assertWPError( rest_validate_value_from_schema( array( 'first' => '1', 'second' => '2' ), $schema ) );
     164        }
     165
     166        public function test_type_unknown() {
     167                $schema = array(
     168                        'type'  => 'lalala',
     169                );
     170                $this->assertTrue( rest_validate_value_from_schema( 'Best lyrics', $schema ) );
     171                $this->assertTrue( rest_validate_value_from_schema( 1, $schema ) );
     172                $this->assertTrue( rest_validate_value_from_schema( array(), $schema ) );
     173        }
    142174}