Creating WordPress block themes

Level: Beginner, developer

Estimated reading time: 6 minutes

This lesson is the first in a series of exercises to learn how to create block themes.
In this lesson, you will learn about the minimum file requirements and theme setup.

For this full site editing lesson, you will need:

  • A WordPress installation with some test content and the Gutenberg plugin.
  • Your favorite code editor

Updated December 29, 2021.

Once the site editor is completed, the editor will be your primary tool for creating WordPress block themes. That is where you will assemble, style, and edit blocks.
But the editor will not expose all settings. Knowing how to make manual edits to the theme files is perhaps not as exciting, but it is good basic knowledge.

A block theme needs to be installed and activated before you can use the site editor to create new block templates. That is why the first lesson in this section will be about manually creating a basic theme that you can build upon.

You can follow along and create your first block theme together with me,
or you can use the “super quick start guide” and only use this page as a reference.

Super quick start guide for eager theme developers

First, you must activate Gutenberg.

1. Create a new theme folder inside wp-content/themes.
2. Create a style.css file for your new theme.
3. Create a functions.php file.
4. Create a blank index.php file.
5. Create two new folders inside the theme folder: templates and parts.
6. Inside the parts folder, create an HTML file called header.html.
7. In header.html, add the following code: <!-- wp:site-title /--> and save.
8. Inside the templates folder, create an HTML file called index.html.
9. In index.html, add the block code below, and save:

<!-- wp:template-part {"slug":"header"} /-->
<!-- wp:query -->
<div class="wp-block-query">
<!-- wp:post-template -->
<!-- wp:post-title /-->
<!-- wp:post-date /-->
<!-- wp:post-content /-->
<!-- /wp:post-template -->
</div>
<!-- /wp:query -->

10: Activate the theme.

Theme setup today and in the future

You can expect that the theme setup will be more straightforward and require fewer files in the future. It is even possible that the only file you will need is the new theme.json configuration file. But let’s look at the theme file structure and block templates needed to create block themes today.

Minimum requirements

First, select a name for your theme and use the theme slug to create your theme folder.
If your theme name is “FSE,” short for full site editing, then your theme folder will be:

wp-contents/themes/fse/

These first two files are required for any theme to be activated:

index.php
Please create a new blank file in the root folder and name it index.php.
Without index.php, the WordPress installation will consider the theme broken.

style.css
Create a style.css file inside the root folder.
The file header provides the WordPress installation with information about the theme.
Full site editing themes use a standard style.css file header:

/*
Theme Name: Name of the theme.
Author: The name of the individual or organization who developed the theme.
Description: A short description of the theme.
Version: The version, written in X.X or X.X.X format.
Requires at least: The oldest main WordPress version supported, written in X.X format. 
Tested up to: The last main WordPress version the theme has been tested up to, i.e. 5.9. Write only the number.
Requires PHP: The oldest PHP version supported, in X.X format, only the number.
License: The license of the theme.
License URI: The URL of the theme license.
Text Domain: The string used for textdomain for translation. The theme slug.
*/

What about the styles?

Our theme will rely on the block styles and theme.json as much as possible.
I suggest that you start with a blank style.css, and if you can not achieve what you need, you can start adding styles. This is an excellent way to learn the strengths and limitations of theme.json.

Including functions.php

Themes do not require functions.php to work. But you can use it to cover things that full site editing can not do yet.
Include this file if you need to: Enqueue styles, JavaScript or fonts, create block patterns, or use hooks that are not available for blocks.

Create a new file in the root folder and name it functions.php.
Add the file header and if you like, enqueue the style.css file for later use:

<?php
/**
 * Functions and definitions
 *
 * @link https://developer.wordpress.org/themes/basics/theme-functions/
 *
 * @package FSE
 * @since 1.0.0
 */

/**
 * Enqueue the style.css file.
 * 
 * @since 1.0.0
 */
function fse_styles() {
	wp_enqueue_style(
		'fse-style',
		get_stylesheet_uri(),
		wp_get_theme()->get( 'Version' )
	);
}
add_action( 'wp_enqueue_scripts', 'fse_styles' );

I am choosing not to enqueue the comment-reply script because the comments block enqueues this automatically from version 10 of Gutenberg.

Theme support

Our theme will have a setup function for adding theme support, but it will only have one item:
wp-block-styles. Including the block-style CSS file is optional.

if ( ! function_exists( 'fse_setup' ) ) {
	function fse_setup() {
            add_theme_support( 'wp-block-styles' );
        }
}
add_action( 'after_setup_theme', 'fse_setup' );

Since Gutenberg 11.8, the following theme support is automatically enabled for block themes:
post-thumbnails, editor-styles, responsive-embeds, automatic-feed-links, html5 styles, and html5 scripts (View the pull request).

I have not used add_theme_support( 'title-tag' ) because the title tag is already rendered with full site editing (View the source).

Similarly, you do not need to register widget areas, menus, add support for a custom logo, custom header, or colors.

If you want to add specific image sizes or set the post thumbnail size, you can still do that in the setup function.

Later you will add support for wide and full-width blocks and color palettes, gradients, and font sizes via the theme.json file.

Block templates

Heads up!
In WordPress 5.9 and from Gutenberg 12.1, the folder names were simplified.
The new folder names are templates and parts.

For Gutenberg and WordPress to recognize that the active theme has support for full site editing, the theme must include an index.html file and it must be placed inside a folder called templates.

Block templates are your base files. They are HTML files, and you place them inside a folder called templates.
Block templates follow the WordPress template hierarchy:
/templates/index.html is the equivalent of index.php in a classic theme.
/templates/404.html is the equivalent of 404.php and so on.

If WordPress is unable to find a matching .html file, it will look for a .php file in the root folder.

Block template parts

Block template parts are not required, but they help theme authors structure the theme with reusable, smaller parts.
A template part is a block that is a container for other blocks. They are HTML files and you place them inside a folder called parts.
/parts/header.html is the equivalent of header.php.

The template hierarchy -refresher

The following default templates are supported in the WordPress template hierarchy:
index,
404,
archive,
author,
category,
tag,
taxonomy,
date,
embed,
home,
front-page,
privacy-policy,
page,
search,
single,
singular,
and attachment.

https://developer.wordpress.org/themes/basics/template-hierarchy/

Inside the theme folder, create the two new folders: templates and parts.
Your theme structure should now look like this:

/wp-content/themes/fse/
index.php
functions.php
style.css
templates/
parts/

Templates are loaded in the body element

Templates and template parts use block markup and not plain HTML.
When you create the templates in the next lesson, you will find that the header template part does not include a <!DOCTYPE>,<html>, or <head>. There is also no <body> element.

Gutenberg already adds the necessary HTML elements and WordPress hooks. The full code is:

<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
	<meta charset="<?php bloginfo( 'charset' ); ?>" />
	<?php wp_head(); ?>
</head>

<body <?php body_class(); ?>>
<?php wp_body_open(); ?>

(template)

<?php wp_footer(); ?>
</body>
</html>

Source

On the front, templates are loaded in the <body> inside a <div> with the class “wp-site-blocks”:

<body>
<div class="wp-site-blocks">
...
</div>
</body>

You can download the blank theme from GitHub.