WordPress User Roles, Explained: What Each One Can Actually Do

Ask five WordPress users what an Editor can do and you will get five answers, and most of them will be wrong. The user role names suggest a tidy ladder — administrator, editor, author, contributor, subscriber — and the ladder exists, but the rungs do not sit where people assume.

An Editor cannot open Appearance → Menus. A Contributor cannot upload an image. A Subscriber is not a customer. An Administrator on a multisite install cannot install a plugin unless they are also a Super Admin.

None of that is a bug. Each of those limits follows from a specific capability, and once you can see the capabilities, the roles stop being a mystery and become a tool you can edit. This is the map.

A Role Is Just a Named List of Capabilities

WordPress does not store “Editor” on a user and check that name at runtime. It stores capabilities — booleans with names like edit_posts, publish_posts, upload_files — and a role is a named bundle of them.

The bundle is saved as an array in the wp_user_roles option. That is the whole mechanism. A user’s roles go in their wp_capabilities user meta, and a user can hold more than one role at a time, which matters later.

Permissions are then checked against capabilities, not roles. When a screen decides whether to show the Plugins menu, it calls current_user_can( 'activate_plugins' ). It never asks “is this person an administrator?”

That indirection is why the roles behave in ways the names do not predict. It is also why you can build a role called Client that has exactly three capabilities and no way to publish anything.

The Five Default Roles

WordPress creates five roles on install. The roles and capabilities documentation lists a sixth, Super Admin, which is a network flag rather than a row in this table.

RoleWrite postsPublish postsEdit others’ postsUpload filesMenus and widgetsPlugins, themes, users
Administratoryesyesyesyesyesyes
Editoryesyesyesyesnono
Authoryesyesown onlyyesnono
Contributoryesnonononono
Subscribernononononono

Read the middle column twice. Those six columns account for almost every support question about roles, and three of the answers are counterintuitive.

Administrator

An Administrator holds every capability that applies to a single site: manage_options for settings, install_plugins, activate_plugins, edit_users, promote_users, edit_theme_options, plus the content capabilities of every role below.

On a multisite network the list shrinks. Network capabilities such as create_sites, manage_network, and manage_network_plugins belong to the Super Admin, and a site Administrator cannot install plugins unless the network allows it. The WordPress documentation calls this out because it trips up people who migrate a single site into a network and find half the admin menu missing.

An Administrator can also edit any other user’s role, including their own. That is the capability that locks people out of their own sites, and there is a recovery command for it below.

Editor

An Editor gets edit_posts, edit_others_posts, publish_posts, edit_pages, edit_others_pages, publish_pages, delete_others_posts, moderate_comments, manage_categories, and upload_files.

In practice that means full control over content: every post and page on the site, published or draft, including other people’s. An Editor can delete an article an Administrator wrote. They can approve or trash any comment. They can create, rename, and delete categories, which changes URLs.

They cannot install a plugin, update core, create a user, or change a password for anyone else.

Author

An Author gets edit_posts, edit_published_posts, publish_posts, upload_files, and read.

The important line is the one that is missing: edit_others_posts. An Author sees only their own posts in the post list. They can publish without review, which is the difference between Author and Contributor, and they can upload images, which is the next difference.

An Author cannot create or edit a page. Pages need edit_pages, and only Administrator and Editor hold it.

Contributor

A Contributor gets edit_posts and read. That is the entire list.

They can write a post and save it as a draft or submit it for review. They cannot publish it, because they lack publish_posts. They cannot upload an image, because they lack upload_files, and the Add Media button is simply absent rather than broken.

This is the role that most often gets assigned by accident to a guest writer who then cannot add a featured image, and the fix is either a capability grant or a move to Author.

Subscriber

A Subscriber gets read. One capability.

read is what makes a user a logged-in user: it grants access to the dashboard, the profile screen, and the admin bar. Nothing else. A Subscriber cannot see a single unpublished post, cannot comment differently from a logged-out visitor, and cannot reach any content feature.

If you are selling memberships, Subscriber on its own protects nothing. The content has to be gated by a plugin that checks a capability the Subscriber does not have, which is why membership plugins ship their own roles.

What the Editor Role Cannot Do

The Editor surprises people most, because “editor” sounds like “runs the site.”

An Editor cannot open Appearance → Menus, Appearance → Widgets, or the Site Editor. Those screens are gated by edit_theme_options, a capability held by Administrator only. A site owner who hires an editor to rearrange the navigation will hand over the login and then field a support call.

