WordPress Custom Post Types Unveiled

In this tutorial, we will illustrate how to create a WordPress custom post type called My Things. I have narrowed the procedure down to 4 steps, which will be explained in depth. The most obvious place to insert the code is somewhere within your functions.php, but to add another level of organization, I recommend linking to a separate file. In my first attempts at creating WordPress custom post types, I reviewed numerous articles explaining how. Some are better than others, and a few were exceptionally helpful, yet none were the whole enchilada. So here is my attempt to document & share exactly what worked for me.

Outline

Below is a oversimplified outline of a wordpress custom post type. It is not meant for cutting & pasting, but rather to help familiarize you with the fundamental steps for preparing your custom post type. Also, it is good practice to prefix your IDs in order to make them more unique. In this case, we will be using mt_, as in My Things.

// Part I: Initialize & Register
add_action( 'init', 'mythings_init' );

function mythings_init() { 
    register_post_type( 
        'mythings', // $post_type -- your post type slug
        /* YOUR POST TYPE ARGUMENTS */
    );
}
// Part II: Add Taxonomies
add_action( 'init', 'create_mythings_taxonomies' );

function create_mythings_taxonomies() {
    register_taxonomy( 
        'mt_groups', // $taxonomy
        'mythings', // $object_type -- stick with $post_type for now
        /* YOUR TAXONOMY ARGUMENTS */
    );
}
// Part III: Add Metaboxes
add_action( 'admin_init', 'mt_admin_init' );

function mt_admin_init(){
    add_meta_box( 
        /* SETUP YOUR META BOX ARGUMENTS HERE */
        );

function mt_first_metabox() { 
    /* CREATE YOUR ADMIN FORM */
}
// Part IV: Save your Data
add_action('save_post', 'mt_save_data');

function mt_save_data(){ 
    /* YOUR FORM-SAVING CODE */
}

And that’s it in a nutshell. Now we can swap in some usable code.

Part I: Basic

This will start the job off right, but in its simplest form. WordPress secretly provides us with a number of handy default arguments, which saves us a lot of real estate in this example.
This example differs slightly from that of WordPress Codex. It has been recommended on new2wp.com to save the register( ) function until after the init( ) function. I believe I have felt the adverse side effects of doing it the other way around.

// create your init() function
add_action( 'init', 'mythings_init' );

// use your init() function
function mythings_init() {
    array(
        'labels' => array(
	'name' => __( 'Things' ), // general name in menu & admin page
	'singular_name' => __( 'Thing' ) 
	),
	'public' => true,
	'has_archive' => true,
    );

    // now register the post type
    register_post_type( 'mythings', $args );
}

Part I: Advanced

You will find yourself wanting to be much more specific, so this example includes most of the different parameters, and I’ve done my best to comment on their function. Since we have a lot more information to add, we will be as organized as possible by utilizing the custom variables $labels and $args.

// add your init() function
add_action( 'init', 'mythings_init' );
// use your init() function
function mythings_init() {
    // setup an array called $labels to insert into 'labels'
    $labels = array(
        'name' => ( 'Things' ), 
	'singular_name' => ( 'Thing' ),
	'add_new' => ( 'Add New', 'mythings' ),
	'add_new_item' => ( 'Add New Thing' ),
	'edit_item' => ( 'Edit Thing' ),
	'new_item' => ( 'New Thing' ),
	'view_item' => ( 'View Thing' ),
	'search_items' => ( 'Search Things' ),
	'not_found' =>  ( 'No thingamajigs found' ),
	'not_found_in_trash' => ( 'No thingamajigs found in Trash' ),
	'parent_item_colon' => ''
    );

    // setup an array called $args to insert into 'args'
    $args = array( 
        'labels' => $labels, // adds your $labels array from above
	'public' => true,
	'publicly_queryable' => true,
	'show_ui' => true,
	'query_var' => true,
	'capability_type' => 'post',
	'hierarchical' => false,
        // choose name used within permalink structure
	'rewrite' => array( 'slug' => 'things' ), // changes name in permalink structure
        'menu_position' => null, // search WordPress Codex for menu_position parameters
        'supports' => array( 
            'title', 
            'editor', // adds the default text editor
            'author', 
            'thumbnail', // adds Featured Image metabox**
            'comments' 
        )
    ); 

    // now register the post type
    register_post_type( 'mythings', $args ); // adds your $args array from above
	// flush the rewrite rules so you don't have to visit Settings > Permalinks
	flush_rewrite_rules();
} // end of mythings_init() function

**NOTE: Including ‘thumbnail’ in the support parameters hasn’t always worked for me on it’s own. If it doesn’t, you can add this function after that last “}”

