How to Create a Custom Post Type

So you have some experience in wordpress and would like to add some custom content to your site. other than blog post and basic pages.  You can do this by creating a “custom post type” or “CPT” with a bit of php code in your theme’s functions.php file or somewhere else such as the mu-plugins folder, but for the sake of this demo we’ll just add it to the functions.php file.

CPT’s are loaded everytime you load wordpress usually in the “init” phase, so we’ll create the a function that runs when wordpress is in this “init” phase.

Open functions.php in your theme (or child theme) and create a function with an appropriate name for registering custom post types such as “register_custom_post_types”. I also added a comment above to keep everything organized.

/**
 * Registers All Custom Post Types
 */
function register_custom_post_types() {
		
}

Next we’ll use wordpress’s built in function “register_post_type” to do exactly this. This function accept two arguments (or paramenters). The first the the post type’s name, this must be a max of 20 lowercase letters only. The second is an array of settings for our CPT. Here I’ve created two variables and passed them into “register_post_type” function.

Finally to run this function run it in an “Action Hook” function, in this case the “init” hook.

/**
 * Registers All Custom Post Types
 */
function register_custom_post_types() {

     $post_type_staff_member = 'staff';
     $args = array();

     register_post_type( $post_type_staff_member, $args );
		
}
add_action( 'init', 'register_custom_post_types' );

Save your file and refresh your admin screen and you should now see a new menu left menu item with the name “staff”. At this point you’re gonna want to customize it a bit.

Replace your args array with this one below.

/**
 * Registers All Custom Post Types
 */
function register_custom_post_types() {

     $post_type_staff_member = 'staff';
     $args = array(
            'label'	=> 'Staff',
            'labels'	=> array(
                    'name'              => 'Staff',
                    'singular_name'     => 'Staff'',
                    'add_new_item'      => 'Add New Tut',
                    'edit_item'         => 'Edit Tut',
                    'all_items'         => 'All Tutorials',
                    'new_item'          => 'New Tut',
                    'view_item'         => 'View Tut',
                    'search_items'      => 'Search Tutorials',
                    'not_found'         => 'No tutorials found.',
                    'not_found_in_trash'=> 'No tutorials found in Trash.'
            ),
            'public'         => true,
            'hierarchical'   => false,
            'supports'       => array( 'title', 'editor', 'thumbnail', 'excerpt', 'revisions', 'page-attributes' ),
            'has_archive'    => true,
            'menu_icon'      => 'dashicons-groups',
            'rewrite'        => array(
                'slug'          => 'staff-members',
                'with_front'    => false
            )
        );

     register_post_type( $post_type_staff_member, $args );
		
}
add_action( 'init', 'register_custom_post_types' );

This might look like a load of settings, but its really straightforward. I’ll explain each part one by one.

This first ‘label’ is for a Plural name marked for translation. The Second are a set of labels used in the admin area. The comments explain each piece.


'label'	=> 'Staff',
'labels'	=> array(
    'name'              => 'Staff', // I've always used the same name are the label above
    'singular_name'     => 'Staff'', //
    'add_new_item'      => 'Add New Tut', // the add new button
    'edit_item'         => 'Edit Tut', // the edit button
    'all_items'         => 'All Tutorials', // the all tutorials sub menu link
    'new_item'          => 'New Tut', // the add new button
    'view_item'         => 'View Tut', // the view tutorial sub menu link
    'search_items'      => 'Search Tutorials',  // the search tutorial button on the listing page
    'not_found'         => 'No tutorials found.', // no tutorials message in the listing area
    'not_found_in_trash'=> 'No tutorials found in Trash.' // no tutorials message the trash
),

The “public” option determines if you want the post from this new post type to be view able in the front end of your site. In this case we set this to true, although you can leave the option out altogether and it will default to not public facing.

'public' => true,

The next part is post hierarchy, or rather if you want to enable a parent child structure to this post type. I’ve set this to true.

'hierarchical' => true,

The “supports” list is where you can really customize what is available to use in the post type. Like in pages and posts you can enable the title, main content editor, excerpt, featured image etc. These are all optional features and won’t be included unless added here.

 'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt', 'revisions', 'page-attributes' ),

This enables the built in archive page just like the blogroll page but for your new custom post type.

 'has_archive' => true,

This is the artistic bit, you can either choose a custom icon and provide its URL, or you can just use a “dashicon” by copying its css class name here instead.

'menu_icon' => 'dashicons-groups',

The rewrite “slug” is something you want to make right the first time, this will form the url and will require doing a find and replace later on the database if you change this after the fact. use lower case letters and and simple dashes only. The with front option determines if the url will be pre-pended with a example.com/blog/staff-members (set to true) vs example.com/staff-members (set to false) if you’ve setup your permalinks with the “front base” ( example.com/blog/)

'rewrite' => array(
    'slug'          => 'staff-members',
    'with_front'    => false
)

This is just a guide to get you going, check out the WordPress codex for a full description of what is possible with WordPress’s “register_post_type” function.

I hope this tutorial was helpful!