Anatomy of a Wordpress Custom Post Type

I recently created a custom post type, and there was a lot of trial and error, a lot of searching and probably a lot of wasted time.

Here is the code that gets things set up, don’t worry I’ll break it down below:

$plugin_dir = basename(dirname(__FILE__));
$lang_dir = realpath($plugin_dir . DIRECTORY_SEPARATOR . "lang");
load_plugin_textdomain( 'pj-movies', false, $lang_dir );

// Register Post Type        
$args = array(
    'label' => _x("Movies", "label", "pj-movies"),
    'labels' => array(
        'add_new_item' => _x("Add New Movie Review", "add_new_item", "pj-movies"),
        'edit_item' => _x("Edit Movie Review", "edit_item", "pj-movies"),
        'new_item' => _x("New Movie Review", "new_item", "pj-movies"),
        'view_item' => _x("View Movie Review", "view_item", "pj-movies"),
        'search_items' => _x("Search Movie Reviews", "search_items", "pj-movies"),
        'not_found' => _x("No Movie Reviews Found", "not_found", "pj-movies"),
        'not_found_in_trash' => _x("No Movie Reviews found in Trash", "not_found_in_trash", "pj-movies")
    ),
    'singular_label' => _x("Movie", "singular_label", "pj-movies"),
    'public' => true,
    'show_ui' => true,
    'capability_type' => 'post',
    'has_archive' => true,
    'hierarchical' => false,
    'rewrite' => array("slug" => "movies"),
    'supports' => array('title', 'excerpt', 'editor', 'thumbnail', 'comments', 'revisions')
);
register_post_type( 'movie' , $args );
$this->register_post_type_archives('movie', 'movies');

register_taxonomy(  
    'movie_categories',  
    'movie',
    array(  
        'hierarchical' => true,  
        'label' => _x('Categories', 'taxonomy label', "pj-movies"),  
        'query_var' => true,  
        'rewrite' => array('slug' => 'movie-categories', 'hierarchical' => true)  
    )
);

Localizable Plugins

If you plan to share your work then the benefits for ensuring it is localizable are obvious, even if you only speak one language. Check out the following lines:

$plugin_dir = basename(dirname(__FILE__));
$lang_dir = realpath($plugin_dir . DIRECTORY_SEPARATOR . "lang");
load_plugin_textdomain( 'pj-movies', false, $lang_dir );

    'label' => _x("Movies", "label", "pj-movies"),

The load_plugin_textdomain loads all the strings that you’ll need, and the _x method retrieves the appropriate string.

There’s an excellent plugin called Codestyling Localization which helps set up the Wordpress compatible files for l10n and does all the hard work for you. If you plan on making your plugin localizable I can’t recommend this plugin enough.

What the post type “supports”

Does your post type either support or not support some base Wordpress features unexpectedly? Check out the supports line:

    'supports' => array('title', 'excerpt', 'editor', 'thumbnail', 'comments', 'revisions')

Here is Wordpress’ own description of each feature:

  • ‘title’
  • ‘editor’ (content)
  • ‘author’
  • ‘thumbnail’ (featured image, current theme must also support post-thumbnails)
  • ‘excerpt’
  • ‘trackbacks’
  • ‘custom-fields’
  • ‘comments’ (also will see comment count balloon on edit screen)
  • ‘revisions’ (will store revisions)
  • ‘page-attributes’ (menu order, hierarchical must be true to show Parent option)
  • ‘post-formats’ add post formats, see Post Formats

Custom taxonomy

Depending on your custom post type you may want to register a new custom taxonomy for it. Check out the lines I have set up here:

register_taxonomy(  
    'movie_categories',  
    'movie',
    array(  
        'hierarchical' => true,  
        'label' => _x('Categories', 'taxonomy label', "pj-movies"),  
        'query_var' => true,  
        'rewrite' => array('slug' => 'movie-categories', 'hierarchical' => true)  
    )
);

In this case I had a totally different taxonomy in mind for my “Movies” compared to my normal posts. As always, the important thing is to read the documentation on register_taxonomy.

Full Codebase at Github

For the full codebase and working plugin head over to Github.

https://github.com/patrickmjones/pjones_wp_movies