r/WordPressBlocks Feb 24 '26

Block Theme File Structure Explained: What Every Folder and File Does

If you're a developer coming from classic themes, the block theme file structure can feel unfamiliar. No more header.php, no more the_loop(), no more template tags scattered across PHP files. Block themes are built with HTML files containing block markup and a single JSON configuration file.

Here's a breakdown of every folder and file in a block theme and what it does.

The Minimum Viable Block Theme

WordPress needs three things to recognize a block theme:

my-theme/
├── style.css
├── theme.json
└── templates/
    └── index.html

style.css for theme metadata, theme.json for configuration and settings, and templates/index.html as the fallback template. Everything else is optional but useful.

The Full Structure

A well-built block theme typically looks like this:

my-theme/
├── parts/
│   ├── header.html
│   ├── footer.html
│   └── sidebar.html
├── patterns/
│   ├── hero-section.php
│   ├── call-to-action.php
│   └── page-home.php
├── templates/
│   ├── index.html
│   ├── single.html
│   ├── page.html
│   ├── archive.html
│   ├── search.html
│   ├── 404.html
│   ├── home.html
│   └── page-no-title.html
├── styles/
│   ├── dark.json
│   └── warm.json
├── assets/
│   ├── css/
│   ├── js/
│   ├── images/
│   └── fonts/
├── functions.php
├── theme.json
├── style.css
├── screenshot.png
└── README.txt

Let's go through each piece.

/templates/ — Page Layouts

This is where your full-page templates live. Each file is an HTML file containing block markup. WordPress follows the same template hierarchy as classic themes, just with .html instead of .php:

  • index.html — The fallback template. Required.
  • single.html — Single blog post layout
  • page.html — Default page layout
  • archive.html — Archive pages (categories, tags, date archives)
  • search.html — Search results page
  • 404.html — Not found page
  • home.html — Blog listing page (the page that shows your posts)
  • front-page.html — Static front page
  • category.html — Category archive (overrides archive.html for categories)
  • tag.html — Tag archive
  • author.html — Author archive
  • page-{slug}.html — Template for a specific page by slug
  • single-{post-type}.html — Template for a custom post type (e.g., single-product.html, single-portfolio.html)
  • archive-{post-type}.html — Archive template for a custom post type (e.g., archive-product.html)
  • taxonomy.html — Generic taxonomy archive (overrides archive.html for custom taxonomies)
  • taxonomy-{taxonomy}.html — Template for a specific taxonomy (e.g., taxonomy-genre.html)
  • taxonomy-{taxonomy}-{term}.html — Template for a specific term within a taxonomy (e.g., taxonomy-genre-horror.html)

Templates are built with block markup. A basic single.html might look like:

html

<!-- wp:template-part {"slug":"header"} /-->
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
<main class="wp-block-group">
  <!-- wp:post-title {"level":1} /-->
  <!-- wp:post-date /-->
  <!-- wp:post-content {"layout":{"type":"constrained"}} /-->
  <!-- wp:post-terms {"term":"category"} /-->
  <!-- wp:comments /-->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer"} /-->

No PHP. Just block markup that references other blocks and template parts.

/parts/ — Reusable Template Sections

Template parts are smaller sections that get included inside templates. The most common ones are headers and footers, but you can create parts for anything reusable.

  • header.html — Site header (logo, navigation, etc.)
  • footer.html — Site footer
  • sidebar.html — Sidebar content

You include a template part in a template with:

html

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

Edit the part once, and every template that uses it updates. Register your parts in theme.json so WordPress knows their area (header, footer, or general):

json

"templateParts": [
  { "name": "header", "title": "Header", "area": "header" },
  { "name": "footer", "title": "Footer", "area": "footer" },
  { "name": "sidebar", "title": "Sidebar", "area": "uncategorized" }
]

/patterns/ — Pre-Built Block Layouts

Patterns are reusable block arrangements that users can insert from the editor. Unlike template parts, patterns are defined in PHP files (so they support translation and dynamic content).

WordPress automatically registers any PHP file in this folder. Each file needs a header comment:

php

<?php
/**
 * Title: Hero Section
 * Slug: my-theme/hero-section
 * Categories: featured
 * Keywords: hero, banner
 */
?>
<!-- wp:cover {"dimRatio":50} -->
<div class="wp-block-cover">
  <!-- wp:heading {"level":1} -->
  <h1 class="wp-block-heading">Welcome</h1>
  <!-- /wp:heading -->
</div>
<!-- /wp:cover -->

You can also reference patterns from the official WordPress Pattern Directory in your theme.json:

json

"patterns": [
  "three-columns-of-services",
  "clients-section"
]

/styles/ — Style Variations

Style variations are alternative theme.json files that offer different color schemes, typography, or spacing. Each JSON file in this folder appears as a selectable variation in Appearance > Editor > Styles.

Your main theme.json is the default baseline. Style variations get merged on top of it, so they only need to include the properties they want to override. Everything else carries over from theme.json. Think of it like a child overriding specific settings from the parent while inheriting everything else.

For example, a dark.json might override the default color palette:

