How to Control WordPress Custom Post Types, Capabilities and Roles

As We all knows about Custom Post Types and how to create them, when we create custom post types without Capabilities all users except subscriber roles can publish, read, edit and delete them by default. What if we wanted to create a custom post type that Author could read, edit and publish but Author Staff could only read? Well here’s were custom post types and capabilities gets interesting! Take the following basic custom post type for registering Article:

<?php 
add_action( 'init', 'register_article_post' );

function register_article_post() {

    $labels = array( 
        'name' => _x( 'Articles', 'article' ),
        'singular_name' => _x( 'Article', 'article' ),
        'add_new' => _x( 'Add New', 'article' ),
        'add_new_item' => _x( 'Add New Article', 'article' ),
        'edit_item' => _x( 'Edit Article', 'article' ),
        'new_item' => _x( 'New Article', 'article' ),
        'view_item' => _x( 'View Article', 'article' ),
        'search_items' => _x( 'Search Articles', 'article' ),
        'not_found' => _x( 'No articles found', 'article' ),
        'not_found_in_trash' => _x( 'No articles found in Trash', 'article' ),
        'parent_item_colon' => _x( 'Parent Article:', 'article' ),
        'menu_name' => _x( 'Articles', 'article' ),
    );

    $args = array( 
        'labels' => $labels,
        'hierarchical' => true,
        'supports' => array( 'title', 'editor' ),
        'public' => true,
        'show_ui' => true,
        'show_in_menu' => true,
        'show_in_nav_menus' => true,
        'publicly_queryable' => true,
        'exclude_from_search' => false,
        'has_archive' => true,
        'query_var' => true,
        'can_export' => true,
        'rewrite' => true,
    );
    register_post_type( 'article', $args );
}
?>

The above example would give all users (above subscriber) full capabilities over the custom post type Article, like all can read, publish, edit and delete them. When we add ‘map_meta_cap, capabilities and capability_type’ to the $args array we can take more control over it.

Lets modify the $args first by adding map_meta_cap capabilities, and capability_type:

<?php 
add_action( 'init', 'register_article_post' );

function register_article_post() {

    $labels = array( 
        'name' => _x( 'Articles', 'article' ),
        'singular_name' => _x( 'Article', 'article' ),
        'add_new' => _x( 'Add New', 'article' ),
        'add_new_item' => _x( 'Add New Article', 'article' ),
        'edit_item' => _x( 'Edit Article', 'article' ),
        'new_item' => _x( 'New Article', 'article' ),
        'view_item' => _x( 'View Article', 'article' ),
        'search_items' => _x( 'Search Articles', 'article' ),
        'not_found' => _x( 'No articles found', 'article' ),
        'not_found_in_trash' => _x( 'No articles found in Trash', 'article' ),
        'parent_item_colon' => _x( 'Parent Article:', 'article' ),
        'menu_name' => _x( 'Articles', 'article' ),
    );

    $args = array( 
        'labels' => $labels,
        'hierarchical' => true,
        'supports' => array( 'title', 'editor' ),
        'public' => true,
        'show_ui' => true,
        'show_in_menu' => true,
        'show_in_nav_menus' => true,
        'publicly_queryable' => true,
        'exclude_from_search' => false,
        'has_archive' => true,
        'query_var' => true,
        'can_export' => true,
        'rewrite' => true,

        'map_meta_cap' => true,
        // map_meta_cap will allow us to remap the existing capabilities with new capabilities to match the new custom post type

        // capabilities are what we are customising so lets remap them
        'capabilities' => array(
            'edit_post' => 'edit_article',
            'edit_posts' => 'edit_articles',
            'edit_others_posts' => 'edit_other_articles',
            'publish_posts' => 'publish_articles',
            'edit_publish_posts' => 'edit_publish_articles',
            'read_post' => 'read_articles',
            'read_private_posts' => 'read_private_articles',
            'delete_post' => 'delete_article'
        ),
        // capability_type defines how to make words plural, by default the
        // second word has an 's' added to it and for 'article' that's fine
        // however when it comes to words like book the plural would become
        // books so it's worth adding your own regardless of the plural.
        'capability_type' => array('article', 'articles'),
    );
    register_post_type( 'article', $args );
}
?>

So now we have a Custom Post Type with Capabilities remapped to our own custom Capabilities with our own plural words. All we have to do now is add the capability to the roles.

Look at bellow example:

<?php 
function manage_capabilities() {
    // gets the role to add capabilities to
    $admin = get_role( 'administrator' );
    $editor = get_role( 'editor' );
	// replicate all the remapped capabilites from the custom post type article
    $caps = array(
    	'edit_article',
    	'edit_articles',
    	'edit_other_articles',
    	'publish_articles',
    	'edit_published_articles',
    	'read_articles',
    	'read_private_articles',
    	'delete_article'
    );
    // give all the capabilities to the administrator
    foreach ($caps as $cap) {
	    $admin->add_cap( $cap );
    }
    // limited the capabilities to the editor or a custom role 
    $editor->add_cap( 'edit_article' );
    $editor->add_cap( 'edit_articles' );
    $editor->add_cap( 'read_articles' );
}
add_action( 'admin_init', 'manage_capabilities');
?>

I think this blog post is really helpful for my blog reader’s, if any one have any query’s then please put your comments

Add a Custom Post Type Submenu To Another Post Type Menu

