WP_Roles{} │ WP 2.0.0 │ AllowDynamicProperties

The class lets you manage roles and role capabilities in WordPress.

Role options are simple. The structure is organized by role name, which is the key of the main array. A role's capabilities are in a nested array with two parameters: name and capabilities:

[
	'rolename' => [
	   'name' => 'rolename',
	   'capabilities' => []
	]
]

Works together with WP_Role, which creates objects for the $this->role_objects property.

Roles and capabilities are not generated continuously; they are stored in the wp_user_roles option.

To get the global instance of this class, always use the wp_roles() helper function.

Hooks from the class

Usage

global $wp_roles;
$wp_roles = new WP_Roles();

// or simply
$wp_roles = wp_roles();

Class properties

$roles(array)

List of roles and capabilities. Similar to the $role_objects property and has the following structure:

[
   'rolename' => [
   'name' => 'rolename',
   'capabilities' => []
   ]
]
$role_objects(array)

List of role objects. Has the following structure:

[
   'rolename' => [
	   'name' => 'rolename',
	   'capabilities' => []
   ]
]
$role_names(array)

List of role names only:

[role_names] => [
	[administrator] => Administrator
	[editor] => Editor
	[author] => Author
	[contributor] => Contributor
	[subscriber] => Subscriber
]
$role_key(string)
The name of the option that contains the role list, for example: 'wp_user_roles'.
$use_db(bool)
Whether to use the database to retrieve and store roles.

Methods

__construct()(public)
Constructor. Calls _init().
Returns: nothing
__call( $name, $arguments ) (public)
For backward compatibility, so non-existent methods work.
Returns: false/mixed
_init()(protected)

Sets object properties. Uses the globals: $wpdb, $wp_user_roles.

If the global $wp_user_roles is not set, the "{$wpdb->prefix}user_roles" expression is used as the key.
Returns: nothing

reinit() (public)
Reinitializes the object. Usually called by switch_to_blog() after it switches wpdb to another site in a Multisite installation.
Returns: nothing
add_role( $role, $display_name, $capabilities = [] ) (public)
Adds a role with capabilities to the list. Updates the role list if the role does not already exist.
Capabilities are defined in this format: [ 'read' => true ];
To deny the specified capability, set its value to false: [ 'read' => false ];
This method has a wrapper function: add_role().
Returns: WP_Role|nothing. WP_Role if the role was added.
remove_role( $role ) (public)
Removes a role by name. This method has a wrapper function: remove_role().
Returns: nothing
add_cap( $role, $cap, $grant = true ) (public)
Adds the $cap capability to the role specified in $role. The boolean $grant determines whether to grant or deny the capability. See add_cap() for details.
Returns: nothing
remove_cap( $role, $cap ) (public)
Removes the $cap capability from the role specified in $role.
Returns: nothing
get_role( $role ) (public)
Retrieves the specified role object.
Returns: a WP_Role object if the role is found, or null if it does not exist.
get_names()(public)
Retrieves an array of all role names.
Returns: an array of names
is_role( $role ) (public)
Checks whether the specified role exists in the current role list.
Returns: true|false

Examples

#1 What the roles array contains

