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”
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?
Yes, I would agree with that. 🙂