,

How to Rename WordPress User Roles Safely

How to Rename WordPress User Roles Safely

On a recent client project, we ran into a surprisingly annoying UX bug: user roles with old names that no longer matched the business.

The client runs a subscription-based WordPress site. At launch they had separate “Print” and “Digital” products, with roles like:

  • Customer Print Access
  • Former Customer Print Access

Later, they introduced a combined “Bundle” subscription (print + digital). Marketing and support started talking about “Bundle access”, and some newer roles reflected that, for example:

  • Customer Bundle Access (Ordered)

But the old roles were still showing as “Print Access” in the WordPress admin. Support agents saw “Print”, “Digital”, and “Bundle” side-by-side and had to guess which role was actually active for which subscription. The only thing wrong was the label; the underlying permissions and role IDs were fine.

This post walks through how we fixed it via a small WP-CLI migration, and then offers easier alternatives for non-technical site owners.

Notice: This issue is one we’ve personally encountered. You can explore similar cases and their solutions in our WordPress Bug Fixing category.


How WordPress actually stores role labels

WordPress user roles are made of two key pieces:

  • A role ID / slug (e.g. administrator, editor, bundle, print-ex)
  • A display label (e.g. “Administrator”, “Customer Bundle Access”)

Internally, all roles live in a single option in the database: wp_user_roles (or {prefix}_user_roles on sites with a custom prefix). According to the official WP_Roles class documentation, that option is an array keyed by role ID, where each entry contains a name (the label) and a capabilities array.

A simplified shape looks like this:

[
  'print' => [
    'name'         => 'Customer Print Access',
    'capabilities' => [
      'read' => true,
      // …
    ],
  ],
  // …
];

When you create roles with add_role(), WordPress writes them into this wp_user_roles option using the role ID, the display label, and the capabilities you pass.

Two important implications:

  1. Calling add_role( 'print', 'Customer Bundle Access', $caps ) does not rename an existing role; it just skips creation if the ID already exists.
  2. The built-in WP-CLI wp role commands let you list, create, delete, and reset roles — but they don’t have a “rename label only” subcommand.

In our case, that meant the “Print” roles were stuck with old labels inside wp_user_roles, even though the rest of the system had moved on to “Bundle” terminology.


Constraints for the fix

Before touching any code, we set some guardrails:

  • ✅ Keep the role IDs (e.g. print, print-ex) exactly the same
  • ✅ Don’t change capabilities (permissions must stay identical)
  • ✅ Don’t create or delete roles (many users already have them)
  • ✅ Make it a one-time migration we can run via WP-CLI
  • ✅ Make it idempotent (safe to run multiple times)
  • ✅ Avoid adding plugins just for this

So we didn’t want to do “delete the role and recreate it”; we just wanted to update the name field for two existing entries in wp_user_roles.


A one-time WP-CLI helper to rename role labels

Instead of writing a full custom command, we added a small static method and invoked it with wp eval. Here’s a simplified version you can adapt.

Imagine you want:

  • Customer Print AccessCustomer Bundle Access
  • Former Customer Print AccessFormer Customer Bundle Access

Add this to a class that’s autoloaded (for example, MyVendor\Schema):

namespace MyVendor;

class Schema
{
    /**
     * Keep the DB's role labels in sync for two legacy roles.
     * Safe to re-run (no-op if already correct).
     *
     * Run:
     *   wp eval '\MyVendor\Schema::syncRoleLabelsWithSubscriptions();'
     */
    public static function syncRoleLabelsWithSubscriptions(): void {
        global $wpdb;

        $option_name  = $wpdb->prefix . 'user_roles';
        $roles_option = get_option($option_name);

        if (!is_array($roles_option)) {
            \WP_CLI::error("Option '{$option_name}' is missing or not an array. Aborting.");
            return;
        }

        // Desired labels (new naming).
        $target_labels = [
            'print'    => 'Customer Bundle Access',
            'print-ex' => 'Former Customer Bundle Access',
        ];

        $changes = [];

        foreach ($target_labels as $role => $new_label) {
            if (!isset($roles_option[$role]['name'])) {
                \WP_CLI::warning("Role '{$role}' not found; skipping.");
                continue;
            }

            $current_label = (string) $roles_option[$role]['name'];

            if ($current_label !== $new_label) {
                $roles_option[$role]['name'] = $new_label;
                $changes[$role] = [$current_label, $new_label];
                \WP_CLI::log("✓ Will update '{$role}': '{$current_label}' → '{$new_label}'");
            } else {
                \WP_CLI::log("• '{$role}' already OK ('{$current_label}'); no change.");
            }
        }

        if (!$changes) {
            \WP_CLI::success('No changes necessary. All role labels are already correct.');
            return;
        }

        $updated = update_option($option_name, $roles_option, true);
        if ($updated) {
            \WP_CLI::log("Persisted changes to option '{$option_name}'.");
        } else {
            \WP_CLI::warning("update_option returned false; the option may already contain the new values.");
        }

        \WP_CLI::log('Updated role labels:');
        foreach ($changes as $role => [$old, $new]) {
            \WP_CLI::log("- {$role}: '{$old}' -> '{$new}'");
        }

        \WP_CLI::success('Role label sync complete.');
    }
}

This function:

  • Reads the wp_user_roles option
  • Looks up the two role IDs we care about (print and print-ex)
  • Compares the current name with the desired label
  • If they differ, updates the label and logs what changed
  • Saves the updated array back with update_option()

