Click here to Skip to main content
14,972,640 members
Articles / Hosted Services / WordPress
Posted 12 Feb 2016

Tagged as


2 bookmarked

How to Guide for Creating Custom Post Types

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
12 Feb 2016CPOL4 min read
For those of us who haven’t been living under a rock for the last 6 years, we know that since WordPress 3.0 release we are now free to create our own post types. Basically, you can set a standard ‘format’ to display a certain ‘type’ of content via custom post types. This article will guide you step-

For those of us who haven’t been living under a rock for the last 6 years, we know that since WordPress 3.0 release we are now free to create our own post types. Basically, you can set a standard ‘format’ to display a certain ‘type’ of content via custom post types.

This article will guide you step-by-step through that process. But first, let’s make note of a few things, just to brush up on our WordPress knowledge.

There are five post types that available by default on WordPress:
  • Post (post_type: 'post') used for creating feeds, post is the type used by most blogs to display one published post at a time.
  • Page (post_type: 'page') same as posts, with some differences. Page type use templates, are not bound by time based listings (as is the case of typical blog posts), cannot be assigned categories/tags, and can be displayed in a hierarchical structure.
  • Attachment (post_type: 'attachment') holds information about files (including images and related metadata) uploaded through the WordPress media upload system.
  • Revision (post_type: 'revision') used to hold a draft post as well as any past revisions of a published post. 
  • Navigation menu (post_type: 'nav_menu_item') holds information on every single item in WordPress navigation menu system.

Custom Post Types

These are new post_type you can create. A custom post type must be added to WordPress via register_post_type() function: it defines the post_type’s specifics like labels, features, availability, etc.

Codex Tip: Note that you must call register_post_type() before the admin_menu and after the after_setup_theme action hooks. You can use the init hook here.

Here's a basic example of adding a custom post type:

