Edit WordPress usernames programmatically
Published: – Leave a comment
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:
<?php
global $wpdb;
$site_admins = [];
if ( \is_multisite() ) {
$site_admins = \get_site_option( 'site_admins' );
}
$users = \get_users( [
'blog_id' => 0,
'fields' => [
'ID',
'user_email',
'user_login',
],
] );
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;
},
$site_admins
);
\update_site_option( 'site_admins', $site_admins );
}
// update the user in the database
$wpdb->update(
$wpdb->users,
[ '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.