Skip to content

Custom post type capabilities and roles in WordPress

  • Last updated: September 8, 2020
custom post type capabilities

We often use custom post types for various purposes. I believe all WordPress plugin developers love this feature. But many of us who are relatively new in WordPress development, probably not aware of custom capabilities and it’s potentials. In this article, I will try to put some light on custom post type capabilities.

Why use new capabilities for custom post type

The heart of the question is why I should use new capabilities instead of the defaults. The answer is simple. Whenever you need precise control for different users, you need custom capabilities. For example, if your plugin have custom post types and you want to distribute specific tasks to different users, you need custom capabilities.


Let’s say I have a post type book and only authors can create, edit books. I will assign custom capabilities to authors only. There is a brilliant plugin available to customize user roles and capabilities. It’s called “User Role Editor“. By default, WordPress assigns capabilities based on the user roles such as “admin”, “editor”, “author” and so on. To know about user role based capabilities, use get_role() function.

How to create new capabilities

Now that we have understood the potentials, let’s see how we can create. When we register a new post type in a plugin, we can define custom capabilities.

A custom post type needs to be registered with register_post_type() function and init action hook. For example, let’s register a book post type with custom capabilities

function book_post_type() {
    $args = array(
        'public'          => true,
        'label'           => __( 'Books', 'textdomain' ),
        'menu_icon'       => 'dashicons-book',
        'show_in_rest'    => true,
        'taxonomies'      => array( 'category' ),
        'capability_type' => array('book','books'), //custom capability type
        'map_meta_cap'    => true, //map_meta_cap must be true
    );
    register_post_type( 'book', $args );
}
add_action( 'init', 'book_post_type' ); //action hook

If you notice, we have used 'capability_type' => array('book','books') which will create new capability type for the book post type. It is also important to use 'map_meta_cap' => true, for custom post types. If you don’t set it true, WordPress will not be able to map new capabilities. Default capability keys are –

/**
 * Default capability type keys
 * Will be mapped with our types which are "book"(singular), "books"(plural)
 */

[edit_post]              => edit_book
[read_post]              => read_book
[delete_post]            => delete_book
[edit_posts]             => edit_books
[edit_others_posts]      => edit_other_books
[publish_posts]          => publish_books
[read_private_posts]     => read_private_books
[delete_posts]           => delete_books
[delete_private_posts]   => delete_private_books
[delete_published_posts] => delete_published_books
[delete_others_posts]    => delete_others_books
[edit_private_posts]     => edit_private_books
[edit_published_posts]   => edit_published_books

The restrictions

Now at this point, WordPress will not show the custom post type (book) for any logged in user. This is for security purposes. As we have added new capabilities, we need to tell WordPress which user have these capabilities.

Add newly added capabilities for admin

Admin users are at the top level with all default capabilities assigned to them. So admin users also should have all custom capabilities. Let’s do that in an efficient way.

Role based capability can be added by the WP_Role::add_cap( string $cap ) function. This is important that we hook this function on plugin or theme activation. We shall use a class based static methods for better code management. We need to add the following code to the main plugin file.

// add custom capabilities to the admin on plugin activation
register_activation_hook( __FILE__, array( 'Admin_Roles', 'add_admin_capabilities' ) );

The main class for admin role

/**
 * Main class for ADMINISTRATOR
 */
class Admin_Roles {
    /**
     * Custom capabilities of custom post types
     */
    private static $customCaps = array(
        [ 'singular' => 'book', 'plural' => 'books' ],
    );

    /**
     * Add custom capabilities for admin
     */
    public static function add_admin_capabilities() {

        $role = get_role( 'administrator' );

        foreach( self::$customCaps as $cap ){
            
            $singular = $cap['singular'];
            $plural = $cap['plural'];

            $role->add_cap( "edit_{$singular}" ); 
            $role->add_cap( "edit_{$plural}" ); 
            $role->add_cap( "edit_others_{$plural}" ); 
            $role->add_cap( "publish_{$plural}" ); 
            $role->add_cap( "read_{$singular}" ); 
            $role->add_cap( "read_private_{$plural}" ); 
            $role->add_cap( "delete_{$singular}" ); 
            $role->add_cap( "delete_{$plural}" );
            $role->add_cap( "delete_private_{$plural}" );
            $role->add_cap( "delete_others_{$plural}" );
            $role->add_cap( "edit_published_{$plural}" );
            $role->add_cap( "edit_private_{$plural}" );
            $role->add_cap( "delete_published_{$plural}" );
            
        }

    }

}

Now that we have our class ready, we can add any number of post type capabilities for admin. We just need to add capability types to private static $customCaps variable. For example, a newly added custom post type capability can be added like this –

private static $customCaps = array(
    [ 'singular' => 'book', 'plural' => 'books' ],
    [ 'singular' => 'story', 'plural' => 'stories' ],
);

Deactivate and reactivate the plugin

As we have used register_activation_hook() function, you need to deactivate and then reactivate the plugin to make this code work. The activation hook will add all the new capabilities for the admin. From this point, you may use the “User Role Editor” plugin and control user roles and assign custom post type capabilities for them.

Conclusion

All custom post types should have custom capability types as it gives the power to the plugin users. This particular method is very simple and manageable. I use this method for all of my plugins that registers custom post types. My recent plugin “Classic Quiz Feedback Survey” is also using this method. This plugin is now available on WordPress plugin directory.

I hope you enjoyed this article and if you have any question, please ask in the comment section.


Leave a Reply