Because it’s idempotent, running it again later just prints “already OK” and exits.


Running it with WP-CLI

Once the code is deployed, you can run the migration like this:

wp eval '\MyVendor\Schema::syncRoleLabelsWithSubscriptions();'

You should see output along the lines of:

✓ Will update 'print': 'Customer Print Access' → 'Customer Bundle Access'
✓ Will update 'print-ex': 'Former Customer Print Access' → 'Former Customer Bundle Access'
Persisted changes to option 'wp_user_roles'.
Updated role labels:
- print: 'Customer Print Access' -> 'Customer Bundle Access'
- print-ex: 'Former Customer Print Access' -> 'Former Customer Bundle Access'
Success: Role label sync complete.

From that point forward, the WordPress admin will show the new labels everywhere roles are displayed, without changing permissions or user assignments.

If you’re curious about broader role/CLI tooling, the official wp role command docs and the separate wp cap command docs are worth a skim.


Why not just use built-in WP-CLI role commands?

WP-CLI’s wp role commands let you:

  • List roles
  • Check if a role exists
  • Create new roles
  • Delete roles
  • Reset default roles to their default capabilities

What they don’t provide is a way to say “change only the display name of this existing role ID”.

Under the hood, roles and their labels are stored in that wp_user_roles option. If you edit it incorrectly, you can lock yourself out of the admin entirely — there are horror stories on places like WordPress Stack Exchange where manually editing wp_user_roles went wrong.

Our helper is essentially a tiny, targeted data migration: it updates the name field for two known role IDs and leaves everything else untouched.


Easier options for non-technical users

If all of this code and wp eval talk feels a bit much, there are friendlier approaches.

1. Use a role management plugin

Several plugins expose role labels directly in the WordPress admin:

  • PublishPress Capabilities – lets you rename roles from its Capabilities → Roles screen; their docs show exactly how to change a role’s “Role Name” field without touching the ID. See their guide on renaming WordPress user roles. (PublishPress)
  • WPFront User Role Editor – explicitly distinguishes between Display Name and Role Name and lets you edit the display name for existing roles. Their plugin page explains how it works.

Typical steps with these tools:

  1. Install and activate the plugin from Plugins → Add New.
  2. Open the plugin’s Roles or Capabilities page.
  3. Select the role with the outdated label (e.g. “Customer Print Access”).
  4. Change only the display name to your new wording (e.g. “Customer Bundle Access”).
  5. Save.

Behind the scenes, the plugin updates the wp_user_roles option for you, similar to what our WP-CLI helper does, but with a nice UI.

Tip: Before changing roles or capabilities, take a backup. If something goes wrong, you can always restore. Good general guides, like this user role overview on WPBeginner, help you understand what each role actually does.


2. Ask your developer or host to run the migration for you

If you’re a site owner with access to a developer or managed hosting support:

  • Share the requirement in plain language:
    “Rename role labels Customer Print AccessCustomer Bundle Access and Former Customer Print AccessFormer Customer Bundle Access, but don’t change permissions or which users have which roles.”
  • Ask them to implement a small helper like the one above and run it once via WP-CLI.
  • Have them test on staging first, then production.

For a developer familiar with roles and the add_role() / WP_Roles APIs, this is a quick, well-bounded task.


3. For very small sites: create new roles and migrate users

On very small sites with only a handful of users, another (simpler, but more disruptive) option is:

  1. Use a role editor plugin to create new roles with the correct names (e.g. “Customer Bundle Access”).
  2. In Users → All Users, edit each affected user and switch them to the new role.
  3. Once no one is using the old roles anymore, delete them.

This approach changes the role IDs themselves, so it’s only safe if your theme and plugins are not checking for the old role IDs (e.g. $user->has_role( 'print' )). For anything beyond a simple brochure site, I usually prefer the “rename label only” approach instead.


Takeaways

A few things this little bug fix reinforced:

  • WordPress stores role labels and capabilities together in wp_user_roles, keyed by role ID. Changing labels is a data migration problem, not just a code problem.
  • Core and WP-CLI give you great tools for managing roles — but not a built-in “rename label” command, so you either:
    • use a role editor plugin, or
    • write a small script to update wp_user_roles safely.
  • For complex membership or subscription sites, a small, idempotent WP-CLI helper is often the safest and most auditable way to align your role naming with how your business actually talks.

If your marketing, support, and product names have evolved but your WordPress roles haven’t, it’s worth cleaning them up. Even a tiny change — like “Print Access” → “Bundle Access” — can make life quite a bit easier for everyone who lives in the admin every day.

  • How To Use the WordPress Register Sidebar Function

    How To Use the WordPress Register Sidebar Function

    In this article, we’ll explore practical approaches for using the WordPress register sidebar function. We’ll also share some advanced techniques to help you get even more out of your sidebars! WordPress Register Sidebar – Single If you’d like to add a sidebar to your WordPress theme, the first step is to let WordPress know about…

  • How to Rename WordPress User Roles Safely

    How to Rename WordPress User Roles Safely

    On a recent client project, we ran into a surprisingly annoying UX bug: user roles with old names that no longer matched the business. The client runs a subscription-based WordPress site. At launch they had separate “Print” and “Digital” products, with roles like: Later, they introduced a combined “Bundle” subscription (print + digital). Marketing and…