print_r( wp_roles() );
/*
WP_Roles Object
(
	[roles] => Array
		(
			[administrator] => Array
				(
					[name] => Administrator
					[capabilities] => Array
						(
							[switch_themes] => 1
							[edit_themes] => 1
							[activate_plugins] => 1
							[edit_plugins] => 1
							[edit_users] => 1
							[edit_files] => 1
							[manage_options] => 1
							[moderate_comments] => 1
							[manage_categories] => 1
							[manage_links] => 1
							[upload_files] => 1
							[import] => 1
							[unfiltered_html] => 1
							[edit_posts] => 1
							[edit_others_posts] => 1
							[edit_published_posts] => 1
							[publish_posts] => 1
							[edit_pages] => 1
							[read] => 1
							[level_10] => 1
							[level_9] => 1
							[level_8] => 1
							[level_7] => 1
							[level_6] => 1
							[level_5] => 1
							[level_4] => 1
							[level_3] => 1
							[level_2] => 1
							[level_1] => 1
							[level_0] => 1
							[edit_others_pages] => 1
							[edit_published_pages] => 1
							[publish_pages] => 1
							[delete_pages] => 1
							[delete_others_pages] => 1
							[delete_published_pages] => 1
							[delete_posts] => 1
							[delete_others_posts] => 1
							[delete_published_posts] => 1
							[delete_private_posts] => 1
							[edit_private_posts] => 1
							[read_private_posts] => 1
							[delete_private_pages] => 1
							[edit_private_pages] => 1
							[read_private_pages] => 1
							[delete_users] => 1
							[create_users] => 1
							[unfiltered_upload] => 1
							[edit_dashboard] => 1
							[update_plugins] => 1
							[delete_plugins] => 1
							[install_plugins] => 1
							[update_themes] => 1
							[install_themes] => 1
							[manage_downloads] => 1
							[manage_database] => 1
							[democracy_admin] => 1
							[update_core] => 1
							[list_users] => 1
							[remove_users] => 1
							[add_users] => 1
							[promote_users] => 1
							[edit_theme_options] => 1
							[delete_themes] => 1
							[export] => 1
						)

				)

			[editor] => Array
				(
					[name] => Editor
					[capabilities] => Array
						(
							[moderate_comments] => 1
							[manage_categories] => 1
							[manage_links] => 1
							[upload_files] => 1
							[unfiltered_html] => 1
							[edit_posts] => 1
							[edit_others_posts] => 1
							[edit_published_posts] => 1
							[publish_posts] => 1
							[edit_pages] => 1
							[read] => 1
							[level_7] => 1
							[level_6] => 1
							[level_5] => 1
							[level_4] => 1
							[level_3] => 1
							[level_2] => 1
							[level_1] => 1
							[level_0] => 1
							[edit_others_pages] => 1
							[edit_published_pages] => 1
							[publish_pages] => 1
							[delete_pages] => 1
							[delete_others_pages] => 1
							[delete_published_pages] => 1
							[delete_posts] => 1
							[delete_others_posts] => 1
							[delete_published_posts] => 1
							[delete_private_posts] => 1
							[edit_private_posts] => 1
							[read_private_posts] => 1
							[delete_private_pages] => 1
							[edit_private_pages] => 1
							[read_private_pages] => 1
							[democracy_admin] => 1
						)

				)

			[author] => Array
				(
					[name] => Author
					[capabilities] => Array
						(
							[upload_files] => 1
							[edit_posts] => 1
							[edit_published_posts] => 1
							[publish_posts] => 1
							[read] => 1
							[level_2] => 1
							[level_1] => 1
							[level_0] => 1
							[delete_posts] => 1
							[delete_published_posts] => 1
						)

				)

			[contributor] => Array
				(
					[name] => Contributor
					[capabilities] => Array
						(
							[edit_posts] => 1
							[read] => 1
							[level_1] => 1
							[level_0] => 1
							[delete_posts] => 1
						)

				)

			[subscriber] => Array
				(
					[name] => Subscriber
					[capabilities] => Array
						(
							[read] => 1
							[level_0] => 1
						)

				)

		)

	[role_objects] => Array
		(
			[administrator] => WP_Role Object
				(
					[name] => administrator
					[capabilities] => Array
						(
							[switch_themes] => 1
							[edit_themes] => 1
							[activate_plugins] => 1
							[edit_plugins] => 1
							[edit_users] => 1
							[edit_files] => 1
							[manage_options] => 1
							[moderate_comments] => 1
							[manage_categories] => 1
							[manage_links] => 1
							[upload_files] => 1
							[import] => 1
							[unfiltered_html] => 1
							[edit_posts] => 1
							[edit_others_posts] => 1
							[edit_published_posts] => 1
							[publish_posts] => 1
							[edit_pages] => 1
							[read] => 1
							[level_10] => 1
							[level_9] => 1
							[level_8] => 1
							[level_7] => 1
							[level_6] => 1
							[level_5] => 1
							[level_4] => 1
							[level_3] => 1
							[level_2] => 1
							[level_1] => 1
							[level_0] => 1
							[edit_others_pages] => 1
							[edit_published_pages] => 1
							[publish_pages] => 1
							[delete_pages] => 1
							[delete_others_pages] => 1
							[delete_published_pages] => 1
							[delete_posts] => 1
							[delete_others_posts] => 1
							[delete_published_posts] => 1
							[delete_private_posts] => 1
							[edit_private_posts] => 1
							[read_private_posts] => 1
							[delete_private_pages] => 1
							[edit_private_pages] => 1
							[read_private_pages] => 1
							[delete_users] => 1
							[create_users] => 1
							[unfiltered_upload] => 1
							[edit_dashboard] => 1
							[update_plugins] => 1
							[delete_plugins] => 1
							[install_plugins] => 1
							[update_themes] => 1
							[install_themes] => 1
							[manage_downloads] => 1
							[manage_database] => 1
							[democracy_admin] => 1
							[update_core] => 1
							[list_users] => 1
							[remove_users] => 1
							[add_users] => 1
							[promote_users] => 1
							[edit_theme_options] => 1
							[delete_themes] => 1
							[export] => 1
						)

				)

			[editor] => WP_Role Object
				(
					[name] => editor
					[capabilities] => Array
						(
							[moderate_comments] => 1
							[manage_categories] => 1
							[manage_links] => 1
							[upload_files] => 1
							[unfiltered_html] => 1
							[edit_posts] => 1
							[edit_others_posts] => 1
							[edit_published_posts] => 1
							[publish_posts] => 1
							[edit_pages] => 1
							[read] => 1
							[level_7] => 1
							[level_6] => 1
							[level_5] => 1
							[level_4] => 1
							[level_3] => 1
							[level_2] => 1
							[level_1] => 1
							[level_0] => 1
							[edit_others_pages] => 1
							[edit_published_pages] => 1
							[publish_pages] => 1
							[delete_pages] => 1
							[delete_others_pages] => 1
							[delete_published_pages] => 1
							[delete_posts] => 1
							[delete_others_posts] => 1
							[delete_published_posts] => 1
							[delete_private_posts] => 1
							[edit_private_posts] => 1
							[read_private_posts] => 1
							[delete_private_pages] => 1
							[edit_private_pages] => 1
							[read_private_pages] => 1
							[democracy_admin] => 1
						)

				)

			[author] => WP_Role Object
				(
					[name] => author
					[capabilities] => Array
						(
							[upload_files] => 1
							[edit_posts] => 1
							[edit_published_posts] => 1
							[publish_posts] => 1
							[read] => 1
							[level_2] => 1
							[level_1] => 1
							[level_0] => 1
							[delete_posts] => 1
							[delete_published_posts] => 1
						)

				)

			[contributor] => WP_Role Object
				(
					[name] => contributor
					[capabilities] => Array
						(
							[edit_posts] => 1
							[read] => 1
							[level_1] => 1
							[level_0] => 1
							[delete_posts] => 1
						)

				)

			[subscriber] => WP_Role Object
				(
					[name] => subscriber
					[capabilities] => Array
						(
							[read] => 1
							[level_0] => 1
						)

				)

		)

	[role_names] => Array
		(
			[administrator] => Administrator
			[editor] => Editor
			[author] => Author
			[contributor] => Contributor
			[subscriber] => Subscriber
		)

	[role_key] => wp_user_roles
	[use_db] => 1
)
*/

