WordPress Custom Post Types

The Ultimate Guide to WordPress Custom Post Types

If you purchase through a link on our site, we may earn a commission. Learn more.

Custom Post Types turned WordPress from a simple blog engine into a versatile Content Management Platform. Apart from posts and pages, we can also manage news and deal sections, shop items, event, and many more. Learn more about Custom Post Types in this article and how you can create and extend them with or without coding skills.
Table of Contents
WP Engine High Performance Hosting
BionicWP Hosting

More than a decade ago, I made the life- and career-changing decision to focus solely on using WordPress as my publishing platform and the CMS for which I build plugins. The primary reasons were the excellent documentation, including countless posts with snippets and tutorials, and the ease of extending WordPress. For my use cases back then, the most prominent feature to extend WordPress was Custom Post Types.

Improved mainly with WordPress version 3 in 2010, Custom Post Types (CPTs) are used in many ways. I am sure you have met them without knowing. Let me give you an overview of CPTs, specific examples of how I used them over time, how to set them up yourself, and how to accomplish even more with related plugins.

What Are Custom Post Types?

WordPress core comes with various Post Types. The most obvious are Posts, Pages, and Attachments.

In WordPress 6.4, there are four more:

  • Revisions
  • Navigation menus
  • Block templates
  • Template parts

Fun fact: Comments are not a Post Type. I think if WordPress weren’t originally a blogging platform with comments as such a central part, one would nowadays handle them as a post type as well.

As these might suggest, Post Types are not always obvious and not necessarily something visible in the frontend that we would describe as “content”. They are more of a group of related items in the database.

You can add more of these “things,” which would then be called “Custom” Post Types.

It is not an official WordPress term, but I like the phrase Custom “Content” Types for any visible Custom Post Type. I will get into a few examples later.

Why Use a Custom Post Type?

WP Mayor has used multiple Custom Post Types over time, such as the Lifetime Deals one that you can see right now.

I have personally used Custom Post Types for many things.

The most common are separate content sections on websites. This makes the most sense when that content should show and behave differently than built-in posts and pages.

Let’s imagine that WP Mayor would also have a dedicated “News” post type. Just by registering this custom post type, one would have the following benefits:

  • A distinct “News” item in the menu in WP Admin.
  • The chance to grant users and user roles different capabilities to that type.
  • Have different templates for showing single news items on the frontend.
  • A separate archive and feed for news.
  • Additional post metadata is stored only with and displayed for news.

I have also used Custom Post Types for content elements in various plugins. I once built a booking platform for vacation homes, where homes, reservations, and payments each were a distinct Custom Post Type with unique attributes. It’s something that most e-commerce plugins for WordPress are also doing.

In another case, I wanted to log the content of all outgoing emails. So, I built a “Log” post type with the email content and all attached metadata that was only visible with the appropriate capabilities in the WordPress backend.

Finally, the Advanced Ads plugin I originally developed used a CPT to store the ad content.

These are just a few examples of Custom Post Types. I know I must have forgotten to mention many other exciting use cases I met over the years.

The main advantage of CPTs in WordPress is that they only need a few lines of code or quick setup via a plugin, and WordPress takes care of a lot of the logic you need to manage and display them on your site. So, let’s get right into how to create WordPress Custom Post Types.

Creating a Custom Post Type

Custom Post Types can be created manually or through a plugin.

If you have no experience in coding, plugins make it much easier for you to create custom post types.

One disadvantage of using a plugin is that your Custom Post Type is gone as soon as you delete the plugin. While it probably still exists in the database, WordPress no longer knows about it in the frontend or backend.

As a developer who has done this dozens of times, I still prefer the manual method. However, I happily admit that I also use plugins with nice UIs if the WordPress Custom Post Type is used temporarily or to create a showcase for a client.

Decisions for Custom Post Types

Despite the method we are using to create our Custom Post Type, we need to make a few decisions first. While you could theoretically change any of them later, doing so might greatly impact your site and setup, so it’s best to think about them in advance.

Public or not?

The main decision about Custom Post Types is who should see and interact with them. With your custom code or within a plugin, you can choose whether the CPT is visible in the frontend, including archives and single pages accessible directly, and whether users find it via search. Should it appear on the backend of your WordPress site with its menu item?

While a “News” CPT is probably fully visible in the frontend, an internal log or something like payments might be restricted to users with a specific role in your WordPress backend.

Hierarchial

