Building a WordPress Series Plugin: Custom Post Types

Milestone 1: Redux
By Sol in Lab

Though simple to implement, WordPress’ custom taxonomies we not ideal for robust series management, so today we’re evaluating custom post types.

Refactoring

Before development progresses too far along, it was time to organize our code a bit. I truly loath repetition, so one of the main reasons I started wrapping my WordPress plugins in classes is so that I did not have to prefix every single function with the plugin’s name. This makes method names a whole lot cleaner.

//Out in the wild, custom functions must be prefixed to avoid conflicts with existing functions
function series_register_hooks() {}

//Wrapped in a class, we can use any name we want
class My_Plugin {
    function register_hooks();
}

The same goes a class that’s used as a catch-all. If you have methods that handle multiple components of a plugin’s functionality packed into a single class, then you’re eventually going to have to start prefixing your method names.

The solution? Break the code for each component into a separate class.

//Main controller
class ARS_Series_Model {}

//Series management
class ARS_Series_Controller {}

//Individual series functionality
class ARS_Series {}

Now we have a separate class for each of the core components of our plugin, keeping things neat and tidy.

Creating a Custom Post Type

Similar to custom taxonomies, creating a custom post type in WordPress is very straightforward. Simply define the post type’s parameters and register the post type:

//Custom post type parameters
$args = array(
    'show_ui'               => true,
    'show_in_nav_menus'     => true,
    'show_in_menu'          => true,
    'public'                => true,
    'has_archive'           => true,        
    'labels'    => array(
        'name'              => 'Series',
        'singular_name'     => 'Series',
        'add_new_item'      => 'Add New Series',
        'edit_item'         => 'Edit Series',
        'new_item'          => 'New Series',
        'view_item'         => 'View Series',
        'search_items'      => 'Search Series',
        'not_found'         => 'No series found',
        'not_found_in_trash'=> 'No series found in trash',
        'all_items'         => 'All Series',
        'menu_name'         => 'Series' 
    )
);
//Register custom post type
register_post_type($this->get_post_type(), $args);

You may have noticed the use of $this->get_post_type() instead of simply writing “series” when registering the custom post type. Just as methods have been moved into separate classes to avoid repetition, the custom post type’s ID has been moved to a discrete method since it is used multiple times throughout our code. Using a method instead of hard coding this value throughout the plugin allows the ID to be defined once instead of multiple times, decreasing the likelihood of typos and other issues. Changing the post type’s ID now incredibly simple as it only needs to be changed in one location to update the entire plugin.

Meta Boxes

Whereas custom taxonomies had the ability to automatically add a meta box to the post editor, we have to manually build meta boxes when using custom post types. Thankfully this is pretty simple.

First we hook into WordPress to add the meta box at the appropriate time:

add_action('add_meta_boxes', $this->m('add_meta_boxes'));

Then we add the meta box via the callback function defined in the last step:

public function add_meta_boxes() {
    //Add series selection meta box
    add_meta_box($this->meta_box, 'Series', $this->m('meta_box_selection'), 'post', 'side');
}

Finally we output the content for our meta box:

public function meta_box_selection($post) {
    //Build meta box output
}

WordPress wraps our output in a meta box endowed with all of the functionalities of built-in meta boxes (draggable, collapsible, etc.). All we need to do in our output function (e.g. meta_box_selection()) is print the desired output to the browser.

Post editor meta box

Post editor meta box

Another benefit of using a custom meta box over the one generated by a custom taxonomy is that we can now limit a post to a single series as per our original requirements.

Standard vs Custom meta box comparison

Series Management

Custom post types are not second-class citizens in WordPress (ahem, taxonomies), they stand toe-to-toe with the built-in post types such as Posts and Pages.

Our Series post type can be accessed directly via the admin menu.

Series link in Admin Menu

Series link in Admin Menu

We also have a full UI for managing series, compliments of WordPress.

Series Management

Series Management

The series editing UI is also generated by WordPress, though we can add custom meta boxes to provide additional functionality. I’ve added a meta box to manage the items in a series, which simply lists the items in the series at the moment.

Series editor

Series editor

Final Touches

Even though the internal code is completely different, it only takes a few updates and our post output is displaying series information once again like nothing has changed.

Post content updated

Series information in post content output

Next: Getting Advanced

Custom post types definitely fit the bill, providing us with all the flexibility and power we need to effectively manage series. Now that the basic functionality is implemented, the next step is advanced series management, which I am definitely looking forward to.