Using Custom Post Types

A WordPress website can contain multiple content types, known as “post types” in the WordPress world. The default post types are “Post” and “Page”, but you can create your own custom post types.

On my website I’ve created a Code Snippets post type and a Projects post type. This simplifies the content creation process by grouping different types of content in the backend, and lets you have dynamic archives. I can customize the edit screen with Custom Metaboxes and Taxonomies.

Registering a post type

In your core functionality plugin, use the register_post_type() function to create a post type.

* Register the Testimonial post type
function be_register_testimonial_post_type() {
$labels = array(
'name' => 'Testimonials',
'singular_name' => 'Testimonial',
'add_new' => 'Add New',
'add_new_item' => 'Add New Testimonial',
'edit_item' => 'Edit Testimonial',
'new_item' => 'New Testimonial',
'view_item' => 'View Testimonial',
'search_items' => 'Search Testimonials',
'not_found' => 'No Testimonials found',
'not_found_in_trash' => 'No Testimonials found in Trash',
'parent_item_colon' => 'Parent Testimonial:',
'menu_name' => 'Testimonials',
$args = array(
'labels' => $labels,
'hierarchical' => false,
'supports' => array( 'title', 'editor', 'thumbnail' ),
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_nav_menus' => true,
'show_in_rest' => true,
'publicly_queryable' => true,
'exclude_from_search' => false,
'has_archive' => true,
'query_var' => true,
'can_export' => true,
'rewrite' => array( 'slug' => 'testimonials', 'with_front' => false ),
'menu_icon' => 'dashicons-groups', //
register_post_type( 'testimonial', $args );
add_action( 'init', 'be_register_testimonial_post_type' );
view raw post-type.php hosted with ❤ by GitHub

The labels parameter lets you customize all the labels used throughout the WordPress backend. It’s usually as simple as find/replacing the plural and singular forms of the post type, but you may want to tweak some of the other labels more extensively.


The supports parameter lets you specify which WordPress features should be enabled for this post type. Options:

  • ‘title’
  • ‘editor’ (content)
  • ‘author’
  • ‘thumbnail’ (featured image, current theme must also support post-thumbnails)
  • ‘excerpt’
  • ‘trackbacks’
  • ‘custom-fields’
  • ‘comments’ (also will see comment count balloon on edit screen)
  • ‘revisions’ (will store revisions)
  • ‘page-attributes’ (menu order, hierarchical must be true to show Parent option)
  • ‘post-formats’ add post formats, see Post Formats
Show in REST

The show_in_rest parameter lets you decide if this post type should be visible in the REST API. This must be set to true if you’d like to use the new Gutenberg block editor

Has Archive

The has_archive parameter enables the post type archive, a dynamic archive listing recent content in this post type.


The rewrite parameter lets you enable and customize the URL rewriting for this content type.

Menu Icon

The menu_icon parameter lets you specify a Dashicon to use as the icon in the admin area.

Using a plugin

Rather than coding it yourself, you can use Custom Post Type UI to create and manage your custom post types. The plugin lets you specify the post type slug, labels, and settings shown above.

Bill Erickson

Bill Erickson is a freelance WordPress developer and a contributing developer to the Genesis framework. For the past 14 years he has worked with attorneys, publishers, corporations, and non-profits, building custom websites tailored to their needs and goals.

Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk

Reader Interactions


  1. Neil says

    Great post. Bill, do you think there is a speed-to-load advantage in adding your own code in custom functions versus these custom post plugins? Or is any advantage out-weighed by their ease of use?

    • Bill Erickson says

      That’s a good question, and I’ve never tested both options from a performance standpoint. I do know that once you use the Custom Post Type UI plugin to create the post type, you can remove the plugin and everything still works (it’s only used once to create it). I don’t think there’s a performance hit for using either plugin over hand-coding, but I can’t be sure.

  2. Katarsis says

    Hi, i ´am starting my own bussiness in develope wordpress site (i love this) and i have a question
    do you update plugins in the customers sites? or disable the upg´s annoucement and do not upg never? or only when strongly necessary?

    tks but i don´t know how to treat this topic in the future?

    tks again and sorry my language (i am from uruguay)

    • Bill Erickson says

      I try and minimize the use of plugins, but there are a few that I use often. Examples would be All in One SEO (for sites not built with Thesis or Genesis), Contact Form 7, and Akismet. Since I try to use well-established plugins, I don’t often update them because the updates aren’t (usually) security-based, they only provide new features. If the old plugin is working, no reason to upgrade and take a chance of it breaking.

    • Nanette says

      I tried followed your tutorial, thanks… but I am having a problem. When I pasted this code into my custom_page template I get errors. And I dont see any of the custom post.

      • Bill Erickson says

        What type of error did you get?

        I didn’t provide the complete code for displaying them on the page, so I’m not sure what code you copied.

        • Nanette says

          I guess I need the full code that I would put int customfunctions.php (in Thesis.) Can you help me out?

          I already have custom template that replaces my thesis_custom_template that I use for my home page. Is it possible to use a conditional tag that says if front_page use template “A” and then if product_page (which is my custom post type use template “B”?

    • Bill Erickson says

      Change query_posts to this: query_posts(‘post_type=staff-directory&showposts=-1&orderby=title&order=ASC’);

      That will sort them by the title, from A-Z.

      • Kyle Jones says

        I ran across this a bit after posting, but my situation is that I don’t use the default title, I use meta fields name_last_name and name_first_name. So, I need to be able to sort by name_last_name.


        • Bill Erickson says

          Ah, then you should change query_posts to this:

  3. ptim says

    Hi Bill, thanks so much for your great resources (love core-functionality, in particular).

    Just wanted to clarify – you’ve written: “You can customize this using the archive-ebook.php template file. For single posts, use archive-ebook.php.” Should that last line read single-ebook.php?

    I’m was having trouble with the has_archives property – eventually found that I needed to flush the rewrite rules by hitting Save on the Permalink settings. Had me scratching my head – hope it helps someone 🙂

  4. Jamie says

    Dear Bill

    i’m using a custom post type of ‘portfolio’ and the genesis framework.

    the portfolio will be the home page (for a designers site so the latest work is up front)

    i created a function in the home.php to show my ‘portfolio’ custom post type, BUT, other regular posts show too?

    how can i only show the custom post types? or is this not possible with the home.php in genesis, might need to just do a page template, and set that as the home page.

    thanks in advance

    • Bill Erickson says

      home.php should really only be used for listing your blog posts. If you want portfolio items on your homepage, I recommend:
      1. Creating a page called “Home”, then go to Settings > Reading and set it as the front page.
      2. If you still want a blog, create a page called “Blog” and in Settings > Reading set it as the posts page (home.php will be used for this page)
      3. You could either create a front-page.php template file for the front page, or a page template and then specify that the homepage is using that template. In this file, build your custom query.

      • Jamie says

        Thanks for clearing that up Bill, you just saved me a few hours of my time, as i was completely on the wrong track. I get it all now.

        Really appreciate your support 🙂

  5. Chris says

    Hey Bill, thanks for this great plugin!

    Currently I have a banner image (featured image) after the Genesis header that it is pulling from for the posts in the grid. Is there a way to set a different image for the archive page teasers? I thought possibly adding max-height to 100% in CSS might do it, but something tells me I may need to set up something to crop it on upload…it’s all a bit new to me how to do this. Would appreciate any thoughts or suggestions on how to achieve this, thanks!

  6. Jason says

    Hey Bill,

    I have set up a custom post type and taxonomy for my site but when I go to the post type page and the custom taxonomy base page they are completely blank. Not a 404, just blank. I have created an archive template, archive-kellen_clients.php and I am using your template selection function but still nothing. I have re-saved the permalink structure but this didn’t help either.

    Custom Post Type Page

    Custom Taxonomy – for a category that I created

    The post itself shows up

    Here is my entry from my functions.php file.

    Any clue what I am doing wrong? I am hoping that you have seen this before. Thank you for your help and a huge thank you for all of your tutorials.

    • Bill Erickson says

      It looks like you have a php error that’s preventing the page from loading.

      In wp-config.php, add define( 'WP_DEBUG', true ); to turn on debug mode.

      Once debug mode is on, reload those pages and you should get an error message that points you in the right direction.

  7. Hans says

    Hi Bill,

    I’ve been reading a lot of your posts lately with growing appreciation for the clarity and willingness to help and share that you demonstrate here. I am a gratefull for the opportunity to learn from such an expert. I begin to understand more and more of how wp works and can be handled. There’s a lot to know and learn. So thanks for the clarification you offer and the related sources you point to. Some great articles here.

    At the moment I use genesis/studiopress themes and have only made some slight adjustments with help of snippets and documentation.

    Now I want to add to my website, functions like a shop and payed courses, and I’ve been looking at cpt’s. Reading the codex and your article, making a cpt seems not that difficult, reducing the need to use extra plugins. But in my case I also want visitors to be able to submit a custom post (entering custom fields data) in a form at the frontend.

    I’m not sure about how to do that, except for using more advanced plugins like wp-types / toolset that seems to have it all (especially combined with beaver builder), but I’m a bit worried that such a combo could be too heavy for a shared server and that pageload would skyrocket. Would you advise for such a combination? If not, why not?

    You did mention ACF in another post and said you use that sometimes in projects, but not to present custom field data in the frontend. I guess that plugin could be used to add the custom fields to the cpt, but I then still need a form plugin that can submit the data on the frontend and save it in the cpt and cf. Could Gravity Forms be sufficient for that in combination with acf?

    I would appreciate any pointer to what option could be feasible/advisable. The solution has to run on a well managed ssd shared hosting plan (2 cores).

    Thanks, Hans

      • Hans says

        Great, I’m looking forward to reading that article. 🙂

        I’m using the free version of NinjaForms now (as was advised by StudioPress), but will probably upgrade to a premium forms plugin like Gravity Forms soon and WPForms is looking good too. So I will wait for your article on that. With my current knowledge and skillset the help of some well-build and maintained plugins seems inevitable.

        I understand implicitly you don’t advise using solutions like wp-types toolset, and just use php and wordpress and perhaps acf to build and present cpt’s with cf’s. I hope I will be able to pull it of with help of your articles and pointers.

        Thanks, Hans

  8. Alvina says

    I am trying to enable Gutenberg editor for custom post types and having an error. Can you help me resolve this error? I am having in this line of code

    register_post_type( ‘portfolio’,
    // WordPress CPT Options Start
    ‘labels’ => array(
    ‘name’ => __( ‘Portfolio’ ),
    ‘singular_name’ => __( ‘Portfolio’ )
    ‘has_archive’ => true,
    ‘public’ => true,
    ‘rewrite’ => array(‘slug’ => ‘portfolio’),


    I have seen this code here

Leave A Reply