The Complete Guide To WordPress Custom Post Types — Smashing Magazine (2024)

  • Daniel Pataki
  • 0 comments
  • 15 min read
  • WordPress,Techniques,Guides

About The Author

Hello, I’m Daniel and I make things for the web. I’m the CTO at Kinsta and I write for a number of amazing publications like Smashing Magazine and …More aboutDaniel↬

Email Newsletter

.
Trusted by 200,000+ folks.

Creating a CMS is pretty easy due to the modular nature of WordPress controls and functions. Daniel Pataki outlines some methods that can be used extremely well to create customized admins for nearly anything you can think of.

WordPress has been gaining a foothold in the general content management system (CMS) game for a few years now, but the real breakthrough was the custom post type mechanism which allows for the creation of a wide variety of content. Let’s take a look at how this came to be and all the options that this great functionality offers.

The Complete Guide To WordPress Custom Post Types — Smashing Magazine (9)

What It Used To Be Like

In practice, custom post types have been around for a long time, more specifically since February 17, 2005, when WordPress 1.5 added support for static pages, creating the post_type database field.

The wp_insert_post() function has been around since WordPress 1.0, so when the post_type field was implemented in 1.5, you could simply set the post_type value when inserting a post. Of course, creating and managing custom post types required much more than that, but the amount of coding needed became less and less as WordPress functions became more and more flexible.

By version 2.8, the register_post_type() function and some other helpful things were added to the nightly builds, and when 2.9 came out, the functions became available to everyone. At this point, extensive coding and hacks were not needed to make WordPress a full blown CMS; you could use plenty of great built-in functions to make WordPress do your bidding.

What WordPress Can Do For You Now

A custom post type is nothing more than a regular post with a different post_type value in the database. The post type of regular posts is post, pages use page, attachments use attachment and so on. You can now create your own to indicate the type of content created. You could create custom post types for books, movies, reviews, products and so on.

If created correctly, you can achieve the following with a few lines of code:

  • The custom post type will show up in the back end as a separate menu item with its own post list and “add new” page
  • Navigating to https://mysite.com/customposttype/ will take you to the archive page for the post type. This is akin to visiting the front page for latest posts from the “post” post type.
  • Categories and tags can be made available to the custom post type, or you can create custom taxonomies.

Apart from these, you can modify countless options, such as where the custom post type should be placed in the menu, should it be searchable, which user level can access it, should it be hierarchical, custom rewrite rules, etc.

Different types of content have different data requirements. For regular posts, you’ll want to specify the author, category, date and so on. For a “book” custom post type, ideally you’d like to have the option to specify the book’s author, the page count, genre, publisher and other book-specific data. Using custom meta boxes, this is easily achieved and managed as well.

Custom meta boxes enable you to add additional boxes to the edit screen of a post. They usually use custom fields, so you could just use custom fields as well, but by separating out some custom fields as meta boxes, you can create a much smoother and usable admin.

Working With Custom Post Types

To effectively create and use custom post types, you’ll need to be familiar with the following:

  • Creating custom post types,
  • Creating custom taxonomies,
  • Creating custom meta boxes.

Creating Custom Post Types

First on our agenda is creating the post type itself. Ideally you should create a plugin when working with custom post types, but if you don’t know how, or just need a quick test, you can use the functions.php file in your theme.

function my_custom_post_product() { $args = array(); register_post_type( 'product', $args ); }add_action( 'init', 'my_custom_post_product' );

In its simplest form, it will create a post type which has almost no customization. It won’t be public, it won’t show up in the admin, interaction messages will be the same as posts (“post saved,” “post updated,” etc.) and so on. To tailor our new post type to our needs, I’ll go through some of the more frequently-used options and add them to the previously empty $args array.

