Enumerable Blog
About coding, web development, and fun to be had in tech

Custom Post Types and Roles in WordPress

- Part 1 Last Updated:

Recently I built a WordPress website where visitors can create testimonials with pictures. The examples in the WordPress documentation is limited and doesn't illustrate the combination of custom post types and custom roles. There's also been a bit of confusion on forums so here's a tutorial that explains the necessary code.

Go here if you're looking for Part 2 which explains how to add a new user role with the right permissions.

Constructing register_post_type()

A call to register_post_type() from functions.php is used to set up a new post type. In our example, this post type will be a testimonial post. Once you're done here, make sure to keep reading Creating Administrator Permissions below since you won't see this post type show up on your Dashboard until you get that set up.

Without further ado, here's the code:

# /wp-content/themes/theme_name/functions.php
# Create a Testimonials Post Type for Visitors
function create_testimonial_post_type() {
  register_post_type( 'testimonials',
      'labels' => array(
        'name' => __( 'Testimonials' ),
        'singular_name' => __( 'Testimonial' )
      'public' => true,
      'has_archive' => true,
      'capability_type' => array("testimonial", "testimonials"),
      'map_meta_cap' => true,
add_action( 'init', 'create_testimonial_post_type' );

If you're new to editing functions.php then should know that the name of this function is up to you. I like to give my functions full, unabbreviated names that reflect the purpose of the function so that it is easy to remember and helpful to future editors.

The register_post_type function takes two arguments: the name of the post type (you'll use this name in other WP functions, as in query_posts('post_type' => 'testimonials')) and an associative array of various arguments. Be sure to check these out since I'm only using what is necessary for this example.

The arguments explained:

This array of names tells WordPress how the post type should be displayed on the Dashboard and in other front-end contexts.
By setting this to true, WordPress allows the posts to be visible on the Dashboard to front-end users.
This tells WP that you'd like this post type to be available to an archive page for viewing a list of testimonials. I'd like to have a page with all testimonials so this needs to be true.
Permissions will be explained in Part 2 and these strings are used in the creation of those permissions.
Cap stands for capabilities and setting this argument to true tells WordPress to call the map_meta_cap function with respect to this post type. This allows you to use meta capabilities rather than primitive capabilities (which are more work). See the Arguments > Capabilities documentation (scroll down a bit) for more info.

The add_action() function simply tells WordPress that we want it to process the create_testimonial_post_type() code when the theme initializes for any page render.

Note on __() and _e() Functions

WordPress and community-built plugins have made it easy to build a multilingual blog using these translation functions. If you want to build a multilingual site, use one of these functions on all user-facing Strings (like the post type labels above). Then make sure you've got the translations set up yourself or by using a translation plugin.

These functions are not necessary on an English only website.

__() is an alias for the translate() function. The first argument should be the string that gets translated. If you're developing a plugin, you need to add a unique identifier string as a second argument as well (see the documentation). Finally, _e() echoes the string to the page and is an alias for echo __().

Creating Administrator Permissions

At this point, you've probably created your post type and you're wondering why it hasn't shown up on your dashboard! Well, that's because you, as the administrator of the site, don't have permissions to create, read, update, or destroy (CRUD) your new post type. You've got to grant yourself these because WordPress doesn't want to make assumptions about who is allowed to use your new post type.

Here's the code to give the administrator and editor roles all CRUD permissions:

# /wp-content/themes/theme_name/functions.php
# Give Administrators and Editors All Testimonial Capabilities
function add_testimonial_caps_to_admin() {
  $caps = array(
  $roles = array(
    get_role( 'administrator' ),
    get_role( 'editor' ),
  foreach ($roles as $role) {
    foreach ($caps as $cap) {
      $role->add_cap( $cap );
add_action( 'after_setup_theme', 'add_testimonial_caps_to_admin' );

This requires a little less explanation. The basic process here is to gather all the permissions that you'd like to give out in an array (WordPress likes to refer to permissions as capabilities, hence the $caps array). Next gather all user roles you're interested in. I give the Administrator and Editor Roles full permissions to moderate inappropriate testimonials. Finally loop through and assign permissions.

I'm using two new WordPress functions which behave as you'd expect:

Retrieves the PHP object for a particular user role
Instance method of each role which adds the supplied permission or capability to that role. The permissions that you can add are listed here (just replace 'post' with 'testimonial' or 'posts' with 'testimonials'). An important distinction: All permissions that you add will work if you are the original author of a post. Only permissions that contain the word 'others' will allow you to edit, update, or delete other people's posts. Perhaps this is obvious but it isn't clarified in the WordPress documentation.

Adding this action after_setup_theme allows the post type to be created before you add permissions to it.

Voila! As an administrator or editor you should see the custom post type on the left hand menu of your Dashboard and be able to create, read, update, and destroy all testimonial posts!

Check out Part 2 to learn about creating a custom user role and setting the right permissions!

comments powered by Disqus