While creating a WordPress user there’s no information that the username cannot be changed later. But what to do if you need to change it? The field in the profile edit page is disabled and also enabling it manually via the developer tools won’t trick WordPress – yeah, I tried that. But also using wp_update_user doesn’t update the username, since the field user_login will be explicitly excluded from being updated.

You could just update the username in the database if you have access to it, but since this won’t invalidate the caches, setups with a persistent object cache like Redis won’t update the username. So I searched for a solution.

In my case all usernames were firstname.lastname@domain.tld, which came from a single sign on (SSO) plugin. Since we moved to a different SSO plugin to login, the username format changed to just firstname.lastname. So we needed to get rid of the @domain.tld in the end.

Additionally, if it’s a multisite, you need to update the super admins, too. This information is stored in the site option site_admins and contains a list of usernames (whoever thought it would be a good idea to use the usernames instead of the user IDs 🥲).

This is my code:

global $wpdb;

$site_admins = [];

if ( \is_multisite() ) {
	$site_admins = \get_site_option( 'site_admins' );

$users = \get_users( [
	'blog_id' => 0,
	'fields' => [
] );

foreach ( $users as $user ) {
	// do our desired replacements
	if ( ! \str_contains( $user->user_login, '@domain.tld' ) && \str_contains( $user->user_email, '@domain.tld' ) ) {
		$new_username = \str_replace( '@domain.tld', '', $user->user_email );
	else {
		$new_username = \str_replace( '@domain.tld', '', $user->user_login );
	// update user only if if the username changes
	if ( $user->user_login !== $new_username ) {
		echo 'Change ' . \esc_html( $user->user_login ) . ' to ' . \esc_html( $new_username ) . \PHP_EOL;
		// check if current user is a super admin
		if ( \in_array( $user->user_login, $site_admins, true ) ) {
			$user_loginname = $user->user_login;
			// replace this user's name in the list of super admins
			$site_admins = \array_map(
				function( $username ) use ( $user_loginname, $new_username ) {
					return $username === $user_loginname ? $new_username : $username;
			\update_site_option( 'site_admins', $site_admins );
		// update the user in the database
			[ 'user_login' => $new_username ],
			[ 'ID' => $user->ID ]
		// invalidate object cache
		\clean_user_cache( $user->ID );
Code language: PHP (php)

Since you cannot use any builtin function to update the username, we need to use a database update statement directly. Additionally, to clear the object cache, we need to use clean_user_cache to invalidate the cache for the given user.

I used this code in a file and called it directly via WP-CLI’s wp eval-file. On a multisite, there’s no need to run it multiple times for each site since the user data is stored globally.

Leave a Reply

Your email address will not be published. Required fields are marked *