DOC & Help Center


How to Create Custom Post Types In WordPress

In this tutorial, we will create a plugin that adds two new post types to WordPress. Then we will create new layouts for both post types using templates. We will also enable the post editor’s Custom Fields feature for each post type, and display the fields in the new templates.

Custom Post Types give you full control over how content is displayed to your visitors. If you write personal blog posts, you can create a layout just for those. If you also write movie or music reviews, you can add extra content areas to those posts that don’t appear in your blog posts.

But before we proceed, let’s find our what are custom post types.

What Are WordPress Custom Post Types?

In short WordPress custom post types allow you to sort posts based on their content. In WordPress, the default post types are Post, Page, Attachment, etc.

Typically, you write all your posts in the Posts section of the Admin Control Panel, then assign a category to them. Every post of every type appears in the same list, making it difficult to differentiate by the type of content they contain.

Custom post types have their own link in the admin control panel, leading to a list of posts of that type. Posts created this way can be assigned categories like a normal post, so you have absolute freedom to sort and present posts any way you like.

In the example above, if a user goes to the movie database section of your site, the review posts are not included. If you make, for example, ‘Action’ and ‘Romance’ categories, your users could go to the category page for Action movies and see all reviews and movie entries for that category.

When creating a new post type, you have numerous options such as where in the admin menu the link appears, whether that type of post is included in search results, whether it supports excerpts, whether comments are allowed, and so on.

You can change various pieces of text (defined using the $labels array), such as renaming Add New Post as Add New Movie. For example, you can rename the Featured Image text so it reads Add Poster instead.

You can also choose to enable the custom fields feature in the post editor, which is hidden by default and must be enabled using the Screen Options link at the top of the editor.

Continuing with the Movies and Movie Reviews example, a Movie post can add custom fields for things like release year, director, IMDB rating, and so on, with the movie synopsis as the content of the post.

Normally, any custom fields you create are selectable on all post types, so a plugin is required to limit where each field appears.

Creating New Post Types

When performing significant changes to WordPress, creating a plugin is one of the available options. You could also create custom post types in a theme’s functions.php file. For this tutorial, we will create a plugin and continue using the movie database/reviews example.

To create a custom post type, you must write a new function that calls the WordPress function named register_post_type() with two parameters. Your function must be hooked to the init action hook, otherwise, your custom post type will not register correctly.

All custom functions should be prefixed to avoid conflicts with other plugins or theme functions. I’ll be using my initials for this tutorial – LC.

The two parameters for register_post_type() are:

  1. The name of the post type, maximum of 20 characters and must not contain spaces or capital letters
  2. An associative array named $args that contains information about the post type in ‘key’ => ‘value’ pairs

As the arguments and labels are both arrays, it’s cleaner to first write the labels in their own variable, then the args variable, then call the function.

The $args Array

