Build Your First WordPress Block Theme from Scratch: A Complete Guide

If you have been putting off learning WordPress theme development because classic PHP theme files felt intimidating, this is the guide you have been waiting for. Block themes flip the script entirely. Instead of wrestling with PHP template hierarchies and action hooks, you build your theme in pure HTML files using block markup – the same blocks you already use in the editor. By the time you finish this guide, you will have a working, installable WordPress block theme built from scratch.


What You Need Before You Start

Block theme development does not require deep PHP knowledge. You need familiarity with HTML and JSON, a basic understanding of how WordPress works (posts, pages, menus, widgets), and a local WordPress environment running version 5.9 or later. Tools like Local by Flywheel or Lando work well. You also need a code editor – VS Code with the WordPress block theme snippets extension is a solid choice.

The Site Editor (Appearance – Editor in your WordPress dashboard) must be available, which means you need a block-theme-compatible WordPress install. If you are running WordPress 6.0 or later on a fresh local install, you are good to go.

Block themes are the future of WordPress theme development. Learning them now puts you ahead of the curve and makes your skills directly transferable to Full Site Editing projects.

Block Theme Design Philosophy

Block Theme File Structure: What Goes Where

A block theme is a folder inside wp-content/themes/. Unlike classic themes, which can have dozens of PHP files, a minimal block theme needs only a handful of files to be fully functional. Here is the structure you will build:

  • style.css – Theme header file (name, author, version). Can also hold CSS overrides.
  • theme.json – The heart of your theme. Controls colors, fonts, spacing, layout, and global styles.
  • templates/ – Full-page templates (index.html, single.html, page.html, 404.html, etc.)
  • parts/ – Reusable template parts (header.html, footer.html, sidebar.html)
  • styles/ – Style variation JSON files (alternate color/font palettes users can switch between)
  • patterns/ – PHP files that register block patterns (reusable content sections)

No functions.php is required for basic functionality. No header.php or footer.php. WordPress handles all the bootstrapping when it detects a block theme via the theme header in style.css.

Create Your Theme Folder

Open your local WordPress install’s themes directory and create a new folder. Name it something lowercase with hyphens: my-first-block-theme. Inside it, create the subfolders: templates/, parts/, styles/, and patterns/. Then create style.css and theme.json as empty files. Your folder is now ready.


The style.css Theme Header

WordPress reads style.css to understand your theme’s identity. The file header is a block of CSS comments that tells WordPress the theme name, author, version, and a few other details. Without this header, WordPress will not recognize your folder as a theme.

The critical line here is Template: – if you leave it blank, WordPress registers this as a block theme automatically in WP 5.9+. The blank Template: is what distinguishes block themes from classic child themes. Notice there is no PHP, no get_header(), no template tags – just structured comments.


theme.json: The Control Center of Your Block Theme

If there is one file that separates block theme development from classic theme development, it is theme.json. This JSON file controls every aspect of your theme’s design system – colors, typography, spacing, layout widths, and which block-level customizations users can access in the editor. Getting comfortable with theme.json is the single most important skill for block theme development.

The Four Main Sections

SectionPurposeKey Properties
settingsDefines available design options and enables/disables block featurescolor, typography, spacing, layout, blocks
stylesSets global CSS applied to all blocks and elementscolor, typography, spacing, elements
customTemplatesRegisters named templates available in the editorname, title, postTypes
templatePartsDeclares template parts (header, footer) so the editor knows about themname, title, area

Here is a complete, production-ready theme.json for your first block theme. This covers a full design system with colors, fonts, spacing, and layout:

Reading the settings Section

The settings.color.palette array defines the color swatches that appear in the editor color picker. Each color gets a slug (used internally as a CSS custom property like --wp--preset--color--primary), a name (shown in the UI), and a color value. You can use any valid CSS color here – hex, rgb, hsl.

The settings.typography.fontFamilies array works the same way. You define font stacks with slugs and names. If you are using Google Fonts, you need to enqueue them in functions.php and reference them here with the correct font stack. The fontFamilyFace array lets you declare the font files directly for self-hosted fonts, with WordPress handling the @font-face CSS generation automatically.

The settings.spacing.spacingSizes array is one of the most useful features. It defines a spacing scale (like a t-shirt size system) that appears in block spacing controls. Users pick Small, Medium, Large, or XL instead of typing raw pixel values. This keeps spacing consistent across the whole site without requiring CSS knowledge from the site editor.

The styles Section: Applying Your Design System

The styles section is where you set the actual CSS values using your design tokens. When you write "background": "var:preset|color|background", you are referencing the background slug from your color palette. WordPress translates this to the CSS custom property var(--wp--preset--color--background) automatically. This reference syntax keeps your styles tied to the design system so changing a palette color updates every block that uses it.

theme.json is not just configuration – it is your design system. Every color, font, and spacing value you define here becomes a CSS custom property that all blocks can use automatically.