add_action( 'init', 'create_post_type' );
function create_post_type() {
  register_post_type( 'selsior_product',
      'labels' => array(
        'name' => __( 'Products' ),
        'singular_name' => __( 'Product' )
      'public' => true,
      'has_archive' => true,


This creates a post_type named Product identified as selsior_product.

The register_post_type() function has two major arguments: labels define post_type name (in singular and plural forms); the public is a flag to show the post_type on admin screens and publicly (on the website), if it has archive, etc.

You can add more options to your first labels array to further detail and define it. Here’s a different example:

* Creating a function to create our CPT

function custom_post_type() {

// Set UI labels for Custom Post Type
	$labels = array(
		'name'                => _x( 'Movies', 'Post Type General Name', 'twentythirteen' ),
		'singular_name'       => _x( 'Movie', 'Post Type Singular Name', 'twentythirteen' ),
		'menu_name'           => __( 'Movies', 'twentythirteen' ),
		'parent_item_colon'   => __( 'Parent Movie', 'twentythirteen' ),
		'all_items'           => __( 'All Movies', 'twentythirteen' ),
		'view_item'           => __( 'View Movie', 'twentythirteen' ),
		'add_new_item'        => __( 'Add New Movie', 'twentythirteen' ),
		'add_new'             => __( 'Add New', 'twentythirteen' ),
		'edit_item'           => __( 'Edit Movie', 'twentythirteen' ),
		'update_item'         => __( 'Update Movie', 'twentythirteen' ),
		'search_items'        => __( 'Search Movie', 'twentythirteen' ),
		'not_found'           => __( 'Not Found', 'twentythirteen' ),
		'not_found_in_trash'  => __( 'Not found in Trash', 'twentythirteen' ),
// Set other options for Custom Post Type
	$args = array(
		'label'               => __( 'movies', 'twentythirteen' ),
		'description'         => __( 'Movie news and reviews', 'twentythirteen' ),
		'labels'              => $labels,
		// Features this CPT supports in Post Editor
		'supports'            => array( 'title', 'editor', 'excerpt', 'author', 'thumbnail', 'comments', 'revisions', 'custom-fields', ),
		// You can associate this CPT with a taxonomy or custom taxonomy. 
		'taxonomies'          => array( 'genres' ),
		/* A hierarchical CPT is like Pages and can have
		* Parent and child items. A non-hierarchical CPT
		* is like Posts.
		'hierarchical'        => false,
		'public'              => true,
		'show_ui'             => true,
		'show_in_menu'        => true,
		'show_in_nav_menus'   => true,
		'show_in_admin_bar'   => true,
		'menu_position'       => 5,
		'can_export'          => true,
		'has_archive'         => true,
		'exclude_from_search' => false,
		'publicly_queryable'  => true,
		'capability_type'     => 'page',
	// Registering your Custom Post Type
	register_post_type( 'movies', $args );


/* Hook into the 'init' action so that the function
* Containing our post type registration is not 
* unnecessarily executed. 

add_action( 'init', 'custom_post_type', 0 );


Now we have created a post_type movies that will categorized in Genres and support configuration of excerpt, author, comments, custom-fields, etc. through post-editor.

Displaying your Custom Post Type

If you don’t create a custom template for your post type, WordPress will use default templates in your theme (archive.php and single.php) to show your new post types. If you stick with this road, you will need to update the permalink structure.

Go to Appearance >> Menus and add a new custom link to your menu (For e.g., products, movies). By default it should look something like this:

Write your own domain and replace the ‘products’ with your custom post type’s name.

You can also create a custom template to display your post type archive or singly. The easiest (and reasonable) way to do this would be copy everything from your theme’s archive.php into a new file named archive-{post_type name}.php and then start modifying it. You can do the same with your single-{post-type name}.php file.

There are also a few practices to keep in mind:

  • In order to avoid breaking a site or losing the custom post types upon switching to another theme, it would be better to define custom post types as a plugin.
  • Instead of generic custom post type name (as used in the examples above like ‘products’ or ‘movies’, go for prefixes with your post-type name. This minimizes the chances of conflict with post types created by another plugin or theme. Just don’t exist char length of 20 or it’ll become to huge to fit in the VARCHAR field, and don’t use wp_.
  • Give your clients/admins/self some control over the post-type configuration by adding proper controls. For example, here’s how you edit the columns for your custom post type’s overview page:
// Change the columns for the edit CPT screen
function change_columns( $cols ) {
  $cols = array(
    'cb'       => '<input type="checkbox" />',
    'url'      => __( 'URL',      'trans' ),
    'referrer' => __( 'Referrer', 'trans' ),
    'host'     => __( 'Host', 'trans' ),
  return $cols;
add_filter( "manage_<CPT>_posts_columns", "change_columns" );


Querying by Post Type

You can create new queries via post_type argument of WP_Query in any template to display posts from specific post_type. Here’s an example of a loop to display 10 latest posts of type ‘product’ with their titles and content:

$args = array( 'post_type' => 'product', 'posts_per_page' => 10 );
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
  echo '<div class="entry-content">';
  echo '</div>';

Source: Codex

Custom Post Types in the Main Query

Creating and registering a custom post type does not mean it gets added to the main query on its own. To make your custom post type posts show up on default archives or the homepage (along with other custom and default post types), you need this code:

// Show posts of 'post', 'page' and 'movie' post types on home page
add_action( 'pre_get_posts', 'add_my_post_types_to_query' );
function add_my_post_types_to_query( $query ) {
  if ( is_home() && $query->is_main_query() )
    $query->set( 'post_type', array( 'post', 'page', 'movie' ) );
  return $query;

Source: Codex

Key Takeaway

There are so many awesome things you can do now that you have a grasp on custom post types. Essentially, this is the way to fit WordPress to your needs with your own hands.

Just remember to check out the WordPress Codex and other resources, and if this is your first time fiddling with the code, make sure you are working with a child theme.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Lucy Barret Geek
Web Developer HireWPGeeks Ltd.
United States United States
Lucy Barret is a Working Developer with over 5 years of experience. She is employed at HireWPGeeks, HTML to WP Company. She has the responsibility to handle all major HTML to WP projects with her team of developers.

Comments and Discussions

-- There are no messages in this forum --