The most used keys for the $args array are below, all are optional:

  • labels – An array that defines various pieces of text, i.e. ‘Add New Post’ can be renamed ‘Add New Movie’. The keys for the labels array are explained below this list.
  • description – A short & descriptive summary of the post type, this can be shown in the post type’s template but is not used anywhere else.
  • public – Whether the post type is visible to authors and visitors, the default value is FALSE which means it does not even appear in the Admin Control Panel.
  • exclude_from_search – Whether posts of this type appear in normal search results. The default value is the opposite of public’s value.
  • publicly_queryable – Whether posts of this type can be retrieved using an URL such as, or in advanced usage, via the query_posts() function. The default value is public’s value
  • show_ui – Whether the menu links and post editor are visible in the Admin Control Panel. The default value is public’s value.
  • show_in_nav_menus – Whether posts of this type can be added to navigation menus created via the Appearance -> Menus screen. The default value is public’s value.
  • show_in_menu – Where the post type link appears in the Admin Control Panel navigation. FALSE hides the link. TRUE adds the link as a new top-level link. Entering a string allows you to place link as sub-link of existing top-level link i.e. entering options-general.php places it under the Settings link.
  • show_in_admin_bar – Whether this post type appears in the upper Admin bar, under the + New link
  • menu_position – Position of the new link in the Admin Control Panel navigation menu, 5 puts it below Posts, 100 puts it below Settings, visit the WordPress Codex entry for the full list of positions
  • hierarchical – whether posts can be assigned to a Parent post, if TRUE, the $supports array must contain the feature ‘page-attributes’
  • supports – selectively enable various post features such as featured images, excerpts, custom fields, etc. If set to FALSE instead of an array, it disables the editor for this post type – useful if you want to lock all posts of this type while keeping them visible (list of array values is below)
  • taxonomies – an array of taxonomies that can be applied to posts of this type, taxonomies must already be registered – this does not create them!
  • has_archive – whether the post type has an archive page, the url follows your permalink structure, and the slug is the name you entered in parameter 1 of register_post_types() i.e. shows all movie_review posts.
  • query_var – TRUE or FALSE sets whether a post can be viewed by typing the post type and post name as a query in the URL i.e. ‘‘. If you enter a string of text, you can set the text to use after the ? character, so entering ‘film’ would result in ‘?film=the-matrix‘ instead.

The full list can be viewed on the WordPress Codex page for register_post_type().

The labels Array

The first key in the $args array is named labels and must be an array. It defines various pieces of text related to the post type. As this contains a lot of information, it’s better to create a variable named $labels to hold it. The example code above makes this clearer.

Below are some of the important keys for the labels array, all are optional:

  • name – The general plural name for the post type e.g. movies
  • singular_name – Name for a single post of this type e.g. movie
  • add_new – Replaces the ‘Add New’ text e.g. ‘Add Movie’
  • add_new_item – Replaces ‘Add New Post’ e.g. ‘Add New Movie’
  • edit_item – Replaces ‘Edit Post’ e.g. ‘Edit Movie’
  • featured_image – Replaces ‘Featured Image’ in post editor e.g. ‘Movie Poster’
  • set_featured_image – Replaces ‘Set Featured Image’ i.e. ‘Add Movie Poster’
  • menu_name – Changes the text of the top-level link, default text for the link is the name key

The full list can be viewed on the WordPress Codex page for register_post_type().

The ‘supports’ Array

// Enable specific features in the post editor for my post type
$supports = array ( 'title', 'editor', 'author', 'thumbnail' );

// Disable ALL features of the post editor for my post type
$supports = FALSE;

One of the keys in the $args array is named supports. This is a simple array where you write the list of post editor features you want to enable for your custom post type. By default, only title and editor are enabled.

You can also write FALSE here instead of an array, to disable all post editing features including title and the content area. This means posts can’t be edited, but are still fully visible.

Here is the list of post editor features you can enable in the $supports array:

  • title
  • editor
  • author – NOTE: this allows you to change the author of the post
  • thumbnail
  • excerpt
  • trackbacks
  • custom-fields
  • comments
  • revisions
  • page-attributes
  • post-formats

Creating the New Post Types via Plugin

Now that we know what information is required for the function, we can build our plugin, write the custom functions, and hook them to the init action hook.

If you enable this plugin, you will now see two new links in the Admin Control Panel navigation, directly below the Posts link.

Mousing over either will show you sub-links to ‘View All’ and ‘Add New’, the text will be what was defined in the relevant $labels array. Look around the editor to see where labels are changed.

Limiting Custom Fields to Specific Post Type

When adding custom fields to a post, the field is saved so you can quickly add it to any new posts. Custom fields you have added will appear in a drop-down list on every post. This can make it difficult to find the field you need on specific post types. If you want to limit custom fields so they are only selectable on certain post types, the easiest way is to use a plugin.

The advanced custom fields plugin adds a simple editor to WordPress that allows you to create custom fields and tell them to only appear on your post type.

You can set what type of input the field should be, such as text box, text area, email address, etc, or something more advanced like a Google maps embed where you can select a location to highlight and display in your posts.

