The transition of WordPress from blogging platform to full-fledged CMS is an ongoing process, but it was around Version 3.0 that the ability to register our own custom post type really kicked it into high gear. Custom post types allow us to take advantage of a number of WordPress defaults- the admin UI, taxonomies, archives, thumbnails, revisions, page templates, and more- in order to handle our own types of repeatable data.
Some of the more common use cases include testimonials, product listings, contact forms, video libraries, podcast feeds, news/link aggregators, or any proprietary data type that your website or client needs to have displayed online.
However, it’s important not to conflate post types with post categories. If you could simply break your posts into categories, you’re better off going with that route for one simple reason: custom post types create separate silos for this data. It’s a lot easier to separate out different post categories than it is to combine multiple post types into one stream on say, an archive page.
A quick note on function generators
As you begin to work with custom post types, you’ll undoubtedly come across one of the many function generators. GenerateWP, as one example, is one of a few great resources to help you quickly throw together the correct functions for common WordPress tasks, like registering post types or taxonomies.
It’s a cool project, but don’t use it. At least, not right now (though probably not ever).
There’s nothing wrong with the idea of it and the convenience it offers, but its also one unnecessary abstraction from the very real work of modifying your default WordPress setup.
Even compared to a quick copy/paste of the full demo function from the codex, how much time is a generator really saving? With a generator, you’re still going to go field by field, typing in your variables and labels for each setting. Sure you might make a mistake, miss a comma or add an extra semicolon when doing it by hand, but that’s the learning curve of development.
More importantly, wouldn’t you rather be looking at the final code, learning what it means and how to better understand it? What happens when you decide you need to change the post type URL slug? Do you enter every variable again? Having a sense of familiarity with your function code, and it’s corresponding page in the Codex or Developer Resources, will save you more time in the long run.
Custom Post Type Registration Basics
Here’s our code for reference. Click here to open it in a new window.
The code example above seems long (and it doesn’t even cover all of the many arguments and arrays we can use to set up our custom post types), but it’s a pretty simple function once you spend some time with it.
The basis of creating a custom post type is really just two arrays: labels and arguments. More specifically, labels is just an array that we’ll actually store inside the arguments array. When we actually call our function on
line 37, we’ll only pass two agruments – our post type name and
$args. And of course, we’ll wrap up the whole thing in another function which we’ll hook up to the
init action for safe-keeping.
Let’s look through our two arrays:
Take a look at the array stored in
Lines 3 - 18:
$labels. The values we store here are meant to alter how WordPress will display your post type in the backend, as part of the admin UI. Without labels, WordPress would default to the same text it uses for Posts, phrases like ‘Edit Post’ and View all Posts’. In the example above, you’ll see that Post is generally replaced with Book. Go through the labels and adjust accordingly.
Let’s move down to the array stored in
Lines 20 - 35:
$args. In typical WordPress function fashion, we’re creating our array of arguments to pass into our function:
register_post_type(). Of course we could do this all in-line inside of the function call itself, but separating these arrays out and indenting them is really useful for our eyes and our sanity. You’ll even notice that our first argument on
line 21, labels, is simply using the
$labels array we created earlier. Again, we could have simply included that inline, but breaking it apart adds a little visual clarity for us that we’ll be grateful for later.
As we go down the list, we’ll take a closer look at some, but not all, of the more important arguments. A full list is available in the developer reference documentation.
Default Functionality Setting – Line 23
The ‘supports’ argument is the basis for building our custom post type. We’ll talk in future parts about using CMB2 for building out our custom fields, but before that happens, it’s worth taking a look at the default functionality that comes with each post object and seeing if it might help us.
For example, we could make a custom meta field for an image, but if we have access to the default featured image (thumbnail), along with all of its usual functions and integrations with other plugins, why not use it? Each case is different, but with the integration of additional labels (see this update) to really customize your Edit page, at least see if the defaults can work for you.
Here’s a few of the options we can grab:
Then again, you might not need any of these.
Publicity Settings – Lines 24 – 27
Do you want your post type to be visible on the front end, specifically to unregistered visitors to your site? These settings (along with a few more that aren’t shown, like ‘exclude_from_search’ and ‘query_var’) are there to help you fine tune how and if you want your custom post type displayed on the front end of the site, visible in search results and feeds, and publicly queryable.
If the answer is no, this is a good time to reflect on why you might be using a custom post type. As you go through each variable, if you find yourself turning off a majority of these features, maybe we’re putting a square peg in a round hole?
Also, if you’re concerned with keeping this data private, you may need to step up from custom post types and move to using the $wpdb object, which allows you to interact directly with the database.
One of the main benefits of using custom post types is getting access to post-type-specific archive.php and single.php templates for displaying your data on the front-end. If that’s how you plan on using this, then the default settings should be good and you can keep moving!
Admin UI Settings – Lines 28 – 31
Similar to the section above, but relates to the backend. Do you plan on using the default View all Posts, New Post, and Edit Post pages, with some major modifications of course? If so, the defaults here are good for you. Feel free to browse the default Dashicons to find a suitable ‘menu_icon’ and update the ‘menu_postition’ to something suitable (I prefer using
20, which places it right below the Posts on the admin sidebar.
Rest API Setting – Lines 32- 34
Although these settings are not required (‘show_in_rest’ will default to false) and the WP REST API is not entirely available in the WordPress core (and requires a plugin to use), I’ve decided to include them now for a few reasons.
The REST API is the future of WordPress. It’s not a matter of if, but when. So while the functions and arguments may change, the underlying idea will remain. Hopefully you’ll start seeing ideas of how to use the REST API. For example, I like to use it with CMB2 so that I can populate a mobile app with data from a WordPress site. In fact, the REST API is one of the main reasons I use a custom post type and specifically custom meta information.
It’s also important to be thinking ahead about potential uses for your custom post type right now in the registration phase. Of course you can change settings later, but getting all the correct arguments in place before you start inputting any data is pretty crucial. Every change can have a ripple effect. If there’s a chance you’ll be wanting to access this information from somewhere other than the site itself, that’s good to know.
Registration Function – Line 37
As discussed above, the actual function to register the post type only needs those two arguments. In this example, the post type is called ‘prefix_book’, as I recommend prefixing your post type if you can. You never know when you’ll test out a plugin that happens to use the same post type name. Plus, you can still customize the labels (
line 21), the slug (
line 27), and the REST API base (
line 33) to keep that prefix off the front end.
It’s worth restating that there are a lot of other options we could be mucking with as we set up our custom post type. The ones included in the example above are simply the ones I find that I use most often. I recommend reviewing the reference docs for
register_post_type() just in case there’s some other functionality you’d like toggled on or off.
For now, you actually have all of the pieces in place to start using your custom post type. If you view a post on the front end of your site, you’ll notice it simply uses the basic post styles (such as single.php and archive.php). Stay tuned for the next parts of the series where we’ll spend time add custom meta and modifying our template files to display them. We’ll also look at some other ways to access your data, such as registering custom shortcodes or injecting them back into the wp_query feed or search results.
Leave a comment and be sure to subscribe below to get the next part of the Super Custom WP Series.