From 3e876734aea33975cfa89a7ce0783fc805b73e3b Mon Sep 17 00:00:00 2001 From: Shawn Hooper Date: Sat, 17 Jan 2026 15:07:21 -0500 Subject: [PATCH 1/4] fix: returns 409 if conflicting user login or email --- .../class-wp-rest-users-controller.php | 33 ++++++++++----- .../tests/rest-api/rest-users-controller.php | 42 +++++++++++++++++++ 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php index 9b25cf7974cbc..ff5a4ff79995f 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php @@ -622,9 +622,6 @@ public function create_item( $request ) { } return $error; } - } - - if ( is_multisite() ) { $user_id = wpmu_create_user( $user->user_login, $user->user_pass, $user->user_email ); if ( ! $user_id ) { @@ -637,21 +634,35 @@ public function create_item( $request ) { $user->ID = $user_id; $user_id = wp_update_user( wp_slash( (array) $user ) ); + } else { + $user_id = wp_insert_user( wp_slash( (array) $user ) ); + } - if ( is_wp_error( $user_id ) ) { - return $user_id; + if ( is_wp_error( $user_id ) ) { + if ( in_array( $user_id->get_error_code(), array( 'existing_user_email') ) ) { + return new WP_Error( + 'rest_user_existing_user_email', + __( 'A user already exists with this email address.' ), + array( 'status' => 409 ) + ); } + if ( in_array( $user_id->get_error_code(), array( 'existing_user_login') ) ) { + return new WP_Error( + 'rest_existing_user_login', + __( 'A user already exists with this username.' ), + array( 'status' => 409 ) + ); + } + + return $user_id; + } + + if ( is_multisite() ) { $result = add_user_to_blog( get_site()->id, $user_id, '' ); if ( is_wp_error( $result ) ) { return $result; } - } else { - $user_id = wp_insert_user( wp_slash( (array) $user ) ); - - if ( is_wp_error( $user_id ) ) { - return $user_id; - } } $user = get_user_by( 'id', $user_id ); diff --git a/tests/phpunit/tests/rest-api/rest-users-controller.php b/tests/phpunit/tests/rest-api/rest-users-controller.php index b78e95b95f48d..f4ac07b5ed271 100644 --- a/tests/phpunit/tests/rest-api/rest-users-controller.php +++ b/tests/phpunit/tests/rest-api/rest-users-controller.php @@ -1689,6 +1689,48 @@ public function test_create_user_invalid_role() { $this->assertErrorResponse( 'rest_user_invalid_role', $response, 400 ); } + /** + * @ticket 41672 + */ + public function test_create_user_with_existing_username_or_email() { + $this->allow_user_to_manage_multisite(); + wp_set_current_user( self::$user ); + + // Create User + $params = array( + 'username' => 'testjsonuser', + 'password' => 'testjsonpassword', + 'email' => 'testjson@example.com', + ); + $request = new WP_REST_Request( 'POST', '/wp/v2/users' ); + $request->add_header( 'content-type', 'application/json' ); + $request->set_body( wp_json_encode( $params ) ); + $response = rest_get_server()->dispatch( $request ); + $this->check_add_edit_user_response( $response ); + + // Make request again, expecting existing_user_email response + $params = array( + 'username' => 'testjsonuser1', + 'password' => 'testjsonpassword', + 'email' => 'testjson@example.com', + ); + $request->set_body( wp_json_encode( $params ) ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_user_existing_user_email', $response, 409 ); + + // Make request again, expecting existing_user_login response + $params = array( + 'username' => 'testjsonuser', + 'password' => 'testjsonpassword', + 'email' => 'testjson1@example.com', + ); + + $request->set_body( wp_json_encode( $params ) ); + $response = rest_get_server()->dispatch( $request ); + + $this->assertErrorResponse( 'rest_existing_user_login', $response, 409 ); + } + public function test_update_item() { $user_id = self::factory()->user->create( array( From 1afaf9d389a0785588feb3b0cd440f377f02fcdf Mon Sep 17 00:00:00 2001 From: Shawn Hooper Date: Sat, 17 Jan 2026 15:14:34 -0500 Subject: [PATCH 2/4] fix: reverted the order change, and updated english error messages --- .../class-wp-rest-users-controller.php | 12 ++++++------ .../tests/rest-api/rest-users-controller.php | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php index ff5a4ff79995f..fa0a7ed045839 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php @@ -639,18 +639,18 @@ public function create_item( $request ) { } if ( is_wp_error( $user_id ) ) { - if ( in_array( $user_id->get_error_code(), array( 'existing_user_email') ) ) { + if ( in_array( $user_id->get_error_code(), array( 'existing_user_login') ) ) { return new WP_Error( - 'rest_user_existing_user_email', - __( 'A user already exists with this email address.' ), + 'rest_existing_user_login', + __( 'Sorry, that username already exists!' ), array( 'status' => 409 ) ); } - if ( in_array( $user_id->get_error_code(), array( 'existing_user_login') ) ) { + if ( in_array( $user_id->get_error_code(), array( 'existing_user_email') ) ) { return new WP_Error( - 'rest_existing_user_login', - __( 'A user already exists with this username.' ), + 'rest_user_existing_user_email', + __( 'Sorry, that email address is already used!",' ), array( 'status' => 409 ) ); } diff --git a/tests/phpunit/tests/rest-api/rest-users-controller.php b/tests/phpunit/tests/rest-api/rest-users-controller.php index f4ac07b5ed271..e8f89d17cfa60 100644 --- a/tests/phpunit/tests/rest-api/rest-users-controller.php +++ b/tests/phpunit/tests/rest-api/rest-users-controller.php @@ -1708,27 +1708,27 @@ public function test_create_user_with_existing_username_or_email() { $response = rest_get_server()->dispatch( $request ); $this->check_add_edit_user_response( $response ); - // Make request again, expecting existing_user_email response + // Make request again, expecting existing_user_login response $params = array( - 'username' => 'testjsonuser1', + 'username' => 'testjsonuser', 'password' => 'testjsonpassword', - 'email' => 'testjson@example.com', + 'email' => 'testjson1@example.com', ); + $request->set_body( wp_json_encode( $params ) ); $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_user_existing_user_email', $response, 409 ); + $this->assertErrorResponse( 'rest_existing_user_login', $response, 409 ); - // Make request again, expecting existing_user_login response + // Make request again, expecting existing_user_email response $params = array( - 'username' => 'testjsonuser', + 'username' => 'testjsonuser1', 'password' => 'testjsonpassword', - 'email' => 'testjson1@example.com', + 'email' => 'testjson@example.com', ); - $request->set_body( wp_json_encode( $params ) ); $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_user_existing_user_email', $response, 409 ); - $this->assertErrorResponse( 'rest_existing_user_login', $response, 409 ); } public function test_update_item() { From 8337f1e7def50ccf6cb2e2cd76ccdb359ba58b4f Mon Sep 17 00:00:00 2001 From: Shawn Hooper Date: Sat, 17 Jan 2026 15:48:52 -0500 Subject: [PATCH 3/4] chore: linting --- .../rest-api/endpoints/class-wp-rest-users-controller.php | 4 ++-- tests/phpunit/tests/rest-api/rest-users-controller.php | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php index fa0a7ed045839..7060d806a6106 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php @@ -639,7 +639,7 @@ public function create_item( $request ) { } if ( is_wp_error( $user_id ) ) { - if ( in_array( $user_id->get_error_code(), array( 'existing_user_login') ) ) { + if ( in_array( $user_id->get_error_code(), array( 'existing_user_login' ) ) ) { return new WP_Error( 'rest_existing_user_login', __( 'Sorry, that username already exists!' ), @@ -647,7 +647,7 @@ public function create_item( $request ) { ); } - if ( in_array( $user_id->get_error_code(), array( 'existing_user_email') ) ) { + if ( in_array( $user_id->get_error_code(), array( 'existing_user_email' ) ) ) { return new WP_Error( 'rest_user_existing_user_email', __( 'Sorry, that email address is already used!",' ), diff --git a/tests/phpunit/tests/rest-api/rest-users-controller.php b/tests/phpunit/tests/rest-api/rest-users-controller.php index e8f89d17cfa60..914c38be01a51 100644 --- a/tests/phpunit/tests/rest-api/rest-users-controller.php +++ b/tests/phpunit/tests/rest-api/rest-users-controller.php @@ -1728,7 +1728,6 @@ public function test_create_user_with_existing_username_or_email() { $request->set_body( wp_json_encode( $params ) ); $response = rest_get_server()->dispatch( $request ); $this->assertErrorResponse( 'rest_user_existing_user_email', $response, 409 ); - } public function test_update_item() { From 11b0693fdf02a29e7c5609f9754e11d797466580 Mon Sep 17 00:00:00 2001 From: Shawn Hooper Date: Sat, 17 Jan 2026 15:53:20 -0500 Subject: [PATCH 4/4] chore: phpcs --- tests/phpunit/tests/rest-api/rest-users-controller.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/phpunit/tests/rest-api/rest-users-controller.php b/tests/phpunit/tests/rest-api/rest-users-controller.php index 914c38be01a51..931027666bc27 100644 --- a/tests/phpunit/tests/rest-api/rest-users-controller.php +++ b/tests/phpunit/tests/rest-api/rest-users-controller.php @@ -1702,6 +1702,7 @@ public function test_create_user_with_existing_username_or_email() { 'password' => 'testjsonpassword', 'email' => 'testjson@example.com', ); + $request = new WP_REST_Request( 'POST', '/wp/v2/users' ); $request->add_header( 'content-type', 'application/json' ); $request->set_body( wp_json_encode( $params ) );