An Editor also cannot:

  • Install, update, or delete plugins and themes
  • Update WordPress core
  • Create users, change roles, or reset another person’s password
  • Change site settings such as the permalink structure, reading settings, or the site title
  • Edit robots.txt through a plugin that gates on manage_options

What an Editor can do is more consequential than most people realize. On a single-site install, the Editor role includes unfiltered_html, so their post HTML is not passed through KSES. They can paste script and iframe markup into a post and have it survive. That is not a summary from a role comparison chart; it is the list in core’s role definitions.

On a multisite network that same capability is denied to everyone except a Super Admin. WordPress handles this in map_meta_cap: if the install is multisite and the user is not a super admin, unfiltered_html maps to do_not_allow regardless of what the role says, as the capability source shows. The role still lists the capability. The check still fails. This is the clearest example of why role tables and real behavior can disagree.

Super Admin Is Not a Role

The six-role list includes Super Admin, but it does not live in wp_user_roles with the others. It is a network-level flag stored in the site_admins option, and is_super_admin() reads it.

That difference explains three behaviors:

  1. A Super Admin passes every capability check on every site in the network, including capabilities no role grants.
  2. A site Administrator on a network is not a Super Admin and cannot grant themselves the flag.
  3. On a single-site install the distinction rarely appears, which is why it surprises people the first time they build a network.

If you only ever run one site, you can ignore Super Admin. If you run a network, the question “who is the Super Admin” is a different and more important question than “who is an administrator.”

Check a Capability, Not a Role Name

The single most common bug in role-related plugin code is a role-name check:

// Do not do this.
if ( in_array( 'administrator', (array) $user->roles, true ) ) {
    // show the settings screen
}

It fails in four ways. A user can hold two roles, and $user->roles order is not guaranteed. A Super Admin passes capability checks without that string ever appearing in their roles. A custom role that was deliberately given the capability is excluded. And on multisite, the role check ignores network-level denial entirely.

Use the capability instead:

if ( current_user_can( 'manage_options' ) ) {
    // show the settings screen
}

if ( user_can( $order->get_customer_id(), 'edit_shop_orders' ) ) {
    // acting on another user, not the current one
}

current_user_can() asks about the logged-in user. user_can() asks about a specific user ID, which is what you want in a REST callback, a cron job, or anywhere the actor is not the current session.

One caution: current_user_can() is a policy check, not a security boundary on its own. Every write path still needs a nonce or a permission callback, and every read needs escaping. Capabilities decide who may attempt an action; they do not sanitize what the action receives.

Adding a Custom Role Without the Update Trap

Custom roles are ordinary. A client portal, a vendor dashboard, a translator who may edit drafts but never publish — each is a role with a short capability list.

The trap is in how they get created. add_role() writes to the database and returns null if the role already exists, so calling it on every page load does nothing after the first run. The failure is quieter than that: if you add a capability to your add_role() array in a later plugin version, existing sites never receive it, because the role already exists and the array is ignored.

Seed the role once, then update capabilities through get_role():

add_action( 'init', function () {
	$version = '1.0.3';

	if ( get_option( 'awplife_roles_version' ) === $version ) {
		return;
	}

	$role = get_role( 'client' );

	if ( ! $role ) {
		add_role( 'client', 'Client', array( 'read' => true ) );
		$role = get_role( 'client' );
	}

	if ( $role ) {
		$role->add_cap( 'edit_posts' );
		$role->add_cap( 'upload_files' );
	}

	update_option( 'awplife_roles_version', $version );
} );

Bump $version whenever the capability list changes. The option check keeps init from writing to the database on every request, and the get_role() branch means existing installs pick up the new capabilities while new ones get the same result. The Plugin Handbook page on roles and capabilities covers the same functions, and it is the reference to keep open while writing this code.

Two rules follow from how this works:

  • Never build a role on the Administrator role. Copying administrator and removing a few capabilities leaves the rest, and the rest includes manage_options and edit_users.
  • Clean up on uninstall, not deactivation. remove_role() drops the role but leaves users holding it, and a user whose role no longer exists has no capabilities at all. They can log in to a dashboard with nothing in it.

Auditing Roles With WP-CLI

Guessing at a site’s role setup from the admin screens is slow, and it hides the capability list entirely. Four commands answer most questions:

# Every role on the site
wp role list --fields=role,name --format=table