You may have noticed that WordPress Posts and Pages post types behave slightly differently. Pages don’t have an archive in the frontend, but you can have parent and child pages.

The latter is called a “hierarchy,” which is also defined when creating your own post type.

For hierarchical post types, the edit page offers the option to choose a parent page and an order.

The page attributes section in the WordPress editor showing options for page hierarchy.
Hierarchy options when editing a page.

The order and parent page could matter when creating menus or lists from pages automatically. The hierarchy is also visible in the URL slug. If my page was “Troubleshooting” with “Documentation” as a parent page, the final URL might be documentation/troubleshooting.

Tip: If you have a CPT with a deeper hierarchy, I recommend using the Nested Pages plugin to quickly arrange posts in the correct order.

Block or classic editor

When creating a Custom Post Type, you are asked whether to show it in the “REST API” or not. That technical term does one crucial thing: it determines whether your CPT is using the block editor or the classic editor view.

As a rule of thumb, using the block editor makes sense if your post type is similar to regular content and you want to use WordPress blocks. Any Custom Post Type that does not need a large portion of the screen for content should choose the classic editor. Hence, it should not be delivered via the REST API.

URL slugs and structure

Another critical decision you need to make is naming the CPT slug. Our “News” post type might be referenced as news in the URL, but if you have more fancy internal names, you might want to choose a short form for the frontend URLs.

This might be an important decision for your SEO, so take a few minutes to think about this.

Supported elements

Depending on the post type you are building, you might also want to decide upfront whether to enable support for the following elements:

  • Titles (enabled by default)
  • The editor showing up (enabled by default)
  • Comments
  • Revisions
  • Authors
  • Excerpts
  • Thumbnails

There are many more options to fine-tune. However, the above are the most important to consider before using our WordPress Custom Post Type.

Create a Custom Post Type with a plugin

With this in mind, let’s look at creating Custom Post Types using a plugin and then do the same manually.

I am going with one of the most popular free ones from wordpress.org: Custom Post Type UI (CPTUI) by WebDevStudios.

Their interface is pretty straightforward, with all the options one would expect from a Custom Post Types plugin. However, it also makes it clear that custom post types are still an abstract concept to grasp and not a feature a usual WordPress publisher should tinker with without deeper knowledge of the options.

First screen with options when creating a new WordPress Custom Post Type using the Custom Post Type UI plugin.
Creating a new CPT with the Custom Post Type UI plugin.

Tip: I am personally conservative on the “public” options for my CPTs and limit them as much as possible regarding who should see them in the frontend and who should be able to change them in the backend. If needed, you can always grant more access later.

Advantages of Custom Post Type UI

There are a few things I like about this plugin that others might or might not have.

I usually create my CPTs manually, so I know that writing the labels takes a lot of time. There are around three dozen if you want to adjust all of them to mention your CPT’s name. As you can see in the screenshot above, the Custom Post Type UI plugin has an option to auto-populate these labels for you. You can still adjust them later in the interface.

Next, I can save my Custom Post Type and edit it later. I can even change the slug, and the plugin will then migrate all posts of that type. While I would try to prevent a situation in which I would need that, it is good to know that it is possible and handled by the plugin.

Custom Post Type UI keeps an overview of my post types. While it feels a bit overwhelming, it is much easier to review than custom code. I also like seeing the list of the templates in the last column.

An overview of WordPress Custom Post Types created by the Custom Post Type UI plugin.
Custom Post Type listed.

These templates are part of the magic of WordPress Custom Post Types. If our News CPT used the slug news then WordPress would automatically look for a file called archive-news.php in your theme to render the archive page of that post type or single-news.php for a single news page. See Template Hierarchy for more information.

Generating code with CPTUI

The feature that finally made me recommend Custom Post Type UI was the tool to export the CPT into PHP code. Under CPT UI > Tools > Get Code, you will find the PHP code to use in your plugin or functions.php. Kudos to the plugin developers for not locking people in.

This makes CPTUI an ideal tool for developers since we can quickly set up a Custom Post Type through the interface and then get the PHP code to use it. We can even let our customer set it up on a test site—with all the labels and so on—and then migrate it to where we need it.

The only option I couldn’t find in the plugin is to remove the custom post type with all its entities. In general, if you delete a plugin or code, the custom posts will remain in the database. However, there are dedicated plugins for cleaning that up.

Using code

If you are a developer and want to implement a Custom Post Type using code, then let me point you to the relevant sections in the WordPress documentation.