Custom Post Types are the most powerful features of WordPress, specially if you’re in the business of creating custom solutions for clients beyond normal bloging functionality.

Introducing a new menu in the WordPress dashboard is really easy when using the custom post type API; however, what about the case when you have a custom post type and is a child of another post type?

Specifically, what about the case when you want to add a custom post type submenu to an existing post type menu?

First, let’s introduce a Testimonial custom post type. This will be a top-level menu in the WordPress dashboard.

 /**
        * Define the 'Testimonial' post type.
        *
        * This will be our top-level custom post type menu.
        */
        $args = array(
        'labels'    =>    array(
        'all_items'    =>    'All Testimonial',
        'menu_name'    =>	'Testimonial',
        'singular_name'       =>	'Testimonial',
        'edit_item'           =>	'Edit Testimonial',
        'new_item'            =>	'New Testimonial',
        'view_item'           =>	'View Testimonial',
        'items_archive'       =>	'Testimonial Archive',
        'search_items'        =>	'Search Testimonial',
        'not_found'	          =>	'No testimonial found',
        'not_found_in_trash'  =>	'No testimonial found in trash'
        ),
        'supports'		=>	array( 'title', 'editor', 'author', 'revisions' ),
        'menu_position'	=>	5,
        'public'		=>	true
        );
        register_post_type( 'testimonial', $args );
    

Now, we can introduce a second post type, say, Client that will be used to represent all of the locations that we’ve used throughout the testimonial.

        /**
        * Next, we'll define a second custom post type called 'Client' where we could
        * potentially display a list of client that are used as part of our testimonial.
        *
        * This custom post type will be added as a submenu to the 'Client' menu<br>
        */
        $args = array(
        'labels'    =>	array(
        'all_items'           =>    'Client',
        'menu_name'	          =>    'Client',
        'singular_name'       =>    'Client',
        'edit_item'           =>    'Edit Client',
        'new_item'            =>    'New Client',
        'view_item'           =>    'View Client',
        'items_archive'       =>    'Client Archive',
        'search_items'        =>    'Search Client',
        'not_found'	          =>    'No client found.',
        'not_found_in_trash'  =>    'No client found in trash.'
        ),
        'supports'        =>    array( 'title', 'editor', 'revisions' ),
        'show_in_menu'    =>    'edit.php?post_type=testimonial',
        'public'		  =>    true
        );
        register_post_type( 'testimonial', $args );
    

Note that the following line is key in adding the menu as a submenu:

        'show_in_menu'    =>    'edit.php?post_type=testimonial', 
        /* 
        * testimonial is post type. you can change it as you want.
        */
    

Let’s Create a Custom Post Type !

Here we shall create a custom post type which will display portfolio. Lets started.

  • Register Your Custom Function.

    Open your function.php of current theme. At the end of the function file, type the following line of code to execute the custom function named create_portfolio during the initialization phase every time a page is generated.

     add_action( 'init', 'create_movie_review' ); 
  • Function Implementation

    Provide an implementation of the create_portfolio function.

     function create_movie_review() {
        register_post_type( 'portfolio',
            array(
                'labels' => array(
                    'name' => 'Portfolio',
                    'singular_name' => 'Portfolio',
                    'add_new' => 'Add New',
                    'add_new_item' => 'Add New Portfolio',
                    'edit' => 'Edit',
                    'edit_item' => 'Edit Portfolio',
                    'new_item' => 'New Portfolio',
                    'view' => 'View',
                    'view_item' => 'View Portfolio',
                    'search_items' => 'Search Portfolio',
                    'not_found' => 'No Portfolio found',
                    'not_found_in_trash' => 'No Portfolio found in Trash',
                    'parent' => 'Parent Portfolio'
                ),
                'public' => true,
                'menu_position' => 25,
                'supports' => array( 'title', 'editor', 'comments', 'thumbnail', 'custom-fields' ),
                'taxonomies' => array( '' ),
                'menu_icon' => plugins_url( 'images/image.png', __FILE__ ),
                'has_archive' => true
            )
        );
    } 

    The

    register_post_type

    function does most of the work for us. As soon as it is called it prepares the WordPress environment for a new custom post type including a different sections in wordpress admin. This function takes two arguments: first one is an unique name of the custom post type and the second one an array demonstrating the properties of the new custom post type. Here it’s another array containing the different labels, which indicates the text strings to be displayed in the different sections of the custom post type e.g. ‘name‘ displays the custom post type name in the dashboard, ‘edit‘ and ‘view‘ are displayed in Edit and View buttons respectively.

    In the second arguments:

    • 'public' => true

      determines the visibility of the custom post type both in the admin panel and front end.

    • 'menu_position' => 25

      determines the menu position of the custom post type.

    • 'supports' => array( 'title', 'editor', 'comments', 'thumbnail', 'custom-fields' )

      determines the features of the custom post type which is to be displayed.

    • 'taxonomies' => array( '' )

      creates custom taxonomies.

    • 'menu_icon' => ''

      put the image url which is displaying in admin.

    • 'has_archive' => true

      enables/disable archive of the custom post type.

    For more details please visit the WordPress Codex

    register_post_type

    page

  • Now save the function file and go to your wordpress admin.
  • Add new item

    Click on the Add New link to go to the custom post type editor. Provide a portfolio title, a small description and set the featured image.

  • Publish

    Publish the portfolio and click on View Portfolio to view the created portfolio in the browser.