# The full capability list for one role
wp cap list editor

# Everyone holding the highest role
wp user list --role=administrator --fields=ID,user_login,user_email,roles

# The raw stored structure
wp option get wp_user_roles --format=json

The last one is worth running once. It prints the exact array WordPress consults before any plugin filter touches it, and it makes the role model concrete: a nested set of capability booleans, nothing more.

If you manage more than one site, compare the administrator lists. The usual finding is old accounts that belonged to a contractor, an agency, or a previous developer, still holding full access years later.

When a Role Change Locks You Out

Demoting the last Administrator, or removing your own role while editing your profile, produces a site nobody can administer. WordPress does not prevent it.

WP-CLI recovers it:

wp user add-role 1 administrator
wp user list --role=administrator

The first command restores the role to user ID 1. The second confirms there is at least one other account that can do the same, which is the state you want before you close the terminal.

If you have no command-line access, the recovery path is phpMyAdmin: open wp_usermeta, find the wp_capabilities row for your user, and set it to a serialized array containing the administrator role. That is a fragile edit and a good argument for keeping a second administrator account you control.

Granting Less Without Breaking the Workflow

Least privilege is not a slogan; it is a set of specific decisions about this site. The OWASP guidance on least privilege frames it as granting only the access required to perform a task, for only as long as the task requires it. Applied to WordPress, that produces a short checklist:

  1. One Administrator per person who needs one, and no shared logins. Shared admin accounts destroy the audit trail in the activity log, because every action belongs to the same user.
  2. Editors who need menus get a capability plugin, not the Administrator role. Granting edit_theme_options to the Editor role is one line, and it is far less dangerous than promoting someone to Administrator so they can reorder a menu.
  3. Contributors who need images usually need upload_files only. Add it to the role, not to the person’s role assignment, so the next contributor inherits the same behavior.
  4. Protect every Administrator account with two-factor authentication. The 2FA setup guide covers the enrollment flow, and the WordPress security guide puts it in the wider context of hardening a site.
  5. Review roles after every plugin removal. Plugins that ship custom roles often leave the users behind. A user with a deleted role can log in and do nothing, which looks like a broken account rather than a missing role.

Two smaller items belong on the same list. If you allow public registration, set the default new-user role to Subscriber and check it after every plugin install, because a membership plugin will often change it. And if you accept uploads from non-administrators, restrict what those uploads can contain; upload_files on an Author is normal, upload_files on an open registration form is an incident waiting to happen.

Registration is the other place roles get assigned, and the login and registration setup guide shows where that default is chosen.

The Role Model in One Sentence

A role is a saved list of capability booleans, the user’s list of roles lives in user meta, and every permission question is answered by a capability check that can override the list — which is why the role name is the least reliable thing to test and the capability is the only thing worth trusting.

FAQ

What are the default WordPress user roles?

Administrator, Editor, Author, Contributor, and Subscriber, plus Super Admin on a network. The first five are created on install and stored in the wp_user_roles option.

Can an Editor install plugins?

No. Installing, activating, and updating plugins requires install_plugins, activate_plugins, and update_plugins, which belong to Administrator. On a multisite network those capabilities belong to the Super Admin instead.

Why can’t my Editor edit the menu?

Menus, widgets, and the Site Editor are gated by edit_theme_options, and the Editor role does not include it. Grant that capability to the Editor role through a small plugin, or use a plugin that gives a specific user access to menus only.

Can a Contributor upload images?

Not by default. The Contributor role contains only edit_posts and read, so upload_files is missing and the Add Media button does not appear. Add the capability to the role if the workflow needs it.

What is the difference between Administrator and Super Admin?

Administrator is a role with every capability on one site. Super Admin is a network-level flag stored in the site_admins option that grants every capability on every site in a multisite network. A site Administrator is not a Super Admin.

Do users have to have exactly one role?

No. A user can hold several roles, and the capabilities are combined. That is one reason to check capabilities with current_user_can() instead of reading the roles array.

How do I change the default role for new users?

Settings → General → New User Default Role. Check it after installing a membership or registration plugin, because several of them change it without asking.

Can I create my own role?

Yes. add_role() creates it and stores it in the database, then get_role() returns the object so you can add or remove capabilities later. Guard the code with a version option so capability changes reach existing installs.

A WP Life
A WP Life

Hi! We are A WP Life, we develop best WordPress themes and plugins for blog and websites.