Including Page Templates from a WordPress Plugin

Recently, It occurred to me while writing a plugin dealing with custom post types and taxonomies for WordPress that it’d be nice to have some custom templates to go along with it. I seemed onerous to ask the the user to add template tags to their theme to be able to display a better page then what WordPress displays by default. So I set out to make the plugin include the template pages from the plugin directory itself. The code below is derived directly from the WordPress source code, which means it’s GPL, so feel free to use it in your GPL licensed projects.

So the first thing I needed to figured out was what functions needed to be filtered to let me add the plugin directory to the locations that WordPress checks for. I eventually found the appropriate ones by reading the source code and asking in the #wordpress IRC chat (not #wordpress-dev, that’d be the wrong chat to ask this kind of question). “get_single_template()” and “get_taxonomy_template()” are the functions of interest and they in turn call “locate_template()” which is the function we need to rewrite.

function locate_plugin_template($template_names, $load = false, $require_once = true )
{
    if ( !is_array($template_names) )
        return '';
   
    $located = '';
   
    $this_plugin_dir = WP_PLUGIN_DIR.'/'.str_replace( basename( __FILE__), "", plugin_basename(__FILE__) );
   
    foreach ( $template_names as $template_name ) {
        if ( !$template_name )
            continue;
        if ( file_exists(STYLESHEETPATH . '/' . $template_name)) {
            $located = STYLESHEETPATH . '/' . $template_name;
            break;
        } else if ( file_exists(TEMPLATEPATH . '/' . $template_name) ) {
            $located = TEMPLATEPATH . '/' . $template_name;
            break;
        } else if ( file_exists( $this_plugin_dir .  $template_name) ) {
            $located =  $this_plugin_dir . $template_name;
            break;
        }
    }
   
    if ( $load && '' != $located )
        load_template( $located, $require_once );
   
    return $located;
}

(reference: ‘function locate_template‘)

The “locate_plugin_template()” function is a direct copy of “locate_template” function but I added the $this_plugin_dir variable (using code I found on the wordpress.org forums) and added a 3rd check to the foreach loop. (Some of the code here can be removed, for example the $load check with the load_template() call, as our code won’t be invoking it but I left it to better reflect the source.)

Next we have to filter the appropriate functions to call our new function.

add_filter( 'taxonomy_template', 'get_custom_taxonomy_template' );
add_filter( 'single_template', 'get_custom_single_template' );

There’s not much in the original functions that need to be changed:

function get_custom_taxonomy_template($template)
{
    // Twenty Ten adds a 'pretty' link at the end of the excerpt. We don't need it for the taxonomy.
        remove_filter( 'get_the_excerpt', 'twentyten_custom_excerpt_more' );
    remove_filter( 'get_the_excerpt', 'twentyten_auto_excerpt_more' );
   
    $taxonomy = get_query_var('taxonomy');
   
    if ( 'custom_taxonomy_name' == $taxonomy ) {
        $term = get_query_var('term');
   
        $templates = array();
        if ( $taxonomy && $term )
                $templates[] = "taxonomy-$taxonomy-$term.php";
        if ( $taxonomy )
                $templates[] = "taxonomy-$taxonomy.php";
   
        $templates[] = "taxonomy.php";
        $template = locate_plugin_template($templates);
    }
    // return apply_filters('taxonomy_template', $template);
    return $template;
}

(reference ‘function get_taxonomy_template‘)

There’s some bonus remove_filter calls at the beginning and ‘locate_template’ is replace by ‘locate_plugin_template’. The only other thing is that we simply return the $template variable instead of using ‘apply_filters’ (I got errors when trying to apply the filter while running the filter filtering the filter :-/). There is also a check to see if we are working with our own taxonomy: The code in the if statement doesn’t really need to run again unless it’s one of our taxonomies, else it’ll just return the original $template.

The single template function filter is much the same:

function get_custom_single_template($template)
{
    global $wp_query;
    $object = $wp_query->get_queried_object();
   
    if ( 'custom_post_type_name' == $object->post_type ) {
        $templates = array('single-' . $object->post_type . '.php', 'single.php');
        $template = locate_plugin_template($templates);
    }
    // return apply_filters('single_template', $template);
    return $template;
}

(reference ‘function get_single_template‘)

Now, this isn’t a perfect solution. For example, themes have much varying structures, so building a template that’s compatible with Twenty Ten wouldn’t necessarily be compatible with any other theme. If the theme isn’t compatible, it could be bad since you’ve interrupted the fallback that the theme provides in favor of yours. You should probably include a check to see if the current theme is the theme you are targeting. I suggest you use this code in a plugin that is basically a companion plugin for your own theme or framework. Additionally, you could offer template tag functions, shortcodes, and widgets as a more robust solution.

jQuery.historyKeeper

unFocus History Keeper is a JavaScript based library for managing browser history (back button) and providing support for deep linking for Flash and Ajax applications.

What I’m proposing is taking History Keeper and making a jQuery plugin, and also a WordPress plugin to include the History Keeper library for use in WordPress. I am primarily interested in this for the process of it: to learn more about making plugins.

End of Life for IE6

Internet Explorer 6 is approaching its end of life! I did a quick Google search and found an “End of Life” movement calling for developers to abandon support on December 31, 2009 or January 1, 2010, but according to the Internet Explorer’s “Lifecycle Supported Service Packs” , it looks like support officially expires on July 13, 2010. Notwithstanding the 7 1/2 month difference, I’m simply happy the the end is in sight! And then I read that IE6 is covered under XP SP3 and therefor supported until 2014…

The only way to kill Internet Explorer, is to simply stop supporting it as developers. I feel we owe it to the web in general to support the latest standard (official or defacto) and the latest browsers.