Making WordPress themes III : template hierarchy
Posted by Leonid Mamchenkov on August 22, 2007
(This is the third post in “Making WordPress themes” series. If you missed the previous two, here are the links: “Making WordPress themes I : static basics” and “Making WordPress themes II : The Loop” ).
In this post we’ll see which filenames WordPress recognizes in the theme directory, and how it knows which posts to show to the visitor based on where the visitor is.
Hopefully by now you’ve looked through the source code of a few WordPress themes. While each and every theme is unique, there are parts which are common among all themes. One of the common things that you probably noticed, is how themes are separated into files – index.php, category.php, search.php, single.php, home.php, etc. Practically any theme out there use some combination of files with common names. Those themes that don’t use any files or use just a few, usually apply a different technique – they have conditional statements like is_home() or is_page() within index.php.
The questions you probably asked yourself at some point were – “Which filenames does WordPress recognize?” and “Which other conditions similar to is_home() or is_page() can I use?”. And if you have a really inquiring mind, you probably also asked “What happens if I use different, non-standard filenames?” and “How does WordPress knows that a visitor is looking at search results and not archives?”.
The answers to all those questions lie in WordPress template hierarchy. While it looks like yet another Codex page, don’t be mislead. This particular page is priceless. It’s The Holy Grail of WordPress theming. Mostly, because of two things – a diagram and a link to Conditional Tags page. The diagram alone is so precious that I’ll have a copy of it here, just in case it disappears from Codex.
This diagram, just in one little drawing, tells us most of what we need to know about organization of WordPress themes. Let’s take a better look.
On the left side, we have the visitor, coming to the WordPress web site. The visitor can navigate to a number of pages – front page, full post, full page, category, author page, date-based archive, search results, and even a non-existing page. WordPress knows where the visitor is based on the URL which is used to get there. You can see from the diagram that WordPress understands both fancy URLs as well as URLs with parameters.
For each of those location, our theme can have a separate template file. WordPress checks if that file exists, and uses it if it does. Otherwise it falls back on to the next template file in the hierarchy, and checks for its existence, and so on, and so forth, until either a file is found or an index.php is reached.
So, from the diagram, if you want to separate the code for displaying the front page from everything else, use home.php . Or use is_home() conditional tag in index.php . Use single.php or is_single() condition in the index.php for single posts. And so on.
As you can see (from the diagram again), there is a very flexible way of controlling what happens when a particular post, page, or category is displayed. For example, you can have different logic and presentation for category with ID 5 from the one with ID 6.
Do we have to separate our theme into files? No. We can do everything with just conditional tags from within our index.php. But the truth is that if done this way, our index.php can often get rather large and complex, with a lot of conditions, and difficult to maintain. To make things simpler we probably should use multiple smaller files.
While we are on the topic of filenames, I think it’s good to look also at Include Tags. Include tags cover a few more filenames, which are recognized by WordPress, but not documented in template hierarchy. header.php, footer.php, sidebar.php and comments.php can be easily included from your other theme files by using calls to get_header(), get_footer(), get_sidebar(), and comments_template() respectively. Also, note that there is some magic about the comments_template() call:
This tag includes the file comments.php from your current theme’s directory. If that file is not found, it will instead include wp-content/themes/default/comments.php. To display comments on the main index or archive pages, you’ll need to set the $withcomments variable to “1″ before calling this tag.
Last time, when we talking about The Loop, we mentioned that there was some magic about how WordPress knows which posts to show. I hope now you see how that magic is done. The core of The Loop is the have_posts() function call. Because WordPress recognizes the current visitor location from the URL, have_posts() knows which posts it should get – the ones in archives, the ones in the category, the ones on the front page, or the ones in the search results.
Now we know how theme part of WordPress works. In the next post we’ll see how we can control and modify WordPress behavior using The Query.