Capabilities and Custom Post Types

I have a custom post type that I’d like to restrict access to certain roles however, I’ve already added content using the custom post type and now I have to make them restricted. The capability_type was ‘post’

'capability_type' => 'post'

Which is fine as the content show up in the backend however, now as soon as I add any capabilities the content disappears from the backend?

Read More

I’ve tried customising the capability type to include plural definitions to construct my own but as soon as I remove or change capability types it’s gone!

full code:

add_action( 'init', 'register_cpt_gallery' );

function register_cpt_gallery() {
$labels = array( 
    'name' => _x( 'Galleries', 'gallery' ),
    'singular_name' => _x( 'Gallery', 'gallery' ),
    'add_new' => _x( 'Add New', 'gallery' ),
    'add_new_item' => _x( 'Add New Gallery', 'gallery' ),
    'edit_item' => _x( 'Edit Gallery', 'gallery' ),
    'new_item' => _x( 'New Gallery', 'gallery' ),
    'view_item' => _x( 'View Gallery', 'gallery' ),
    'search_items' => _x( 'Search Galleries', 'gallery' ),
    'not_found' => _x( 'No galleries found', 'gallery' ),
    'not_found_in_trash' => _x( 'No galleries found in Trash', 'gallery' ),
    'parent_item_colon' => _x( 'Parent Gallery:', 'gallery' ),
    'menu_name' => _x( 'Galleries', 'gallery' ),
);

$args = array( 
    'labels' => $labels,
    'hierarchical' => true,
    'description' => 'Image galleries for teachers classes',
    'supports' => array( 'title', 'editor', 'author'),

    'public' => true,
    'show_ui' => true,
    'show_in_menu' => true,

    'menu_icon' => get_bloginfo('template_url') . '/images/imagegallery.png',
    'show_in_nav_menus' => true,
    'publicly_queryable' => true,
    'exclude_from_search' => false,
    'has_archive' => true,
    'query_var' => true,
    'can_export' => true,
    'rewrite' => true,
    'capability_type' => 'post',
    'capabilities' => array(
        'edit_post' => 'edit_gallery',
        'edit_posts' => 'edit_galleries',
        'edit_others_posts' => 'edit_other_galleries',
        'publish_posts' => 'publish_galleries',
        'read_post' => 'read_gallery',
        'read_private_posts' => 'read_private_galleries',
        'delete_post' => 'delete_gallery'
    )
);

register_post_type( 'gallery', $args );
}

I’ve also tested this with a completely new custom post type and regardless of the capability type I get the same issue eg even if I remove it and add my custom one:

'capability_type' => array('movie','movies');

Related posts

4 comments

  1. After a quick chat with Magicroundabout who pointed out a useful resource from Justin Tadlock, it turns out that capabilities for custom post types don’t actually exist unless you use add_cap to the role, for example for the following custom post type:

    add_action( 'init', 'register_cpt_gallery' );
    
    function register_cpt_gallery() {
    $labels = array( 
        'name' => __( 'Galleries', 'gallery' ),
        'singular_name' => __( 'Gallery', 'gallery' ),
        'add_new' => __( 'Add New', 'gallery' ),
        'add_new_item' => __( 'Add New Gallery', 'gallery' ),
        'edit_item' => __( 'Edit Gallery', 'gallery' ),
        'new_item' => __( 'New Gallery', 'gallery' ),
        'view_item' => __( 'View Gallery', 'gallery' ),
        'search_items' => __( 'Search Galleries', 'gallery' ),
        'not_found' => __( 'No galleries found', 'gallery' ),
        'not_found_in_trash' => __( 'No galleries found in Trash', 'gallery' ),
        'parent_item_colon' => __( 'Parent Gallery:', 'gallery' ),
        'menu_name' => __( 'Galleries', 'gallery' ),
    );
    
    $args = array( 
        'labels' => $labels,
        'hierarchical' => true,
        'description' => 'Image galleries for teachers classes',
        'supports' => array( 'title', 'editor', 'author'),
        'public' => true,
        'show_ui' => true,
        'show_in_menu' => true,
        'menu_icon' => get_bloginfo('template_url') . '/images/imagegallery.png',
        'show_in_nav_menus' => true,
        'publicly_queryable' => true,
        'exclude_from_search' => false,
        'has_archive' => true,
        'query_var' => true,
        'can_export' => true,
        'rewrite' => true,
        'capabilities' => array(
            'edit_post' => 'edit_gallery',
            'edit_posts' => 'edit_galleries',
            'edit_others_posts' => 'edit_other_galleries',
            'publish_posts' => 'publish_galleries',
            'read_post' => 'read_gallery',
            'read_private_posts' => 'read_private_galleries',
            'delete_post' => 'delete_gallery'
        ),
        // as pointed out by iEmanuele, adding map_meta_cap will map the meta correctly 
        'map_meta_cap' => true
    );
    
    register_post_type( 'gallery', $args );
    }
    

    The additional capabilities should be added to a role for the permissions to actually work in the backend, including the ‘administrator’ – for example:

    function add_theme_caps() {
        // gets the administrator role
        $admins = get_role( 'administrator' );
    
        $admins->add_cap( 'edit_gallery' ); 
        $admins->add_cap( 'edit_galleries' ); 
        $admins->add_cap( 'edit_other_galleries' ); 
        $admins->add_cap( 'publish_galleries' ); 
        $admins->add_cap( 'read_gallery' ); 
        $admins->add_cap( 'read_private_galleries' ); 
        $admins->add_cap( 'delete_gallery' ); 
    }
    add_action( 'admin_init', 'add_theme_caps');
    

    I hope this is useful to others.

    Additionally, the _x() translation function expects the second argument to be string $context, which is a short description, and the third to be string $domain. When not providing a description, use the __() translation function instead which has the string $domain as the second argument.

  2. IMHO you never map your own capabilities. Make sure to use map meta cap plugin to do so.
    http://codex.wordpress.org/Function_Reference/map_meta_cap

    I spent days trying to map my custom caps manually with code. Just install that plugin, map your caps and deactivate once working. If creating custom roles you WILL need Members plugin.

    The way I test to MAKE sure my role has those capabilites (sometimes you swear you do but don’t actually) make a debugging page with:

        if( !function_exists( 'current_user_has_role' ) ){
            function current_user_has_role( $role ){
                $current_user = new WP_User( wp_get_current_user()->ID );
                $user_roles = $current_user->roles;
                $is_or_not = in_array( $role, $user_roles );
                return $is_or_not;
            }
        }
    

    This will show you which capabilities you do in fact have.

  3. For Custom Post Types, I DON’T suggest using hook:

    add_action( 'registered_post_type', 'your_func', 10, 2 );
    

    instead I suggest using:

    add_filter( 'register_post_type_args', 'your_func', 10, 2 );
    function your_func( $args, $name ) 
    {
       if ( $name == "your_custom_post_name" ) 
       ...
    }
    

Comments are closed.