Template Hierarchy
Every time WordPress serves a page, it has to decide which single PHP file, out of everything in your active theme, should render it. That decision isn't random — it follows a strict, well-documented set of rules called the template hierarchy. Understanding it means you always know exactly which file to create or edit to customize any given type of page.
1. How the Hierarchy Works, in General
For each request, WordPress first figures out what kind of page is being viewed (a single post,
a category archive, a search results page, and so on), then looks through your active theme folder for
a series of increasingly generic filenames, using the first one it finds. If your theme doesn't provide
any of the specific files, WordPress ultimately falls back to the one file every theme is required to
have: index.php.
2. Worked Example: Rendering a Single Post
Say a visitor requests a single blog post whose post type is the default post and whose
slug is hello-world. WordPress searches for a template in exactly this order, using the
first match it finds in your theme:
single-post-hello-world.php— a template for that one specific post, by slugsingle-post.php— a template for thepostpost type generallysingle.php— the generic template for any single item of any post typeindex.php— the universal fallback every theme must have
Most themes never bother with the slug-specific file and just provide single.php — but the
fact that WordPress checks for it first means you can override the display of one particular post
without touching anything else, simply by adding that one file.
3. Reference Table: Main Page Types and Their Templates
| Page type | Template file(s), most specific first |
|---|---|
| The homepage | front-page.php, then home.php (if "Your homepage displays: a static page" isn't set), then index.php |
| A single post | single-{post-type}-{slug}.php, single-{post-type}.php, single.php, index.php |
| A static page | page-{slug}.php, page-{id}.php, page.php, index.php |
| A category/tag/date archive | category-{slug}.php (or tag/date equivalent), archive.php, index.php |
| Search results | search.php, index.php |
| 404 Not Found | 404.php, index.php |
4. Checking the Current Page Type: The is_*() Conditional Tags
Inside functions.php or directly in a template, you often need to ask "what kind of page am
I currently on?" — for example, to add different body classes, load different scripts, or tweak a
query. WordPress provides a family of conditional tag functions for exactly this:
| Function | Returns true when... |
|---|---|
is_home() | The main blog listing page is being shown |
is_single() | A single post (optionally of a given type or ID) is being viewed |
is_page() | A static page (optionally a given slug or ID) is being viewed |
is_archive() | Any archive page (category, tag, date, author, custom taxonomy) is being viewed |
<?php
function my_body_classes($classes) {
if (is_single()) {
$classes[] = 'single-post-layout';
} elseif (is_page('contact')) {
$classes[] = 'contact-page-layout';
} elseif (is_archive()) {
$classes[] = 'archive-layout';
}
return $classes;
}
add_filter('body_class', 'my_body_classes');
This example hooks into the body_class filter (covered properly in the next lesson) to add
a different CSS class depending on the page type, letting you style each layout differently from one
shared stylesheet.
5. Why This Matters for Theme Development
Without understanding the hierarchy, developers often resort to giant if/else blocks inside
index.php trying to detect the page type manually and change behavior — exactly what the
is_*() tags and the hierarchy itself already do for you. Knowing the rules means:
- You can create
page-contact.phpand know with certainty it will render only the "Contact" page, with zero risk of affecting other pages. - You know exactly which file to open when a client says "the category pages look wrong" (
archive.phpor a more specificcategory-*.php). - You avoid accidentally editing a file that's actually a fallback for many different page types at once.
pre_get_posts and body_class hooks used above) that lets you extend WordPress everywhere without touching core files.