Build classic and block WordPress themes from scratch: the template hierarchy, The Loop, the_title() and the_content(), template parts, menus, the Customizer, child themes and theme.json.
Lessons
The template hierarchy is the fixed order in which WordPress looks for a template file for each request — it tries the most specific file first and falls back step by step until it reaches index.php.
Understanding it is what separates guessing from theme development. Once you know the order, you can change how one category, one page or one post type looks just by creating a file with the right name — no if statements needed.
For a single blog post with the slug hello-world, WordPress checks for these files in this order and uses the first one that exists:
single-post-hello-world.php — this exact postsingle-post.php — any post of type postsingle.php — any single post of any typesingular.php — any single post or pageindex.php — the final fallback, always presentIf your theme has only index.php, everything uses it. Add single.php and posts suddenly get their own layout, while pages and archives are unaffected.
| Visitor is viewing | WordPress tries, in order |
|---|---|
| The front page | front-page.php → home.php or the page hierarchy → index.php |
| The blog posts index | home.php → index.php |
| A single post | single-{post-type}-{slug}.php → single-{post-type}.php → single.php → singular.php → index.php |
| A page | Assigned page template → page-{slug}.php → page-{id}.php → page.php → singular.php → index.php |
| A category | category-{slug}.php → category-{id}.php → category.php → archive.php → index.php |
| A tag | tag-{slug}.php → tag-{id}.php → tag.php → archive.php → index.php |
| An author | author-{nicename}.php → author-{id}.php → author.php → archive.php → index.php |
| A date archive | date.php → archive.php → index.php |
| A custom post type archive | archive-{post-type}.php → archive.php → index.php |
| A custom taxonomy term | taxonomy-{taxonomy}-{term}.php → taxonomy-{taxonomy}.php → taxonomy.php → archive.php → index.php |
| Search results | search.php → index.php |
| A missing page | 404.php → index.php |
This trips up almost everyone, because the names suggest the opposite of what they do.
front-page.php renders the site's home page — whatever is at your root URL — regardless of the Reading settings.home.php renders the blog posts index. If Settings → Reading shows "Your latest posts", that index is the home page too. If it is set to a static page, the blog index moves to the "Posts page" you chose, and home.php renders that page instead.Tip: A practical rule: usefront-page.phpfor a marketing-style home page, andhome.phpfor the list of blog posts.
Say the "News" category (slug news) needs a different layout from every other category. You do not touch archive.php at all — you create a new file:
<?php
/**
* category-news.php
*
* WordPress picks this file automatically for /category/news/,
* because category-{slug}.php is checked before archive.php.
*/
get_header();
?>
<main class="news-archive">
<h1 class="news-archive__title">Latest News</h1>
<?php if ( have_posts() ) : ?>
<?php while ( have_posts() ) : the_post(); ?>
<?php get_template_part( 'template-parts/content', 'news' ); ?>
<?php endwhile; ?>
<?php endif; ?>
</main>
<?php
get_footer();Every other category still uses archive.php. That is the hierarchy doing exactly what it is for.
With Query Monitor active, open any page on the front end and click the admin bar entry. The Template panel shows the file that rendered the page and the full list of candidates WordPress tried. This is the fastest way to learn the hierarchy — browse your site and watch it.
category-News.php — slugs are lowercase, so it is never found.page-42.php on a site that will be migrated. IDs change between environments; slugs usually do not.if ( is_category( 'news' ) ) checks inside archive.php instead of creating category-news.php.index.php to single.php and change the heading. Open a post and a page — only the post changes.page-about.php for a page with the slug about and confirm it is used only for that page.In accordance with Section 6 & Section 7 of the DPDP Act 2023, third-party analytics and marketing trackers are strictly gated behind your affirmative consent. You may withdraw consent at any time under Section 6(4).
Essential for session authentication (ci_session), Cross-Site Request Forgery security (csrf_cookie_name), and Cloudflare DDoS/bot prevention. Cannot be disabled.
Gated under DPDP Section 7. Allows Google Analytics 4 (Google Consent Mode v2) to measure aggregate, anonymized tool usage.
Enables browser local storage to preserve your theme selection (dark/light mode) and code editor layout between visits.
Used to display developer sponsorships and native tool partner notices.