diff -r 34716fd837a4 -r be944660c56a wp/wp-includes/rest-api/class-wp-rest-request.php --- a/wp/wp-includes/rest-api/class-wp-rest-request.php Tue Dec 15 15:52:01 2020 +0100 +++ b/wp/wp-includes/rest-api/class-wp-rest-request.php Wed Sep 21 18:19:35 2022 +0200 @@ -324,9 +324,22 @@ } /** + * Checks if the request has specified a JSON content-type. + * + * @since 5.6.0 + * + * @return bool True if the content-type header is JSON. + */ + public function is_json_content_type() { + $content_type = $this->get_content_type(); + + return isset( $content_type['value'] ) && wp_is_json_media_type( $content_type['value'] ); + } + + /** * Retrieves the parameter priority order. * - * Used when checking parameters in get_param(). + * Used when checking parameters in WP_REST_Request::get_param(). * * @since 4.4.0 * @@ -335,8 +348,7 @@ protected function get_parameter_order() { $order = array(); - $content_type = $this->get_content_type(); - if ( isset( $content_type['value'] ) && 'application/json' === $content_type['value'] ) { + if ( $this->is_json_content_type() ) { $order[] = 'JSON'; } @@ -359,10 +371,10 @@ $order[] = 'defaults'; /** - * Filters the parameter order. + * Filters the parameter priority order for a REST API request. * - * The order affects which parameters are checked when using get_param() and family. - * This acts similarly to PHP's `request_order` setting. + * The order affects which parameters are checked when using WP_REST_Request::get_param() + * and family. This acts similarly to PHP's `request_order` setting. * * @since 4.4.0 * @@ -658,9 +670,7 @@ $this->parsed_json = true; // Check that we actually got JSON. - $content_type = $this->get_content_type(); - - if ( empty( $content_type ) || 'application/json' !== $content_type['value'] ) { + if ( ! $this->is_json_content_type() ) { return true; } @@ -792,7 +802,8 @@ $order = $this->get_parameter_order(); - $invalid_params = array(); + $invalid_params = array(); + $invalid_details = array(); foreach ( $order as $type ) { if ( empty( $this->params[ $type ] ) ) { @@ -815,10 +826,12 @@ continue; } + /** @var mixed|WP_Error $sanitized_value */ $sanitized_value = call_user_func( $param_args['sanitize_callback'], $value, $this, $key ); if ( is_wp_error( $sanitized_value ) ) { - $invalid_params[ $key ] = $sanitized_value->get_error_message(); + $invalid_params[ $key ] = implode( ' ', $sanitized_value->get_error_messages() ); + $invalid_details[ $key ] = rest_convert_error_to_response( $sanitized_value )->get_data(); } else { $this->params[ $type ][ $key ] = $sanitized_value; } @@ -831,8 +844,9 @@ /* translators: %s: List of invalid parameters. */ sprintf( __( 'Invalid parameter(s): %s' ), implode( ', ', array_keys( $invalid_params ) ) ), array( - 'status' => 400, - 'params' => $invalid_params, + 'status' => 400, + 'params' => $invalid_params, + 'details' => $invalid_details, ) ); } @@ -845,7 +859,7 @@ * * @since 4.4.0 * - * @return bool|WP_Error True if there are no parameters to validate or if all pass validation, + * @return true|WP_Error True if there are no parameters to validate or if all pass validation, * WP_Error if required parameters are missing. */ public function has_valid_params() { @@ -858,13 +872,9 @@ $attributes = $this->get_attributes(); $required = array(); - // No arguments set, skip validation. - if ( empty( $attributes['args'] ) ) { - return true; - } + $args = empty( $attributes['args'] ) ? array() : $attributes['args']; - foreach ( $attributes['args'] as $key => $arg ) { - + foreach ( $args as $key => $arg ) { $param = $this->get_param( $key ); if ( isset( $arg['required'] ) && true === $arg['required'] && null === $param ) { $required[] = $key; @@ -888,13 +898,15 @@ * * This is done after required checking as required checking is cheaper. */ - $invalid_params = array(); + $invalid_params = array(); + $invalid_details = array(); - foreach ( $attributes['args'] as $key => $arg ) { + foreach ( $args as $key => $arg ) { $param = $this->get_param( $key ); if ( null !== $param && ! empty( $arg['validate_callback'] ) ) { + /** @var bool|\WP_Error $valid_check */ $valid_check = call_user_func( $arg['validate_callback'], $param, $this, $key ); if ( false === $valid_check ) { @@ -902,7 +914,8 @@ } if ( is_wp_error( $valid_check ) ) { - $invalid_params[ $key ] = $valid_check->get_error_message(); + $invalid_params[ $key ] = implode( ' ', $valid_check->get_error_messages() ); + $invalid_details[ $key ] = rest_convert_error_to_response( $valid_check )->get_data(); } } } @@ -913,14 +926,27 @@ /* translators: %s: List of invalid parameters. */ sprintf( __( 'Invalid parameter(s): %s' ), implode( ', ', array_keys( $invalid_params ) ) ), array( - 'status' => 400, - 'params' => $invalid_params, + 'status' => 400, + 'params' => $invalid_params, + 'details' => $invalid_details, ) ); } + if ( isset( $attributes['validate_callback'] ) ) { + $valid_check = call_user_func( $attributes['validate_callback'], $this ); + + if ( is_wp_error( $valid_check ) ) { + return $valid_check; + } + + if ( false === $valid_check ) { + // A WP_Error instance is preferred, but false is supported for parity with the per-arg validate_callback. + return new WP_Error( 'rest_invalid_params', __( 'Invalid parameters.' ), array( 'status' => 400 ) ); + } + } + return true; - } /** @@ -1017,7 +1043,7 @@ } /** - * Filters the request generated from a URL. + * Filters the REST API request generated from a URL. * * @since 4.5.0 *