From 3abe80eea1b1afb571ad52557def05265d9ffbe8 Mon Sep 17 00:00:00 2001 From: "K. Adam White" Date: Thu, 9 Apr 2020 19:28:58 +0000 Subject: [PATCH] REST API: Handle parameter types consistently within set_param(). A request has multiple parameter types, including "query" and "json." Updating a parameter could previously modify a key's value in the wrong parameter type, leading to confusing and self-contradictory response objects. Props mnelson4, TimothyBlynJacobs, vagios, jnylen0. Fixes #40838. git-svn-id: https://develop.svn.wordpress.org/trunk@47559 602fd350-edb4-49c9-b593-d223f7449a82 --- .../rest-api/class-wp-rest-request.php | 19 ++- tests/phpunit/tests/rest-api/rest-request.php | 115 ++++++++++++++++++ 2 files changed, 132 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/rest-api/class-wp-rest-request.php b/src/wp-includes/rest-api/class-wp-rest-request.php index d6146127ed..e3ed8c424a 100644 --- a/src/wp-includes/rest-api/class-wp-rest-request.php +++ b/src/wp-includes/rest-api/class-wp-rest-request.php @@ -420,14 +420,29 @@ class WP_REST_Request implements ArrayAccess { /** * Sets a parameter on the request. * + * If the given parameter key exists in any parameter type an update will take place, + * otherwise a new param will be created in the first parameter type (respecting + * get_parameter_order()). + * * @since 4.4.0 * * @param string $key Parameter name. * @param mixed $value Parameter value. */ public function set_param( $key, $value ) { - $order = $this->get_parameter_order(); - $this->params[ $order[0] ][ $key ] = $value; + $order = $this->get_parameter_order(); + $found_key = false; + + foreach ( $order as $type ) { + if ( 'defaults' !== $type && array_key_exists( $key, $this->params[ $type ] ) ) { + $this->params[ $type ][ $key ] = $value; + $found_key = true; + } + } + + if ( ! $found_key ) { + $this->params[ $order[0] ][ $key ] = $value; + } } /** diff --git a/tests/phpunit/tests/rest-api/rest-request.php b/tests/phpunit/tests/rest-api/rest-request.php index 2dd539a509..9cbb0f3994 100644 --- a/tests/phpunit/tests/rest-api/rest-request.php +++ b/tests/phpunit/tests/rest-api/rest-request.php @@ -650,4 +650,119 @@ class Tests_REST_Request extends WP_UnitTestCase { $request->get_json_params() ); } + + /** + * @ticket 40838 + */ + public function test_set_param_updates_param_in_json_and_query() { + $request = new WP_REST_Request(); + $request->add_header( 'content-type', 'application/json' ); + $request->set_method( 'POST' ); + $request->set_body( + wp_json_encode( + array( + 'param' => 'value_body', + ) + ) + ); + $request->set_query_params( + array( + 'param' => 'value_query', + ) + ); + $request->set_param( 'param', 'new_value' ); + + $this->assertEquals( 'new_value', $request->get_param( 'param' ) ); + $this->assertEquals( array(), $request->get_body_params() ); + $this->assertEquals( array( 'param' => 'new_value' ), $request->get_json_params() ); + $this->assertEquals( array( 'param' => 'new_value' ), $request->get_query_params() ); + } + + /** + * @ticket 40838 + */ + public function test_set_param_updates_param_if_already_exists_in_query() { + $request = new WP_REST_Request(); + $request->add_header( 'content-type', 'application/json' ); + $request->set_method( 'POST' ); + $request->set_body( + wp_json_encode( + array( + 'param_body' => 'value_body', + ) + ) + ); + $original_defaults = array( + 'param_query' => 'default_query_value', + 'param_body' => 'default_body_value', + ); + $request->set_default_params( $original_defaults ); + $request->set_query_params( + array( + 'param_query' => 'value_query', + ) + ); + $request->set_param( 'param_query', 'new_value' ); + + $this->assertEquals( 'new_value', $request->get_param( 'param_query' ) ); + $this->assertEquals( array(), $request->get_body_params() ); + $this->assertEquals( array( 'param_body' => 'value_body' ), $request->get_json_params() ); + $this->assertEquals( array( 'param_query' => 'new_value' ), $request->get_query_params() ); + // Verify the default wasn't overwritten. + $this->assertEquals( $original_defaults, $request->get_default_params() ); + } + + /** + * @ticket 40838 + */ + public function test_set_param_to_null_updates_param_in_json_and_query() { + $request = new WP_REST_Request(); + $request->add_header( 'content-type', 'application/json' ); + $request->set_method( 'POST' ); + $request->set_body( + wp_json_encode( + array( + 'param' => 'value_body', + ) + ) + ); + $request->set_query_params( + array( + 'param' => 'value_query', + ) + ); + $request->set_param( 'param', null ); + + $this->assertEquals( null, $request->get_param( 'param' ) ); + $this->assertEquals( array(), $request->get_body_params() ); + $this->assertEquals( array( 'param' => null ), $request->get_json_params() ); + $this->assertEquals( array( 'param' => null ), $request->get_query_params() ); + } + + /** + * @ticket 40838 + */ + public function test_set_param_from_null_updates_param_in_json_and_query_with_null() { + $request = new WP_REST_Request(); + $request->add_header( 'content-type', 'application/json' ); + $request->set_method( 'POST' ); + $request->set_body( + wp_json_encode( + array( + 'param' => null, + ) + ) + ); + $request->set_query_params( + array( + 'param' => null, + ) + ); + $request->set_param( 'param', 'new_value' ); + + $this->assertEquals( 'new_value', $request->get_param( 'param' ) ); + $this->assertEquals( array(), $request->get_body_params() ); + $this->assertEquals( array( 'param' => 'new_value' ), $request->get_json_params() ); + $this->assertEquals( array( 'param' => 'new_value' ), $request->get_query_params() ); + } }