#2 Create a new role: "Basic contributor":

$result = add_role(
	'basic_contributor', 'Basic contributor',
	[
		'read'         => true,  // true grants this capability
		'edit_posts'   => true,  // true allows editing posts
		'delete_posts' => false, // false prevents deleting posts
	]
);
if ( null !== $result ) {
	echo 'Hooray! The new role was created!';
}
else {
	echo 'Oops... This role already exists.';
}

#3 Remove the "subscriber" role:

register_deactivation_hook( __FILE__, function(){
	remove_role( 'subscriber' );
} );

Changelog

Since 2.0.0 Introduced.

WP_Roles{} code WP 7.1.4

class WP_Roles {
	/**
	 * List of roles and capabilities.
	 *
	 * @since 2.0.0
	 * @var array[]
	 */
	public $roles;

	/**
	 * List of the role objects.
	 *
	 * @since 2.0.0
	 * @var WP_Role[]
	 */
	public $role_objects = array();

	/**
	 * List of role names.
	 *
	 * @since 2.0.0
	 * @var string[]
	 */
	public $role_names = array();

	/**
	 * Option name for storing role list.
	 *
	 * @since 2.0.0
	 * @var string
	 */
	public $role_key;

	/**
	 * Whether to use the database for retrieval and storage.
	 *
	 * @since 2.1.0
	 * @var bool
	 */
	public $use_db = true;

	/**
	 * The site ID the roles are initialized for.
	 *
	 * @since 4.9.0
	 * @var int
	 */
	protected $site_id = 0;

