Oh, the template hierarchy is a temptress. The reason being when themes create a new template it can work in really strange ways. A good example are the front-page and home templates. The tricky part is knowing when to use the right one. A far less common one is page templates.

Many like to use the naming convention of page-{template-name}.php but that can be a bad thing. The way the template hierarchy works is by looking through a list of file names to load but that is for pages and certain scenarios. Let’s take a look at how the template is actually loaded:

The following snippet is from the template loader file from core:

if ( defined('WP_USE_THEMES') && WP_USE_THEMES ) :
	$template = false;
	if     ( is_404()            && $template = get_404_template()            ) :
	elseif ( is_search()         && $template = get_search_template()         ) :
	elseif ( is_front_page()     && $template = get_front_page_template()     ) :
	elseif ( is_home()           && $template = get_home_template()           ) :
	elseif ( is_post_type_archive() && $template = get_post_type_archive_template() ) :
	elseif ( is_tax()            && $template = get_taxonomy_template()       ) :
	elseif ( is_attachment()     && $template = get_attachment_template()     ) :
		remove_filter('the_content', 'prepend_attachment');
	elseif ( is_single()         && $template = get_single_template()         ) :
	elseif ( is_page()           && $template = get_page_template()           ) :
	elseif ( is_singular()       && $template = get_singular_template()       ) :
	elseif ( is_category()       && $template = get_category_template()       ) :
	elseif ( is_tag()            && $template = get_tag_template()            ) :
	elseif ( is_author()         && $template = get_author_template()         ) :
	elseif ( is_date()           && $template = get_date_template()           ) :
	elseif ( is_archive()        && $template = get_archive_template()        ) :
	elseif ( is_comments_popup() && $template = get_comments_popup_template() ) :
	elseif ( is_paged()          && $template = get_paged_template()          ) :
	else :
		$template = get_index_template();
	endif;
	/**
	 * Filter the path of the current template before including it.
	 *
	 * @since 3.0.0
	 *
	 * @param string $template The path of the template to include.
	 */
	if ( $template = apply_filters( 'template_include', $template ) )
		include( $template );
	return;
endif;

A slight break down

That is a lot of code! Break it down and you will see that all it really does is check to see what type of page we are on and if we should load it. Let’s look at the first check:

if( is_404() && $template = get_404_template() ) :

The first thing it checks is whether or not the page to be displayed is an error page. In particular the 404 page. If it is and the $template is an existing file within either the child theme or parent theme then it will load it, other wise it will use the index.php file for the 404 template.

The file is retrieved with get_query_template. It doesn’t look like it because you see get_404_page() instead. Let’s look at that function below:

function get_404_template() {
	return get_query_template('404');
}

Great! Now you can see get_query_template() being called. What does that one do? Well, let us take a quick look:

function get_query_template( $type, $templates = array() ) {
	$type = preg_replace( '|[^a-z0-9-]+|', '', $type );

	if ( empty( $templates ) )
		$templates = array("{$type}.php");

	$template = locate_template( $templates );

	return apply_filters( "{$type}_template", $template );
}

Ok, it uses locate_template() to find the right $template, which in this case is the 404, and loads it if that file does exist. In this case it would be the 404.php file. Awesome. This can be seen from the locate_template() in core:

function locate_template($template_names, $load = false, $require_once = true ) {
	$located = '';
	foreach ( (array) $template_names as $template_name ) {
		if ( !$template_name )
			continue;
		if ( file_exists(STYLESHEETPATH . '/' . $template_name)) {
			$located = STYLESHEETPATH . '/' . $template_name;
			break;
		} elseif ( file_exists(TEMPLATEPATH . '/' . $template_name) ) {
			$located = TEMPLATEPATH . '/' . $template_name;
			break;
		}
	}

	if ( $load && '' != $located )
		load_template( $located, $require_once );

	return $located;
}

What’s pretty cool is the function first looks at the child theme’s files and if it finds it, returns that path

Other templates

But there are some that will use different files. Let’s take a look at the tag template hierarchy, shall we:

function get_tag_template() {
	$tag = get_queried_object();

	$templates = array();

	if ( ! empty( $tag->slug ) ) {
		$templates[] = "tag-{$tag->slug}.php";
		$templates[] = "tag-{$tag->term_id}.php";
	}
	$templates[] = 'tag.php';

	return get_query_template( 'tag', $templates );
}

As you can see, the first thing done is populate a variable with the queried object. That is so we can get the needed information. From there we use the tag’s slug as the first file to locate and load, the tag’s term_id as the second, and finally just tag as the filename to locate and load. What this means is that you can use tag-random.php for the random tagged post list. Or if you want a specific tag ID’s archives to look a certain way you can use the template tag-37.php to do that.

And more templates

Yes, there are a few more. If you look closely there are about 17 checks that are conducted. If all those fail the template that is loaded is the index template. I’ll list off the possible template files that a theme can potentially have.

  • 404
  • search
  • front-page
  • home
  • post-type archive
  • taxonomy
  • attachment
  • single
  • page
  • singular
  • category
  • tag
  • author
  • date
  • archive
  • comments-popup
  • paged

Do keep in mind those are some of the possible theme template files you could have. As you can see it can be a little tricky and at times odd when you use certain file naming conventions so try to keep that template hierarchy in mind when you are creating a theme that wants to use page templates.

So go explore those templates, break a theme, make a child theme, and perhaps share your errors on the forums to help others out.


Comments

2 responses to “Another template hierarchy post”

  1. Many like to use the naming convention of page-{template-name}.php but that can be a bad thing.

    To be clear:

    Naming a global template (ie a template with the opening PHP comment: Template Name: ) is a bad idea.

    Creating a template for a specific page and using this naming convention is fine.

    Would you agree on that?

    1. Yes, I would agree with that. 🙂