function my_custom_post_product() { $labels = array( 'name' => _x( 'Products', 'post type general name' ), 'singular_name' => _x( 'Product', 'post type singular name' ), 'add_new' => _x( 'Add New', 'book' ), 'add_new_item' => __( 'Add New Product' ), 'edit_item' => __( 'Edit Product' ), 'new_item' => __( 'New Product' ), 'all_items' => __( 'All Products' ), 'view_item' => __( 'View Product' ), 'search_items' => __( 'Search Products' ), 'not_found' => __( 'No products found' ), 'not_found_in_trash' => __( 'No products found in the Trash' ), 'parent_item_colon' => ’, 'menu_name' => 'Products' ); $args = array( 'labels' => $labels, 'description' => 'Holds our products and product specific data', 'public' => true, 'menu_position' => 5, 'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt', 'comments' ), 'has_archive' => true, ); register_post_type( 'product', $args ); }add_action( 'init', 'my_custom_post_product' );
  • labels The labels option should be an array defining the different labels that a custom post type can have. I have separated this out above just to make the arguments for registering a post type clearer.
  • description A short explanation of our custom post type; what it does and why we’re using it.
  • public This option controls a bunch of things in one go. Setting this to true will set a bunch of other options (all to do with visibility) to true. For example, it is possible to have the custom post type visible but not queryable. More on this later.
  • menu_position Defines the position of the custom post type menu in the back end. Setting it to “5” places it below the “posts” menu; the higher you set it, the lower the menu will be placed.
  • supports This option sets up the default WordPress controls that are available in the edit screen for the custom post type. By default, only the title field and editor are shown. If you want to add support for comments, revisions, post formats and such you will need to specify them here. For a full list take a look at the arguments section in the Codex.
  • has_archive If set to true, rewrite rules will be created for you, enabling a post type archive at https://mysite.com/posttype/ (by default)
The Complete Guide To WordPress Custom Post Types — Smashing Magazine (10)

After setting this up, you should see the menu entry for the custom post type. You should be able to add posts, view the post list in the admin and also visit the published posts on the website.

As I mentioned there are a lot of things you can modify when creating a post type. I suggest looking at the arguments list in the Codex for a full description of each option and the possible values.

Custom Interaction Messages

WordPress generates a number of messages triggered by user actions. Updating, publishing, searching, etc., in the back end all lead to messages which — by default — are tailored to regular posts. You can change the text of these messages easily by using the post_updated_messages hook.