// enable Featured Image attachments
add_theme_support('post-thumbnails');

Mental Note: You can define & redefine $labels, or any of your custom variables, as often as you wish.

If all went well, Things should now appear in your admin menu, and you should be able to view All Things and Add New. If that checks out, you are ready for the next step.

Part II: Create Your Custom Taxonomies

Taxonomies are not required, but if you do want to add them, now is the time. You’ll see that we can use much of the same format from above.

// add action to create your custom taxonomies
add_action( 'init', 'create_mythings_taxonomies' );

// use your action
function create_mythings_taxonomies() {

// add a hierarchical taxonomy called Group (same as Post Categories)

    // create the array for 'labels'
    $labels = array(
	'name' => ( 'Groups' ),
	'singular_name' => ( 'Group' ),
	'search_items' =>  ( 'Search Groups' ),
	'all_items' => ( 'All Groups' ),
	'parent_item' => ( 'Parent Group' ),
	'parent_item_colon' => ( 'Parent Group:' ),
	'edit_item' => ( 'Edit Group' ),
	'update_item' => ( 'Update Group' ),
	'add_new_item' => ( 'Add New Group' ),
	'new_item_name' => ( 'New Group Name' ),
    ); 
	
    // register your Groups taxonomy
    register_taxonomy( 'mt_groups', array( 'mythings' ), array(
	'hierarchical' => true,
	'labels' => $labels, // adds the above $labels array
	'show_ui' => true,
	'query_var' => true,
	'rewrite' => array( 'slug' => 'mygroups' ), // changes name in permalink structure
    ));

// add a non-hierarchical taxonomy called Flags (same as Post Tags)

    // create the array for 'labels'
    $labels = array(
	'name' => ( 'Flags' ),
	'singular_name' => ( 'Flag' ),
	'search_items' =>  ( 'Search Flags' ),
	'popular_items' => ( 'Popular Flags' ),
	'all_items' => ( 'All Flags' ),
	'parent_item' => null,
	'parent_item_colon' => null,
	'edit_item' => ( 'Edit Flag' ),
	'update_item' => ( 'Update Flag' ),
	'add_new_item' => ( 'Add New Flag' ),
	'new_item_name' => ( 'New Flag Name' ),
	'separate_items_with_commas' => ( 'Separate Flags with commas' ),
	'add_or_remove_items' => ( 'Add or remove Flags' ),
	'choose_from_most_used' => ( 'Choose from the most used Flags' )
    );
	
    // register your Flags taxonomy
    register_taxonomy( 'mt_flags', 'mythings', array(
	'hierarchical' => false,
	'labels' => $labels, // adds the above $labels array
	'show_ui' => true,
	'query_var' => true,
	'rewrite' => array( 'slug' => 'myflags' ), // changes name in permalink structure
    ));

} // end of create_mythings_taxonomies() function

Now your two custom taxonomies should show up in your My Things dropdown menu.

Part III: Create Your Meta Boxes

This is important if you want your custom post type to do something more than Posts & Pages, and I hope you do…