The core function to register a new Custom Post Type is the register_post_type function. Its parameters allow you to set all the options I mentioned above.

All Post Types are stored in the wp_posts table in your database. The field post_type determines which entry a post type belongs to.

You can use post metadata if your Custom Post Type is about more than just content. This data is stored in wp_postmeta.

By the way, some plugins use custom tables to manage content types. Don’t go that route unless you really have to since you wouldn’t be able to use all the built-in WordPress features and functions that come with the Custom Post Types API.

Extend Custom Post Types

If your Custom Post Type is public, you might want to customize it even more. Here are a few options.

Custom Fields and Meta Boxes

More advanced CPTs, like events or shop items, need more than content. This is where custom fields come into play. They offer input fields to structure your data in various ways. For example, an “Event” post type might need a beginning and end date or a venue so that events can be displayed and filtered.

While you can add custom fields and meta boxes with custom code, an excellent plugin for that is the very well-known Advanced Custom Fields. It has so many options and is so well maintained that even I, as a developer, wouldn’t code custom fields on my own sites.

Custom Taxonomies

As the default “Posts” post type can be ordered with “Categories” and “Tags”, you can register taxonomies for your Custom Post Type as well.

The Custom Post Type UI plugin I recommended above does help you create them as well.

Capability Management

You can use plugins like Members to create a new role for authors on your site who can only create and change your new Custom Post Type or adjust existing related user roles. This is recommended if your editorial workflow is different for each post type.

Switching Post Types

I am currently reorganizing content in an internal knowledge base built with WordPress. Posts and pages have very different goals here. Some of them changed goals, so I needed a solution to switch the post type.

While I wouldn’t recommend doing this lightly with a public post type, there is no issue doing that on a non-public site with similar post types. To accomplish this, I installed the Post Type Switcher, an excellent plugin that makes you do that with no fuss. After installing it, the plugin will add a “Post Type” section on the “Edit Post” screen. You can use this interface to change post types as needed.

Conclusion

I still consider Custom Post Types a critical feature that allowed WordPress to flourish in the last decade and beyond. It is the basis that turned our favorite CMS from a simple blogging platform into a versatile tool for managing events or online shopping.

When building plugins used on many websites, I still meet with code to create new post types. But when building sites for myself and customers, I am using plugins. They make creating and changing Custom Post Types much more straightforward and have a much better UI than I could ever build.

Thomas Maier

Thomas Maier grew his publishing business to over 40 MM page impressions, developed the popular Advanced Ads plugin for monetization, and now enjoys programming again by focusing on his Image Source Control plugin.

Discover more from our archives ↓

Popular articles ↓

