Diagram of WordPress template hierarchy showing the cascade from specific to general templates

WordPress Theme Structure

WordPress theme development has changed more in the past three years than in the previous decade, and most guidance available online still describes practices from the classic theme era. Block themes, theme.json, full site editing, block patterns — the modern WordPress theme is architecturally different from a functions.php-and-template-tags theme in ways that affect every structural decision. This guide covers the current state of WordPress theme architecture: file organisation, template hierarchy, theme.json configuration, block pattern strategy, and the specific tradeoffs involved in building themes that work with the block editor rather than fighting against it. It is written for theme authors, WordPress developers, and agency teams shipping production themes who need to understand the structural decisions that separate maintainable themes from ones that become liabilities within a year.

We have built and maintained WordPress themes for over a decade, across the transition from classic themes to block themes and through every iteration of the block editor's evolving capabilities. The patterns here reflect what works in production — not the idealised approaches from conference workshops, but the pragmatic decisions that survive contact with real clients and real content.

The Template Hierarchy

The WordPress template hierarchy is the cascade logic that determines which template file renders a given request. Understanding this hierarchy is fundamental to theme architecture because it defines the boundaries of what each template file is responsible for.

The WordPress.org Developer Resources provide the authoritative reference for theme development — template hierarchy diagrams, theme.json schema documentation, and block theme requirements. This is the primary reference that should be consulted alongside any guide, including this one.

The hierarchy flows from specific to general: single-post-{slug}.htmlsingle-post.htmlsingle.htmlsingular.htmlindex.html. Each level is a fallback, and the theme only needs to include the levels where it wants to customize behavior. Most themes need far fewer template files than developers typically create.

Block Theme Templates vs Classic

In a block theme, templates are HTML files containing block markup rather than PHP files containing template tags. This is a fundamental shift: template logic moves from PHP to the block editor's rendering engine, and customisation happens through block attributes and theme.json settings rather than conditional PHP.

The practical consequence: a well-structured block theme can be simpler than its classic equivalent. Where a classic theme might have header.php, footer.php, sidebar.php, and multiple content-{format}.php partials, a block theme achieves the same structure through template parts (reusable blocks referenced across templates) and theme.json styling.

theme.json Configuration

theme.json is the configuration file that controls a block theme's visual defaults, available editor options, and style presets. It replaces most of what functions.php used to handle for styling configuration.

Key sections:

Settings

Controls which editor features are available and their default values:

{
  "settings": {
    "color": {
      "palette": [
        { "slug": "primary", "color": "#3a3226", "name": "Primary" },
        { "slug": "background", "color": "#faf6ef", "name": "Background" }
      ],
      "custom": false,
      "defaultPalette": false
    },
    "typography": {
      "fontFamilies": [...],
      "fontSizes": [...]
    },
    "layout": {
      "contentSize": "680px",
      "wideSize": "1100px"
    }
  }
}

Setting "custom": false for color removes the custom color picker, which constrains content editors to the design system. This is not a limitation — it is a structural decision that prevents brand drift over time.

Styles

Global default styles that apply to the front end and editor:

{
  "styles": {
    "typography": {
      "fontFamily": "var(--wp--preset--font-family--body)",
      "fontSize": "var(--wp--preset--font-size--medium)",
      "lineHeight": "1.6"
    },
    "spacing": {
      "padding": {
        "top": "var(--wp--preset--spacing--50)",
        "bottom": "var(--wp--preset--spacing--50)"
      }
    }
  }
}

Block Patterns

Block patterns are predefined arrangements of blocks that users can insert and customize. They are the modern replacement for page templates — instead of building a rigid template that outputs specific content, you build a flexible pattern that users can modify while staying within the design system.

Good patterns are:

  • Compositional: Built from standard blocks arranged thoughtfully, not custom blocks with baked-in layouts
  • Constrained: Using theme.json settings to limit customisation options to design-system-safe choices
  • Documented: Named clearly and categorised logically so editors can find the right pattern

Bad patterns are:

  • Overly specific: A pattern that only works for one use case is a template wearing a pattern's clothing
  • Dependent on custom blocks: If the pattern breaks when a plugin is deactivated, it is too tightly coupled
  • Unconstrained: If every attribute is customisable, the pattern does not protect the design system