Creating Your First Template: index.html

Templates in a block theme are HTML files that contain Gutenberg block markup. WordPress renders these files through the block editor engine, so every <!-- wp:something --> comment you write gets translated into actual HTML on the front end. The index.html template is the fallback – WordPress uses it whenever a more specific template does not exist.

Create templates/index.html inside your theme folder. This template will include your header and footer template parts, and display a list of your latest posts in the main content area.

Let’s break down what is happening in this file:

  • wp:template-part – Pulls in your header.html and footer.html files. The slug attribute matches the filename, and area tells WordPress whether it is a header, footer, or general part.
  • wp:group with tagName=”main” – Creates a <main> element, which is important for accessibility and HTML semantics.
  • wp:query – The main loop block. It fetches posts and renders them. The queryId must be unique if you have multiple query blocks on the same page.
  • wp:post-template – Renders each post in the query. Everything inside this block is output once per post.
  • wp:query-pagination – Adds next/previous page navigation below the post list automatically.

Other Templates You Will Want

Once you have index.html working, you can add more specific templates following the same pattern. WordPress uses a hierarchy to pick the right template – more specific templates win over generic ones. Here are the most useful ones to add:

Template FileWhen WordPress Uses It
single.htmlSingle blog post view
page.htmlStatic pages (About, Contact, etc.)
archive.htmlCategory, tag, and date archives
404.htmlPage not found errors
search.htmlSearch results page
front-page.htmlHomepage (overrides index.html)

Template Parts: Header and Footer

Template parts are reusable chunks of block markup that you can include in multiple templates. They live in the parts/ folder and are referenced by slug. Any change to a template part is automatically reflected everywhere it is used – exactly like you would expect from a component system.

Building the Header

Create parts/header.html. A good header includes your site title/logo, a navigation menu, and a semantic <header> wrapper:

A few important things to notice here:

  • The wp:site-title block renders your site name automatically from WordPress Settings. No hardcoded text needed.
  • The wp:navigation block connects to WordPress menus. The ref attribute links to a specific navigation menu by its post ID. On a fresh install you can omit ref and WordPress creates a default navigation from your pages.
  • The layout=”flex” attribute on the group block makes it a flexbox container, so the logo and navigation sit side by side without any custom CSS.

Building the Footer

Create parts/footer.html. Keep it simple – site name, a short copyright line, and a footer navigation if you want one:

Notice the wp:site-tagline block – it pulls your site’s tagline from Settings automatically. The wp:paragraph with the copyright text is plain content that users can edit directly in the Site Editor. This is one of the great things about block themes: “static” content like copyright notices are just regular blocks, not hardcoded PHP strings.


Block Patterns: Reusable Content Sections

Block patterns are pre-built block layouts that users can insert into pages with a single click. They are perfect for things like hero sections, call-to-action areas, feature grids, testimonial rows, and pricing tables. Patterns save time and enforce design consistency without locking users into a rigid layout.

Patterns live in the patterns/ folder as PHP files. Each file has a header comment block (similar to style.css) that registers the pattern, followed by the block HTML that makes up the pattern’s content.

The header comment registers the pattern with WordPress. The Categories line determines which section of the pattern inserter the pattern appears in. The Slug must be unique across all themes and plugins. The actual block markup follows the PHP header comment – notice it is echoed or just placed as HTML after the comment block. WordPress reads the file and registers the pattern automatically – no register_block_pattern() call needed when using the patterns folder.

Pattern Categories Reference

  • featured – Highlighted patterns shown at the top of the inserter
  • header – Page header sections
  • footer – Page footer sections
  • hero – Full-width hero/banner sections
  • cta – Call-to-action blocks
  • text – Text and prose layouts
  • gallery – Image grid layouts

Style Variations: Multiple Looks from One Theme

Style variations are one of the most powerful features in block themes. A variation is a JSON file in the styles/ folder that overrides parts of your theme.json. Users can switch between variations in the Site Editor under Styles – Browse styles. This means you can offer multiple color palettes, font combinations, or layout styles from a single theme install – no child theme needed.

Create styles/dark.json for a dark color scheme variation:

  • Each variation file must have a "title" and "version": 2 at the top level
  • Only include the properties you want to override – everything else inherits from theme.json
  • WordPress automatically lists all valid JSON files in styles/ as style variations in the editor

Setting Up Navigation

Navigation in block themes is handled entirely through the wp:navigation block. Unlike classic themes where you register nav menus in functions.php and display them with wp_nav_menu(), block themes let users build and edit menus directly in the Site Editor. Your template part just includes the navigation block, and WordPress handles the rest.

On a fresh install, the navigation block will either be empty or auto-populated with pages. To create a proper navigation:

  1. Go to Appearance – Editor in your WordPress dashboard
  2. Click on your header area to select it
  3. Click the navigation block inside the header
  4. Use the block toolbar to add pages, custom links, or search
  5. Save – WordPress stores this navigation as a Navigation post type and references it by ID in your template

