What is Template Hierarchy?
When someone visits a URL on your WordPress site, WordPress has to decide which PHP file to load to render that page.
This decision-making system is called the Template Hierarchy.
WordPress looks for template files in a specific order — from most specific to most generic — and loads the first one it finds. If none are found, it always falls back to index.php.
Think of it like Laravel's route matching — most specific route wins. Same concept here, but with files instead of routes.
Why is This the Most Important Concept?
Because everything in theme development is built around this. When you create a template file with the right name — WordPress automatically uses it for the right content type. No routing code, no configuration — just the filename.
Visitor goes to /movies/inception/
↓
WordPress checks: what type of content is this?
↓
It is a single post of type 'movie'
↓
WordPress looks for template files in this order:
1. single-movie-inception.php ← most specific
2. single-movie.php
3. single.php
4. singular.php
5. index.php ← most generic (always exists)
↓
Loads the first file it finds
The Complete Template Hierarchy
Let us go through every content type and its template hierarchy.
1. Front Page (Homepage)
When someone visits https://streamvault.local/
front-page.php
↓
home.php
↓
index.php
Note: front-page.php is always used for the homepage regardless of whether you set a static page or latest posts in Settings → Reading. It is the highest priority homepage template.
2. Home / Blog Posts Index
When someone visits your blog posts page (the page you set in Settings → Reading → Posts page):
home.php
↓
index.php
3. Single Blog Post
When someone visits an individual blog post like /top-10-action-movies/
single-post-{slug}.php e.g. single-post-top-10-action-movies.php
↓
single-post.php
↓
single.php
↓
singular.php
↓
index.php
4. Single Custom Post Type
When someone visits a single movie like /movies/inception/
single-{post-type}-{slug}.php e.g. single-movie-inception.php
↓
single-{post-type}.php e.g. single-movie.php
↓
single.php
↓
singular.php
↓
index.php
This is exactly what we will use for StreamVault. We will create single-movie.php and WordPress will automatically use it for every single movie page.
5. Static Page
When someone visits a page like /about/
{custom-template}.php (if assigned via Page Attributes)
↓
page-{slug}.php e.g. page-about.php
↓
page-{id}.php e.g. page-5.php
↓
page.php
↓
singular.php
↓
index.php
So if you create a file called page-about.php in your theme — WordPress automatically uses it only for the About page. Every other page uses page.php.
6. Category Archive
When someone visits /category/movie-reviews/
category-{slug}.php e.g. category-movie-reviews.php
↓
category-{id}.php e.g. category-3.php
↓
category.php
↓
archive.php
↓
index.php
7. Tag Archive
When someone visits /tag/christopher-nolan/
tag-{slug}.php e.g. tag-christopher-nolan.php
↓
tag-{id}.php e.g. tag-8.php
↓
tag.php
↓
archive.php
↓
index.php
8. Custom Taxonomy Archive
When someone visits /genre/action/ (our StreamVault genre taxonomy)
taxonomy-{taxonomy}-{term}.php e.g. taxonomy-genre-action.php
↓
taxonomy-{taxonomy}.php e.g. taxonomy-genre.php
↓
taxonomy.php
↓
archive.php
↓
index.php
So taxonomy-genre.php will be used for ALL genre archive pages — action, drama, comedy, thriller, etc.
9. Custom Post Type Archive
When someone visits /movies/ (the movies archive page)
archive-{post-type}.php e.g. archive-movie.php
↓
archive.php
↓
index.php
We will create archive-movie.php for the StreamVault movies listing page.
10. Author Archive
When someone visits /author/admin/
author-{nicename}.php e.g. author-admin.php
↓
author-{id}.php e.g. author-1.php
↓
author.php
↓
archive.php
↓
index.php
11. Date Archive
When someone visits /2024/01/ or /2024/
date.php
↓
archive.php
↓
index.php
12. Search Results
When someone searches on your site — /search/inception/
search.php
↓
index.php
13. 404 Not Found
When someone visits a URL that does not exist
404.php
↓
index.php
14. Attachment Page
When someone visits a media file page
{mime-type}.php e.g. image.php, video.php
↓
attachment.php
↓
single.php
↓
singular.php
↓
index.php
Visual Map of the Entire Hierarchy
Any URL on your site
│
├── Is it the homepage?
│ ├── front-page.php
│ └── home.php
│
├── Is it a single post/CPT?
│ ├── single-{type}-{slug}.php
│ ├── single-{type}.php
│ ├── single.php
│ └── singular.php
│
├── Is it a static page?
│ ├── {custom-template}.php
│ ├── page-{slug}.php
│ ├── page-{id}.php
│ ├── page.php
│ └── singular.php
│
├── Is it an archive?
│ ├── Category → category-{slug}.php → category.php
│ ├── Tag → tag-{slug}.php → tag.php
│ ├── Taxonomy → taxonomy-{tax}-{term}.php → taxonomy-{tax}.php
│ ├── CPT Archive → archive-{type}.php
│ ├── Author → author-{name}.php → author.php
│ ├── Date → date.php
│ └── All fall back to → archive.php
│
├── Is it a search results page?
│ └── search.php
│
├── Is it a 404 page?
│ └── 404.php
│
└── ULTIMATE FALLBACK → index.php
How WordPress Finds These Files
WordPress looks for template files in this order:
1. Child theme folder (if a child theme is active)
2. Parent theme folder (your main theme folder)
3. Falls back to index.php (always present)
This is why child themes work — you put only the files you want to override in the child theme, and WordPress finds them first.
Practical Example — StreamVault Templates We Will Build
Based on the template hierarchy, here are the files we will create for StreamVault:
streamvault/
├── index.php ← ultimate fallback
├── front-page.php ← StreamVault homepage (hero, featured movies)
├── single-movie.php ← individual movie page
├── single-series.php ← individual series page
├── archive-movie.php ← all movies listing page
├── archive-series.php ← all series listing page
├── taxonomy-genre.php ← genre archive (action, drama, etc.)
├── taxonomy-language.php ← language archive
├── page.php ← static pages (about, contact)
├── search.php ← search results
├── 404.php ← not found page
├── header.php ← header partial
├── footer.php ← footer partial
└── functions.php ← theme brain
Every single filename is chosen based on the template hierarchy. WordPress will automatically route the right URL to the right file.
Custom Page Templates
Beyond the automatic hierarchy, you can create custom page templates — files that an admin can manually assign to any page from the Page Attributes panel.
To create a custom page template, add this comment at the top of any PHP file in your theme:
<?php /* * Template Name: Full Width Page * Template Post Type: page */
Now in WordPress admin — when editing any Page — under Page Attributes → Template you will see "Full Width Page" as an option.
For StreamVault we will create:
<?php /* * Template Name: StreamVault Home */
<?php /* * Template Name: Movies Browse Page */
How to Debug Which Template is Loading
This is where Query Monitor plugin becomes useful. After activating it:
- Visit any page on your site frontend
- Click on Query Monitor bar at the top
- Click "Template" tab
Query Monitor → Template
------------------------
Template file: single-movie.php
Theme: streamvault
It tells you exactly which template file is being used for the current page. Extremely useful when debugging why a page looks wrong.
Alternatively — you can also temporarily add this to the top of index.php:
<?php echo get_template_part( basename( __FILE__, '.php' ) ); ?>
Or use this in any template to see its name:
<?php echo '<!-- Template: ' . basename(__FILE__) . ' -->'; ?>
Then inspect the page source — you will see the template name in an HTML comment.
The get_template_part() Function
Before finishing this module — one function you need to know right now.
get_template_part() lets you include reusable partial template files inside other templates:
get_template_part('template-parts/content', 'movie');
WordPress looks for these files in order:
template-parts/content-movie.php ← first choice
template-parts/content.php ← fallback
This is how we will build reusable components for StreamVault:
streamvault/
└── template-parts/
├── content-movie.php ← movie card component
├── content-series.php ← series card component
├── content-episode.php ← episode item component
└── content-none.php ← "nothing found" message
Then in archive-movie.php:
while (have_posts()) {
the_post();
get_template_part('template-parts/content', 'movie');
}
Clean, reusable, exactly like Laravel's @include or components.
Summary
- Template Hierarchy is WordPress's automatic routing system based on filenames.
- WordPress always looks from most specific to most generic, falling back to
index.php. - Single CPT:
single-{type}.php— we will usesingle-movie.phpandsingle-series.php. - CPT Archive:
archive-{type}.php— we will usearchive-movie.php. - Custom Taxonomy:
taxonomy-{tax}.php— we will usetaxonomy-genre.php. - Homepage:
front-page.phptakes highest priority. - Custom page templates are created with a
Template Name:comment at the top. get_template_part()is used for reusable partial files — like Laravel's@include.- Query Monitor → Template tab tells you exactly which file is loading for any page.
No comments:
Post a Comment