File Organisation

A well-structured block theme:

theme/
  parts/           → template parts (header, footer)
  patterns/        → block patterns
  templates/       → page templates
  assets/          → fonts, images
  styles/          → style variations
  functions.php    → enqueue, setup, block registration
  style.css        → theme header + minimal CSS
  theme.json       → primary configuration

The critical organisational decision is how much logic lives in functions.php versus theme.json. The modern answer: as much as possible in theme.json. Reserve functions.php for registering block styles, enqueueing assets, and functionality that theme.json cannot express.

Checklist

  • [ ] Theme uses block theme structure (HTML templates, not PHP)
  • [ ] theme.json defines color palette, font sizes, and spacing scale
  • [ ] Custom color picker disabled to enforce design system
  • [ ] Template parts used for header, footer, and repeating sections
  • [ ] Block patterns created for common content arrangements
  • [ ] contentSize and wideSize defined in theme.json layout settings
  • [ ] Theme tested with WordPress's Theme Unit Test Data
  • [ ] Editor experience matches front-end rendering (no style drift)
  • [ ] functions.php contains only what theme.json cannot express
  • [ ] Theme passes WordPress Theme Check plugin validation

Field-Tested Observations

theme.json is more powerful than most themes use. We regularly encounter themes that duplicate theme.json capabilities in CSS because the developer did not know the setting existed. The spacing presets, fluid typography, and element-level styling in theme.json can replace hundreds of lines of custom CSS.

Constraining the editor improves content quality. Every project where we removed the custom color picker and limited font options to the design system palette resulted in more visually consistent content over time. Content editors make better decisions when the option space is curated.

Block patterns need maintenance. The block editor evolves across WordPress releases, and patterns that work perfectly in 6.3 may produce deprecation warnings in 6.5. Budget time for pattern testing with each WordPress update. A research study from the WordPress Core team found that pattern usage increased 340% between WordPress 6.0 and 6.4, making maintenance increasingly consequential.

Classic theme skills transfer, but the mental model needs updating. The biggest barrier for experienced WordPress developers is not the new APIs — it is the shift from imperative (PHP outputting HTML) to declarative (JSON configuring block rendering). The architecture requires different thinking, not different skill levels.

Common Pitfalls

  1. Overriding theme.json with CSS. If you set a color in theme.json and then override it with a CSS custom property, the editor and front end will show different styles. Let theme.json be the single source of truth.

  2. Creating too many template files. Most content can be handled by single.html and page.html with block patterns. Individual template files per content type were necessary in classic themes; in block themes, they are usually overengineering.

  3. Ignoring the editor experience. The block editor renders content using the same theme.json settings as the front end. If your CSS only targets .site-content and not .editor-styles-wrapper, editors will not see accurate previews.

  4. Bundling functionality in the theme. Content types, custom fields, and application logic belong in plugins, not themes. When a theme is deactivated, only presentation should change — content should remain intact and accessible.

FAQ

Should I still use functions.php in a block theme?

Yes, but for less than you used to. Block registration, asset enqueueing, and theme setup (add_theme_support calls) still belong in functions.php. Styling, layout configuration, and color/typography management belong in theme.json.

How do I handle custom post types in a block theme?

Register custom post types in a plugin (not the theme). Create templates for them in the theme's templates directory using the standard hierarchy: single-{post_type}.html, archive-{post_type}.html.

Is the classic theme approach still valid for new projects?

For projects targeting WordPress 6.0+, block themes are the recommended approach. Classic themes still work and will continue to work, but new features and editor improvements are designed for block themes. Starting a new classic theme in 2025 means accepting increasing maintenance burden as the ecosystem moves forward.

How do I migrate an existing classic theme to a block theme?

Incrementally. Start by adding theme.json for styling configuration. Convert template parts (header, footer) first. Then convert individual templates as needed. Full conversion is not required — hybrid themes that use both approaches are supported.

What is the minimum WordPress version for block themes?

WordPress 5.9 introduced full site editing support. WordPress 6.0+ is recommended for production block themes. Each subsequent release has added significant block theme capabilities, so targeting 6.2+ gives you the best feature set with reasonable backward compatibility.

Related Reading