From 57b4193b9ae36b657cc23fec96f42af1add5abc2 Mon Sep 17 00:00:00 2001 From: Jonny Harris Date: Tue, 13 Feb 2024 09:55:38 +0000 Subject: [PATCH] REST API: Improve error handling in REST meta fields This update modifies the error handling mechanism in the REST API meta fields functionality. Instead of halting execution and returning on the first encountered error, it now collects all errors in a WP_Error object and continues execution. Thus, this enhancement enables handling and displaying of multiple errors in a single response, improving the debugging process. Props TimothyBlynJacobs, spacedmonkey, hellofromTonya, oglekler. Fixes #48823. git-svn-id: https://develop.svn.wordpress.org/trunk@57611 602fd350-edb4-49c9-b593-d223f7449a82 --- .../fields/class-wp-rest-meta-fields.php | 19 ++++++-- .../tests/rest-api/rest-post-meta-fields.php | 46 +++++++++++++++++++ 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php b/src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php index 60c3c3ab24..7b46905a7a 100644 --- a/src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php +++ b/src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php @@ -141,6 +141,7 @@ abstract class WP_REST_Meta_Fields { */ public function update_value( $meta, $object_id ) { $fields = $this->get_registered_fields(); + $error = new WP_Error(); foreach ( $fields as $meta_key => $args ) { $name = $args['name']; @@ -163,35 +164,38 @@ abstract class WP_REST_Meta_Fields { $current = get_metadata( $this->get_meta_type(), $object_id, $meta_key, true ); if ( is_wp_error( rest_validate_value_from_schema( $current, $args['schema'] ) ) ) { - return new WP_Error( + $error->add( 'rest_invalid_stored_value', /* translators: %s: Custom field key. */ sprintf( __( 'The %s property has an invalid stored value, and cannot be updated to null.' ), $name ), array( 'status' => 500 ) ); + continue; } } $result = $this->delete_meta_value( $object_id, $meta_key, $name ); if ( is_wp_error( $result ) ) { - return $result; + $error->merge_from( $result ); } continue; } if ( ! $args['single'] && is_array( $value ) && count( array_filter( $value, 'is_null' ) ) ) { - return new WP_Error( + $error->add( 'rest_invalid_stored_value', /* translators: %s: Custom field key. */ sprintf( __( 'The %s property has an invalid stored value, and cannot be updated to null.' ), $name ), array( 'status' => 500 ) ); + continue; } $is_valid = rest_validate_value_from_schema( $value, $args['schema'], 'meta.' . $name ); if ( is_wp_error( $is_valid ) ) { $is_valid->add_data( array( 'status' => 400 ) ); - return $is_valid; + $error->merge_from( $is_valid ); + continue; } $value = rest_sanitize_value_from_schema( $value, $args['schema'] ); @@ -203,10 +207,15 @@ abstract class WP_REST_Meta_Fields { } if ( is_wp_error( $result ) ) { - return $result; + $error->merge_from( $result ); + continue; } } + if ( $error->has_errors() ) { + return $error; + } + return null; } diff --git a/tests/phpunit/tests/rest-api/rest-post-meta-fields.php b/tests/phpunit/tests/rest-api/rest-post-meta-fields.php index dcf39f59c9..1418db19db 100644 --- a/tests/phpunit/tests/rest-api/rest-post-meta-fields.php +++ b/tests/phpunit/tests/rest-api/rest-post-meta-fields.php @@ -3095,6 +3095,52 @@ class WP_Test_REST_Post_Meta_Fields extends WP_Test_REST_TestCase { $this->assertSame( 'Goodnight Moon', $schema['default'] ); } + /** + * @ticket 48823 + */ + public function test_multiple_errors_are_returned_at_once() { + $this->grant_write_permission(); + register_post_meta( + 'post', + 'error_1', + array( + 'single' => true, + 'show_in_rest' => array( + 'schema' => array( + 'enum' => array( 'a', 'b' ), + ), + ), + ) + ); + register_post_meta( + 'post', + 'error_2', + array( + 'single' => true, + 'show_in_rest' => array( + 'schema' => array( + 'minLength' => 1, + ), + ), + ) + ); + + $request = new WP_REST_Request( 'PUT', '/wp/v2/posts/' . self::$post_id ); + $request->set_body_params( + array( + 'meta' => array( + 'error_1' => 'c', + 'error_2' => '', + ), + ) + ); + $response = rest_do_request( $request ); + $error = $response->as_error(); + $this->assertWPError( $error ); + $this->assertContains( 'meta.error_1 is not one of a and b.', $error->get_error_messages() ); + $this->assertContains( 'meta.error_2 must be at least 1 character long.', $error->get_error_messages() ); + } + /** * Internal function used to disable an insert query which * will trigger a wpdb error for testing purposes.