How to take your WordPress sites to the next level with custom post types

Custom post types are one of the key elements you should grasp if you want to create flexible, professional-grade, WordPress sites.

What custom post types do is allow you to add your own type of data; that may be an article, a song, a movie, or thousands of other things. Custom post types allow you to categorize your data according to your individual needs, which in turn allows you to take greater control over how your site behaves.

In this article I’ll take you through creating a custom movie post type for a movie database.

Why use custom post types?

In order to create a movie website, we need to set up a database. To do so without custom post types would be extremely tricky, and potentially clash with our existing WordPress installation. However, our custom post type will have its own admin menu and custom editing page, if we wanted to we could even add custom taxonomies to the page with the names and properties that suit the project.

Custom post types are what take WordPress from a blogging platform to a full-blown CMS. They give us the freedom to set up our movie website without any nasty hacks.

Creating our movie post type

In this article I’ll lay out all the code that is necessary to create a custom post type, and then we’ll go through it line-by-line so you can learn what each part does and customize it to your needs.

Here’s the full code that gets added to your functions.php file:

add_action( 'init', 'register_movie' );

function register_movie() {

 $labels = array( 
 'name' => 'Movies',
 'singular_name' => 'Movie',
 'add_new' => 'Add New',
 'add_new_item' => 'Add New Movie',
 'edit_item' => 'Edit Movie',
 'new_item' => 'New Movie',
 'view_item' => 'View Movie',
 'search_items' => 'Search Movies',
 'not_found' => 'No movies found',
 'not_found_in_trash' => 'No movies found in Trash',
 'menu_name' => 'Movies',
 );

 $args = array( 
 'labels' => $labels,
 'hierarchical' => false,
 'description' => 'Here you will add all the movies for the database',
 'supports' => array( 'title', 'editor', 'thumbnail' ),
 'taxonomies' => array( 'genre', 'movies', 'year' ),
 'public' => true,
 'show_ui' => true,
 'show_in_menu' => true,
 'menu_position' => 5,
 //'menu_icon' => the image link here,
 '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'
 );

 register_post_type( 'movie', $args );
}

As you can see a somewhat big chunk of code goes into creating a custom post type but if you understand it you will be able to get this code and adapt it to your projects. In the first line we hook the function with our custom post type to the init and this means our function will fire when WordPress does so that we will always have it in our dashboard:

add_action( 'init', 'register_movie' );

The labels

In the next line we start by declaring the name of our function and a variable with all the labels that will be associated with our movie post type so that everything can be customized.

The first thing we declare in the labels is the name of our custom post type, in plural and singular form:

'name' => 'Movies',
'singular_name' => 'Movie',

In the next two lines we have to specify our Add New text (if we wish to change it) and then we set Add New Movie so that when we are adding a new movie we have a custom experience instead of adding a movie and having a headline saying ‘Add New Post’.

'add_new' => 'Add New',
'add_new_item' => 'Add New Movie',

After the labels for creating a new movie, we need to set the labels for editing, the new item text (by default is New Post/New Page) and we also need to set the view post text:

'edit_item' => 'Edit Movie',
'new_item' => 'New Movie',
'view_item' => 'View Movie',

Now in the labels we move on to the search capabilities in the wordpress admin and our labels for that. We need to set labels for when we search movies, when no results are found, and also when no results are found in the trash:

'search_items' => 'Search Movies',
'not_found' => 'No movies found',
'not_found_in_trash' => 'No movies found in Trash',

The last label speaks for itself, in here we have to place the name we want the custom post type to have in the menu UI, in this case we’re just sticking with “Movies”:

'menu_name' => 'Movies',
);

The arguments

Now we have to move to our arguments, for that I created another variable that will hold all the arguments, I called it args.

The first argument it asks for is the labels and all we have to do is point to the labels variable we just examined, like so:

