Phase 2 — Module 2.1: Template Hierarchy — The Most Important WordPress Concept

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:

  1. Visit any page on your site frontend
  2. Click on Query Monitor bar at the top
  3. 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 use single-movie.php and single-series.php.
  • CPT Archive: archive-{type}.php — we will use archive-movie.php.
  • Custom Taxonomy: taxonomy-{tax}.php — we will use taxonomy-genre.php.
  • Homepage: front-page.php takes 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

PHP & Laravel — Zero to Hero Episode 23: Deploying Laravel — Taking Your Application Live

What Are We Doing in This Post? Your Laravel blog is complete. It has authentication, posts, relationships, validation, and a clean UI. But...