Repository navigation
Conversation
…e to an email address.
When an account is created with an email address as the username (user_login), defaulting display_name, nickname, or user_nicename to that username exposes the user's email address publicly in post bylines, feeds, comment markup, REST API responses, and author archive URLs.
This changeset updates user handling:
* In wp_insert_user(), when $user_login is an email address and no explicit names are supplied, display_name and nickname fall back to a neutral string ('User') instead of the email address.
* In wp_insert_user(), user_nicename is generated as an unexposed random slug (user-{random}) rather than slugifying the email address.
* When updating an existing user with an email username and no user_nicename is passed, the existing user_nicename is preserved.
* In user-edit.php and user-profile.js, display_username is excluded from the "Display name publicly as" options when the username is an email address.
* Adds dedicated unit tests in tests/phpunit/tests/user/wpInsertUser.php covering new user creation, complex email addresses, explicit name overrides, existing user updates, and filter interactions.
Props therssoftware.
Fixes #66446.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. Props Bot commandsYou can trigger Props Bot actions by commenting on this PR:
|
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
|
Thanks for the patch! I tested it locally on single-site and multisite, and the account-default changes passed. I left you feedback on Trac suggesting the profile dropdown changes should not go into this initial fix: https://core.trac.wordpress.org/ticket/66446 |
Restores user-edit.php and user-profile.js so the "Display name publicly as" dropdown remains unchanged, focusing this changeset strictly on account defaults for newly registered users in wp_insert_user(). Props therssoftware, dpknauss. See #66446.
|
Some review observations: The patch covers all three parts of the proposal on Trac #66446: no email fallback for A few notes: On the neutral default
Smaller notes
Test gaps
|
…lose test gaps.
Updates wp_insert_user() to use bin2hex( random_bytes( 4 ) ) for generating
an unexposed, unique random suffix for email logins ('User {suffix}' and
'user-{suffix}'). Scopes nicename preservation on update strictly to email logins.
Aligns user-edit.php and user-profile.js via data-is-email attribute.
Adds tests for downstream privacy, multisite, legacy account updates,
and profile options.
Props therssoftware, dpknauss.
See #66446.
|
Thanks for the thorough and insightful review, @dknauss! I've pushed updates addressing all of your observations:
|
There was a problem hiding this comment.
Thanks for the update. I tested 53264a2 on disposable single-site and multisite installs using PHP 8.4 and SQLite. New accounts created through wp_create_user() and wpmu_create_user() got matching anonymous display-name, nickname, and slug suffixes. Public REST names, REST slugs, and author URLs reflected the anonymous defaults. wp_update_user() preserved an explicitly saved legacy email display name.
I found one update regression in both installs. Two calls to wp_insert_user() with the same existing ID and login, changing only the description and leaving the public name fields out, generated two different display names and nicknames. The author slug stayed fixed. An integration that calls wp_insert_user() directly can therefore change someone’s public byline every time it syncs their profile. Could we preserve the stored display name and nickname when those keys are omitted on update and add coverage for that case? The current legacy test exercises wp_update_user(), which merges stored fields before calling wp_insert_user().
One test gap remains on the profile screen. The new test builds its own array by repeating the condition from user-edit.php. It would still pass if the dropdown or its JS blur handler offered the email login. Could the test exercise the actual profile dropdown, both on initial render and after editing the nickname?
AI assistance: Yes. OpenAI Codex ran the PHP fixtures, inspected the patch, and drafted this review with me.
Trac ticket: #66446
What
Prevents WordPress from automatically using an email address as a user's public
display_name,nickname, oruser_nicenamewhen accounts are created with an email address as their username (user_login).Why
Many sites and plugins (membership plugins, WooCommerce, SSO integrations, self-registration) register users whose
user_loginis formatted as an email address. Currently:display_name: Falls back to$user_login(john@example.com) if first/last names are absent. This gets exposed in post bylines viaget_the_author(), RSS/Atom feeds (<dc:creator>), oEmbed data, and the public REST API (/wp/v2/users).nickname: Defaults to$user_login(john@example.com).user_nicename: Generatessanitize_title( $user_login )(johnexample-com), exposing the user's email domain and local-part in author archive URLs (/author/johnexample-com/), sitemaps, and comment CSS classes (comment-author-{nicename}).user-edit.php&user-profile.js: Unconditionally offersuser_loginin the "Display name publicly as" select dropdown.Because WordPress accounts allow authenticating with email addresses (since 4.5), exposing the email address as a public display name and URL slug presents both an account enumeration surface and a privacy violation (GDPR Art. 25(2) - data protection by default).
How
wp_insert_user()insrc/wp-includes/user.php:display_name&nickname: When$user_loginis an email address (is_email( $user_login )) and no explicit names are provided, default to a neutral string (__( 'User' )) instead of the email address. Explicit first/last names or explicitdisplay_nameinputs still take precedence.user_nicename: When$user_loginis an email address and no explicit nicename is passed, generate an unexposed random slug ('user-' . strtolower( wp_generate_password( 8, false, false ) )) rather than slugifying the email domain into the URL.$update = true) where no newuser_nicenameis provided in$userdata, preserve$old_user_data->user_nicenameso existing accounts and author links are never altered.@since 7.2.0changelog and@typedescriptions for$display_name,$nickname, and$user_nicename.src/wp-admin/user-edit.php:$public_display['display_username']from the "Display name publicly as" dropdown whenis_email( $profile_user->user_login )is true.src/js/_enqueues/admin/user-profile.js:blur.user_profileevent handler, avoid re-addingdisplay_usernameif the username contains an@/ email address.Dedicated Unit Tests (
tests/phpunit/tests/user/wpInsertUser.php):wp_create_user(), complex email addresses, and filter overrides (pre_user_display_name,pre_user_nickname,pre_user_nicename).Testing Instructions
Automated Tests
Run PHPUnit tests across single-site and multisite:
Expected output:
OK (11 tests, 42 assertions)on both single-site and multisite.0 errors, 0 warningson PHPCS.Manual Testing
wp_create_user( 'member@example.com', 'password', 'member@example.com' )).member@example.comand Email =member@example.comwithout providing First Name or Last Name.User, notmember@example.com./author/user-{random}/, not/author/memberexample-com/.regularuser):display_name,nickname, anduser_nicenametoregularuseras before.