$args = array( 
 'labels' => $labels,

In the next line we need to set whether our post type will be hierarchical like pages or not (like posts). In my case I don’t want movies to be hierarchical so I’ve set it to false. The next line is just an optional description of the post type.

'hierarchical' => false,
'description' => 'Here you will add all the movies for the database',

The next line is an important one; in here we have to specify what our custom post type will support, what fields it will have. The options for this field are:

  • ‘title’
  • ‘editor’
  • ‘author’
  • ‘thumbnail’
  • ‘excerpt’
  • ‘trackbacks’
  • ‘custom-fields’
  • ‘comments’
  • ‘revisions’
  • ‘page-attributes’
  • ‘post-formats’

In my case and for my post type I only want it to support title, the WYSIWYG editor, a thumbnail and comments and to do that I need to add an array in this line, like so:

'supports' => array( 'title', 'editor', 'thumbnail','comments' ),

In the next line we need to specify what taxonomies it will be using, and since we will be creating custom taxonomies those are the ones that will be added in this line:

'taxonomies' => array( 'genre', 'actors', 'year' ),

The next three lines have to do with the post type’s visibility in the administration area and all I do is set all of that to true:

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

Next we move to the position of the menu in which the post type should appear. Here we also have a lot options to choose from:

  • 5 – Below Posts
  • 10 – Below Media
  • 15 – Below Links
  • 20 – Below Pages
  • 25 – Below comments
  • 60 – Below first separator
  • 65 – Below Plugins
  • 70 – Below Users
  • 75 – Below Tools
  • 80 – Below Settings
  • 100 – Below second separator

In my case I wanted movies to appear immediately after posts so I set its menu position to 5, like so:

'menu_position' => 5,

In the next line we take care of the icon, we can set our own icon or leave it blank and we will get the posts icon instead, the line after that takes care of whatever we want this post type to appear for selection in our menus.

'menu_icon' => //the image link here,
'show_in_nav_menus' => true,

In the next 3 lines we add the post type’s capabilities; we first set whether we want that post type to be queried on the front end, then we decide if we want the post type results to be excluded from searches and finally we decide if we want an archive for the movies post type:

'publicly_queryable' => true,
'exclude_from_search' => false,
'has_archive' => true,

In the next line we set the query variable for our post type and this will define how the URL will look, for this option we have three possible parameters: we can set it to true and then we can reach the movie by using /?movie=name_of_movie; we can set it to a string so that movie in the URL will be replaced by anything we want, such as “show” and we would have to use /?show=name_of_movie in order to reach the same movie; the last option is to set it to false and this way you make it impossible to reach a movie using the query_var. In my case, and with the latter option in mind, I set my query var to true so that we can reach it with the query_var of movie:

'query_var' => true,

In the next line we decide if we want the movies to be exportable and then we choose the slug for this post type, in my case I just stuck with true to have ‘movie’ as the slug but you can choose any string to be the slug and you actually have plenty of options, this parameter is an extensive one.

'can_export' => true,
'rewrite' => true,

The final line of our arguments is where we set the capability type of our post and since I want it to have the exact same ones as normal posts, I just gave it the value of post, like so:

 'capability_type' => 'post'
);

Our labels and arguments are done , all we need to do now is register our post type and the register_post_type function takes two parameters, the first one is the name of our custom post type (this has a maximum of 20 letters and with no capital letters or spaces) and the second one is the arguments for the post type and in this one we will just place our args variable:

 register_post_type( 'movie', $args );
}

Our post type is created and completely functional and all you need to have it show up in your pages is some wp_query magic.

Final words

I hope you can see why so many people use custom post types in WordPress.

This article was meant to give you an understanding of the process of creating a custom post type, and give you a starting point for creating your own amazing custom post types.

Featured image/thumbnail, customized image by ATOMIC Hot Links, via Flickr.

Sara Vieira

Sara Vieira

Sara Vieira is a freelance Web Designer and Developer with a passion for HTML5/CSS3 and jQuery. You can follow her on twitter or check out her website.

Join to our thriving community of like-minded creatives!