{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "name": "WordPress Block Theme Template Hierarchy",
  "description": "For each route WordPress can render, the ordered list of block-theme template files it looks for, most specific first. `candidates` is the fallback chain: WordPress uses the first one that exists in the theme.",
  "source": "https://odiethemes.com/reference/block-theme-template-hierarchy",
  "license": "CC-BY-4.0",
  "licenseUrl": "https://creativecommons.org/licenses/by/4.0/",
  "attribution": "Data from Odie Themes — https://odiethemes.com/reference/block-theme-template-hierarchy",
  "note": "Templates live in templates/*.html and template parts in parts/*.html. A template edited in the Site Editor is stored as a wp_template record in the database and overrides the theme file on disk.",
  "count": 16,
  "routes": [
    {
      "id": "front-page",
      "label": "Front page",
      "description": "The site's front page, whether it is set to your latest posts or a static page.",
      "candidates": [
        "front-page.html",
        "home.html",
        "index.html"
      ],
      "note": "front-page.html wins regardless of the Settings → Reading choice. If the front page is a static page and there is no front-page.html, it falls through to the static-page chain, not home.html."
    },
    {
      "id": "home",
      "label": "Blog posts index",
      "description": "The page that lists your latest posts (the \"posts page\" in Settings → Reading).",
      "candidates": [
        "home.html",
        "index.html"
      ]
    },
    {
      "id": "single-post",
      "label": "Single post",
      "description": "An individual blog post.",
      "candidates": [
        "single-post-{slug}.html",
        "single-post.html",
        "single.html",
        "singular.html",
        "index.html"
      ]
    },
    {
      "id": "single-cpt",
      "label": "Single custom post type",
      "description": "An individual entry of a custom post type (e.g. a \"book\").",
      "candidates": [
        "single-{post-type}-{slug}.html",
        "single-{post-type}.html",
        "single.html",
        "singular.html",
        "index.html"
      ],
      "note": "For a post type \"book\" with slug \"dune\": single-book-dune.html, then single-book.html, then single.html."
    },
    {
      "id": "page",
      "label": "Static page",
      "description": "A regular WordPress page.",
      "candidates": [
        "page-{slug}.html",
        "page-{id}.html",
        "page.html",
        "singular.html",
        "index.html"
      ]
    },
    {
      "id": "page-custom-template",
      "label": "Page with a custom template",
      "description": "A page assigned a custom template in the editor's Template panel.",
      "candidates": [
        "{custom-template}.html",
        "page-{slug}.html",
        "page-{id}.html",
        "page.html",
        "singular.html",
        "index.html"
      ],
      "note": "Custom templates are declared in theme.json's customTemplates array and live in /templates. The assigned one wins over the whole page chain."
    },
    {
      "id": "category",
      "label": "Category archive",
      "description": "The archive listing posts in one category.",
      "candidates": [
        "category-{slug}.html",
        "category-{id}.html",
        "category.html",
        "archive.html",
        "index.html"
      ]
    },
    {
      "id": "tag",
      "label": "Tag archive",
      "description": "The archive listing posts with one tag.",
      "candidates": [
        "tag-{slug}.html",
        "tag-{id}.html",
        "tag.html",
        "archive.html",
        "index.html"
      ]
    },
    {
      "id": "taxonomy",
      "label": "Custom taxonomy archive",
      "description": "The archive for a term in a custom taxonomy.",
      "candidates": [
        "taxonomy-{taxonomy}-{term}.html",
        "taxonomy-{taxonomy}.html",
        "taxonomy.html",
        "archive.html",
        "index.html"
      ]
    },
    {
      "id": "author",
      "label": "Author archive",
      "description": "The archive of one author's posts.",
      "candidates": [
        "author-{nicename}.html",
        "author-{id}.html",
        "author.html",
        "archive.html",
        "index.html"
      ]
    },
    {
      "id": "date",
      "label": "Date archive",
      "description": "A year / month / day archive.",
      "candidates": [
        "date.html",
        "archive.html",
        "index.html"
      ]
    },
    {
      "id": "cpt-archive",
      "label": "Post type archive",
      "description": "The archive index for a custom post type that has has_archive set.",
      "candidates": [
        "archive-{post-type}.html",
        "archive.html",
        "index.html"
      ]
    },
    {
      "id": "search",
      "label": "Search results",
      "description": "The results page for a site search.",
      "candidates": [
        "search.html",
        "index.html"
      ]
    },
    {
      "id": "404",
      "label": "404 (not found)",
      "description": "Shown when no content matches the URL.",
      "candidates": [
        "404.html",
        "index.html"
      ]
    },
    {
      "id": "attachment",
      "label": "Attachment page",
      "description": "The page for a single media attachment.",
      "candidates": [
        "attachment.html",
        "single.html",
        "singular.html",
        "index.html"
      ],
      "note": "Many sites disable attachment pages entirely (they are thin content). If you keep them, this is the chain."
    },
    {
      "id": "privacy-policy",
      "label": "Privacy policy page",
      "description": "The page set as the site's privacy policy in Settings.",
      "candidates": [
        "page-privacy-policy.html",
        "privacy-policy.html",
        "page.html",
        "singular.html",
        "index.html"
      ]
    }
  ],
  "classicDifferences": [
    "Templates are .html files in /templates, not .php files in the theme root. There is no single.php — it is single.html.",
    "Reusable regions (header, footer) are template PARTS in /parts, referenced with the wp:template-part block, not get_header() / get_footer() PHP calls.",
    "There is no get_template_part() chain and no get_header()/get_footer(). Composition is done with the Template Part block inside the .html files.",
    "index.html is REQUIRED. A block theme without templates/index.html is not a valid block theme — it is the mandatory final fallback for every route above.",
    "The theme is declared a block theme by the PRESENCE of templates/index.html plus a theme.json, not by any header flag.",
    "You can edit any of these templates in the Site Editor (Appearance → Editor) and save the changes to the database — which then OVERRIDE the theme's files until you clear the customization. This surprises people debugging \"why does my template change do nothing\"."
  ]
}