All posts
September 15, 20266 min readBy Ship Templates

How to Create a WordPress Block Theme From Scratch

Learn how to create a WordPress block theme from scratch. Master theme.json settings, HTML block templates, custom patterns, and global styling variations.

wordpressthemesgutenbergfull-site-editingweb-development

WordPress development has fundamentally shifted away from PHP-heavy template hierarchies toward Full Site Editing and modular block themes. By relying on declarative configuration through theme.json and semantic HTML block markup, modern WordPress themes offer superior performance, direct visual customization, and clean codebases. Building a block theme from scratch gives developers granular control over design tokens and editor ergonomics without relying on cumbersome visual page builders.


Block Themes vs Classic PHP Themes: The Architectural Shift

For almost two decades, creating a WordPress theme meant assembling a maze of PHP template files—header.php, index.php, single.php, and footer.php—interleaved with template tags, custom action hooks, and heavy CSS stylesheets. While functional, classic themes fragmented site styling between customizer options, CSS stylesheets, and shortcodes.

Block themes replace this paradigm with declarative data structures and Full Site Editing (FSE). Instead of executing server-side PHP loops to render post content, the core engine parses semantic HTML block comments directly in the editor and on the front end.

Architectural Dimension Classic WordPress Theme Modern Block Theme (FSE)
Primary File Format PHP template files (.php) HTML block markup files (.html)
Design System Configuration Custom CSS, Customizer API, Sass Centralized declarative theme.json
Header / Footer Architecture header.php, get_header() Modular block template parts (parts/*.html)
Visual Customization Theme Customizer or external page builders Native Gutenberg Site Editor
Front-End Performance Often loads unused CSS across all routes Enqueues block CSS selectively per page
Component Reusability PHP template parts or custom shortcodes Composable Block Patterns & Synced Patterns

Understanding this architectural shift is essential. When you audit modern WordPress templates, you will find that the best starters prioritize lightweight block scaffolding over monolithic PHP logic.


The Minimal File Structure for a WordPress Block Theme

Starting a custom block theme requires fewer files than you might anticipate. At its core, WordPress only requires two mandatory files to recognize a block theme, though a practical production theme incorporates a clean folder hierarchy:

my-custom-theme/
├── style.css             # Theme metadata and non-block custom styles
├── theme.json            # Central design tokens, presets, and block styling
├── functions.php         # Optional theme setup, pattern registration, enqueue hooks
├── templates/
│   ├── index.html        # Fallback master template
│   ├── single.html       # Individual blog post layout
│   ├── page.html         # Standard static page layout
│   └── 404.html          # Not found template
└── parts/
    ├── header.html       # Global navigation bar
    └── footer.html       # Global site footer

The style.css file serves as the theme identity descriptor. WordPress parses the comment block at the top:

/*
Theme Name: Custom Block Engine
Theme URI: https://example.com/theme
Author: Engineering Team
Version: 1.0.0
Description: High-performance, clean WordPress block theme built for speed.
Requires at least: 6.4
Tested up to: 6.7
Requires PHP: 8.1
Text Domain: custom-block-engine
*/

No CSS rules are strictly needed in style.css if you configure your design tokens within theme.json.


Configuring the Design System with theme.json

The theme.json file is the heart of any modern block theme. It standardizes typography scales, color palettes, layout widths, and spacing presets into native CSS custom properties automatically managed by WordPress.

Here is a focused configuration demonstrating core design system controls:

{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 3,
  "settings": {
    "appearanceTools": true,
    "layout": {
      "contentSize": "800px",
      "wideSize": "1200px"
    },
    "color": {
      "palette": [
        { "slug": "base", "color": "#ffffff", "name": "Base" },
        { "slug": "contrast", "color": "#111827", "name": "Contrast" },
        { "slug": "primary", "color": "#2563eb", "name": "Primary Accent" },
        { "slug": "muted", "color": "#6b7280", "name": "Muted Text" }
      ]
    },
    "typography": {
      "fontFamilies": [
        {
          "fontFamily": "Inter, sans-serif",
          "slug": "body",
          "name": "Body Font"
        }
      ]
    }
  }
}

By enabling "appearanceTools": true, you automatically activate margins, paddings, border radius, and typography line-height controls across all blocks in the visual Site Editor.


Authoring HTML Block Templates and Template Parts

Templates in a block theme are written using HTML comments that Gutenberg interprets as blocks. Rather than writing PHP loops, you define structural blocks directly inside templates/index.html:

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

<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
<main class="wp-block-group">
  <!-- wp:query {"queryId":1,"query":{"perPage":10,"postType":"post"}} -->
  <div class="wp-block-query">
    <!-- wp:post-template -->
      <!-- wp:post-title {"isLink":true} /-->
      <!-- wp:post-date /-->
      <!-- wp:post-excerpt {"moreText":"Read article"} /-->
    <!-- /wp:post-template -->
    <!-- wp:query-pagination /-->
  </div>
  <!-- /wp:query -->
</main>
<!-- /wp:group -->

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

This declarative format eliminates PHP syntax errors in presentation templates. In parts/header.html, you can define your brand logo and navigation block:

<!-- wp:group {"layout":{"type":"flex","justifyContent":"space-between"}} -->
<div class="wp-block-group">
  <!-- wp:site-title /-->
  <!-- wp:navigation /-->
</div>
<!-- /wp:group -->

Because these components are native block template parts, editors can modify navigation items or site branding visually inside the WordPress admin without touching theme code.


Registering Custom Block Patterns for Reusable Sections

Block patterns allow you to assemble pre-designed layouts—such as pricing tables, FAQ accordions, and hero banners—that users can insert with a single click.

Patterns can be registered effortlessly using a dedicated PHP file placed in your theme's patterns/ directory:

<?php
/**
 * Title: Feature Callout
 * Slug: custom-theme/feature-callout
 * Categories: featured, call-to-action
 */
?>
<!-- wp:group {"style":{"spacing":{"padding":{"top":"3rem","bottom":"3rem"}}},"backgroundColor":"contrast"} -->
<div class="wp-block-group has-contrast-background-color">
  <!-- wp:heading {"textAlign":"center","textColor":"base"} -->
  <h2 class="wp-block-heading has-text-align-center has-base-color">Build Faster with Clean Block Primitives</h2>
  <!-- /wp:heading -->
  <!-- wp:buttons {"layout":{"type":"flex","justifyContent":"center"}} -->
  <div class="wp-block-buttons">
    <!-- wp:button {"className":"is-style-fill"} -->
    <div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="/pricing">Get Started</a></div>
    <!-- /wp:button -->
  </div>
  <!-- /wp:buttons -->
</div>
<!-- /wp:group -->

WordPress automatically detects files in the patterns/ folder and makes them accessible in the Gutenberg block inserter, turning your theme into an intuitive design kit.


Performance Tuning and Production Deployment

Block themes are inherently faster than classic themes because WordPress only injects the CSS styles required by the blocks actually present on the rendered page. However, keeping load times under 800 milliseconds requires deliberate optimization:

  1. Self-Host Web Fonts: Use the WordPress Font Library in theme.json to load fonts locally instead of triggering third-party DNS lookups to external font providers.
  2. Disable Unnecessary Core Block Assets: If your custom build does not use heavy core widgets (like calendar or tag cloud blocks), dequeue them via functions.php.
  3. Audit Template Complexity: Avoid deeply nested groups and wrapper blocks that bloat the final DOM tree unnecessarily.

If you are developing complex content hubs or marketing sites, pairing a custom block theme with dedicated blog templates or modular starter kits ensures that your publication ranks high on Google while delivering instant page transitions.


Build Modern WordPress Solutions Faster

Explore curated themes, starters, and boilerplates designed for professional developers:

Production-Ready Starters

Skip weeks of boilerplate setup with complete source code, authentication, and modern UI.

All WordPress templates
Continue Reading
All guides →

Ready to ship faster?

Browse production-ready web framework templates and starter kits.

Browse templates