Skip to content

WordPress Patterns – An Elegant way to create a Custom Post Type

I would like to share a simple design pattern that I follow when programmatically creating custom post types in WordPress. This solution is fairly elegant.

Why?

  • It’s re-usable
  • It’s easy to modify and scale
  • It’s easy to read

The same pattern can be used for other things as well such as shortcodes and taxonomies but more on that later.

Pretty much all of the time when developing bespoke themes for WordPress I take an Object Oriented approach which enables me to compartmentalise things like post type or taxonomy registration.

Generally, I’d create a directory named post-type and create a file in that which contains the name of the post type followed by pt.php.
So – post-type/event.pt.php.

There are some variables declared at the top of the class which contain some common things that can be quickly changed if this code was to be re-used for another post type – all for speed.

You’ll notice that the code begins by using the PostType namespace. This is because I can name the class Event without fear of conflicting class names. If I wanted to use methods from this class in other template files I would be able to do something like.

// OR (accessing a static method)
$events = \PostType\Event::get_events();
 
// OR (instantiating new object and accessing one of its public methods)
$eventObj = new \PostType\Event();
$events = $eventObj->get_events();

The code below is well commented. Fill in the gaps with your own code. You’ll see the admin post table column action
manage_edit-{name}_columns
and filter
manage_{name}_posts_column
have been mapped to methods ready for code.

// event.pt.php
 
/**
 * Use namespace to avoid conflict
 */
namespace PostType;
 
/**
 * Class Event
 * @package PostType
 *
 * Use actual name of post type for
 * easy readability.
 *
 * Potential conflicts removed by namespace
 */
class Event {
 
    /**
     * @var string
     *
     * Set post type params
     */
    private $type               = 'event';
    private $slug               = 'events';
    private $name               = 'Events';
    private $singular_name      = 'Event';
 
    /**
     * Register post type
     */
    public function register() {
        $labels = array(
            'name'                  => $this->name,
            'singular_name'         => $this->singular_name,
            'add_new'               => 'Add New',
            'add_new_item'          => 'Add New '   . $this->singular_name,
            'edit_item'             => 'Edit '      . $this->singular_name,
            'new_item'              => 'New '       . $this->singular_name,
            'all_items'             => 'All '       . $this->name,
            'view_item'             => 'View '      . $this->name,
            'search_items'          => 'Search '    . $this->name,
            'not_found'             => 'No '        . strtolower($this->name) . ' found',
            'not_found_in_trash'    => 'No '        . strtolower($this->name) . ' found in Trash',
            'parent_item_colon'     => '',
            'menu_name'             => $this->name
        );
 
        $args = array(
            'labels'                => $labels,
            'public'                => true,
            'publicly_queryable'    => true,
            'show_ui'               => true,
            'show_in_menu'          => true,
            'query_var'             => true,
            'rewrite'               => array( 'slug' => $this->slug ),
            'capability_type'       => 'post',
            'has_archive'           => true,
            'hierarchical'          => true,
            'menu_position'         => 8,
            'supports'              => array( 'title', 'editor', 'excerpt', 'author', 'thumbnail'),
            'yarpp_support'         => true
        );
 
        register_post_type( $this->type, $args );
    }
 
    /**
     * @param $columns
     * @return mixed
     *
     * Choose the columns you want in
     * the admin table for this post
     */
    public function set_columns($columns) {
        // Set/unset post type table columns here
 
        return $columns;
    }
 
    /**
     * @param $column
     * @param $post_id
     *
     * Edit the contents of each column in
     * the admin table for this post
     */
    public function edit_columns($column, $post_id) {
        // Post type table column content code here
    }
 
    /**
     * Event constructor.
     *
     * When class is instantiated
     */
    public function __construct() {
 
        // Register the post type
        add_action('init', array($this, 'register'));
 
        // Admin set post columns
        add_filter( 'manage_edit-'.$this->type.'_columns',        array($this, 'set_columns'), 10, 1) ;
 
        // Admin edit post columns
        add_action( 'manage_'.$this->type.'_posts_custom_column', array($this, 'edit_columns'), 10, 2 );
 
    }
 
}
 
/**
 * Instantiate class, creating post type
 */
new Event();

About 

I run a small web development agency in Salisbury, UK. We provide both front-end/back end solutions and infrastructure management. My specific role is to identify the needs of our clients and providing an online solution that is easy to administer, secure, scalable and maintainable.

 

My agency website is white-fire.co.uk. Contact us if you need a consultant.

Published inWeb DesignWordPress

One Comment

  1. Pablo Pablo

    Can you show me how to unit-test this class?? This week I am trying to found an elegant way to create custom_post_types from my plugin. I was thinking about having one class and an array and do foreach. This class can be extended to specific custom post type if needed (class_exist).

    My first approach was like yours. With new at the end and hooks on the constructor, but I do not think this can be unit-test. Isolation principle.

    Second approach. Having same hooks code on init method instead of constructor. Init method can be unit-test.

Leave a Reply

Your email address will not be published. Required fields are marked *