Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/wp-admin/includes/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ function edit_user( $user_id = 0 ) {
$errors->add( 'user_login', __( '<strong>Error:</strong> This username is already registered. Please choose another one.' ) );
}

if ( ! $update && email_exists( $user->user_login ) ) {
$errors->add( 'user_login', __( '<strong>Error:</strong> This username is not available. Please choose another one.' ) );
}

/** This filter is documented in wp-includes/user.php */
$illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );

Expand All @@ -218,6 +222,13 @@ function edit_user( $user_id = 0 ) {
if ( $owner_id && ( ! $update || ( $owner_id !== $user->ID ) ) ) {
$errors->add( 'email_exists', __( '<strong>Error:</strong> This email is already registered. Please choose another one.' ), array( 'form-field' => 'email' ) );
}

// Only check a new or changed email address against existing usernames.
$is_new_email = ! $update || 0 !== strcasecmp( $user->user_email, $userdata->user_email );
$login_owner_id = $is_new_email ? username_exists( $user->user_email ) : false;
if ( $login_owner_id && ( ! $update || ( (int) $login_owner_id !== $user->ID ) ) ) {
$errors->add( 'email_exists_as_username', __( '<strong>Error:</strong> This email address is not available. Please choose another one.' ), array( 'form-field' => 'email' ) );
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,19 @@ public function update_item( $request ) {
);
}

// A new email address must not match another user's username.
if ( is_string( $request['email'] ) && 0 !== strcasecmp( $request['email'], $user->user_email ) ) {
$login_owner_id = username_exists( $request['email'] );

if ( $login_owner_id && (int) $login_owner_id !== $id ) {
return new WP_Error(
'rest_user_invalid_email',
__( 'Invalid email address.' ),
array( 'status' => 400 )
);
}
}

if ( ! empty( $request['username'] ) && $request['username'] !== $user->user_login ) {
return new WP_Error(
'rest_user_invalid_argument',
Expand Down
46 changes: 35 additions & 11 deletions src/wp-includes/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -2351,8 +2351,20 @@ function wp_insert_user( $userdata ) {
return new WP_Error( 'user_login_too_long', __( 'Username may not be longer than 60 characters.' ) );
}

if ( ! $update && username_exists( $user_login ) ) {
return new WP_Error( 'existing_user_login', __( 'Sorry, that username already exists!' ) );
/*
* The username can only be set when creating a user, so these checks never
* run on update. This keeps existing users editable even if their username
* already matches another user's email address.
*/
if ( ! $update ) {
if ( username_exists( $user_login ) ) {
return new WP_Error( 'existing_user_login', __( 'Sorry, that username already exists!' ) );
}

// Username must not match another user's email address.
if ( ! defined( 'WP_IMPORTING' ) && email_exists( $user_login ) ) {
return new WP_Error( 'existing_user_email_as_login', __( 'Sorry, that username is not available.' ) );
}
}

/**
Expand Down Expand Up @@ -2422,15 +2434,21 @@ function wp_insert_user( $userdata ) {
$user_email = apply_filters( 'pre_user_email', $raw_user_email );

/*
* If there is no update, just check for `email_exists`. If there is an update,
* check if current email and new email are the same, and check `email_exists`
* accordingly.
* Only validate the email address when creating a user or when the email
* address is changing, so that existing users can always be updated.
*/
if ( ( ! $update || ( ! empty( $old_user_data ) && 0 !== strcasecmp( $user_email, $old_user_data->user_email ) ) )
&& ! defined( 'WP_IMPORTING' )
&& email_exists( $user_email )
) {
return new WP_Error( 'existing_user_email', __( 'Sorry, that email address is already used!' ) );
$is_new_email = ! $update || ( ! empty( $old_user_data ) && 0 !== strcasecmp( $user_email, $old_user_data->user_email ) );

if ( $is_new_email && ! defined( 'WP_IMPORTING' ) ) {
if ( email_exists( $user_email ) ) {
return new WP_Error( 'existing_user_email', __( 'Sorry, that email address is already used!' ) );
}

// Email address must not match another user's username.
$login_owner_id = username_exists( $user_email );
if ( $login_owner_id && ( ! $update || (int) $login_owner_id !== $user_id ) ) {
return new WP_Error( 'existing_user_login_as_email', __( 'Sorry, that email address is not available.' ) );
}
}

$raw_user_url = empty( $userdata['user_url'] ) ? '' : $userdata['user_url'];
Expand Down Expand Up @@ -3596,6 +3614,8 @@ function register_new_user( $user_login, $user_email ) {
$sanitized_user_login = '';
} elseif ( username_exists( $sanitized_user_login ) ) {
$errors->add( 'username_exists', __( '<strong>Error:</strong> This username is already registered. Please choose another one.' ) );
} elseif ( email_exists( $sanitized_user_login ) ) {
$errors->add( 'username_exists_as_email', __( '<strong>Error:</strong> This username is not available. Please choose another one.' ) );
} else {
/** This filter is documented in wp-includes/user.php */
$illegal_user_logins = (array) apply_filters( 'illegal_user_logins', array() );
Expand All @@ -3619,6 +3639,8 @@ function register_new_user( $user_login, $user_email ) {
esc_url( wp_login_url() )
)
);
} elseif ( username_exists( $user_email ) ) {
$errors->add( 'email_exists_as_username', __( '<strong>Error:</strong> This email address is not available. Please choose another one.' ) );
}

/**
Expand Down Expand Up @@ -3924,7 +3946,9 @@ function send_confirmation_on_profile_email( $user_id = 0 ) {
return;
}

if ( email_exists( $_POST['email'] ) ) {
$login_owner_id = username_exists( $_POST['email'] );

if ( email_exists( $_POST['email'] ) || ( $login_owner_id && (int) $login_owner_id !== $current_user->ID ) ) {
$errors->add(
'user_email',
__( '<strong>Error:</strong> The email address is already used.' ),
Expand Down
42 changes: 42 additions & 0 deletions tests/phpunit/tests/rest-api/rest-users-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -1820,6 +1820,48 @@ public function test_update_item_existing_email_case_not_own() {
$this->assertSame( 'rest_user_invalid_email', $data['code'] );
}

/**
* @ticket 57394
*/
public function test_update_item_email_matching_another_user_login() {
self::factory()->user->create(
array(
'user_login' => 'login-57394@example.com',
'user_email' => 'other-57394@example.com',
)
);

wp_set_current_user( self::$editor );

$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', self::$editor ) );
$request->set_param( 'email', 'login-57394@example.com' );
$response = rest_get_server()->dispatch( $request );

$this->assertErrorResponse( 'rest_user_invalid_email', $response, 400 );
}

/**
* @ticket 57394
*/
public function test_update_item_email_matching_own_login() {
$user_id = self::factory()->user->create(
array(
'role' => 'editor',
'user_login' => 'self-57394@example.com',
'user_email' => 'self-other-57394@example.com',
)
);

wp_set_current_user( $user_id );

$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', $user_id ) );
$request->set_param( 'email', 'self-57394@example.com' );
$response = rest_get_server()->dispatch( $request );

$this->assertSame( 200, $response->get_status() );
$this->assertSame( 'self-57394@example.com', $response->get_data()['email'] );
}

public function test_update_item_invalid_locale() {
$user1 = self::factory()->user->create(
array(
Expand Down
Loading
Loading