33 Responses

  1. Do you like Types more than Easy Content Types [i.e., independent of views]? Is it possible to use Easy Content Types in conjunction with views?

    Also, one month later – what are you thoughts about Views?

    1. Yeah Types and Views are definitely leaders now when it comes to custom post types, custom fields and metaboxes. This is the only plugin combination I use nowadays.

  2. Hello! Thanks for sharing your vast information with the rest of us.
    I have a question, and I know it must have a somewhat simple answer, but I guess I don’t know how to word it correctly to get a decent answer in a Google search.
    I have manually inserted a Custom Post Type on my front page that works fine.
    Actually I am using Excerpts on the front page in a side column.
    I want the “Read more” link to link to a custom page template for my Custom Post Type entries only instead of the generic page template.
    How do I accomplish this? Is there a way to associate a Custom Template in the function that creates the Custom Post Type in functions.php?
    Any help you can offer would be greatly appreciated.
    Thanks!

    1. I did find an answer to my own question on . I had apparently overlooked it several times.

      “In the same way that posts are shown on their own page with single.php, custom post types will use single-{posttype}.php if it’s available.”

      I renamed my custom page using that manner and it works beautifully.

  3. Thanks Jean.

    Perhaps you can help out with an issue I’m having? I’m using a shortcode to insert custom post content into a regular post content. Unfortunately, the share plugin I’ve been using (Socialable) adds share links to both the reg post *and* the inserted custom post.

    Is there a way to force add_filter(‘the_content,…) to only filter standard posts and ignore custom posts?

    If you have any suggestions and can ping me via email that would be great. Thanks.

  4. Wow, excellent article 😉

    Jean a question:

    I need a search engine in WordPress, which is able to see beyond simple pages and post, also post type, taxonomies and custom field.

    Some time ago I used “wp custom search field”, but with the new version of wordpress does not work anymore.

    You have found some solution to this problem?

    Thank you very much 😉

  5. Thanks for the tutorial

    created the books [posttype] and additional fields but I can’t make the books apear on the website. It won’t show. Do you have an additional tutorial for creating a suitable working template for it?

    John

  6. Hi thanks for the tutorial I’m getting an error:
    Notice: Undefined index: url_noncename in /Users/admin/Dropbox/Sites/pianocourse/wp-content/themes/pianocourse/custom-posts.php on line 380

    any ideas? Many thanks

  7. No not really.

    Let’s say I have a relational database with books – in one table I have all the books, in another table all the authors biographies, in another table I have information about publisher. The whole database is relational, so that each book relate to the tables with author biographies and information about the publisher. Now on my wordpress website I want one book pr. page, and I want so that the author biographies and publisher information is visible for each book. When I update the author biography, or the publisher information then it is updated through out the site on every page about every book.

    So what I would like it this, I want to be able to go and make a new book post, and then select in a drop down list, who is the author and who is the publisher. That should then display the author biography, and some short information about the publisher on the page about the book.

    But I also need to be able to update the information, that is go in and ad information about the author biographies in one place, and have it effect every page with books by that author.

    Does that make sense?

    Thanks a lot for taking time to reading this, and hopefully understand 🙂

    1. Ok I understood now, you need to take a look at this plugin:

      Posts 2 Posts and the documentation where its usage is explained very well.

      Also check out Pods which is a bit more advanced.

      Let us know how it goes.

  8. Hi Jean

    Thanks for this great tutorial. In your example – with books, it would make sense if you could get a dropdown menu for authors, publishers etc. Like in a relational database, you should then only have to update in one place if you need to update a lot of pages with a book on each page. Hope you see what I mean – is this possible?

    Thanks in advance for any help

    1. Hi Mads, thanks for your comment. Let’s see if I’m understanding this well. Are you speaking about having the option to tick a few books from the books list, and use a dropdown to set a new author?

  9. Hey Jean,

    Great post! One of the more useful I’ve found on the subject.

    I do have a question: I’m using a custom post type, with the Custom Post Type Relationship plugin. Using their ‘get’ function, with ‘get_post_meta’, I’m pulling custom post types that are related to the single post page that I’m currently on.

    My problem is that I’m trying to get the title of the custom post to show, but the custom post type I created is using the normal post title field. How do I pull that single piece of data onto my page?

    If you have any thoughts, I’d love to hear them. Thanks,
    Dave

    1. Hi Dave, glad you found it useful. I haven’t played around that much with that plugin, you might get a quicker answer on the plugin’s forum or on wordpress.stackexchange.com. Post back if you don’t get a reply from there and I’ll try to investigate further.

    2. You can also try out the Posts 2 Posts plugin which I believe is better than the one you are currently using.

  10. some really really great stuff over here…and a great list of plugins too..thank you for sharing

  11. Excellent! You’ve definitely given one of the most well-rounded resources out there. And thanks for your comments about Easy Content Types!

  12. It is the great article which covers everything about the custom content type in wordpress. Great effort has been made to list each and every option to create custom content type. Thanks for helping the wordpress community.

  13. CHEERS! Great work… a really useful article I’ll be bookmarking as a reference… thanks so much! =)

  14. I’m thinking of using Custom Post Types on a current project and this is by far the most complete resource that I’ve found so far. Thanks very much!

    Do you have any examples of WordPress sites that make use of Custom Post Types that you’d be willing to share? I think this would help myself and others get a better sense of what’s possible.

    1. Thanks Tim, many sites are now using Custom Post Types, although it is not always obvious from the outside that they are using them. You can take a look at the themes and plugins listed above, or else at this site’s own Resources section which is built using Custom Post Types. Another site which I built using CPT is Honda.com.mt.

  15. This is one of the best WordPress tutorials out there. Custom Post Types is essential for transforming WordPress itself from a blogging platform to a complete Content Management System.
    Well done!

Share Your Thoughts

Your email address will not be published. Required fields are marked *

Claim Your Free Website Tip 👇

Leave your name, email and website URL below to receive one actionable improvement tip tailored for your website within the next 24 hours.

"They identified areas for improvement that we had not previously considered." - Elliot

By providing your information, you'll also be subscribing to our weekly newsletter packed with exclusive content and insights. You can unsubscribe at any time with just one click.