Bulk User Removal for WordPress Sites

Recently a web agency asked if I could remove a list of WordPress accounts, if found, from all of their websites. They gave me a list of 15 old email account of which they wanted removed from their 42 sites. I told them, “sure thing!“. This is how I accomplished that.

SSH and WP-CLI are your friends.

First off the following method will only work if each WordPress site is SSH and WP-CLI accessible. With WP-CLI you can do a simple delete with wp user delete <user|email>. However running that arbitrarily on a batch of sites is asking for trouble as any pages or posts owned by own one of those users to become orphaned. I wanted the removal process to be smart and properly assign content to another user.

Hunt from specific account then reassign.

Most of these websites had another common primary account which works for reassignment purposes. If that primary account wasn’t found it I decided it would be best if it skipped over the deletion process and notify me for manual removal. If found it would loop through and remove each user and reassign content to the primary user using the --reassign=<user_id> argument. Create the following script in a file named hunt-and-remove-users.sh and replace the primary_user and users_to_remove bash variables.

primary_user=adminuser
users_to_remove=( oudated-email-1@domain.tld oudated-email-2@domain.tld oudated-email-2@domain.tld )

fetch_user=$( wp user get $primary_user --field=user_login )
home=$( wp option get home )

if [[ $fetch_user != "" ]]; then

    echo "Removing users from $home"
    new_id=$( wp user get $primary_user --field=ID )

    for user in ${users_to_remove[@]}; do
        fetch_user_to_remove=$( wp user get $user --field=user_login )
        if [[ $fetch_user_to_remove != "" ]]; then
            echo "Removing user $fetch_user_to_remove from $home"
            wp user delete $fetch_user_to_remove --reassign=$new_id
        fi
    done

else
    echo "Skipping $home"
fi

Next run this script on any number of websites. Within my toolkit, CaptainCore, that would be running captaincore ssh sitename1 sitename2 sitename3 --script=hunt-and-remove-users.sh. If your doing it from scratch then your script might look something like this.

ssh sitename1@12.34.56.78 -p 12345 "bash -s" < hunt-and-remove-users.sh
ssh sitename2@12.34.56.78 -p 23456 "bash -s" < hunt-and-remove-users.sh
ssh sitename3@12.34.56.78 -p 34567 "bash -s" < hunt-and-remove-users.sh

Capturing results from script

In bash to capture output you simply do the command followed by > filename.log. That will pipe the results of the script into a file. This particular script can be a bit noisy resulting in output that looks like the following.

Error: Invalid user ID, email or login: 'oudated-email-1@domain.tld'
Error: Invalid user ID, email or login: 'oudated-email-2@domain.tld'
Error: Invalid user ID, email or login: 'oudated-email-3@domain.tld'
Removing user oudateduser1 from https://sitename3.kinsta.cloud
Error: Invalid user ID, email or login: 'oudated-email-1@domain.tld'
Success: Removed user 12 from https://sitename3.kinsta.cloud.
Error: Invalid user ID, email or login: 'oudated-email-2@domain.tld'
Error: Invalid user ID, email or login: 'oudated-email-3@domain.tld'

While the script could be coded to produce cleaner output I decided to just let it be noisy and parse the results I wanted using https://regexr.com with a few basic regular expressions like Removing.+ and Skipping.+.

Running the script on 42 sites only took a few minutes to complete 🤖. I’m glad that I didn’t have to manually check and remove them 😄. With that I was able to send a report back to the agency of all of the users found and removed as part of running the hunt-and-remove-users.sh script.