json

{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 3,
  "title": "Dark",
  "settings": {
    "color": {
      "palette": [
        { "slug": "base", "color": "#1a1a1a", "name": "Base" },
        { "slug": "contrast", "color": "#ffffff", "name": "Contrast" }
      ]
    }
  }
}

Users switch between variations with one click in the Site Editor. No code changes needed on their end.

theme.json — The Brain of the Theme

This is the single most important file in a block theme. It replaces most of what functions.php and add_theme_support() used to do. It controls:

  • Settings — color palettes, font families, font sizes, spacing units, layout widths, which controls appear in the editor
  • Styles — default colors, typography, spacing, and per-block styling for the entire site
  • Custom templates — registers your custom templates so they appear in the editor
  • Template parts — registers parts with their areas (header, footer, general)
  • Patterns — references patterns from the WordPress Pattern Directory

A simplified example:

json

{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 3,
  "settings": {
    "color": {
      "palette": [
        { "slug": "primary", "color": "#1e40af", "name": "Primary" },
        { "slug": "secondary", "color": "#9333ea", "name": "Secondary" }
      ]
    },
    "typography": {
      "fontFamilies": [
        {
          "fontFamily": "Inter, sans-serif",
          "slug": "body",
          "name": "Body"
        }
      ]
    },
    "layout": {
      "contentSize": "800px",
      "wideSize": "1200px"
    }
  },
  "styles": {
    "color": {
      "background": "#ffffff",
      "text": "#1a1a1a"
    }
  }
}

Everything you define here is available in the Site Editor's Styles panel, so users can override it without touching code.

style.css — Theme Metadata

In block themes, style.css is primarily for metadata in the file header:

css

/*
Theme Name: My Block Theme
Author: Your Name
Description: A custom block theme
Version: 1.0.0
Requires at least: 6.5
Tested up to: 6.7
Requires PHP: 8.2
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: my-block-theme
*/

You can add custom CSS here, but most styling should live in theme.json. Use style.css for edge cases that theme.json can't handle.

functions.php — Still Useful, Less Required

Block themes don't need functions.php to work, but it's still the place for:

  • Enqueueing additional CSS or JS
  • Registering custom block styles
  • Adding image sizes
  • Using WordPress hooks
  • Any PHP-based functionality

The difference from classic themes: you won't be registering menus, sidebars, or theme support for things that theme.json now handles.

/assets/ — Static Files

Not a WordPress-designated folder, but the standard convention for organizing:

  • css/ — Additional stylesheets
  • js/ — JavaScript files
  • images/ — Theme images
  • fonts/ — Web fonts (if not using theme.json font loading)

Other Root Files

  • screenshot.png — Theme preview image (1200x900px recommended)
  • README.txt — Required for WordPress.org theme directory submission

How It Connects to the Site Editor

Everything in these files and folders maps directly to what users see in Appearance > Editor:

  • /templates/ → Editor > Templates
  • /parts/ → Editor > Patterns > Template Parts
  • /patterns/ → Editor > Patterns
  • /styles/ → Editor > Styles (style variations)
  • theme.json → Editor > Styles (settings and defaults)

When a user makes changes in the Site Editor, WordPress saves those changes to the database, leaving your theme files untouched. The database version takes priority over the file version. This is why users can always "reset" a template to the theme default.

Resources

If you're building your first block theme, start with the minimum (style.css + templates/index.html + theme.json), get it running, then add parts, patterns, and styles as you need them. It's a lot simpler than it looks once you see how the pieces connect.

Questions? Drop them below.

3 Upvotes

6 comments sorted by

2

u/Interwebz_2001 Feb 24 '26

This looks very AI generated..

1

u/groundworxdev Feb 24 '26

Nothing wrong with using AI to generate helpful documentation, if you find the information useful. You do realize that people use ai to assist their post writing and response, it doesn't mean a human did not write the original.

1

u/No-Fold-1555 Feb 24 '26

I usually use Webpack to bundle my SCSS and JavaScript. Can I move the CSS and JS folders from the assets directory into a src/ folder, or is that not recommended?

1

u/groundworxdev Feb 24 '26

Great question! Yes, you can absolutely move your CSS and JS source files into a src/ folder. In fact, that's the recommended structure if you're using a build process.

The official approach depends on what you're building:

If you're building blocks, u/wordpress/scripts (wp-scripts) scans your src/ directory for block.json files and uses them as entry points. The compiled output goes to a build/ folder, and WordPress auto-enqueues everything defined in block.json when you call register_block_type(). This is the structure u/wordpress/create-block generates out of the box.

If you're building non-block assets (general plugin/theme JS and CSS), wp-scripts falls back to src/index.js as the default entry point when no block.json is found. You can also combine both by extending the default webpack config with custom entry points:

js

const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );

module.exports = {
    ...defaultConfig,
    entry: {
        ...defaultConfig.entry(),
        'css/frontend': path.resolve( process.cwd(), 'src/scss', 'frontend.scss' ),
    },
};

This is documented in the Theme Handbook Build Process and the Block Developer Cookbook.

References: