Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I'm in the midst of building a Wordpress Plugin that adds a custom post type, for which I'd like to include a default template to display. Essentially, this is an event management plugin, and the custom post type is for the Events. There's a handful of custom meta fields, as well as a child post type (Performances), so without a default template to display them, using it would be pretty unfriendly. But I would like theme designers to be able to create their own templates for these post types if desired.

Is there a way to use the the template provided with my plugin unless the theme provides its own template? What's the best practice for doing so?

Edit:

Following the advice of Peter Rowell, I caught the template_redirect action and, if the post type was one of mine and a template for it did not exist in the current theme, defaulted to the plugin's template:

class FestivityTemplates {

  public static function determineTemplate(){
    global $post;
    $standard_type = strpos($post->post_type, 'fest_');

    if(is_single() && $standard_type !== false) {
      FestivityTemplates::loadSingleTemplate($post);
    }
  }

  private static function loadSingleTemplate($post) {
    $template_name = 'single-'.$post->post_type.'.php';
    $template = locate_template(array($template_name), true);
    if(empty($template)) {
      include(WP_PLUGIN_DIR . '/Festivity/lib/templates/' . $template_name);
      exit();
    }
  }
}

add_action('template_redirect', array('FestivityTemplates', 'determineTemplate'));
share|improve this question
    
Don't use template_redirect. You should use template_include instead. –  Stephen Harris May 3 '12 at 15:09
    
@StephenHarris Changing this to template_include is breaking everything on the site (any other page view) except the layouts that using the layout override pastebin.com/LWpSrfim but using template_include just prepends content (to any template files placed in the theme directory override) -- the standard single view for example is still output below. Should I start a new question for this? –  Zach May 3 '12 at 16:22
    
@Zach - start a new question and link to it here, you have to do things slightly differently with template_include :) –  Stephen Harris May 3 '12 at 16:24
    
@StephenHarris wordpress.stackexchange.com/questions/51038 Appreciate it! –  Zach May 3 '12 at 16:28
add comment

3 Answers

up vote 4 down vote accepted

You might want to look at the routine that WP uses for this: locate_template(). It is in wp-includes/theme.php and is called from a number of functions in that file. Those functions are used by wp-includes/template-loader.php to select the correct type of template based on the current page and then walk up the theme hierarchy looking for a match.

share|improve this answer
    
Question: Is your suggestion to use locate_template() in the plugin to determine if the template exists, then to load my own in the plugin if it does not? That's the approach I'm considering now; I just wanted to make sure I understood your suggestion correctly. –  saalon Mar 18 '11 at 13:12
1  
@saalon: Yes. The override logic is the same as child themes, except you are adding the final fallback option of having it in the plugin's directory. –  Peter Rowell Mar 18 '11 at 15:56
add comment

There's also a bunch of template related filters (scroll down) you can use to 'hijack' the templates requests and apply your own logic to them.

Here's an example how to hijack the calls for single-saalon_events.php and archive-saalon_events.php and use the files from /your-plugin/templates/ folder instead:

# Template for displaying a single event
add_filter( 'single_template', 'saalon_events_single_template') ) ;
function saalon_events_single_template($single_template) {
    global $post;           
    if ($post->post_type == 'saalon_events')
        $single_template = dirname( __FILE__ ) . '/templates/saalon_events_single.php';
    return $single_template;
}

# Template for displaying the events archive
add_filter( 'archive_template', 'saalon_events_archive_template') ) ;
function saalon_events_archive_template($archive_template) {
    if ( is_post_type_archive('saalon_events') ) // since 3.1
        $archive_template = dirname( __FILE__ ) . '/templates/saalon_events_archive.php';
    return $archive_template;
}

Resources:
http://codex.wordpress.org/Plugin_API/Filter_Reference#Template_Filters http://codex.wordpress.org/Plugin_API/Filter_Reference/_single_template

Oh and template_redirect Action looks good too! http://codex.wordpress.org/Plugin_API/Action_Reference#Template_Actions

Hope this helps!

share|improve this answer
add comment

I don't know if its best practice but when i faced a similar issue i used the_content hook checked the post type to see if its my custom type and if so i returned just what i wanted. for example:

add_filter('the_content','events_conetnt_display');
function events_conetnt_display($content){
    global $post;
    if (!$post_type == "events"){
        return $content;
    }else{
        remove_filter( 'the_content', 'events_conetnt_display' );
        $events_meta = get_post_custom($post->ID);
        $new_content = '<div class="event_container">';
        $new_content .= '<div class="event_title">'.get_the_title($post->ID).'</div>';
        $new_content .= '<div class="event_description">'.apply_filters('the_content',get_the_content()).'</div>';
        $new_content .= '<div class="event_start_date">'.$events_meta['start_date'].'</div>';
        $new_content .= '<div class="event_end_date">'.$events_meta['start_end'].'</div>';
        //...
        //whatever
        //...
        add_filter('the_content','events_conetnt_display');
        return $new_content;
    }
}

and my plugin had an option to let the user decide if he whats to use the_content Hook or if he has a custom template for that something like:

if (get_option('use_content_template')){
  add_filter('the_content','events_conetnt_display');
}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.