The WordPress Template Hierarchy
WordPress Intermediate/Advanced
Chapter 2 · The WordPress Template Hierarchy
Chapter 1 named index.php as the universal fallback template without explaining how WordPress decides whether to use something more specific first. This chapter covers that full decision process — and it's genuinely just PHP underneath, exactly the kind of logic PHP Fundamentals already prepared you to read.
The Core Idea
For any given URL, WordPress builds an ordered list of candidate template filenames — most specific first, most generic last — and uses the first file that actually exists in the active theme. If none of the more specific candidates exist, the search always ends at index.php, exactly as Chapter 1 described.
The Hierarchy for a Single Blog Post
| Checked, in order | Example filename |
|---|---|
| 1. Post-type + slug specific | single-post-my-post-title.php |
| 2. Post-type specific | single-post.php |
| 3. Generic single | single.php |
| 4. Generic singular (posts and pages both) | singular.php |
| 5. Universal fallback | index.php |
The Hierarchy for a Page
| Checked, in order | Example filename |
|---|---|
| 1. A custom template explicitly assigned to that Page | (whichever file was chosen in the editor) |
| 2. Slug specific | page-about.php |
| 3. Page ID specific | page-42.php |
| 4. Generic page | page.php |
| 5. Generic singular | singular.php |
| 6. Universal fallback | index.php |
Archives — Category, Blog Listing, and 404
| Page type | Checked, in order |
|---|---|
| Category archive | category-{slug}.php → category-{id}.php → category.php → archive.php → index.php |
| Main blog listing | home.php → index.php |
| 404 error page | 404.php → index.php |
A Worked Trace
hello-world. WordPress checks, in order: does single-post-hello-world.php exist in the active theme? No. Does single-post.php exist? No. Does single.php exist? Yes — that file is used, and the search stops there. If single.php hadn't existed either, the search would have continued to singular.php, and finally to index.php as the last resort.
Template Tags — Pulling in Dynamic Content
Once the right template file is chosen, it needs to actually display the post or page's own content — that's what template tags are for: PHP functions called directly inside a template to output dynamic, per-page content.
the_content() — the actual post/page body — deliberately isn't shown here, since it needs to be called inside the Loop, the mechanism WordPress Intermediate/Advanced 3 covers next.
Conditional Tags — One File, Many Behaviors
A minimal theme relying heavily on index.php can still behave differently depending on what kind of page is currently being rendered, using conditional tags:
index.php handle every page type through nothing but if/elseif branches — but real themes still split into single.php, page.php, archive.php, and so on, because separate files stay far more readable and maintainable than one enormous file branching on every possible page type. The hierarchy exists to make that split convenient, not to discourage it.
Hands-On Exercises
A theme contains only index.php, header.php, and footer.php — no single.php, no page.php. Explain what template renders a single blog post on this theme, and why.
A theme has both single.php and singular.php. Explain which one WordPress actually uses to render a single blog post, and why the other one is effectively unused for that page type.
Explain why this chapter says the template hierarchy is "genuinely just PHP, not magic," describing the actual underlying mechanism in your own words.
📄 View solutionChapter 2 Quick Reference
- WordPress checks an ordered list of candidate filenames, most specific first, and uses the first one that exists
- Single post: single-{type}-{slug}.php → single-{type}.php → single.php → singular.php → index.php
- Page: assigned custom template → page-{slug}.php → page-{id}.php → page.php → singular.php → index.php
- Archives/404 each have their own ordered chain, always ending at index.php
- Template tags (the_title(), the_permalink(), etc.) output dynamic content; the_content() is deferred to the Loop, next chapter
- Conditional tags (is_single(), is_page(), is_category()) let one file behave differently per page type — real themes still split into many files for readability
- Next chapter: The Loop & WordPress Core Functions