Creating your own Kinds of Content in WordPress; Part 1: Custom Post Types

This is the first of a two-part article on expanding WordPress to include additional types of content that those that are provided by default. After offering some hypothetical situations where one might need new kinds of content, this first article will discuss ways of defining a new Custom Post Type container. The second article will explain how to add custom fields and taxonomies to these and other Post Types.

When Posts and Pages aren’t Enough

WordPress offers two main types of content that are used to add content to a website; Posts and Pages. Posts usually correspond to blog entries or news articles; content that is often date stamped and part of an ongoing journal of entries that usually don’t have a formal navigation structure. Pages, on the other hand, are often part of a larger structured index of related content. Pages stay rooted in a navigation structure, where posts drift down to be part of an overall archive of articles.

These content structures are usually adequate for most websites, but often there is a need to define an additional type of content that will be displayed on the site. The need for this new content type may be driven by a combination of factors including 1) requiring a different set of fields, 2) having unique categories or tags and 3) structured and presented within a different navigation structure or index.

For example, we utilize a Custom Post Type for “productions” on the Passage Theatre website because the content describing a play or other performance has its unique set of requirements, such as 1) additional fields to define the playwright, director, performance times, etc., 2) a unique taxonomy, “season,” to group performances and 3) situations where productions are grouped together for display on a web page, such as list of upcoming shows.

How to Define Custom Post Types

There are two ways to add Custom Post Types to a website, either by utilizing a plugin or adding them programmatically. I recommend adding these programmatically because 1) it’s relatively simple to do and 2) more likely to avoid subsequent, accidental misconfiguration. In addition, I recommend defining Custom Post Types in your own Plugin rather than making it part of a Theme. This will allow changing the Theme without having to redefine your Custom Post Types.

Step 1: Create your Plugin File

Creating a plugin file is fairly easy. Start by creating a folder/directory to house your plugin and create a plain text file and name it “index.php” At the beginning of the file, add the comment text so that WordPress will recognize it as a plugin:

* Plugin Name: My Plugin 
* Description: Provides custom post types for my website 
* Version: 1.0.0 
* Author: Me 
* Author URI: 

Step 2: Define your Custom Post Type

The WordPress documentation provides an overview and examples on how to use the register_post_type function, but I will often use the online post type generator provided be Generate WP which makes the process easier. In any case, there are a number of important configuration arguments to keep in mind:

  • ‘public’ – whether the post type should be viewable. The default setting is false, but most likely you will want to set this to true. This, in turn, will control a number of other arguments to allow editing of the custom post type.
  • ‘hierarchical’ – whether the post type should be organized like a WordPress Pages (true) or Posts (false). Default is false.
  • ‘exclude_from_search’ – whether to return the custom post type in search results.
  • ‘menu_position’ – the relative order of the tab to edit this custom post type on the admin menu.
  • ‘menu_icon’ – the icon to use for the tab. Easiest thing to do is to reference an existing Dashicon icon, for example ‘dashicons-tickets’
  • ‘supports’ – an array of the different built-in fields that the custom post type will support. By default, these are ‘title’ and ‘editor’. However, for example, you can add support for featured images by setting the argument to “array( ‘title’, ‘editor’, ‘thumbnail’)”
  • ‘taxonomies’ – an array of the taxonomies (and potential custom taxonomies) supported. For example: “array( ‘category’ )” to use WordPress’ default categories.
  • ‘show_in_rest” – in set to true, the custom content type will be able to use the Gutenberg editor. You may also need to make sure that the ‘supports’ argument includes ‘editor’ in its array.

Step 3: Add the Code to your Plugin

After generating the code for your custom post type, copy and paste it into your plugin file. If you used the starting code provided by Generate WP, your plugin file will look something like this:

* Plugin Name: My Plugin
* Description: Provides custom post types for my website
* Version: 1.0.0
* Author: Me
* Author URI:

// Register Custom Post Type
function custom_post_type() {

        $labels = array(
                'name'                  => _x( 'Post Types', 'Post Type General Name', 'text_domain' ),
                'singular_name'         => _x( 'Post Type', 'Post Type Singular Name', 'text_domain' ),
                'menu_name'             => __( 'Post Types', 'text_domain' ),
                'name_admin_bar'        => __( 'Post Type', 'text_domain' ),
                'archives'              => __( 'Item Archives', 'text_domain' ),
                'attributes'            => __( 'Item Attributes', 'text_domain' ),
                'parent_item_colon'     => __( 'Parent Item:', 'text_domain' ),
                'all_items'             => __( 'All Items', 'text_domain' ),
                'add_new_item'          => __( 'Add New Item', 'text_domain' ),
                'add_new'               => __( 'Add New', 'text_domain' ),
                'new_item'              => __( 'New Item', 'text_domain' ),
                'edit_item'             => __( 'Edit Item', 'text_domain' ),
                'update_item'           => __( 'Update Item', 'text_domain' ),
                'view_item'             => __( 'View Item', 'text_domain' ),
                'view_items'            => __( 'View Items', 'text_domain' ),
                'search_items'          => __( 'Search Item', 'text_domain' ),
                'not_found'             => __( 'Not found', 'text_domain' ),
                'not_found_in_trash'    => __( 'Not found in Trash', 'text_domain' ),
                'featured_image'        => __( 'Featured Image', 'text_domain' ),
                'set_featured_image'    => __( 'Set featured image', 'text_domain' ),
                'remove_featured_image' => __( 'Remove featured image', 'text_domain' ),
                'use_featured_image'    => __( 'Use as featured image', 'text_domain' ),
                'insert_into_item'      => __( 'Insert into item', 'text_domain' ),
                'uploaded_to_this_item' => __( 'Uploaded to this item', 'text_domain' ),
                'items_list'            => __( 'Items list', 'text_domain' ),
                'items_list_navigation' => __( 'Items list navigation', 'text_domain' ),
                'filter_items_list'     => __( 'Filter items list', 'text_domain' ),
        $args = array(
                'label'                 => __( 'Post Type', 'text_domain' ),
                'description'           => __( 'Post Type Description', 'text_domain' ),
                'labels'                => $labels,
                'supports'              => false,
                'taxonomies'            => array( 'category', 'post_tag' ),
                'hierarchical'          => false,
                'public'                => true,
                'show_ui'               => true,
                'show_in_menu'          => true,
                'menu_position'         => 5,
                'show_in_admin_bar'     => true,
                'show_in_nav_menus'     => true,
                'can_export'            => true,
                'has_archive'           => true,
                'exclude_from_search'   => false,
                'publicly_queryable'    => true,
                'capability_type'       => 'page',
        register_post_type( 'post_type', $args );

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

Save the plugin file and then upload it and its containing folder/directory to your Plugins directory. You can then activate your plugin to see your new Custom Post Type appear!

Next, I will discuss how to add Custom Taxonomies as well as methods for adding custom fields to your Post Types. In the end, we’ll have the tools to extend WordPress to create custom content specific to the unique needs of a particular website!