2 min read

FSE Template Hierarchy: Templates vs. Parts

In Classic themes, the Template Hierarchy relied on PHP files like single.php or archive.php. In FSE Block Themes, this logic remains largely the same, but the implementation has moved to HTML files containing block markup.

1. The Directory Structure

A standard block theme has two critical directories for structure:

  • templates/: Full-page layouts. These correspond to WordPress hierarchy logic (e.g., index.html, 404.html, single.html).
  • parts/: Reusable sections included inside templates (e.g., header.html, footer.html, sidebar.html).

The "Why": Modularity

Separating Parts from Templates allows you to update a Header in one place (parts/header.html) and have it reflect across every Template that includes it.

2. The templates/ Directory

These files dictate the layout for entire pages. WordPress automatically picks the correct file based on the URL.

  • index.html: The fallback for everything. Required.
  • single.html: Used for single blog posts.
  • page.html: Used for static pages.
  • archive.html: Used for category/tag lists.
  • 404.html: Used for when content is not found.

Example templates/index.html:

<!-- wp:template-part {"slug":"header","tagName":"header"} /-->

<!-- wp:group {"tagName":"main"} -->
    <!-- wp:query {"queryId":0,"query":{"perPage":10,"pages":0,"offset":0,"postType":"post","order":"desc","orderBy":"date","author":"","search":"","exclude":[],"sticky":"","inherit":true}} -->
        <!-- wp:post-template -->
            <!-- wp:post-title {"isLink":true} /-->
            <!-- wp:post-excerpt /-->
        <!-- /wp:post-template -->
    <!-- /wp:query -->
<!-- /wp:group -->

<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->

3. The parts/ Directory

Template Parts are "dumb" containers. They don't know about the URL or the Query. They just hold blocks.

Referencing a part: To load parts/header.html, you use the Template Part block in your template:

<!-- wp:template-part {"slug":"header","tagName":"header"} /-->
  • slug: Matches the filename (minus .html).
  • tagName: The HTML wrapper tag (e.g., <header>, <footer>, <div>).

4. Custom Templates

Sometimes you want a specific layout for a specific page (e.g., "Landing Page - No Header"). You can create a custom template file (e.g., templates/landing-page.html), but WordPress won't show it in the Page Editor dropdown unless you register it in theme.json.

Registering in theme.json:

{
    "customTemplates": [
        {
            "name": "landing-page",
            "title": "Landing Page (No Header)",
            "postTypes": ["page"]
        }
    ]
}

File Mapping:

  • name: "landing-page" --> templates/landing-page.html

5. Next Steps

Templates are static without dynamic content. The engine that powers the content grid inside these templates is the Query Loop.

Proceed to Part 6: The Query Loop.