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

Show Custom Post Types on the Homepage

Custom post types are commonly used in WordPress sites, but they don’t show on the homepage or in the archive pages unless you write code to do that. I’ve put together some code that is smart about detecting your public custom post types and automatically adding them to your homepage and archive pages:

/**
 * Show WordPress custom post types on the main blog and archive pages
 **/
function show_my_post_types( $query ) {

  // Show all custom post types on main blog and archive pages
  if ( $query->is_main_query() && ( is_home() || ( is_archive() && !is_post_type_archive() ) ) ) {

    $custom_post_types = get_post_types( array(
       'public' => true,
       '_builtin' => false,
    ) );

    $post_types = array_merge( array('post'), $custom_post_types );
    $query->set( 'post_type', $post_types );
   }

   return $query;
}

add_filter( 'pre_get_posts', 'show_me_post_types' );