// add function to put metaboxes on the admin page
add_action( 'admin_init', 'mt_admin_init' );
// use the function
function mt_admin_init(){
    add_meta_box(
        'mt_first_metabox', // $id
        'First Metabox', // $title
        'mt_first_metabox', // $callback
        'mythings', // $page /* stick with $post_type for now */
        'normal', // $context /* 'normal' = main column. 'side' = sidebar */
        'high' // $priority /* placement on admin page */
        );
    /* ADD ANOTHER META BOX HERE */

// design the first metabox
function mt_first_meta() {
    global $post;
    $custom = get_post_custom($post->ID);
    $mt_field_one = $custom['mt_field_one'][0];
    $mt_field_two = $custom['mt_field_two'][0];
    // etcetera, etcetera
    ?> /* close the php tag to create your metabox layout with HTML */
        <div class="wrap">
	    <p><label>My Text Input:</label><br />
	    <input name="mt_field_one" value="<?php echo $mt_field_one; ?>" /></p>
            <p><label>My Textarea:</label><br />
	    <textarea name="mt_field_two"><?php echo $mt_field_one; ?></textarea></p>
        </div><!-- end .wrap -->
    <?php // reopen the php tag to continue adding functions
}

/* DESIGN ANOTHER META BOX HERE */
[/code]
<h2>Part IV: Save Your Data</h2>
<p>Here is the best part -- making it work.</p>
[code]
// add your data-saving function
add_action('save_post', 'mt_save_data');
// use your function
function mt_save_data(){
    global $post;
 
    update_post_meta($post->ID, 'mt_field_one', $_POST['mt_field_one']);
    update_post_meta($post->ID, 'mt_field_two', $_POST['mt_field_two']);
    /* INCLUDE FIELDS FROM ALL OF YOUR META BOXES HERE */
} // end mt_save_data() function

Now test it out by filling in your fields on the admin page. Click save and watch your entries not disappear. If it works, you have earned your inflated sense of accomplishment.

There is plenty more functionality to play around with, but I must save that for my next post as this has gotten rather long.

Final: The Whole Shebang

// add your init() function
add_action( 'init', 'mythings_init' );
// use your init() function
function mythings_init() {
    // setup an array called $labels to insert into 'labels'
    $labels = array(
        'name' => ( 'Things' ), 
	'singular_name' => ( 'Thing' ),
	'add_new' => ( 'Add New', 'mythings' ),
	'add_new_item' => ( 'Add New Thing' ),
	'edit_item' => ( 'Edit Thing' ),
	'new_item' => ( 'New Thing' ),
	'view_item' => ( 'View Thing' ),
	'search_items' => ( 'Search Things' ),
	'not_found' =>  ( 'No thingamajigs found' ),
	'not_found_in_trash' => ( 'No thingamajigs found in Trash' ),
	'parent_item_colon' => ''
    );

    // setup an array called $args to insert into 'args'
    $args = array( 
        'labels' => $labels, // adds your $labels array from above
	'public' => true,
	'publicly_queryable' => true,
	'show_ui' => true,
	'query_var' => true,
	'capability_type' => 'post',
	'hierarchical' => false,
        // choose name used within permalink structure
	'rewrite' => array( 'slug' => 'things' ), // changes name in permalink structure
        'menu_position' => null, // search WordPress Codex for menu_position parameters
        'supports' => array( 
            'title', 
            'editor', // adds the default text editor
            'author', 
            'thumbnail', // adds Featured Image metabox**
            'comments' 
        )
    ); 

    // now register the post type
    register_post_type( 'mythings', $args ); // adds your $args array from above
	// flush the rewrite rules so you don't have to visit Settings > Permalinks
	flush_rewrite_rules();
} // end of mythings_init() function

// add action to create your custom taxonomies
add_action( 'init', 'create_mythings_taxonomies' );

// use your action
function create_mythings_taxonomies() {

// add a hierarchical taxonomy called Group (same as Post Categories)

    // create the array for 'labels'
    $labels = array(
	'name' => ( 'Groups' ),
	'singular_name' => ( 'Group' ),
	'search_items' =>  ( 'Search Groups' ),
	'all_items' => ( 'All Groups' ),
	'parent_item' => ( 'Parent Group' ),
	'parent_item_colon' => ( 'Parent Group:' ),
	'edit_item' => ( 'Edit Group' ),
	'update_item' => ( 'Update Group' ),
	'add_new_item' => ( 'Add New Group' ),
	'new_item_name' => ( 'New Group Name' ),
    ); 
	
    // register your Groups taxonomy
    register_taxonomy( 'mt_groups', array( 'mythings' ), array(
	'hierarchical' => true,
	'labels' => $labels, // adds the above $labels array
	'show_ui' => true,
	'query_var' => true,
	'rewrite' => array( 'slug' => 'mygroups' ), // changes name in permalink structure
    ));

// add a non-hierarchical taxonomy called Flags (same as Post Tags)

    // create the array for 'labels'
    $labels = array(
	'name' => ( 'Flags' ),
	'singular_name' => ( 'Flag' ),
	'search_items' =>  ( 'Search Flags' ),
	'popular_items' => ( 'Popular Flags' ),
	'all_items' => ( 'All Flags' ),
	'parent_item' => null,
	'parent_item_colon' => null,
	'edit_item' => ( 'Edit Flag' ),
	'update_item' => ( 'Update Flag' ),
	'add_new_item' => ( 'Add New Flag' ),
	'new_item_name' => ( 'New Flag Name' ),
	'separate_items_with_commas' => ( 'Separate Flags with commas' ),
	'add_or_remove_items' => ( 'Add or remove Flags' ),
	'choose_from_most_used' => ( 'Choose from the most used Flags' )
    );
	
    // register your Flags taxonomy
    register_taxonomy( 'mt_flags', 'mythings', array(
	'hierarchical' => false,
	'labels' => $labels, // adds the above $labels array
	'show_ui' => true,
	'query_var' => true,
	'rewrite' => array( 'slug' => 'myflags' ), // changes name in permalink structure
    ));

} // end of create_mythings_taxonomies() function

// add function to put metaboxes on the admin page
add_action( 'admin_init', 'mt_admin_init' );
// use the function
function mt_admin_init(){
    add_meta_box(
        'mt_first_metabox', // $id
        'First Metabox', // $title
        'mt_first_metabox', // $callback
        'mythings', // $page /* stick with $post_type for now */
        'normal', // $context /* 'normal' = main column. 'side' = sidebar */
        'high' // $priority /* placement on admin page */
        );
    /* ADD ANOTHER META BOX HERE */

// design the first metabox
function mt_first_meta() {
    global $post;
    $custom = get_post_custom($post->ID);
    $mt_field_one = $custom['mt_field_one'][0];
    $mt_field_two = $custom['mt_field_two'][0];
    // etcetera, etcetera
    ?> /* close the php tag to create your metabox layout with HTML */
        <div class="wrap">
	    <p><label>My Text Input:</label><br />
	    <input name="mt_field_one" value="<?php echo $mt_field_one; ?>" /></p>
            <p><label>My Textarea:</label><br />
	    <textarea name="mt_field_two"><?php echo $mt_field_one; ?></textarea></p>
        </div><!-- end .wrap -->
    <?php // reopen the php tag to continue adding functions
}

/* DESIGN ANOTHER META BOX HERE */

// add your data-saving function
add_action('save_post', 'mt_save_data');
// use your function
function mt_save_data(){
    global $post;
 
    update_post_meta($post->ID, 'mt_field_one', $_POST['mt_field_one']);
    update_post_meta($post->ID, 'mt_field_two', $_POST['mt_field_two']);
    /* INCLUDE FIELDS FROM ALL OF YOUR META BOXES HERE */
} // end mt_save_data() function

 

8 Responses to “WordPress Custom Post Types Unveiled”

  • internal hard disk drive not found says: Aug 21, 2012 at 10:06 pm

    Hi, This is a neat description in simple steps on how to create a WordPress custom post type called My Things. I earlier read their Audio Player(Wordpress plugin) and it was very helpful to me and now this is another piece of fantastic work.

    • natural garcinia cambogia says: Jan 27, 2014 at 1:42 am

      A splendid masterwork notified on this destination, maybe something more could be included here for a great work and liking users.

      • miracle garcinia cambogia reviews says: Jan 27, 2014 at 1:42 am

        This post is so informative especially the images posted here do make this blog more outstanding in comparison to others maybe this post needs to be briefed here

  • Deeptish Dey says: Sep 7, 2012 at 4:51 pm

    Seems there are errors in code, up to adding taxonomy is OK. Would you like to have to code in one shot, its easier then. Thanks anyway for your effort. NR.

    • doug says: Sep 18, 2012 at 7:09 am

      Sorry to hear it. I'll let you know when it's revised & I'll append entire code at the end...

  • aakash says: Oct 25, 2012 at 2:25 am

    great

  • Volomike says: Oct 25, 2012 at 12:43 pm

    Imagine I create 10 custom post types. Do you know of a way to group these into one parent menu item, with children menu items going to each custom post type? I just want to tidy up the admin menus. http://wordpress.stackexchange.com/questions/70505/how-do-i-programmatically-better-organize-custom-post-type-menus

  • wordpress Design says: Jun 12, 2014 at 3:12 am

    Hi, Really great updates. Thanks a lot!

 
Leave a Comment
User

Mail

Globe

Comment