function my_updated_messages( $messages ) { global $post, $post_ID; $messages['product'] = array( 0 => ’, 1 => sprintf( __('Product updated. <a href="%s">View product</a>'), esc_url( get_permalink($post_ID) ) ), 2 => __('Custom field updated.'), 3 => __('Custom field deleted.'), 4 => __('Product updated.'), 5 => isset($_GET['revision']) ? sprintf( __('Product restored to revision from %s'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, 6 => sprintf( __('Product published. <a href="%s">View product</a>'), esc_url( get_permalink($post_ID) ) ), 7 => __('Product saved.'), 8 => sprintf( __('Product submitted. <a target="_blank" href="%s">Preview product</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ), 9 => sprintf( __('Product scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview product</a>'), date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ), 10 => sprintf( __('Product draft updated. <a target="_blank" href="%s">Preview product</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ), ); return $messages;}add_filter( 'post_updated_messages', 'my_updated_messages' );
The Complete Guide To WordPress Custom Post Types — Smashing Magazine (11)

As you can see, this is not the most user-friendly method of managing messages. An associative array would be far better; we could see what each message is for without having to read the actual message.

Notice that you can change the messages for all custom post types using this single function. The $messages array holds the messages for all post types, so you can modify them all here. I personally create a function for each post type just so I can group the post type creation and the custom messages together easily.

Contextual Help

A feature I rarely see implemented is the customized contextual help. As a user, I’ve never actually used this feature myself, but I’m sure that many people do; in any case, it’s nice to provide some hand-holding for less experienced users.

The contextual help feature is a descending tab which can be seen in the top right of pages where available. Let’s take a look at how the contents can be changed.

function my_contextual_help( $contextual_help, $screen_id, $screen ) { if ( 'product' == $screen->id ) { $contextual_help = '<h2>Products</h2> <p>Products show the details of the items that we sell on the website. You can see a list of them on this page in reverse chronological order - the latest one we added is first.</p> <p>You can view/edit the details of each product by clicking on its name, or you can perform bulk actions using the dropdown menu and selecting multiple items.</p>'; } elseif ( 'edit-product' == $screen->id ) { $contextual_help = '<h2>Editing products</h2> <p>This page allows you to view/modify product details. Please make sure to fill out the available boxes with the appropriate details (product image, price, brand) and <strong>not</strong> add these details to the product description.</p>'; } return $contextual_help;}add_action( 'contextual_help', 'my_contextual_help', 10, 3 );

This is also a bit difficult because you have to know the ID of the screen you are on. If you print out the contents of the $screen variable, you should be able to determine the ID easily. This is also a function you can use to modify the contextual help of all custom post types at once, but I personally recommend grouping this together with the previous two blocks and only using it for one custom post type at a time.

Overview

To quickly recap, we used three functions to create a “complete” custom post type. We used register_post_type() to create the post type itself and two hooks — contextual_help and post_updated_messages — to create helpful guidance and relevant messages respectively.

Custom Taxonomies

Your regular blog posts use categories and tags to create an organization structure. However, the same organization doesn’t necessarily make sense for custom post types. Your blog posts could be about your “Life,” your “Thoughts” or your “Dreams.” These are obviously not appropriate for products.

This is the problem that drove developers to create custom taxonomies. You can create a separate taxonomy named “Product Categories” to house categories you only use for products. Kevin Leary wrote a great article about custom taxonomies in WordPress which I highly recommend, so I will only go into minor detail here.

function my_taxonomies_product() { $args = array(); register_taxonomy( 'product_category', 'product' $args );}add_action( 'init', 'my_taxonomies_product', 0 );

Similarly to custom post types, you can create a taxonomy very easily, but you need to work at it a bit to tailor it to your needs. Custom taxonomies behave a bit better out of the box as they are public by default, so the above is actually enough to tie this taxonomy to the product posts. Let’s look at a customized example.

function my_taxonomies_product() { $labels = array( 'name' => _x( 'Product Categories', 'taxonomy general name' ), 'singular_name' => _x( 'Product Category', 'taxonomy singular name' ), 'search_items' => __( 'Search Product Categories' ), 'all_items' => __( 'All Product Categories' ), 'parent_item' => __( 'Parent Product Category' ), 'parent_item_colon' => __( 'Parent Product Category:' ), 'edit_item' => __( 'Edit Product Category' ), 'update_item' => __( 'Update Product Category' ), 'add_new_item' => __( 'Add New Product Category' ), 'new_item_name' => __( 'New Product Category' ), 'menu_name' => __( 'Product Categories' ), ); $args = array( 'labels' => $labels, 'hierarchical' => true, ); register_taxonomy( 'product_category', 'product', $args );}add_action( 'init', 'my_taxonomies_product', 0 );

As you can see, not much has changed. We added some labels and set the hierarchical option to true. This enables “category style” taxonomies. When set to false (this is the default), your taxonomy will be like the default tags.

There are a few other power options available which you can read about in Leary’s article, or you can go to the Codex entry on register_taxonomy().

The Complete Guide To WordPress Custom Post Types — Smashing Magazine (12)

Post Meta Boxes

Meta boxes are the draggable boxes you see in the WordPress edit screen for a post. There are numerous built-in meta boxes like the publishing controls, the taxonomies, the author box, etc., but you can create some for yourself.

Meta boxes tend to be used to manage custom field data in a much more user-friendly way than the built-in custom fields box does. Since you put the controls in place, you can add client-side error checking and many other fancy things.

Justin Tadlock wrote the all-encompassing custom meta box article here on Smashing Magazine, which is a great in-depth article on the subject. I recommend reading it for the full picture, but I’ll get you started here.

Creating a meta box requires three steps:

  • Define the box itself,
  • Define the content of the meta box,
  • Define how the data from the box is handled.

Defining The Meta Box

add_action( 'add_meta_boxes', 'product_price_box' );function product_price_box() { add_meta_box( 'product_price_box', __( 'Product Price', 'myplugin_textdomain' ), 'product_price_box_content', 'product', 'side', 'high' );}

The code above creates the meta box with the following parameters (in the order given):

  • The unique identifier for the meta box (it does not have to match the function name),
  • The title of the meta box (visible to users),
  • The function which will display the contents of the box,
  • The post type the meta box belongs to,
  • The placement of the meta box,
  • The priority of the meta box (determines “how high” it is placed).

Defining The Content Of The Meta Box

function product_price_box_content( $post ) { wp_nonce_field( plugin_basename( __FILE__ ), 'product_price_box_content_nonce' ); echo '<label for="product_price"></label>'; echo '<input type="text" id="product_price" name="product_price" placeholder="enter a price" />';}

This is a simple box which only contains the price, so we have created a label and an input to manage it. A nonce field is also present, which adds security to the data submission.

Handling Submitted Data

In most cases, you will want to save the data as a custom field, but you are by no means restricted to this method. You could use the input to make a third party API call, to generate an XML file or whatever you like. The most common use is saving custom post data, so let’s take a look at how that is done.

add_action( 'save_post', 'product_price_box_save' );function product_price_box_save( $post_id ) { if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return; if ( !wp_verify_nonce( $_POST['product_price_box_content_nonce'], plugin_basename( __FILE__ ) ) ) return; if ( 'page' == $_POST['post_type'] ) { if ( !current_user_can( 'edit_page', $post_id ) ) return; } else { if ( !current_user_can( 'edit_post', $post_id ) ) return; } $product_price = $_POST['product_price']; update_post_meta( $post_id, 'product_price', $product_price );}

The biggest part of this function is all about safety. First of all, if an autosave is being performed, nothing happens because the user hasn’t actually submitted the form. Then the nonce is checked, followed by permission checking. If these are all passed, we take our data and add it to the post using the update_post_meta() function.

The Complete Guide To WordPress Custom Post Types — Smashing Magazine (13)

Displaying Your Content

While there a plenty of nuances to all of the above, you should be familiar with the basics. All that is left is to actually use the data we now have and show things to the user. This involves showing posts — perhaps from various custom post types and taxonomies — and using our post metadata.

Displaying Posts

If you’ve created a post type with the has_archive parameter set to “true,” WordPress will list your posts on the post type’s archive page. If your post type is called “books,” you can simply go to https://mysite.com/books/ and you’ll see your post list.

This page uses archive-[post_type].php for the display if it exists (archive-books.php in our case). If it doesn’t exist, it will use archive.php and if that doesn’t exist it will use index.php.

Another way to display custom post type content is to use a custom query with the WP_Query class. To display posts from a certain post type and custom taxonomy, you could do something like this:

<?php $args = array( 'post_type' => 'product', 'tax_query' => array( array( 'taxonomy' => 'product_category', 'field' => 'slug', 'terms' => 'boardgames' ) ) ); $products = new WP_Query( $args ); if( $products->have_posts() ) { while( $products->have_posts() ) { $products->the_post(); ?> <h1><?php the_title() ?></h1> <div class='content'> <?php the_content() ?> </div> <?php } } else { echo 'Oh ohm no products!'; } ?>

Displaying Metadata

Metadata can be retrieved easily using the get_post_meta() function. In our example above, we saved a post meta field named product_price. We can retrieve the value of this field for a given post using the following code:

<?php // If we are in a loop we can get the post ID easily $price = get_post_meta( get_the_ID(), 'product_price', true ); // To get the price of a random product we will need to know the ID $price = get_post_meta( $product_id, 'product_price', true );?>

Final Words

As you can see, creating a CMS is pretty easy due to the modular nature of WordPress controls and functions. The methods outlined here can be used extremely well to create customized admins for nearly anything you can think of.

Since defining the content of meta boxes is completely up to you, you have the power to create additional features for your controls, making you or your clients very happy.

You can take this one step further with custom admin pages and completely custom content, but that’s a story for another day.

Image source of picture on front page.

Further Reading

  • Extending WordPress With Custom Content Types
  • A Detailed Guide To WordPress Custom Page Templates
  • Customizing WordPress Archives For Categories, Tags
  • Building A Custom Archive Page For WordPress

The Complete Guide To WordPress Custom Post Types — Smashing Magazine (14)(cp, mrn)

Explore more on

The Complete Guide To WordPress Custom Post Types — Smashing Magazine (2024)

FAQs

How do I get all custom post types in WordPress? ›

As luck would have it, WordPress has a get_post_types() function that returns the names of all standard post types and custom post types. So, to find out all the post types available to us, we'll use the get_post_types() function along with the print_r() function in PHP to return and display a result.

Can you create custom post types in WordPress? ›

A: You can create a custom post type category in WordPress by using a plugin or custom code. Follow the steps below if you want to use a plugin: Go to your WordPress dashboard. Download a plugin like Custom Post Type UI.

What is the difference between post type and custom post type? ›

Custom types are different than posts and pages because they are completely created by the admin and have no pre-defined settings within WordPress. They are good content for search engines and the can contain both timely and timeless information about a WordPress website.

How to create custom post type in WordPress step by step without plugin? ›

How To Generate a Custom Post Type Without A Plugin
  1. Go to the Post Type Generator.
  2. Fill in the fields for your custom options.
  3. Click Update Code.
  4. Create a file on your computer that ends with a .php extension (for example, custom-post-type.php )
  5. Add the WordPress plugin file header to the very top of the code1
Jan 7, 2021

How to get custom post type in WordPress programmatically? ›

Before getting started

It's free and you can download them directly from wordpress.org. Just go to your Dashboard > Plugins > Add New and search for "mb custom post types". After installing and activating these above two plugins, a new menu will appear in the left panel. Select the Post Types submenu of that.

Where does WordPress store custom post types? ›

The wp_posts table stores all of the content of your posts, of all post types. So it doesn't matter if we're talking about a blog post, a page, a revision, an attachment, or a custom post type: they'll all be stored in this wp_posts table.

How do I convert posts to custom post type in WordPress? ›

Go to the WordPress editor of the desired post/page and open the Summary tab on the right side of the page. Find the Post Type field and press the link next to it to change the post type. Pick the post type you want to switch your content to; for example, it can be JetEngine's CPT.

When to use custom post type? ›

Custom post types are commonly used when you need to create a new content type that extends the functionality of the default posts post type. A post within a custom post type is similar to a default post but can have a custom layout, custom fields, custom taxonomy, and its own archive pages.

What is the preferred method for adding a custom post type in WordPress? ›

To register a new post type, you use the register_post_type() function. We recommend that you put custom post types in a plugin rather than a theme. This ensures that user content remains portable even if the theme is changed.

How do I add categories to custom post type? ›

All you have to do is add this code to your theme's functions. php file or in a site-specific plugin: function reg_cat() { register_taxonomy_for_object_type('category','CUSTOM_POST_TYPE'); } add_action('init', 'reg_cat'); Don't forget to change the CUSTOM_POST_TYPE to the name of the custom post type you created.

What is the default order of custom post type in WordPress? ›

The order can be customized within default WordPress post type archive list page or a separate Re-Order interface which displays all objects. It allows reordering the posts for any custom post types you defined, including the default Posts.

How to get all custom post types in WordPress? ›

To use this plugin, create a new folder in your WordPress installation's wp-content/plugins directory and name it something like custom-post-type-listing . Then, create a new PHP file named custom-post-type-listing. php inside that folder and copy the code above into it.

Can I assign a template to a custom post type? ›

You can create a custom WordPress template for a page, post, or custom post type and make it appear in the Template dropdown list on page, post, or custom post type editing screens.

How do I move a post to a custom post type in WordPress? ›

Switching Post Types in the Block Editor

Simply click on the 'Post' link next to the 'Post Type' option to open the dropdown menu. After that, select the custom or default post type to which you want to switch your content.

How do I get all the categories of a post type in WordPress? ›

There are several ways to get categories in WordPress. The get_categories() function will retrieve all the categories available in your site regardless of post type. Similarly wp_list_categories() and get_terms() can also fetch and display categories or terms.

How do I see all custom fields in WordPress? ›

By default, the custom fields option is hidden in WordPress. To enable this feature, access your page or post editor. Locate the Screen Options button on the right corner of your screen, and check the Custom Fields box.

Where are custom post types stored in WordPress? ›

The wp_posts table stores all of the content of your posts, of all post types. So it doesn't matter if we're talking about a blog post, a page, a revision, an attachment, or a custom post type: they'll all be stored in this wp_posts table.

Top Articles
Latest Posts
Article information

Author: Geoffrey Lueilwitz

Last Updated:

Views: 6229

Rating: 5 / 5 (80 voted)

Reviews: 95% of readers found this page helpful

Author information

Name: Geoffrey Lueilwitz

Birthday: 1997-03-23

Address: 74183 Thomas Course, Port Micheal, OK 55446-1529

Phone: +13408645881558

Job: Global Representative

Hobby: Sailing, Vehicle restoration, Rowing, Ghost hunting, Scrapbooking, Rugby, Board sports

Introduction: My name is Geoffrey Lueilwitz, I am a zealous, encouraging, sparkling, enchanting, graceful, faithful, nice person who loves writing and wants to share my knowledge and understanding with you.