	/**
	 * Constructor.
	 *
	 * @since 2.0.0
	 * @since 4.9.0 The `$site_id` argument was added.
	 *
	 * @global array $wp_user_roles Used to set the 'roles' property value.
	 *
	 * @param int $site_id Site ID to initialize roles for. Default is the current site.
	 */
	public function __construct( $site_id = null ) {
		global $wp_user_roles;

		$this->use_db = empty( $wp_user_roles );

		$this->for_site( $site_id );
	}

	/**
	 * Makes private/protected methods readable for backward compatibility.
	 *
	 * @since 4.0.0
	 *
	 * @param string $name      Method to call.
	 * @param array  $arguments Arguments to pass when calling.
	 * @return mixed|false Return value of the callback, false otherwise.
	 */
	public function __call( $name, $arguments ) {
		if ( '_init' === $name ) {
			return $this->_init( ...$arguments );
		}
		return false;
	}

	/**
	 * Sets up the object properties.
	 *
	 * The role key is set to the current prefix for the $wpdb object with
	 * 'user_roles' appended. If the $wp_user_roles global is set, then it will
	 * be used and the role option will not be updated or used.
	 *
	 * @since 2.1.0
	 * @deprecated 4.9.0 Use WP_Roles::for_site()
	 */
	protected function _init() {
		_deprecated_function( __METHOD__, '4.9.0', 'WP_Roles::for_site()' );

		$this->for_site();
	}

	/**
	 * Reinitializes the object.
	 *
	 * Recreates the role objects. This is typically called only by switch_to_blog()
	 * after switching wpdb to a new site ID.
	 *
	 * @since 3.5.0
	 * @deprecated 4.7.0 Use WP_Roles::for_site()
	 */
	public function reinit() {
		_deprecated_function( __METHOD__, '4.7.0', 'WP_Roles::for_site()' );

		$this->for_site();
	}

	/**
	 * Adds a role name with capabilities to the list.
	 *
	 * Updates the list of roles, if the role doesn't already exist.
	 *
	 * The list of capabilities can be passed either as a numerically indexed array of capability names, or an
	 * associative array of boolean values keyed by the capability name. To explicitly deny the role a capability, set
	 * the value for that capability to false.
	 *
	 * Examples:
	 *
	 *     // Add a role that can edit posts.
	 *     wp_roles()->add_role( 'custom_role', 'Custom Role', array(
	 *         'read',
	 *         'edit_posts',
	 *     ) );
	 *
	 * Or, using an associative array:
	 *
	 *     // Add a role that can edit posts but explicitly cannot not delete them.
	 *     wp_roles()->add_role( 'custom_role', 'Custom Role', array(
	 *         'read' => true,
	 *         'edit_posts' => true,
	 *         'delete_posts' => false,
	 *     ) );
	 *
	 * @since 2.0.0
	 * @since 6.9.0 Support was added for a numerically indexed array of strings for the capabilities array.
	 *
	 * @param string                               $role         Role name.
	 * @param string                               $display_name Role display name.
	 * @param array<string,bool>|array<int,string> $capabilities Capabilities to be added to the role.
	 *                                                           Default empty array.
	 * @return WP_Role|null WP_Role object, if the role is added.
	 */
	public function add_role( $role, $display_name, $capabilities = array() ) {
		if ( empty( $role ) || isset( $this->roles[ $role ] ) ) {
			return null;
		}

		if ( wp_is_numeric_array( $capabilities ) ) {
			$capabilities = array_fill_keys( $capabilities, true );
		}

		$this->roles[ $role ] = array(
			'name'         => $display_name,
			'capabilities' => $capabilities,
		);
		if ( $this->use_db ) {
			update_option( $this->role_key, $this->roles, true );
		}
		$this->role_objects[ $role ] = new WP_Role( $role, $capabilities );
		$this->role_names[ $role ]   = $display_name;
		return $this->role_objects[ $role ];
	}

	/**
	 * Removes a role by name.
	 *
	 * @since 2.0.0
	 *
	 * @param string $role Role name.
	 */
	public function remove_role( $role ) {
		if ( ! isset( $this->role_objects[ $role ] ) ) {
			return;
		}

		unset( $this->role_objects[ $role ] );
		unset( $this->role_names[ $role ] );
		unset( $this->roles[ $role ] );

		if ( $this->use_db ) {
			update_option( $this->role_key, $this->roles );
		}

		if ( get_option( 'default_role' ) === $role ) {
			update_option( 'default_role', 'subscriber' );
		}
	}

