WordPress Custom Capabilities and User Roles

WordPress ships with five built-in roles: Administrator, Editor, Author, Contributor, and Subscriber. For client sites and membership platforms, you often need a custom role — “Event Manager”, “Store Manager”, “Premium Member” — with a precise set of capabilities.

Problem: WordPress's built-in roles do not map cleanly to custom business requirements — there is no native way to create fine-grained permission groups or restrict specific admin features to specific user types.

Solution: Use add_role() to create a custom role with a specific capability set, get_role()->add_cap() to extend an existing role, and current_user_can() throughout your code to gate features behind the correct capability.

Add a custom role on plugin activation:

register_activation_hook( __FILE__, 'create_event_manager_role' );

function create_event_manager_role() {
    add_role(
        'event_manager',
        __( 'Event Manager', 'textdomain' ),
        [
            // Standard WordPress capabilities
            'read'                   => true,
            'edit_posts'             => false,
            'delete_posts'           => false,

            // Custom capabilities for a hypothetical 'event' CPT
            'edit_events'            => true,
            'edit_published_events'  => true,
            'publish_events'         => true,
            'delete_events'          => false,
            'read_private_events'    => true,
        ]
    );
}

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

Map the custom capabilities on the CPT registration:

register_post_type( 'event', [
    'label'        => __( 'Events', 'textdomain' ),
    'public'       => true,
    'capability_type' => 'event',   // generates edit_events, publish_events, etc.
    'map_meta_cap'    => true,      // let WordPress handle per-post checks
    'capabilities' => [
        'edit_post'          => 'edit_event',
        'edit_posts'         => 'edit_events',
        'edit_others_posts'  => 'edit_others_events',
        'publish_posts'      => 'publish_events',
        'read_private_posts' => 'read_private_events',
        'delete_post'        => 'delete_event',
        'delete_posts'       => 'delete_events',
    ],
] );

Add or remove a capability from an existing role at runtime:

// Give editors the ability to manage WooCommerce
$editor = get_role( 'editor' );
$editor->add_cap( 'manage_woocommerce' );

// Remove a capability
$editor->remove_cap( 'delete_others_posts' );

NOTE: Role and capability data is stored in the wp_user_roles option in the database. Calling add_role() on every page load is harmless but wasteful — run it only on plugin activation. Similarly, use add_cap() and remove_cap() in activation/setup hooks rather than on init.