Mar
3

Setting templates for WordPress 3.0 Custom Post Type

Since WP2.9 WordPress has had the ability to declare custom post types.  However, up until now you have had to build your own backend UI to manage those posts.  Now in the up coming 3.0 version WordPress can provide that too almost automatically, theres a great tutorial at wpengineer.com  http://wpengineer.com/impressions-of-custom-post-type/ that shows you how to add a custom post type and what  options are available.

Anyway today I set about exploring 3.0 alpha 1 and had a mess with custom posts, and immediately decided it would have saved days of work when building this site alone, but what I couldn’t figure out was how to customise the display of my custom posts, after a few searches I came across someone  in the WP.org forums with the same problem and no answers.

So I did some digging in the 3.0 code to figure out what template was getting used, and how it was getting chosen.  After an hour or so looking at the WP_Query class, and the theme.php file in the core I came up with a simple  and more advanced solution.

Simple Solution

Its build in, just not documented, atleast anywhere I could find.  The template used for a custom post view is decided by the 'get_single_template()' function in the wp-includes/theme.php file.  And it basically tells locate_template() to look for single-'post_type'.php or single.php.

So the simplest way to customise the way a custom post is displayed is to add a template file to your theme with the name single-xxxxxx.php

Advanced Solution

Anyway that solution worked but what if you want to do other stuff like single out a specific custom post by id, or anything.

Well a bit more reverse engineering and I came up with a solution.  First I wrote a simple is_ funtion for my custom post type ‘publication’, that way I could test for them.

function is_publication() { 
    $post_type = get_query_var('post_type'); 
    // short had for if / else; 
    return $post_type == 'publication' ? true : false; 
}

Then I added my own get_xxx_template function to choose which template file to load including publication-id.php and fallback to single.php if none is found.

function get_publication_template() { 
    global $wp_query; 
    $object = $wp_query->get_queried_object(); 
    $templates = array( 'publication-'. $object->ID .'.php', 
                        'publication.php', 
                        'single-'. $object->post_type .'.php', 
                        'single.php' );

    $page_template = get_post_meta( $object->ID , 
                                    '_wp_page_template', true ); 

    if ( !empty( $page_template ) ) { 
        $templates = array( $page_template ) + $templates; 
    } 

    return locate_template( $templates ); 
}

Finally I added a function to use the  ‘template_inlcude’ filter hook.  It uses is_publication to check if the publication templates need to be loaded, and if so replaces/filters the template being loaded with the template determined by my get_publication_template function.

function ttd_post_type_publication() { 
    register_post_type( 'publication', 
         array( 'label' => __('Publications'), 
                'public' => true, 
                'show_ui' => true, 
                'supports'=> array( 'post-thumbnails', 
                                'excerpts', 
                                'custom-fields', 'comments' ))); 

    register_taxonomy_for_object_type('post_tag', 'publication'); 
} 

function is_publication() { 
    $post_type = get_query_var('post_type'); 
    // short had for if / else; 
    return $post_type == 'publication' ? true : false; 
} 

function get_publication_template() { 
    global $wp_query; 
    $object = $wp_query->get_queried_object(); 
    $templates = array( 'publication-'. $object->ID .'.php',   
                        'publication.php', 
                        'single-'. $object->post_type .'.php', 
                        'single.php' ); 

    $page_template = get_post_meta( $object->ID , 
                                    '_wp_page_template', true ); 

    if ( !empty( $page_template ) ) { 
        $templates = array( $page_template ) + $templates; 
    } 
    return locate_template( $templates ); 
} 

function set_publication_template( $template ) { 
    if ( is_publication() ) { 
        $template = get_publication_template(); 
    } 
    return $template; 
} 
add_filter('template_include', 'set_publication_template'); 
add_action('init', 'ttd_post_type_publication');

20 Responses to “Setting templates for WordPress 3.0 Custom Post Type”

  1. Geraint, thanks for the solution. I think there is an easier way to do this by adding page-attributes parameter in the supports argument array. It would be something like this:

    // aditional post types
    function rms2_post_type_portfolio() {
    
    register_post_type( 'folio', 
      array('label' => __( 'Portfolio' ),
        'singular_label' => __('Portfolio Item'),
        'public' => true,
        'show_ui' => true,
        'supports' => array('title', 'editor', 
             'author', 'thumbnail', 'excerpt', 
             'custom-fields')
    ));
    
    register_taxonomy_for_object_type('post_tag', 'folio');
    }
    add_action('init', 'rms2_post_type_portfolio');
    

    Thats how I implemented my custom post types on our upcoming site.

    Also I think this a work in progress and the guys at WordPress are still painting it.

  2. Excellent. Thanks a bunch. At least I can get my custom post type showing up with a different template.

    You would of thought that having “page-attributes” in the supports array of register_post_type meant that those attributes actually worked.

    Maybe this will be updated by the time 3.0 is released.

  3. Christopher B:

    Or what about this: add_action("template_redirect", array(&$this, 'template_redirect'));

    // Template selection
    function template_redirect()
    {
    global $wp;
    if ($wp->query_vars["post_type"] == "work")
    {
    include(TEMPLATEPATH . "/casestudy.php");
    die();
    }
    }

  4. Christopher B:

    Rather this is better: // Template selection
    function my_template_redirect()
    {
    global $wp;
    if ($wp->query_vars["post_type"] == "work")
    {
    include(TEMPLATEPATH . "/casestudy.php");
    die();
    }
    }

    add_action("template_redirect", 'my_template_redirect'); Simple hook to check post type and apply a template accordingly.

  5. Thanks for this hint.
    I prefer the simple idea of single-$posttype.php, instead of the advanced declaration.

  6. Works like a charm, thanks a lot for sharing!

  7. Thanks a lot for this article!

    Christopher B, your last example is really simple and worked perfect for what I needed.

    //Frankie

  8. I was having issues with the archive template hierarchy not working properly for me so I modified Christopher B’s idea to query the “taxonomy” var!

    function my_template_redirect()
    {
    global $wp;
    if ($wp->query_vars[“taxonomy”] == “example”)
    {
    include(TEMPLATEPATH . “/taxonomy-example.php”);
    die();
    }
    }
    add_action(“template_redirect”, ‘my_template_redirect’);

  9. thanks for the tip on the single-posttype.php template! made things at on easier…just started trying custom post types with our (incompete) stock market dictionary! http://marketheist.com/definition

  10. Nice Post!!!

    I have created a project collection theme based on this custom post type feature.

    See following to download:

    http://www.techbrij.com/342/create-project-collection-theme-wordpress-3-custom-post-type

  11. Thank you Christopher. Works great! It seems WordPress PROs forum. I’m gonna subscribe RSS now.

  12. Peter Verkooijen:

    What should the code in the single-customtype.php file look like?!

    I have a file that came with a plugin, but it now suddenly always shows the last post added. Apparently the file does not get the right ID. Using the loop from a regular single.php file can’t find anything at all.

  13. Brian Kuyath:

    You just saved me about 2 hours. Thanks!

  14. Good post, like so many simple solutions with wp (e.g. taxonomy) its a matter of the right file name in the right place!

  15. Sorry I know this is a old thread, but was the template ability added in wordpress 3.0?

  16. Matt Smith, modMACRO:

    Great post thanks. The “simple solution” is in fact very direct. Super helpful. Thanks.