You can also set where on the edit screen the custom fields appear.

As these fields are created via plugin, you must use that plugin’s functions to display them, this is explained in the next section.

Styling New Post Types

To create theme templates for your new post types, you just have to create files in your theme’s main directory with the correct name. If you don’t create templates, WordPress will use single.php and archive.php instead, keeping all your posts and archives identical.

  • Template for an individual post – single-{post-type}.php
  • Template for an archive page – archive-{post-type}.php

The {post-type} part of the file names must be the name from parameter 1 of register_post_type().

  • For our movie post type, the file names are single-movie.php and archive-movie.php
  • For our movie reviews post type, the file names are single-review.php and archive-review.php

The best way to start is to duplicate single.php or archive.php and rename them as above. This means that the overall structure is identical to the rest of your theme, and all required template tags are already in place.

Displaying Custom Fields in Posts

To display custom fields created in the standard WordPress editor, you can use two functions.

These functions must go in the template files used to display your post.


Displays all custom fields attached to the post in a <ul> list. The resulting <ul> tags look like this:

This works anywhere in the single post template, but if you’re displaying somewhere else it must be inside the WordPress loop.


Takes 3 parameters and returns a result.

  • The first parameter is the ID of the post, you can use $post->ID here to get the ID of the currently viewed post
  • The second parameter is the name of the custom field, and is case-sensitive.
  • The third parameter is a boolean named $single and can be TRUE (returns the result as a string) or FALSE (returns an array).
NOTE: You can create multiple custom fields with the same name and different values. 
If multiple fields with the same name exist, 
setting FALSE will return an array of all of them.

As get_post_meta() function returns a value, you can use the value in a conditional statement to change the layout appropriately.

In the example above, we check if the movie has box art assigned to it via a custom field. If $movie_box_art is not empty, echo the div and image.

Displaying Advanced Custom Fields

// Display field value
the_field( 'FIELD NAME' );

// Return field value
get_field( 'FIELD NAME' );

The Advanced Custom Fields plugin provides its own functions and shortcodes for displaying fields.

the_field( ‘ FIELD NAME’ );

This displays the value of the specified field, you must use the Field Name you entered when creating the field group.

get_field( ‘FIELD NAME’ );

This returns the value of the specified field, useful for conditional statements.

These are the functions that you will most likely need. There are lots more advanced functions, and you can find them in official Documentation.


You can display fields directly in a post using the shortcode above.

Displaying Custom Post Types on the Front page

Custom post types do not display on the frontpage by default, so you have to write a new function that calls the set method of WordPress’ WP_Query object.

The function checks whether the visitor is on the homepage and if the active query is the primary one generated by WordPress.

$query->set() takes two parameters:

  • First parameter is the property you want to change, in our case we want to change the post_type property
  • Second parameter is the array you want as the value of the post_type property

In the code above, the array starts with ‘post’ – this is because every post in WordPress has a post type of ‘post’, and we want to include these on the frontpage still.

If you only want custom posts of a certain type on the frontpage, you can remove ‘posts’ and just use your custom post type.

We add ‘movie’ and ‘review’ to the array, so the frontpage now shows all regular posts, all movie posts, and all review posts.

The value you enter must be the name you used in parameter 1 of the register_post_type() function.


In this tutorial you learned how to create custom post types and what information you need to give them. The flexibility that custom post types give makes them an essential feature for any WordPress powered website.

When combined with categories and taxonomies, you have full control over how users view your posts.

Resource: WordPress Custom Post Types

Related Content

Our content policy

In WordPress, you can write either posts or Pages. When you’re writing a regular blog entry, you write a post. Posts, in a default setup,

Obtaining the Authorize Access Token

1.) Create an account and login to ( or for test environment ) 2.) Go to “Account > API Credentials & Keys” section

How To Update Seamlessly Every Time

WordPress started in 2003 with a single bit of code to enhance the typography of everyday writing and with fewer users than you can count

Scroll to Top
Scroll to Top