Skip to content
Open
6 changes: 5 additions & 1 deletion src/js/_enqueues/admin/user-profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -512,13 +512,17 @@
if ( select.length ) {
$('#first_name, #last_name, #nickname').on( 'blur.user_profile', function() {
var dub = [],
isEmail = $('#user_login').attr( 'data-is-email' ) === 'true',
inputs = {
display_nickname : $('#nickname').val() || '',
display_username : $('#user_login').val() || '',
display_firstname : $('#first_name').val() || '',
display_lastname : $('#last_name').val() || ''
};

if ( ! isEmail ) {
inputs.display_username = $('#user_login').val() || '';
}

if ( inputs.display_firstname && inputs.display_lastname ) {
inputs.display_firstlast = inputs.display_firstname + ' ' + inputs.display_lastname;
inputs.display_lastfirst = inputs.display_lastname + ' ' + inputs.display_firstname;
Expand Down
50 changes: 50 additions & 0 deletions src/wp-admin/includes/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,56 @@ function default_password_nag() {
);
}

/**
* Computes the public display name options for the user profile screen.
*
* Excludes the user login from display options when the username is an email address,
* preventing email exposure in public author links, feeds, and bylines.
*
* @since 7.2.0
* @access private
*
* @param WP_User|int $user User object or user ID.
* @return string[] Array of unique display name choices.
*/
function _wp_get_user_profile_display_name_options( $user ) {
if ( ! $user instanceof WP_User ) {
$user = get_userdata( $user );
}

if ( ! $user ) {
return array();
}

$public_display = array();
$public_display['display_nickname'] = $user->nickname;

if ( ! is_email( $user->user_login ) ) {
$public_display['display_username'] = $user->user_login;
}

if ( ! empty( $user->first_name ) ) {
$public_display['display_firstname'] = $user->first_name;
}

if ( ! empty( $user->last_name ) ) {
$public_display['display_lastname'] = $user->last_name;
}

if ( ! empty( $user->first_name ) && ! empty( $user->last_name ) ) {
$public_display['display_firstlast'] = $user->first_name . ' ' . $user->last_name;
$public_display['display_lastfirst'] = $user->last_name . ' ' . $user->first_name;
}

if ( ! in_array( $user->display_name, $public_display, true ) ) {
$public_display = array( 'display_displayname' => $user->display_name ) + $public_display;
}

$public_display = array_map( 'trim', $public_display );

return array_values( array_unique( $public_display ) );
}

/**
* Optional SSL preference that can be turned on by hooking to the 'personal_options' action.
*
Expand Down
31 changes: 4 additions & 27 deletions src/wp-admin/user-edit.php
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@
<table class="form-table" role="presentation">
<tr class="user-user-login-wrap">
<th><label for="user_login"><?php _e( 'Username' ); ?></label></th>
<td><input type="text" name="user_login" id="user_login" aria-describedby="user-login-description" value="<?php echo esc_attr( $profile_user->user_login ); ?>" readonly="readonly" class="regular-text ltr" /> <span class="description" id="user-login-description"><?php _e( 'Usernames cannot be changed.' ); ?></span></td>
<td><input type="text" name="user_login" id="user_login" aria-describedby="user-login-description" value="<?php echo esc_attr( $profile_user->user_login ); ?>"<?php echo is_email( $profile_user->user_login ) ? ' data-is-email="true"' : ''; ?> readonly="readonly" class="regular-text ltr" /> <span class="description" id="user-login-description"><?php _e( 'Usernames cannot be changed.' ); ?></span></td>
</tr>

<?php if ( ! IS_PROFILE_PAGE && ! is_network_admin() && current_user_can( 'promote_user', $profile_user->ID ) ) : ?>
Expand Down Expand Up @@ -549,32 +549,9 @@
<td>
<select name="display_name" id="display_name">
<?php
$public_display = array();
$public_display['display_nickname'] = $profile_user->nickname;
$public_display['display_username'] = $profile_user->user_login;

if ( ! empty( $profile_user->first_name ) ) {
$public_display['display_firstname'] = $profile_user->first_name;
}

if ( ! empty( $profile_user->last_name ) ) {
$public_display['display_lastname'] = $profile_user->last_name;
}

if ( ! empty( $profile_user->first_name ) && ! empty( $profile_user->last_name ) ) {
$public_display['display_firstlast'] = $profile_user->first_name . ' ' . $profile_user->last_name;
$public_display['display_lastfirst'] = $profile_user->last_name . ' ' . $profile_user->first_name;
}

if ( ! in_array( $profile_user->display_name, $public_display, true ) ) { // Only add this if it isn't duplicated elsewhere.
$public_display = array( 'display_displayname' => $profile_user->display_name ) + $public_display;
}

$public_display = array_map( 'trim', $public_display );
$public_display = array_unique( $public_display );

?>
<?php foreach ( $public_display as $id => $item ) : ?>
$public_display = _wp_get_user_profile_display_name_options( $profile_user );
foreach ( $public_display as $item ) :
?>
<option <?php selected( $profile_user->display_name, $item ); ?>><?php echo esc_html( $item ); ?></option>
<?php endforeach; ?>
</select>
Expand Down
54 changes: 44 additions & 10 deletions src/wp-includes/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -2198,6 +2198,8 @@ function validate_username( $username ) {
* @since 5.3.0 The `user_activation_key` field can be passed to `$userdata`.
* @since 5.3.0 The `spam` field can be passed to `$userdata` (Multisite only).
* @since 5.9.0 The `meta_input` field can be passed to `$userdata` to allow addition of user meta data.
* @since 7.2.0 Default `display_name`, `nickname`, and `user_nicename` avoid using an email address
* when `$user_login` is an email address.
*
* @global wpdb $wpdb WordPress database abstraction object.
*
Expand All @@ -2208,13 +2210,15 @@ function validate_username( $username ) {
* @type string $user_pass The plain-text user password for new users.
* Hashed password for existing users.
* @type string $user_login The user's login username.
* @type string $user_nicename The URL-friendly user name.
* @type string $user_nicename The URL-friendly user name. Default is a URL-safe version
* of the user's login, or a generated slug (user-{random})
* if the login is an email address.
* @type string $user_url The user URL.
* @type string $user_email The user email address.
* @type string $display_name The user's display name.
* Default is the user's username.
* @type string $nickname The user's nickname.
* Default is the user's username.
* @type string $display_name The user's display name. Default is the user's username,
* or 'User {random}' if the username is an email address.
* @type string $nickname The user's nickname. Default is the user's username,
* or 'User {random}' if the username is an email address.
* @type string $first_name The user's first name. For new users, will be used
* to build the first part of the user's display name
* if `$display_name` is not specified.
Expand Down Expand Up @@ -2370,12 +2374,22 @@ function wp_insert_user( $userdata ) {
return new WP_Error( 'invalid_username', __( 'Sorry, that username is not allowed.' ) );
}

$email_login_suffix = '';
if ( is_email( $user_login ) ) {
$email_login_suffix = bin2hex( random_bytes( 4 ) );
}

/*
* If a nicename is provided, remove unsafe user characters before using it.
* Otherwise build a nicename from the user_login.
* If updating an email-login user and no nicename is provided, preserve existing nicename.
* Otherwise build a nicename from a random slug (if login is an email) or the user_login.
*/
if ( ! empty( $userdata['user_nicename'] ) ) {
$user_nicename = sanitize_user( $userdata['user_nicename'], true );
} elseif ( $update && is_email( $user_login ) && ! empty( $old_user_data->user_nicename ) ) {
$user_nicename = $old_user_data->user_nicename;
} elseif ( is_email( $user_login ) ) {
$user_nicename = 'user-' . $email_login_suffix;
} else {
$user_nicename = mb_substr( $user_login, 0, 50 );
}
Expand Down Expand Up @@ -2463,7 +2477,17 @@ function wp_insert_user( $userdata ) {
// Store values to save in user meta.
$meta = array();

$nickname = empty( $userdata['nickname'] ) ? $user_login : $userdata['nickname'];
if ( empty( $userdata['nickname'] ) ) {
if ( $update && is_email( $user_login ) && ! empty( $old_user_data->nickname ) ) {
$nickname = $old_user_data->nickname;
} elseif ( is_email( $user_login ) ) {
$nickname = 'User ' . $email_login_suffix;
} else {
$nickname = $user_login;
}
} else {
$nickname = $userdata['nickname'];
}

/**
* Filters a user's nickname before the user is created or updated.
Expand Down Expand Up @@ -2498,7 +2522,13 @@ function wp_insert_user( $userdata ) {

if ( empty( $userdata['display_name'] ) ) {
if ( $update ) {
$display_name = $user_login;
if ( is_email( $user_login ) && ! empty( $old_user_data->display_name ) ) {
$display_name = $old_user_data->display_name;
} elseif ( is_email( $user_login ) ) {
$display_name = 'User ' . $email_login_suffix;
} else {
$display_name = $user_login;
}
} elseif ( $meta['first_name'] && $meta['last_name'] ) {
$display_name = sprintf(
/* translators: 1: User's first name, 2: Last name. */
Expand All @@ -2510,6 +2540,8 @@ function wp_insert_user( $userdata ) {
$display_name = $meta['first_name'];
} elseif ( $meta['last_name'] ) {
$display_name = $meta['last_name'];
} elseif ( is_email( $user_login ) ) {
$display_name = 'User ' . $email_login_suffix;
} else {
$display_name = $user_login;
}
Expand Down Expand Up @@ -2581,8 +2613,10 @@ function wp_insert_user( $userdata ) {
* @type string $user_pass The user's password.
* @type string $user_email The user's email.
* @type string $user_url The user's url.
* @type string $user_nicename The user's nice name. Defaults to a URL-safe version of user's login.
* @type string $display_name The user's display name.
* @type string $user_nicename The user's nice name. Defaults to a URL-safe version of user's login,
* or a generated slug (user-{random}) if the login is an email address.
* @type string $display_name The user's display name. Defaults to the user's username, or
* 'User {random}' if the username is an email address.
* @type string $user_registered MySQL timestamp describing the moment when the user registered. Defaults to
* the current UTC timestamp.
* }
Expand Down
Loading
Loading