	/**
	 * Adds a capability to role.
	 *
	 * @since 2.0.0
	 *
	 * @param string $role  Role name.
	 * @param string $cap   Capability name.
	 * @param bool   $grant Optional. Whether role is capable of performing capability.
	 *                      Default true.
	 */
	public function add_cap( $role, $cap, $grant = true ) {
		if ( ! isset( $this->roles[ $role ] ) ) {
			return;
		}

		$this->roles[ $role ]['capabilities'][ $cap ] = $grant;
		if ( $this->use_db ) {
			update_option( $this->role_key, $this->roles );
		}
	}

	/**
	 * Removes a capability from role.
	 *
	 * @since 2.0.0
	 *
	 * @param string $role Role name.
	 * @param string $cap  Capability name.
	 */
	public function remove_cap( $role, $cap ) {
		if ( ! isset( $this->roles[ $role ] ) ) {
			return;
		}

		unset( $this->roles[ $role ]['capabilities'][ $cap ] );
		if ( $this->use_db ) {
			update_option( $this->role_key, $this->roles );
		}
	}

	/**
	 * Retrieves a role object by name.
	 *
	 * @since 2.0.0
	 *
	 * @param string $role Role name.
	 * @return WP_Role|null WP_Role object if found, null if the role does not exist.
	 */
	public function get_role( $role ) {
		return $this->role_objects[ $role ] ?? null;
	}

	/**
	 * Retrieves a list of role names.
	 *
	 * @since 2.0.0
	 *
	 * @return string[] List of role names.
	 */
	public function get_names() {
		return $this->role_names;
	}

	/**
	 * Determines whether a role name is currently in the list of available roles.
	 *
	 * @since 2.0.0
	 *
	 * @param string $role Role name to look up.
	 * @return bool
	 */
	public function is_role( $role ) {
		return isset( $this->role_names[ $role ] );
	}

	/**
	 * Initializes all of the available roles.
	 *
	 * @since 4.9.0
	 */
	public function init_roles() {
		if ( empty( $this->roles ) ) {
			return;
		}

		$this->role_objects = array();
		$this->role_names   = array();
		foreach ( array_keys( $this->roles ) as $role ) {
			$this->role_objects[ $role ] = new WP_Role( $role, $this->roles[ $role ]['capabilities'] );
			$this->role_names[ $role ]   = $this->roles[ $role ]['name'];
		}

		/**
		 * Fires after the roles have been initialized, allowing plugins to add their own roles.
		 *
		 * @since 4.7.0
		 *
		 * @param WP_Roles $wp_roles A reference to the WP_Roles object.
		 */
		do_action( 'wp_roles_init', $this );
	}

	/**
	 * Sets the site to operate on. Defaults to the current site.
	 *
	 * @since 4.9.0
	 *
	 * @global wpdb $wpdb WordPress database abstraction object.
	 *
	 * @param int $site_id Site ID to initialize roles for. Default is the current site.
	 */
	public function for_site( $site_id = null ) {
		global $wpdb;

		if ( ! empty( $site_id ) ) {
			$this->site_id = absint( $site_id );
		} else {
			$this->site_id = get_current_blog_id();
		}

		$this->role_key = $wpdb->get_blog_prefix( $this->site_id ) . 'user_roles';

		if ( ! empty( $this->roles ) && ! $this->use_db ) {
			return;
		}

		$this->roles = $this->get_roles_data();

		$this->init_roles();
	}

	/**
	 * Gets the ID of the site for which roles are currently initialized.
	 *
	 * @since 4.9.0
	 *
	 * @return int Site ID.
	 */
	public function get_site_id() {
		return $this->site_id;
	}

	/**
	 * Gets the available roles data.
	 *
	 * @since 4.9.0
	 *
	 * @global array $wp_user_roles Used to set the 'roles' property value.
	 *
	 * @return array Roles array.
	 */
	protected function get_roles_data() {
		global $wp_user_roles;

		if ( ! empty( $wp_user_roles ) ) {
			return $wp_user_roles;
		}

		if ( is_multisite() && get_current_blog_id() !== $this->site_id ) {
			remove_action( 'switch_blog', 'wp_switch_roles_and_user', 1 );

			$roles = get_blog_option( $this->site_id, $this->role_key, array() );

			add_action( 'switch_blog', 'wp_switch_roles_and_user', 1, 2 );

			return $roles;
		}

		return get_option( $this->role_key, array() );
	}
}