The navigation block supports nested menus (submenus appear on hover), responsive collapse (hamburger menu on mobile), and social icon links. All of this works without any JavaScript you need to write. The block handles it.


Declaring customTemplates and templateParts in theme.json

WordPress discovers your templates and parts automatically from the filesystem, but declaring them in theme.json gives you more control. The customTemplates array lets you give templates friendly names and restrict which post types can use them. The templateParts array registers parts with an area designation so the Site Editor knows where to show them.

In the theme.json file shown earlier, these sections look like this:

  • customTemplates: Each entry has a name (matching the filename without .html), a title (shown in the editor dropdown), and a postTypes array
  • templateParts: Each entry has a name (matching the filename without .html), a title, and an area – either header, footer, or uncategorized

Testing Your Theme in the Site Editor

Once your files are in place, activate your theme from Appearance – Themes. You should see your new theme appear in the list. Click Activate. Then go to Appearance – Editor to open the Site Editor.

What to Check in the Site Editor

  • Templates panel – Verify index.html and any other templates you created appear here. If a template is missing, check the filename and folder location.
  • Template Parts panel – Header and footer should appear here. If they show “uncategorized” instead of the correct area, check your templateParts declaration in theme.json.
  • Styles panel – Click the Styles icon (half-circle) in the top right. You should see your color palette and typography settings. Any style variations you added will appear under “Browse styles”.
  • Front-end preview – Click the eye icon to preview the site. The header, posts list, and footer should render. If you see a blank page, check templates/index.html for syntax errors in the block comments.

Debugging Common Issues

ProblemLikely CauseFix
Theme does not appear in theme listMissing or malformed style.css headerCheck the Theme Name comment is present and correctly formatted
Site Editor shows blank canvasindex.html has syntax errorsValidate block comment pairs – every opening comment needs a closing one
Colors not showing in Styles paneltheme.json JSON syntax errorRun your theme.json through a JSON validator to find the error
Template part not foundWrong filename or folderFile must be in the parts/ folder and the slug must match exactly
Navigation block emptyNo navigation post created yetAdd menu items in the Site Editor’s navigation block

Adding a functions.php for Enqueues and Extras

While a basic block theme does not need functions.php, most real-world themes add one for enqueuing additional stylesheets, registering custom block categories, or adding theme support for specific features. Keep it minimal:

  • Use after_setup_theme to add theme support for post thumbnails, custom logo, etc.
  • Use wp_enqueue_scripts to enqueue your main stylesheet and any Google Fonts
  • Avoid adding PHP template logic here – keep templates in HTML files where they belong

For most block themes, the entire functions.php is under 30 lines. That is a stark contrast to classic themes where functions.php can balloon to hundreds of lines of PHP.


Exporting and Packaging Your Theme

When you edit your theme in the Site Editor – changing colors, adjusting navigation, tweaking the header layout – WordPress saves those changes to the database, not back to your theme files. This is fine for development, but when you want to package your theme for distribution or move it to another site, you need to export the current state.

Two Ways to Export

From the Site Editor: Go to Appearance – Editor – three-dot menu (top right) – Export. This downloads a ZIP file of your theme with all Site Editor changes baked back into the template files. The exported ZIP is ready to upload to another site or distribute.

Manual ZIP: If you have not made Site Editor changes, or you want to export from your code editor, simply ZIP your theme folder directly. Make sure the ZIP contains the theme folder (not just the folder’s contents) – the folder name should match your theme slug.

Before You Distribute

  • Run your theme through the Theme Check plugin to catch any compliance issues
  • Validate your theme.json using the official JSON schema
  • Test on WordPress.com or a staging environment separate from your dev machine
  • Check that all pattern slugs are unique and prefixed with your theme slug to avoid conflicts

What to Build Next

You now have a working block theme with a design system in theme.json, full-page templates, reusable template parts, a hero pattern, and a navigation setup. That foundation covers everything a basic site needs. Here is what to tackle next as you grow your block theme skills:

  • Custom post type templates – Add templates for CPTs (single-{cpt}.html, archive-{cpt}.html)
  • Fluid typography – Use clamp() in theme.json font sizes for responsive type without media queries
  • Block variations – Register pre-configured variations of core blocks (a styled card version of a group block)
  • Theme.json per-block styles – Override styles for specific blocks using the blocks key in the styles section
  • Interactivity API – Add lightweight JavaScript-driven interactions (dropdowns, accordions) without full JS frameworks

Keep Learning Block Theme Development on Brndle

This guide gave you the core foundation – style.css, theme.json, templates, parts, and patterns. But block theme development runs deep. There is fluid typography, custom block styles, the Interactivity API, style variations, and much more to explore. Brndle covers all of it with hands-on developer guides written for people who want to build production-quality block themes, not just toy examples.

Scroll to Top