Tag: Block

Getting Started With WordPress Block Development

Let’s acknowledge that developing for WordPress is weird right now. Whether you’re new to WordPress or have worked with it for eons, the introduction of “Full-Site Editing” (FSE) features, including the Block Editor (WordPress 5.0) and the Site Editor (WordPress 5.9), have upended the traditional way we build WordPress themes and plugins.

Even though it’s been five years since we met the Block Editor for the first time, developing for it is difficult because documentation is either lacking or outdated. That’s more of a statement on how fast FSE features are moving, something Geoff lamented in a recent post.

Case in point: In 2018, an introductory series about getting into Gutenberg development was published right here on CSS-tricks. Times have changed since then, and, while that style of development does still work, it is not recommended anymore (besides, the create-guten-block project it’s based on is also no longer maintained).

In this article, I intend to help you get started with WordPress block development in a way that follows the current methodology. So, yes, things could very well change after this is published. But I’m going to try and focus on it in a way that hopefully captures the essence of block development, because even though the tools might evolve over time, the core ideas are likely to remain the same.

The WordPress Block Editor interface with highlighted areas showing three key features.
The Gutenberg Editor: (1) The block inserter, (2) the content area, and (3) the settings sidebar
Credit: WordPress Block Editor Handbook

What are WordPress blocks, exactly?

Let’s start by airing out some confusion with what we mean by terms like blocks. All of the development that went into these features leading up to WordPress 5.0 was codenamed “Gutenberg” — you know, the inventor of the printing press.

Since then, “Gutenberg” has been used to describe everything related to blocks, including the Block Editor and Site Editor, so it’s gotten convoluted to the extent that some folks depise the name. To top it all off, there’s a Gutenberg plugin where experimental features are tested for possible inclusion. And if you think calling all of this “Full-Site Editing” would solve the issue, there are concerns with that as well.

So, when we refer to “blocks” in this article what we mean are components for creating content in the WordPress Block Editor. Blocks are inserted into a page or post and provide the structure for a particular type of content. WordPress ships with a handful of “core” blocks for common content types, like Paragraph, List, Image, Video, and Audio, to name a few.

Apart from these core blocks, we can create custom blocks too. That is what WordPress block development is about (there’s also filtering core blocks to modify their functionality, but you likely won’t be needing that just yet).

What blocks do

Before we dive into creating blocks, we must first get some sense of how blocks work internally. That will definitely save us a ton of frustration later on.

The way I like to think about a block is rather abstract: to me, a block is an entity, with some properties (called attributes), that represents some content. I know this sounds pretty vague, but stay with me. A block basically manifests itself in two ways: as a graphical interface in the block editor or as a chunk of data in the database.

When you open up the WordPress Block Editor and insert a block, say a Pullquote block, you get a nice interface. You can click into that interface and edit the quoted text. The Settings panel to the right side of the Block Editor UI provides options for adjusting the text and setting the block’s appearance.

The Pullquote block that is included in WordPress Core

When you are done creating your fancy pullquote and hit Publish, the entire post gets stored in the database in the wp_posts table. This isn’t anything new because of Gutenberg. That’s how things have always worked — WordPress stores post content in a designated table in the database. But what’s new is that a representation of the Pullquote block is part of the content that gets stored in post_content field of the wp_posts table.

What does this representation look like? Have a look:

<!-- wp:pullquote {"textAlign":"right"} --> <figure class="wp-block-pullquote has-text-align-right">   <blockquote>     <p>It is not an exaggeration to say that peas can be described as nothing less than perfect spheres of joy.</p>     <cite>The Encyclopedia of world peas</cite>   </blockquote> </figure> <!-- /wp:pullquote -->

Looks like plain HTML, right?! This, in technical lingo, is the “serialized” block. Notice the JSON data in the HTML comment, "textAlign": "right". That’s an attribute — a property associated with the block.

Let’s say that you close the Block Editor, and then some time later, open it again. The content from the relevant post_content field is retrieved by the Block Editor. The editor then parses the retrieved content, and wherever it encounters this:

<!-- wp:pullquote {"textAlign":"right"} -->...<!-- /wp:pullquote -->

…it says out loud to itself:

OK, that seems like a Pullquote block to me. Hmm.. it’s got an attribute too… I do have a JavaScript file that tells me how to construct the graphical interface for a Pullquote block in the editor from its attributes. I should do that now to render this block in all its glory.

As a block developer, your job is to:

  1. Tell WordPress that you want to register a specific type of block, with so-and-so details.
  2. Provide the JavaScript file to the Block Editor that will help it render the block in the editor while also “serializing” it to save it in the database.
  3. Provide any additional resources the block needs for its proper functionality, e.g. styles and fonts.

One thing to note is that all of this conversion from serialized data to graphical interface — and vice versa — takes place only in the Block Editor. On the front end, the content is displayed exactly the way it is stored. Therefore, in a sense, blocks are a fancy way of putting data in the database.

Hopefully, this gives you some clarity as to how a block works.

Diagram outlining the post editor states and how data is saved to a database and parsed for rendering.

Blocks are just plugins

Blocks are just plugins. Well, technically, you can put blocks in themes and you can put multiple blocks in a plugin. But, more often than not, if you want to make a block, you’re going to be making a plugin. So, if you’ve ever created a WordPress plugin, then you’re already part-way there to having a handle on making a WordPress block.

But let’s assume for a moment that you’ve never set up a WordPress plugin, let alone a block. Where do you even start?

Setting up a block

We have covered what blocks are. Let’s start setting things up to make one.

Make sure you have Node installed

This will give you access to npm and npx commands, where npm installs your block’s dependencies and helps compile stuff, while npx runs commands on packages without installing them. If you’re on macOS, you probably already have Node and can can use nvm to update versions. If you’re on Windows, you’ll need to download and install Node.

Create a project folder

Now, you might run into other tutorials that jump straight into the command line and instruct you to install a package called @wordpress/create-block. This package is great because it spits out a fully formed project folder with all the dependencies and tools you need to start developing.

I personally go this route when setting up my own blocks, but humor me for a moment because I want to cut through the opinionated stuff it introduces and focus just on the required bits for the sake of understanding the baseline development environment.

These are the files I’d like to call out specifically:

  • readme.txt: This is sort of like the front face of the plugin directory, typically used to describe the plugin and provide additional details on usage and installation. If you submit your block to the WordPress Plugin Directory, this file helps populate the plugin page. If you plan on creating a GitHub repo for your block plugin, then you might also consider a README.md file with the same information so it displays nicely there.
  • package.json: This defines the Node packages that are required for development. We’ll crack it open when we get to installation. In classic WordPress plugin development, you might be accustomed to working with Composer and a composer.json file instead. This is the equivalent of that.
  • plugin.php: This is the main plugin file and, yes, it’s classic PHP! We’ll put our plugin header and metadata in here and use it to register the plugin.

In addition to these files, there’s also the src directory, which is supposed to contain the source code of our block.

Having these files and the src directory is all you need to get started. Out of that group, notice that we technically only need one file (plugin.php) to make the plugin. The rest either provide information or are used to manage the development environment.

The aforementioned @wordpress/create-block package scaffolds these files (and more) for us. You can think of it as an automation tool instead of a necessity. Regardless, it does make the job easier, so you can take the liberty of scaffolding a block with it by running:

npx @wordpress/create-block

Install block dependencies

Assuming you have the three files mentioned in the previous section ready, it’s time to install the dependencies. First, we need to specify the dependencies we will need. We do that by editing the package.json. While using the @wordpress/create-block utility, the following is generated for us (comments added; JSON does not support comments, so remove the comments if you’re copying the code):

{   // Defines the name of the project   "name": "block-example",   // Sets the project version number using semantic versioning   "version": "0.1.0",   // A brief description of the project   "description": "Example block scaffolded with Create Block tool.",   // You could replace this with yourself   "author": "The WordPress Contributors",   // Standard licensing information   "license": "GPL-2.0-or-later",   // Defines the main JavaScript file   "main": "build/index.js",   // Everything we need for building and compiling the plugin during development   "scripts": {     "build": "wp-scripts build",     "format": "wp-scripts format",     "lint:css": "wp-scripts lint-style",     "lint:js": "wp-scripts lint-js",     "packages-update": "wp-scripts packages-update",     "plugin-zip": "wp-scripts plugin-zip",     "start": "wp-scripts start"   },   // Defines which version of the scripts packages are used (24.1.0 at time of writing)   // https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/   "devDependencies": {     "@wordpress/scripts": "^24.1.0"   } }
View without comments
{   "name": "block-example",   "version": "0.1.0",   "description": "Example block scaffolded with Create Block tool.",   "author": "The WordPress Contributors",   "license": "GPL-2.0-or-later",   "main": "build/index.js",   "scripts": {     "build": "wp-scripts build",     "format": "wp-scripts format",     "lint:css": "wp-scripts lint-style",     "lint:js": "wp-scripts lint-js",     "packages-update": "wp-scripts packages-update",     "plugin-zip": "wp-scripts plugin-zip",     "start": "wp-scripts start"   },   "devDependencies": {     "@wordpress/scripts": "^24.1.0"   } }

The @wordpress/scripts package is the main dependency here. As you can see, it’s a devDependency meaning that it aids in development. How so? It exposes the wp-scripts binary that we can use to compile our code, from the src directory to the build directory, among other things.

There are a number of other packages that WordPress maintains for various purposes. For example, the @wordpress/components package provides several pre-fab UI components for the WordPress Block Editor that can be used for creating consistent user experiences for your block that aligns with WordPress design standards.

You don’t actually need to install these packages, even if you want to use them. This is because these @wordpress dependencies aren’t bundled with your block code. Instead, any import statements referencing code from utility packages — like @wordpress/components — are used to construct an “assets” file, during compilation. Moreover, these import statements are converted to statements mapping the imports to properties of a global object. For example, import { __ } from "@wordpress/i18n" is converted to a minified version of const __ = window.wp.i18n.__. (window.wp.i18n being an object that is guaranteed to be available in the global scope, once the corresponding i18n package file is enqueued).

During block registration in the plugin file, the “assets” file is implicitly used to tell WordPress the package dependencies for the block. These dependencies are automatically enqueued. All of this is taken care of behind the scenes, granted you are using the scripts package. That being said, you can still choose to locally install dependencies for code completion and parameter info in your package.json file:

// etc. "devDependencies": {   "@wordpress/scripts": "^24.1.0" }, "dependencies": {   "@wordpress/components": "^19.17.0" }

Now that package.json is set up, we should be able to install all those dependencies by navigating to the project folder in the command line and running npm install.

Terminal output after running the install command. 1,296 packages were installed.

Add the plugin header

If you’re coming from classic WordPress plugin development, then you probably know that all plugins have a block of information in the main plugin file that helps WordPress recognize the plugin and display information about it on the Plugins screen of the WordPress admin.

Here’s what @wordpress/create-block generated for me in for a plugin creatively called “Hello World”:

<?php /**  * Plugin Name:       Block Example  * Description:       Example block scaffolded with Create Block tool.  * Requires at least: 5.9  * Requires PHP:      7.0  * Version:           0.1.0  * Author:            The WordPress Contributors  * License:           GPL-2.0-or-later  * License URI:       https://www.gnu.org/licenses/gpl-2.0.html  * Text Domain:       css-tricks  *  * @package           create-block  */

That’s in the main plugin file, which you can call whatever you’d like. You might call it something generic like index.php or plugin.php. The create-block package automatically calls it whatever you provide as the project name when installing it. Since I called this example “Block Example”, the package gave us a block-example.php file with all this stuff.

You’re going to want to change some of the details, like making yourself the author and whatnot. And not all of that is necessary. If I was rolling this from “scratch”, then it might look something closer to this:

<?php /**  * Plugin Name:       Block Example  * Plugin URI:        https://css-tricks.com  * Description:       An example plugin for learning WordPress block development.  * Version:           1.0.0  * Author:            Arjun Singh  * License:           GPL-2.0-or-later  * License URI:       https://www.gnu.org/licenses/gpl-2.0.html  * Text Domain:       css-tricks  */

I won’t get into the exact purpose of each line since that’s already a well-established pattern in the WordPress Plugin Handbook.

The file structure

We’ve already looked at the required files for our block. But if you’re using @wordpress/create-block, you will see a bunch of other files in the project folder.

Here’s what’s in there at the moment:

block-example/ ├── build ├── node_modules ├── src/ │   ├── block.json │   ├── edit.js │   ├── editor.scss │   ├── index.js │   ├── save.js │   └── style.scss ├── .editorconfig ├── .gitignore ├── block-example.php ├── package-lock.json ├── package.json └── readme.txt

Phew, that’s a lot! Let’s call out the new stuff:

  • build/: This folder received the compiled assets when processing the files for production use.
  • node_modules: This holds all the development dependencies we installed when running npm install.
  • src/: This folder holds the plugin’s source code that gets compiled and sent to the build directory. We’ll look at each of the files in here in just a bit.
  • .editorconfig: This contains configurations to adapt your code editor for code consistency.
  • .gitignore: This is a standard repo file that identifies local files that should be excluded from version control tracking. Your node_modules should definitely be included in here.
  • package-lock.json: This is an auto-generated file containing for tracking updates to the required packages we installed with npm install.

Block metadata

I want to dig into the src directory with you but will focus first on just one file in it: block.json. If you’ve used create-block , it’s already there for you; if not, go ahead and create it. WordPress is leaning in hard to make this the standard, canonical way to register a block by providing metadata that provides WordPress context to both recognize the block and render it in the Block Editor.

Here’s what @wordpress/create-block generated for me:

{   "$ schema": "https://schemas.wp.org/trunk/block.json",   "apiVersion": 2,   "name": "create-block/block example",   "version": "0.1.0",   "title": "Block Example",   "category": "widgets",   "icon": "smiley",   "description": "Example block scaffolded with Create Block tool.",   "supports": {     "html": false   },   "textdomain": "css-tricks",   "editorScript": "file:./index.js",   "editorStyle": "file:./index.css",   "style": "file:./style-index.css" }

There’s actually a bunch of different information we can include here, but all that’s actually required is name and title. A super minimal version might look like this:

{   "$ schema": "https://schemas.wp.org/trunk/block.json",   "apiVersion": 2,   "name": "css-tricks/block-example",   "version": "1.0.0",   "title": "Block Example",   "category": "text",   "icon": "format-quote",   "editorScript": "file:./index.js", }
  • $ schema defines the schema formatting used to validate the content in the file. It sounds like a required thing, but it’s totally optional as it allows supporting code editors to validate the syntax and provide other additional affordances, like tooltip hints and auto-completion.
  • apiVersion refers to which version of the Block API the plugin uses. Today, Version 2 is the latest.
  • name is a required unique string that helps identify the plugin. Notice that I’ve prefixed this with css-tricks/ which I’m using as a namespace to help avoid conflicts with other plugins that might have the same name. You might choose to use something like your initials instead (e.g. as/block-example).
  • version is something WordPress suggests using as a cache-busting mechanism when new versions are released.
  • title is the other required field, and it sets the name that’s used wherever the plugin is displayed.
  • category groups the block with other blocks and displays them together in the Block Editor. Current existing categories include text, media, design, widgets, theme, and embed, and you can even create custom categories.
  • icon lets you choose something from the Dashicons library to visually represent your block in the Block Editor. I’m using the format-quote icon](https://developer.wordpress.org/resource/dashicons/#format-quote) since we’re making our own pullquote sort of thing in this example. It’s nice we can leverage existing icons rather than having to create our own, though that’s certainly possible.
  • editorScript is where the main JavaScript file, index.js, lives.

Register the block

One last thing before we hit actual code, and that’s to register the plugin. We just set up all that metadata and we need a way for WordPress to consume it. That way, WordPress knows where to find all the plugin assets so they can be enqueued for use in the Block Editor.

Registering the block is a two-fold process. We need to register it both in PHP and in JavaScript. For the PHP side, open up the main plugin file (block-example.php in this case) and add the following right after the plugin header:

function create_block_block_example_block_init() {   register_block_type( __DIR__ . '/build' ); } add_action( 'init', 'create_block_block_example_block_init' );

This is what the create-block utility generated for me, so that’s why the function is named the way it is. We can use a different name. The key, again, is avoiding conflicts with other plugins, so it’s a good idea to use your namespace here to make it as unique as possible:

function css_tricks_block_example_block_init() {   register_block_type( __DIR__ . '/build' ); } add_action( 'init', 'css_tricks_block_example_block_init' );

Why are we pointing to the build directory if the block.json with all the block metadata is in src? That’s because our code still needs to be compiled. The scripts package processes the code from files in the src directory and places the compiled files used in production in the build directory, while also copying the block.json file in the process.

Alright, let’s move over to the JavaScript side of registering the block. Open up src/index.js and make sure it looks like this:

import { registerBlockType } from "@wordpress/blocks";  import metadata from "./block.json"; import Edit from "./edit.js"; import Save from "./save.js";  const { name } = metadata;  registerBlockType(name, {   edit: Edit,   save: Save, });

We’re getting into React and JSX land! This tells WordPress to:

  • Import the registerBlockType module from the @wordpress/blocks package.
  • Import metadata from block.json.
  • Import the Edit and Save components from their corresponding files. We’ll be putting code into those files later.
  • Register the the block, and use the Edit and Save components for rendering the block and saving its content to the database.

What’s up with the edit and save functions? One of the nuances of WordPress block development is differentiating the “back end” from the “front end” and these functions are used to render the block’s content in those contexts, where edit handles back-end rendering and save writes the content from the Block Editor to the database for rendering the content on the front end of the site.

A quick test

We can do some quick work to see our block working in the Block Editor and rendered on the front end. Let’s open index.js again and use the edit and save functions to return some basic content that illustrates how they work:

import { registerBlockType } from "@wordpress/blocks"; import metadata from "./block.json";  const { name } = metadata;  registerBlockType(name, {   edit: () => {     return (       "Hello from the Block Editor"     );   },   save: () => {     return (       "Hello from the front end"     );   } });

This is basically a stripped-down version of the same code we had before, only we’re pointing directly to the metadata in block.json to fetch the block name, and left out the Edit and Save components since we’re running the functions directly from here.

We can compile this by running npm run build in the command line. After that, we have access to a block called “Block Example” in the Block Editor:

If we drop the block into the content area, we get the message we return from the edit function:

The WordPress Block Editor with the block inserter panel open and the pullquote block inserted into the content area. It reads hello from the back end.

If we save and publish the post, we should get the message we return from the save function when viewing it on the front end:

The pullquote block rendered on the front end of the website. It says hello from the front end.

Creating a block

Looks like everything is hooked up! We can revert back to what we had in index.js before the test now that we’ve confirmed things are working:

import { registerBlockType } from "@wordpress/blocks";  import metadata from "./block.json"; import Edit from "./edit.js"; import Save from "./save.js";  const { name } = metadata;  registerBlockType(name, {   edit: Edit,   save: Save, });

Notice that the edit and save functions are tied to two existing files in the src directory that @wordpress/create-block generated for us and includes all the additional imports we need in each file. More importantly, though, those files establish the Edit and Save components that contain the block’s markup.

Back end markup (src/edit.js)

import { useBlockProps } from "@wordpress/block-editor"; import { __ } from "@wordpress/i18n";  export default function Edit() {   return (     <p {...useBlockProps()}>       {__("Hello from the Block Editor", "block-example")}     </p>   ); }

See what we did there? We’re importing props from the @wordpress/block-editor package which allows us to generate classes we can use later for styling. We’re also importing the __ internationalization function, for dealing with translations.

The pullquote block on the back end, selected and with devtools open beside it displaying the markup.

Front-end markup (src/save.js)

This creates a Save component and we’re going to use pretty much the same thing as src/edit.js with slightly different text:

import { useBlockProps } from "@wordpress/block-editor"; import { __ } from "@wordpress/i18n";  export default function Save() {   return (     <p {...useBlockProps.save()}>       {__("Hello from the front end", "block-example")}     </p>   ); }

Again, we get a nice class we can use in our CSS:

The pullquote block on the front end, selected and with devtools open beside it displaying the markup.

Styling blocks

We just covered how to use block props to create classes. You’re reading this article on a site all about CSS, so I feel like I’d be missing something if we didn’t specifically address how to write block styles.

Differentiating front and back-end styles

If you take a look at the block.json in the src directory you’ll find two fields related to styles:

  • editorStyle provides the path to the styles applied to the back end.
  • style is the path for shared styles that are applied to both the front and back end.

Kev Quirk has a detailed article that shows his approach for making the back-end editor look like the front end UI.

Recall that the @wordpress/scripts package copies the block.json file when it processes the code in the /src directory and places compiled assets in the /build directory. It is the build/block.json file that is used to register the block. That means any path that we provide in src/block.json should be written relative to build/block.json.

Using Sass

We could drop a couple of CSS files in the build directory, reference the paths in src/block.json, run the build, and call it a day. But that doesn’t leverage the full might of the @wordpress/scripts compilation process, which is capable of compiling Sass into CSS. Instead, we place our style files in the src directory and import them in JavaScript.

While doing that, we need to be mindful of how @wordpress/scripts processes styles:

  • A file named style.css or style.scss or style.sass, imported into the JavaScript code, is compiled to style-index.css.
  • All other style files are compiled and bundled into index.css.

The @wordpress/scripts package uses webpack for bundling and @wordpress/scripts uses the PostCSS plugin for working for processing styles. PostCSS can be extended with additional plugins. The scripts package uses the ones for Sass, SCSS, and Autoprefixer, all of which are available for use without installing additional packages.

In fact, when you spin up your initial block with @wordpress/create-block, you get a nice head start with SCSS files you can use to hit the ground running:

  • editor.scss contains all the styles that are applied to the back-end editor.
  • style.scss contains all the styles shared by both the front and back end.

Let’s now see this approach in action by writing a little Sass that we’ll compile into the CSS for our block. Even though the examples aren’t going to be very Sass-y, I’m still writing them to the SCSS files to demonstrate the compilation process.

Front and back-end styles

OK, let’s start with styles that are applied to both the front and back end. First, we need to create src/style.scss (it’s already there if you’re using @wordpress/create-block) and make sure we import it, which we can do in index.js:

import "./style.scss";

Open up src/style.scss and drop a few basic styles in there using the class that was generated for us from the block props:

.wp-block-css-tricks-block-example {   background-color: rebeccapurple;   border-radius: 4px;   color: white;   font-size: 24px; }

That’s it for now! When we run the build, this gets compiled into build/style.css and is referenced by both the Block Editor and the front end.

Back-end styles

You might need to write styles that are specific to the Block Editor. For that, create src/editor.scss (again, @wordpress/create-block does this for you) and drop some styles in there:

.wp-block-css-tricks-block-example {   background-color: tomato;   color: black; }

Then import it in edit.js, which is the file that contains our Edit component (we can import it anywhere we want, but since these styles are for the editor, it’s more logical to import the component here):

import "./editor.scss";

Now when we run npm run build, the styles are applied to the block in both contexts:

The pullquote block in the WordPress Block Editor with an applied tomoato-colored background. behind black text.
The pullquote block ion the front end with an applied rebecca purple-colored background behind black text.

Referencing styles in block.json

We imported the styling files in the edit.js and index.js, but recall that the compilation step generates two CSS files for us in the build directory: index.css and style-index.css respectively. We need to reference these generated files in the block metadata.

Let’s add a couple of statements to the block.json metadata:

{   "$ schema": "https://schemas.wp.org/trunk/block.json",   "apiVersion": 2,   "name": "css-tricks/block-example",   "version": "1.0.0",   "title": "Block Example",   "category": "text",   "icon": "format-quote",   "editorScript": "file:./index.js",   "editorStyle": "file:./index.css",   "style": "file:./style-index.css" }

Run npm run build once again, install and activate the plugin on your WordPress site, and you’re ready to use it!

You can use npm run start to run your build in watch mode, automatically compiling your code every time you make a change in your code and save.

We’re scratching the surface

Actual blocks make use of the Block Editor’s Settings sidebar and other features WordPress provides to create rich user experiences. Moreover, the fact that there’s essentially two versions of our block — edit and save — you also need to give thought to how you organize your code to avoid code duplication.

But hopefully this helps de-mystify the general process for creating WordPress blocks. This is truly a new era in WordPress development. It’s tough to learn new ways of doing things, but I’m looking forward to seeing how it evolves. Tools like @wordpress/create-block help, but even then it’s nice to know exactly what it’s doing and why.

Are the things we covered here going to change? Most likely! But at least you have a baseline to work from as we keep watching WordPress blocks mature, including best practices for making them.


Again, my goal here is to map out an efficient path for getting into block development in this season where things are evolving quickly and WordPress documentation is having a little hard time catching up. Here are some resources I used to pull this together:

Getting Started With WordPress Block Development originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.


, , , ,

How To Customize WordPress Block Theme Cover Templates with Dynamic Post Feature Images

If we browse the WordPress theme directory, a majority of themes showcase cover images. It is a feature in popular demand. The cover page trend is true even in the block theme directory screenshots as well.

Let’s consider the following example from Twenty Twenty (a classic theme) which includes a cover template that can be used to display both in single post and page, where the post’s featured image displays at the top that stretches across the browser screen, with post title and other desired meta data below. Cover templates allow creating content that stands out from the traditional constraints of displaying content.

Screenshot showing a single post with Twenty Twenty cover template.

Creating cover templates currently requires writing PHP code as captured here in the Twenty Twenty default theme’s cover template. If we look at the template-parts/content-cover.php file, it contains the code for displaying content when the cover-template is used.

Thus, it is not possible to create a customized cover page if you do not possess a deep knowledge of PHP. For many ordinary WordPress users, the only option is to use plugin like Custom Post Type UI as described in this short video.

Cover sections in block themes

Since WordPress 5.8, theme authors could create custom templates (like single post, author, category, and others) with a top hero section using block editor cover block and bundled into their themes with minimal or no code.

Before diving into how top large cover sections are created in block themes templates, let’s briefly look at the two block themes Twenty Twenty-Two and Wabi by Rich Tabor (full review here).

Screenshot showing cover page thumbnails of Twenty Twenty-Two (left) and Wabi (right) themes.

Behind-the-scenes, Twenty Twenty-Two implements a large header by adding a hidden image stored as a pattern in the header-dark-large parts. Whereas, in the Wabi theme, the large header background color in a single post is implemented with accent background colors and a 50px height spacer block (lines: 5-9). The accent colors are managed by the assets/js/accent-colors.js file.

Many others chose to create a top cover section by using cover block, which allowed users to change the background color and add a static image from Media Library or upload from media devices – without writing any code. With this approach, images from the post featured image block had to be added manually to each single post if you wanted to have the post featured image as the background image in single posts.

Cover Blocks with dynamic post featured image

WordPress 6.0 made available another cool featured image cover blocks feature, which allows use of the featured image of any post or page as the background image in the cover block.

In the following short video, Automattic engineers discuss adding featured images to cover blocks with an example from Archeo theme:

The image block including post featured image block can be further customized using duotone color in theme.json as discussed in this short Connecting The Dots YouTube video (Automattic’s Anne McCarthy).

Use case examples (Wei, Bright Mode)

If we browse the thumbnail images in the block theme directory, we see a majority of them include large cover header sections. If we dig into their template files, they make use of cover blocks with static image background.

Some recently developed themes are using cover blocks with the dynamic post featured image background (e.g., Archeo, Wei, Frost, Bright Mode, etc.). A brief overview of the new feature is available in this short GitHub video.

Screenshot showing cover page thumbnails of Wei (left) and Bright-mode (right) themes.

Combining dynamic accent colors features of Wabi theme with cover and post featured image blocks, Rich Tabor further expands his creativity in his new Wei theme (full review available here) to display dynamic cover images from a single post.

In his Wei announcement post, Rich Tabor writes: “Behind-the-scenes, the single.html template is using a Cover block that leverages the post’s featured image. Then the duotone is applied by the color scheme assigned to the post. This way, just about any image will look fine”.

If you would like to dig deeper into the Wei theme’s header cover block and learn how to create your own, here is a short video from Fränk Klein (WP Development Courses) who explains step-by-step how it was created.

Similar to the Wei theme, Brian Gardner also makes use of cover block with post featured image block in his recent Bright Mode theme to display standout contents with vibrant colors.

Brian told WPTavern: “he loves most about the theme is the way the Cover Block is used on single pages. It pulls the featured image into the Cover block and also offers custom block styles for shadows and full-height options. […] I feel as though this really presents what’s possible with modern WordPress.”

For more detail, here is its demo site and full review of Brian’s Bright Mode theme.

Designing complex layouts with block editor

Recently, WordPress launched a new block editor designed landing homepage and a download page. The announcement attracted mixed reactions from its readers, including from Matt Mullenweg (Automattic) who commented on the 33-days taken to design and launch such a “simple page”. You can find additional behind the scene discussions here.

In response, Jamie Marsland of Pootlepress created this YouTube video where he reproduces a nearly identical homepage in nearly 20 minutes.

Commenting on Marsland video, Sarah Gooding of WP Travern writes: “He is what one might describe as a power user with the block editor. He can quickly shuffle rows, columns, and groups around, adjusting padding and margins as necessary, and assign each section the corresponding color for the design. At this point, this is not something most average WordPress users could do.”

Though the block editor has come a long way, there are still growing pain points to most theme developers and ordinary users to create and design complex layouts with it.

Adding enhancement to TT2 Gopher blocks

In this section, I will walk you through how I added enhancements to the TT2 Gopher Blocks theme that I referenced in my previous article. Inspired by cover blocks from themes that I described earlier, I wanted to add three cover templates (author, category, and single-cover) to the theme.

While browsing websites, we notice two types of cover headers. The mostly observed header is cover section blended with the site header (site title and top navigation) into the cover block (e.g., Twenty Twenty, Twenty Twenty-Two, Wei, Wabi, Frost, Bright Mode, etc.). We also find header cover section which is not blended with site header and positioned just underneath, such as this BBC Future website. For TT2 Gopher blocks theme, I opted for the latter.

Creating cover header patterns

First, let’s create cover header patterns for author, single, and others (categories, tags) templates using cover blocks. Then we will convert them into patterns (as described here previously) and call the respective header cover patterns into the templates.

If you are familiar to working with the block editor, design your header section using cover blocks in the site editor and then convert the cover header code into patterns. However, if you are not familiar with FSE editor, then the easiest way is to copy patterns from the patterns directory in a post, make necessary modification and convert it into a pattern.

In my previous CSS-Tricks article, I discussed in detail on creating and using block patterns. Here is a brief overview of the workflow that I am using to create the single post cover header pattern:

Single post cover header pattern

Step 1: Using FSE interface, let’s create a new blank file and start building block structure as shown on the left panel.

Screenshot of the WordPress UI with the Full Site Editor. A block is being assembled with post date, categories, and post title.

Alternatively, this could be done in a post or page first, and then copy and paste the markup into a pattern file, later.

Step 2: Next, to covert the above markup into a pattern, first we should copy its code markup and paste into a new /patterns/header-single-cover.php in our code editor. We should also add required pattern file header markup (e.g., title, slug, categories, inserter, etc.).

Here is the entire code of the /patterns/header-single-cover.php file:

<?php     /**      * Title: Header cover single      * Slug: tt2gopher/header-cover-single      * Categories: tt2gopher-header      * Block Types: core/template-part/header      * inserter: yes      */ ?>     <!-- wp:cover {"url":"https://pd.w.org/2022/08/15062ed5f5707b5c5.85694718-2048x1536.jpg","id":100,"dimRatio":0,"overlayColor":"foreground","focalPoint":{"x":"0.40","y":"0.37"},"minHeight":50,"minHeightUnit":"vh","isDark":false,"align":"full","style":{"color":{"duotone":["#000000","#00a5ff"]},"spacing":{"margin":{"top":"0px","bottom":"0px"}}}} -->     <div class="wp-block-cover alignfull is-light" style="margin-top:0px;margin-bottom:0px;min-height:50vh"><span aria-hidden="true" class="wp-block-cover__background has-foreground-background-color has-background-dim-0 has-background-dim"></span><img class="wp-block-cover__image-background wp-image-100" alt="" src="https://pd.w.org/2022/08/15062ed5f5707b5c5.85694718-2048x1536.jpg" style="object-position:40% 37%" data-object-fit="cover" data-object-position="40% 37%"/><div class="wp-block-cover__inner-container"><!-- wp:group {"style":{"elements":{"link":{"color":{"text":"var:preset|color|base"}}},"spacing":{"blockGap":"10px"}},"textColor":"base","layout":{"wideSize":"800px"}} -->     <div class="wp-block-group has-base-color has-text-color has-link-color"><!-- wp:group {"style":{"spacing":{"blockGap":"10px"}},"textColor":"primary","layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"center"},"fontSize":"small"} -->     <div class="wp-block-group has-primary-color has-text-color has-small-font-size"><!-- wp:post-date {"textColor":"foreground"} /-->          <!-- wp:paragraph -->     <p>|</p>     <!-- /wp:paragraph -->          <!-- wp:post-terms {"term":"category","style":{"elements":{"link":{"color":{"text":"var:preset|color|foreground"}}}}} /--></div>     <!-- /wp:group -->          <!-- wp:post-title {"textAlign":"center","level":1,"style":{"typography":{"fontStyle":"normal","fontWeight":"400"}},"textColor":"foreground","fontSize":"max-60"} /--></div>     <!-- /wp:group --></div></div>     <!-- /wp:cover -->

Step 3: For this demo, I have used this image from photos directory as a filler background image, and applied the Midnight duotone color. To use post featured image dynamically, we should add "useFeaturedImage":true in the cover block by replacing the above filler image link just before the "dimRatio":50 such that the line 10 should look like the following:

<!-- wp:cover {"useFeaturedImage":true,"dimRatio":0,"overlayColor":"foreground","focalPoint":{"x":"0.40","y":"0.37"},"minHeight":50,"minHeightUnit":"vh","isDark":false,"align":"full","style":{"color":{"duotone":["#000000","#00a5ff"]},"spacing":{"margin":{"top":"0px","bottom":"0px"}}}} -->

Alternatively, the filler image could also be changed by clicking Replace and selecting Use featured image option:

Screenshot of the WordPress UI with ‘Replace’ and ‘Use featured image’ selected.

Now, the header cover patterns should be visible in the patterns inserter panel for use anywhere in the templates, posts, and pages.

Archive cover headers

Inspired by this WP Tavern post and a step-by-step walkthrough to create an author template header, I wanted to create a similar cover header and add to TT2 Gopher theme, too.

First, let’s create the archive cover header pattern for author.html the template as well, following the above workflow. In this case, I am creating this in a new blank page, by adding blocks (as shown below in list view):

Screenshot of the WordPress UI for an Author page using a single post header cover.

In the background for the cover, I used the same image used in the single post header cover.

Because we would like to display a short author biography on the author block, a biographical statement should also be added to the user profile page, or else a blank space will be displayed in the front-end.

The following is the markup code of the header-author-cover, that we will use pattern, in the next step:

    <!-- wp:cover {"url":"https://pd.w.org/2022/03/8256241eff74ef542.61868565.jpeg","id":226,"dimRatio":10,"focalPoint":{"x":"0.50","y":"0.75"},"minHeight":200,"minHeightUnit":"px","isDark":false,"align":"full","style":{"color":{"duotone":["#000000","#00a5ff"]}}} -->     <div class="wp-block-cover alignfull is-light" style="min-height:200px"><span aria-hidden="true" class="wp-block-cover__background has-background-dim-10 has-background-dim"></span><img class="wp-block-cover__image-background wp-image-226" alt="" src="https://pd.w.org/2022/03/8256241eff74ef542.61868565.jpeg" style="object-position:50% 75%" data-object-fit="cover" data-object-position="50% 75%"/><div class="wp-block-cover__inner-container"><!-- wp:group {"layout":{"inherit":true}} -->     <div class="wp-block-group"><!-- wp:group {"style":{"spacing":{"padding":{"top":"1rem","right":"2rem","bottom":"1rem","left":"2rem"}}},"layout":{"type":"flex","flexWrap":"nowrap"}} -->     <div class="wp-block-group" style="padding-top:1rem;padding-right:2rem;padding-bottom:1rem;padding-left:2rem"><!-- wp:avatar {"size":70,"isLink":true,"align":"right","style":{"border":{"radius":"9999px"}}} /-->          <!-- wp:group -->     <div class="wp-block-group"><!-- wp:group {"style":{"spacing":{"blockGap":"6px"}},"layout":{"type":"flex"},"fontSize":"large"} -->     <div class="wp-block-group has-large-font-size"><!-- wp:paragraph {"textColor":"foreground","fontSize":"large"} -->     <p class="has-foreground-color has-text-color has-large-font-size">Published by:</p>     <!-- /wp:paragraph -->          <!-- wp:post-author-name {"isLink":true,"style":{"typography":{"fontStyle":"large","fontWeight":"600"},"elements":{"link":{"color":{"text":"var:preset|color|background"}}}},"textColor":"foreground"} /--></div>     <!-- /wp:group -->          <!-- wp:post-author-biography {"textColor":"foreground","fontSize":"small"} /-->          <!-- wp:separator {"backgroundColor":"foreground"} -->     <hr class="wp-block-separator has-text-color has-foreground-color has-alpha-channel-opacity has-foreground-background-color has-background"/>     <!-- /wp:separator --></div>     <!-- /wp:group --></div>     <!-- /wp:group --></div>     <!-- /wp:group --></div></div>     <!-- /wp:cover -->

To covert the markup into a header-author-cover pattern, we should add the required pattern file header markup as described earlier. By editing the header-author-cover.php pattern, we can create similar header covers for tags, taxonomy, and other custom templates.

The header-category-cover.php pattern for my category.html template is available on GitHub.

Creating Templates with header cover blocks

WordPress 6.0 and the recent Gutenberg 13.7 extended template creating features into the block editor, thus making it possible for many WordPress users, without deep knowledge of coding, to create their customized templates.

For more detailed information and use cases, here is a thorough customization note by Justin Tadlock.

Block editor allows creating various types of templates, including cover templates. Let’s briefly overview how combining cover block and post featured image block with new template UI makes easy to create various types of cover custom templates even with no or low coding skills.

Screenshot of the WordPress UI displaying available templates provided by TT2 Gopher Blocks – Single, Page, Index, Home, 404, Blank, and Archive.

Creating templates has been made much easier with Gutenberg 13.7. How to create block templates with codes and in site editor is described in the Theme handbook and in my previous article.

Author template with cover block

Top (header section) markup of the author.html template is shown below (line 6):

    <!-- wp:template-part {"slug":"header-small-dark","theme":"TT2-GOPHER-V2","tagName":"header"} /-->          <!-- wp:group {"tagName":"main","style":{"spacing":{"margin":{"top":"0","bottom":"0px"},"padding":{"bottom":"80px"},"blockGap":"0px"}},"className":"site-content"} -->     <main class="wp-block-group site-content" style="margin-top:0;margin-bottom:0px;padding-bottom:80px">              <!-- wp:pattern {"slug":"tt2gopher/header-author-cover"} /-->          ...     ...     ...     <!-- /wp:group -->     ...

Here are screenshots of cover headers for the author.html and category.html templates:

Screenshot of Author Page header (left) with author name, avatar, and biography. And screenshot of Category Page header (right).

The entire code for both templates is available on GitHub.

Single post with cover block

To display cover block in our single post, we have to call the header-cover-single pattern below the header section (line 3):

    <!-- wp:template-part {"slug":"header-small-dark","tagName":"header"} /-->           <!-- wp:pattern {"slug":"tt2gopher/header-cover-single"} /-->          <!-- wp:spacer {"height":32} -->     <div style="height:32px" aria-hidden="true" class="wp-block-spacer"></div>     <!-- /wp:spacer -->     ....     ....     ....

Here is a screen capture showing the front-end view of the single post with the header cover section:

Screenshot of TT2 Gopher Blocks Single Post with Header Cover Section Pattern.

The entire single-cover.html template is available on GitHub.

You can find additional step-by-step walkthrough tutorials on creating a hero header post section and using post featured image background cover blocks on WP Tavern and Full Site Editing website.

There you have it!

Helpful Resources

Blog posts

Even though the block themes, in general, are getting lots of pushback from WordPress community members, in my opinion, they are the future of WordPress, too. With block themes, amateur theme authors, without the deep coding skills and mastery of PHP and JavaScript languages, can now create themes with complex layouts with a hero cover section as described in this article combined with patterns and style variations.

As an early Gutenberg user, I couldn’t be more excited with the new theming tools like create block theme plugin and others which allow theme authors to achieve the following directly from block editor UI without writing any code:

  • (i) create
  • (ii) overwrite theme files and export
  • (iii) generate blank or a child theme, and
  • (iv) modify and save style variation of the current theme

Additionally, the recent iterations of the Gutenberg plugin allow enabling fluid typography and layout alignments and other stylistic controls using only theme.json file without JavaScript and a line of CSS rules.

Thank you for reading and share your comments and thoughts below!

How To Customize WordPress Block Theme Cover Templates with Dynamic Post Feature Images originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.


, , , , , , , , ,

How to Create Block Theme Patterns in WordPress 6.0

Block patterns, also frequently referred to as sections, were introduced in WordPress 5.5 to allow users to build and share predefined block layouts in the pattern directory. The directory is the home of a wide range of curated patterns designed by the WordPress community. These patterns are available in simple copy and paste format, require no coding knowledge and thus are a big time saver for users.

Despite many articles on patterns, there is a lack of comprehensive and up-to-date articles on pattern creation covering the latest enhanced features. This article aims to fill the gap with a focus on the recent enhanced features like creating patterns without registration and offer an up-to-date step-by-step guide to create and use them in block themes for novices and experienced authors.

Since the launch of WordPress 5.9 and the Twenty Twenty-Two (TT2) default theme, the use of block patterns in block themes has proliferated. I have been a big fan of block patterns and have created and used them in my block themes.

The new WordPress 6.0 offers three major patterns feature enhancements to authors:

  • Allowing pattern registration through /patterns folder (similar to /parts, /templates, and /styles registration).
  • Registering patterns from the public patterns directory using the theme.json.
  • Adding patterns that can be offered to the user when creating a new page.

In an introductory Exploring WordPress 6.0 video, Automattic product liaison Ann McCathy highlights some newly enhanced patterns features (starting at 15:00) and discusses future patterns enhancement plans — which include patterns as sectioning elements, providing options to pick pattern on page creation, integrating pattern directory search, and more.


The article assumes that readers have basic knowledge of WordPress full site editing (FSE) interface and block themes. The Block Editor Handbook and Full Site Editing website provide the most up-to-date tutorial guides to learn all FSE features, including block themes and patterns discussed in this article.

Section 1: Evolving approaches to creating block patterns

The initial approach to creating block patterns required the use of block pattern API either as a custom plugin or directly registered in the functions.php file to bundle with a block theme. The newly launched WordPress 6.0 introduced several new and enhanced features working with patterns and themes, including pattern registration via a /patterns folder and a page creation pattern modal.

For background, let’s first briefly overview how the pattern registration workflow evolved from using the register pattern API to directly loading without registration.

Use case example 1: Twenty Twenty-One

The default Twenty Twenty-One theme (TT1) and TT1 Blocks theme (a sibling of TT1) showcase how block patterns can be registered in the theme’s functions.php. In the TT1 Blocks experimental-theme, this single block-pattern.php file containing eight block patterns is added to the functions.php as an include as shown here.

A custom block pattern needs to be registered using the register_block_pattern function, which receives two arguments — title (name of the patterns) and properties (an array describing properties of the pattern).

Here is an example of registering a simple “Hello World” paragraph pattern from this Theme Shaper article:

register_block_pattern(     'my-plugin/hello-world',     array(         'title'   => __( 'Hello World', 'my-plugin' ),         'content' => "<!-- wp:paragraph -->n<p>Hello World</p>n<!-- /wp:paragraph -->",     ) );

After registration, the register_block_pattern() function should be called from a handler attached to the init hook as described here.

 function my_plugin_register_my_patterns() {     register_block_pattern( ... );   }    add_action( 'init', 'my_plugin_register_my_patterns' );

Once block patterns are registered they are visible in the block editor. More detailed documentation is found in this Block Pattern Registration.

Block pattern properties

In addition to required title and content properties, the block editor handbook lists the following optional pattern properties:

  • title (required): A human-readable title for the pattern.
  • content (required): Block HTML Markup for the pattern.
  • description (optional): A visually hidden text used to describe the pattern in the inserter. A description is optional but it is strongly encouraged when the title does not fully describe what the pattern does. The description will help users discover the pattern while searching.
  • categories (optional): An array of registered pattern categories used to group block patterns. Block patterns can be shown on multiple categories. A category must be registered separately in order to be used here.
  • keywords (optional): An array of aliases or keywords that help users discover the pattern while searching.
  • viewportWidth (optional): An integer specifying the intended width of the pattern to allow for a scaled preview of the pattern in the inserter.
  • blockTypes (optional): An array of block types that the pattern is intended to be used with. Each value needs to be the declared block’s name.
  • inserter (optional): By default, all patterns will appear in the inserter. To hide a pattern so that it can only be inserted programmatically, set the inserter to false.

The following is an example of a quote pattern plugin code snippets taken from the WordPress blog.

/* Plugin Name: Quote Pattern Example Plugin */  register_block_pattern(     'my-plugin/my-quote-pattern',      array(       'title'       => __( 'Quote with Avatar', 'my-plugin' ),       'categories'  => array( 'text' ),       'description' => _x( 'A big quote with an avatar".', 'Block pattern description', 'my-plugin' ),       'content'     => '<!-- wp:group --><div class="wp-block-group"><div class="wp-block-group__inner-container"><!-- wp:separator {"className":"is-style-default"} --><hr class="wp-block-separator is-style-default"/><!-- /wp:separator --><!-- wp:image {"align":"center","id":553,"width":150,"height":150,"sizeSlug":"large","linkDestination":"none","className":"is-style-rounded"} --><div class="wp-block-image is-style-rounded"><figure class="aligncenter size-large is-resized"><img src="https://blockpatterndesigns.mystagingwebsite.com/wp-content/uploads/2021/02/StockSnap_HQR8BJFZID-1.jpg" alt="" class="wp-image-553" width="150" height="150"/></figure></div><!-- /wp:image --><!-- wp:quote {"align":"center","className":"is-style-large"} --><blockquote class="wp-block-quote has-text-align-center is-style-large"><p>"Contributing makes me feel like I'm being useful to the planet."</p><cite>— Anna Wong, <em>Volunteer</em></cite></blockquote><!-- /wp:quote --><!-- wp:separator {"className":"is-style-default"} --><hr class="wp-block-separator is-style-default"/><!-- /wp:separator --></div></div><!-- /wp:group -->',       ) );

Using patterns in a template file

Once patterns are created, they can be used in a theme template file with the following block markup:

<!-- wp:pattern {"slug":"prefix/pattern-slug"} /-->

An example from this GitHub repository shows the use of “footer-with-background” pattern slug with “tt2gopher” prefix in TT2 Gopher blocks theme.

Early adopters of block themes and Gutenberg plugin took advantage of patterns in classic themes as well. The default Twenty Twenty and my favorite Eksell themes (a demo site here) are good examples that showcase how pattern features can be added to classic themes.

Use case example 2: Twenty Twenty-Two

If a theme includes only a few patterns, the development and maintenance are fairly manageable. However, if a block theme includes many patterns, like in TT2 theme, then the pattern.php file becomes very large and hard to read. The default TT2 theme, which bundles more than 60 patterns, showcases a refactored pattern registration workflow structure that is easier to read and maintain.

Taking examples from the TT2 theme, let’s briefly discuss how this simplified workflow works.

2.1: Registering Patterns Categories

For demonstration purposes, I created a TT2 child theme and set it up on my local test site with some dummy content. Following TT2, I registered footer-with-background and added to the following pattern categories array list in its block-patterns.php file.

/** * Registers block patterns and categories. */ function twentytwentytwo_register_block_patterns() { 	$ block_pattern_categories = array( 		'footer'   => array( 'label' => __( 'Footers', 'twentytwentytwo' ) ), 		'header'   => array( 'label' => __( 'Headers', 'twentytwentytwo' ) ), 		'pages'    => array( 'label' => __( 'Pages', 'twentytwentytwo' ) ),                 // ... 	);  	/** 	 * Filters the theme block pattern categories. 	 */ 	$ block_pattern_categories = apply_filters( 'twentytwentytwo_block_pattern_categories', $ block_pattern_categories );  	foreach ( $ block_pattern_categories as $ name => $ properties ) { 		if ( ! WP_Block_Pattern_Categories_Registry::get_instance()->is_registered( $ name ) ) { 			register_block_pattern_category( $ name, $ properties ); 		} 	}  	$ block_patterns = array( 		'footer-default', 		'footer-dark', 		'footer-with-background', 		//... 		'header-default', 		'header-large-dark', 		'header-small-dark', 		'hidden-404', 		'hidden-bird', 		//... 	);  	/** 	 * Filters the theme block patterns. 	 */ 	$ block_patterns = apply_filters( 'twentytwentytwo_block_patterns', $ block_patterns );  	foreach ( $ block_patterns as $ block_pattern ) { 		$ pattern_file = get_theme_file_path( '/inc/patterns/' . $ block_pattern . '.php' );  		register_block_pattern( 			'twentytwentytwo/' . $ block_pattern, 			require $ pattern_file 		); 	} } add_action( 'init', 'twentytwentytwo_register_block_patterns', 9 );

In this code example, each pattern listed in the $ block_patterns = array() is called by foreach() function which requires a patterns directory file with the listed pattern name in the array which we will add in the next step.

2.2: Adding a pattern file to the /inc/patterns folder

Next, we should have all the listed patterns files in the $ block_patterns = array(). Here is an example of one of the pattern files, footer-with-background.php:

/**  * Dark footer wtih title and citation  */ return array( 	'title'      => __( 'Footer with background', 'twentytwentytwo' ), 	'categories' => array( 'footer' ), 	'blockTypes' => array( 'core/template-part/footer' ),   'content'    => '<!-- wp:group {"align":"full","style":{"elements":{"link":{"color":{"text":"var:preset|color|background"}}},"spacing":{"padding":{"top":"var(--wp--custom--spacing--small, 1.25rem)","bottom":"var(--wp--custom--spacing--small, 1.25rem)"}}},"backgroundColor":"background-header","textColor":"background","layout":{"inherit":true}} -->       <div class="wp-block-group alignfull has-background-color has-background-header-background-color has-text-color has-background has-link-color" style="padding-top:var(--wp--custom--spacing--small, 1.25rem);padding-bottom:var(--wp--custom--spacing--small, 1.25rem)"><!-- wp:paragraph {"align":"center"} -->       <p class="has-text-align-center">' .       sprintf(         /* Translators: WordPress link. */         esc_html__( 'Proudly powered by %s', 'twentytwentytwo' ),         '<a href="' . esc_url( __( 'https://wordpress.org', 'twentytwentytwo' ) ) . '" rel="nofollow">WordPress</a> | a modified TT2 theme.'       ) . '</p>       <!-- /wp:paragraph --></div>           <!-- /wp:group -->', );

Let’s reference the pattern in the footer.html template part:

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

This is similar to adding heading or footer parts in a template file.

The patterns can similarly be added to the parts/footer.html template by modifying it to refer to slug of the theme’s pattern file (footer-with-background):

<!-- wp:pattern {"slug":"twentytwentytwo/footer-with-background"} /-->

Now, if we visit the patterns inserter of the block editor, the Footer with background should be available for our use:

Screenshot of the pattern for Footer with background.

The following screenshot shows the newly created footer with background pattern on the front-end.

Screenshot of the footer background as it appears rendered on the site.

Now that patterns have become the integral part of block theme, many patterns are bundled in block themes — like Quadrat, Seedlet, Mayland, Zoologist, Geologist — following the workflow discussed above. Here is an example of the Quadrat theme /inc/patterns folder with a block-pattern registration file and list of files with content source and required pattern header within return array() function.

Section 2: Creating and loading patterns without registration

Please note that this feature requires the installation of WordPress 6.0 or Gutenberg plugin 13.0 or above in your site.

This new WordPress 6.0 feature allows pattern registration via standard files and folders – /patterns, bringing similar conventions like /parts, /templates, and /styles.

The process, as also described in this WP Tavern article, involves the following three steps:

  • creating a patterns folder at the theme’s root
  • adding plugin style pattern header
  • pattern source content

A typical pattern header markup, taken from the article is shown below:

<?php /** * Title: A Pattern Title * Slug: namespace/slug * Description: A human-friendly description. * Viewport Width: 1024 * Categories: comma, separated, values * Keywords: comma, separated, values * Block Types: comma, separated, values * Inserter: yes|no */ ?>

As described in the previous section, only Title and Slug fields are required and other fields are optional.

Referencing examples from recently released themes, I refactored pattern registration in this TT2 Gopher Blocks demo theme, prepared for a previous article on the CSS-Tricks.

In the following steps, let’s explore how a footer-with-background.php pattern registered with PHP and used in a footer.html template is refactored.

2.1: Create a /patterns folder at the root of the theme

The first step is to create a /patterns folder at TT2 Gopher theme’s root and move the footer-with-background.php pattern file to /patterns folder and refactor.

2.2: Add pattern data to the file header

Next, create the following pattern header registration fields.

<?php /** * Title: Footer with background * Slug: tt2gopher/footer-with-background * Categories: tt2gopher-footer * Viewport Width: 1280 * Block Types: core/parts/footer * Inserter: yes */ ?> <!-- some-block-content /-->

A pattern file has a top title field written as PHP comments. Followed by the block-content written in HTML format.

2.3: Add Pattern Content to the file

For the content section, let’s copy the code snippets within single quotes (e.g., '...') from the content section of the footer-with-background and replace the <!-- some-block-content /-->:

<!-- wp:group {"align":"full","style":{"elements":{"link":{"color":{"text":"var:preset|color|foreground"}}},"spacing":{"padding":{"top":"35px","bottom":"30px"}}},"backgroundColor":"background-header","textColor":"foreground","className":"has-foreground","layout":{"inherit":true}} -->     <div class="wp-block-group alignfull has-foreground has-foreground-color has-background-header-background-color has-text-color has-background has-link-color" style="padding-top:35px;padding-bottom:30px"><!-- wp:paragraph {"align":"center","fontSize":"small"} -->     <p class="has-text-align-center has-small-font-size">Powered by WordPress | TT2 Gopher, a modified TT2 theme</p>     <!-- /wp:paragraph --></div> <!-- /wp:group -->

The entire code snippet of the patterns/footer-with-background.php file can be viewed here on the GitHub.

Please note that the /inc/patterns and block-patterns.php are extras, not required in WordPress 6.0, and included only for demo purposes.

2.4: Referencing the patterns slug in the template

Adding the above refactored footer-with-background.php pattern to footer.html template is exactly the same as described in the previous section (Section 1, 2.2).

Now, if we view the site’s footer part in a block editor or front-end of our site in a browser, the footer section is displayed.

Pattern categories and types Registration (optional)

To categorize block patterns, the pattern categories and types should be registered in theme’s functions.php file.

Let’s consider an example of registering block pattern categories from the TT2 Gopher theme.

After the registration, the patterns are displayed in the pattern inserter together with the core default patterns. To add theme specific category labels in the patterns inserter, we should modify the previous snippets by adding theme namespace:

/** * Registers block categories, and type. */  function tt2gopher_register_block_pattern_categories() {  $ block_pattern_categories = array(   'tt2gopher-header' => array( 'label' => __( 'TT2 Gopher - Headers', 'tt2gopher' ) ),   'tt2gopher-footer' => array( 'label' => __( 'TT2 Gopher - Footers', 'tt2gopher' ) ),   'tt2gopher-page' => array( 'label' => __( 'TT2 Gopher - Page', 'tt2gopher' ) ),   // ... );  /** * Filters the theme block pattern categories. */ $ block_pattern_categories = apply_filters( 'tt2gopher_block_pattern_categories', $ block_pattern_categories );  foreach ( $ block_pattern_categories as $ name => $ properties ) {   if ( ! WP_Block_Pattern_Categories_Registry::get_instance()->is_registered( $ name ) ) {     register_block_pattern_category( $ name, $ properties );   } } add_action( 'init', 'tt2gopher_register_block_pattern_categories', 9 );

The footer-with-background pattern is visible in the patterns inserted with its preview (if selected):

Screenshot showing pattern category displayed in patterns inserter (left panel) and corresponding default footer pattern displayed in the editor (right panel).

This process greatly simplifies creating and displaying block patterns in block themes. It is available in WordPress 6.0 without using the Gutenberg plugin.

Examples of themes without patterns registration

Early adopters have already started using this feature in their block themes. A few examples of the themes, that are available from the theme directory, that load patterns without registration are listed below:

Section 3: Creating and using patterns with low-code

The official patterns directory contains community-contributed creative designs, which can be copied and customized as desired to create content. Using patterns with a block editor has never been so easier!

Any patterns from the ever-growing directory can also be added to block themes just by simple “copy and paste” or include in the theme.json file by referring to their directory pattern slug. Next, I will go through briefly how easily this can be accomplished with very limited coding.

Adding and customizing patterns from patterns directory

3.1: Copy pattern from directory into a page

Here, I am using this footer section pattern by FirstWebGeek from the patterns directory. Copied the pattern by selecting the “Copy Pattern” button and directly pasted it in a new page.

3.2: Make desired customizations

I made only a few changes to the color of the fonts and button background. Then copied the entire code from the code editor over to a clipboard.

Screenshot showing modified pattern (left panel) and corresponding code in code editor (right panel)

If you are not familiar with using the code editor, go to options (with three dots, top right), click the Code editor button, and copy the entire code from here.

3.3: Create a new file in /patterns folder

First, let’s create a new /patterns/footer-pattern-test.php file and add the required pattern header section. Then paste the entire code (step 3, above). The pattern is categorized in the footer area (lines: 5), we can view the newly added in the pattern inserter.

<?php  /**  * Title: Footer pattern from patterns library  * Slug: tt2gopher/footer-pattern-test  * Categories: tt2gopher-footer  * Viewport Width: 1280  * Block Types: core/template-part/footer  * Inserter: yes  */ ?>  <!-- wp:group {"align":"full","style":{"spacing":{"padding":{"top":"100px","bottom":"70px","right":"30px","left":"30px"}}},"backgroundColor":"black","layout":{"contentSize":"1280px"}} --> <div class="wp-block-group alignfull has-black-background-color has-background" style="padding-top:100px;padding-right:30px;padding-bottom:70px;padding-left:30px"><!-- wp:columns --> <div class="wp-block-columns"><!-- wp:column --> <div class="wp-block-column"><!-- wp:heading {"style":{"typography":{"fontStyle":"normal","fontWeight":"700","textTransform":"uppercase"}},"textColor":"cyan-bluish-gray"} --> <h2 class="has-cyan-bluish-gray-color has-text-color" style="font-style:normal;font-weight:700;text-transform:uppercase">lorem</h2> <!-- /wp:heading -->  <!-- wp:paragraph {"style":{"typography":{"fontSize":"16px"}},"textColor":"cyan-bluish-gray"} --> <p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px">One of the main benefits of using Lorem Ipsum is that it can be easily generated, and it takes the pressure off designers to create meaningful text. Instead, they can focus on crafting the best website data.</p> <!-- /wp:paragraph -->  <!-- wp:social-links {"iconColor":"vivid-cyan-blue","iconColorValue":"#0693e3","openInNewTab":true,"className":"is-style-logos-only","style":{"spacing":{"blockGap":{"top":"15px","left":"15px"}}}} --> <ul class="wp-block-social-links has-icon-color is-style-logos-only"><!-- wp:social-link {"url":"#","service":"facebook"} /-->  <!-- wp:social-link {"url":"#","service":"twitter"} /-->  <!-- wp:social-link {"url":"#","service":"instagram"} /-->  <!-- wp:social-link {"url":"#","service":"linkedin"} /--></ul> <!-- /wp:social-links --></div> <!-- /wp:column -->  <!-- wp:column --> <div class="wp-block-column"><!-- wp:heading {"level":4,"style":{"typography":{"textTransform":"capitalize","fontStyle":"normal","fontWeight":"700","fontSize":"30px"}},"textColor":"cyan-bluish-gray"} --> <h4 class="has-cyan-bluish-gray-color has-text-color" style="font-size:30px;font-style:normal;font-weight:700;text-transform:capitalize">Contact Us</h4> <!-- /wp:heading -->  <!-- wp:paragraph {"style":{"typography":{"fontSize":"16px","lineHeight":"1.2"}},"textColor":"cyan-bluish-gray"} --> <p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px;line-height:1.2">123 BD Lorem, Ipsum<br><br>+123-456-7890</p> <!-- /wp:paragraph -->  <!-- wp:paragraph {"style":{"typography":{"fontSize":"16px","lineHeight":"1"}},"textColor":"cyan-bluish-gray"} --> <p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px;line-height:1">sample@gmail.com</p> <!-- /wp:paragraph -->  <!-- wp:paragraph {"style":{"typography":{"fontSize":"16px","lineHeight":"1"}},"textColor":"cyan-bluish-gray"} --> <p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px;line-height:1">Opening Hours: 10:00 - 18:00</p> <!-- /wp:paragraph --></div> <!-- /wp:column -->  <!-- wp:column --> <div class="wp-block-column"><!-- wp:heading {"level":4,"style":{"typography":{"fontSize":"30px","fontStyle":"normal","fontWeight":"700","textTransform":"capitalize"}},"textColor":"cyan-bluish-gray"} --> <h4 class="has-cyan-bluish-gray-color has-text-color" style="font-size:30px;font-style:normal;font-weight:700;text-transform:capitalize">Newsletter</h4> <!-- /wp:heading -->  <!-- wp:paragraph {"style":{"typography":{"fontSize":"16px"}},"textColor":"cyan-bluish-gray"} --> <p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px">Lorem ipsum dolor sit amet, consectetur ut labore et dolore magna aliqua ipsum dolor sit</p> <!-- /wp:paragraph -->  <!-- wp:search {"label":"","placeholder":"Enter Your Email...","buttonText":"Subscribe","buttonPosition":"button-inside","style":{"border":{"width":"1px"}},"borderColor":"tertiary","backgroundColor":"background-header","textColor":"background"} /--></div> <!-- /wp:column --></div> <!-- /wp:columns --></div> <!-- /wp:group -->

3.4: View the new pattern in the inserter

To view the newly added Footer pattern from patterns library pattern, go to any post or page and select the inserter icon (blue plus symbol, top left), and then select “TT2 Gopher – Footer” categories. The newly added pattern is shown on the left panel, together with other footer patterns and its preview on the right (if selected):

Screenshot showing new footer pattern (left panel) and its preview (right panel).

Registering patterns directly in theme.json file

In WordPress 6.0, it is possible to register any desired patterns from the pattern directory with theme.json file with the following syntax. The 6.0 dev note states, “the patterns field is an array of [pattern slugs] from the Pattern Directory. Pattern slugs can be extracted by the [URL] in single pattern view at the Pattern Directory.”

{     "version": 2,     "patterns": ["short-text", "patterns-slug"] }

This short WordPress 6.0 features video demonstrates how patterns are registered in the /patterns folder (at 3:53) and registering the desired patterns from the pattern director in a theme.json file (at 3:13).

Then, the registered pattern is available in the patterns inserter search box, which is then available for use just like theme-bundled patterns library.

{   "version": 2,   "patterns": [ "footer-from-directory", "footer-section-design-with-3-column-description-social-media-contact-and-newsletter" ] }

In this example, the pattern slug footer-section-design-with-3-column-description-social-media-contact-and-newsletter from the earlier example is registered via theme.json.

Page creation pattern model

As part of “building with patterns” initiatives, WordPress 6.0 offers a pattern modal option to theme authors to add page layout patterns into block theme, allowing site users to select page layout patterns (e.g., an about page, a contact page, a team page, etc.) while creating a page. The following is an example taken from the dev note:

register_block_pattern(     'my-plugin/about-page',     array(         'title'      => __( 'About page', 'my-plugin' ),         'blockTypes' => array( 'core/post-content' ),         'content'    => '<!-- wp:paragraph {"backgroundColor":"black","textColor":"white"} -->         <p class="has-white-color has-black-background-color has-text-color has-background">Write you about page here, feel free to use any block</p>         <!-- /wp:paragraph -->',     ) );

This feature is currently limited to Page Post Type only and not for “Posts Post Type”, yet.

The page creation pattern modal can also be disabled completely by removing the post-content block type of all the patterns. An example sample code is available here.

You can follow and participate in GitHub’s discussion from the links listed under the resource section below.

Using patterns directory to build page

Patterns from the directory can also be used to create the desired post or page layout, similar to page builders. The GutenbergHub team has created an experimental online page builder app using patterns directly from the directory (introductory video). Then the codes from the app can be copied and pasted in a site, which greatly simplifies the building complex page layout process without coding.

In this short video, Jamie Marsland demonstrates (at 1:30) how the app can be used to create an entire page layout similar to page builder using desired page sections of the directory.

Wrapping up

Patterns allow users to recreate their commonly used content layout (e.g., hero page, call out, etc.) in any page and lower the barriers to presenting content in styles, which were previously not possible without coding skills. Just like the plugins and themes directories, the new patterns directory offers users options to use a wide range of patterns of their choices from the pattern directory, and write and display content in style.

Indeed, block patterns will change everything and surely this is a game changer feature in the WordPress theme landscape. When the full potential of building with patterns effort becomes available, this is going to change the way we design block themes and create beautiful content even with low-code knowledge. For many creative designers, the patterns directory may also provide an appropriate avenue to showcase their creativity.


WordPress 6.0

Creating patterns

Patterns enhancement (GitHub)

Blog articles

How to Create Block Theme Patterns in WordPress 6.0 originally published on CSS-Tricks. You should get the newsletter.


, , , ,

Creating Style Variations in WordPress Block Themes

Global styles, a feature of the block themes, is one of my favorite parts of creating block themes. The concept of global style variations in WordPress were introduced in Gutenberg 12.5 which would allow theme authors to create alternate variations of a block theme with different combinations of colors, fonts, typography, spacing, etc. Different theme.json files stored under /styles folder “lets users quickly and easily switch between different looks in the same theme.”

The global styles panel UI is in active development iteration. More details on the development of this feature can be found and tracked here at this GitHub ticket (#35619).

In this article, I will walk through creating a proof-of-concept global style variation using alternate /styles/theme.json files and create child themes with different color modes by swapping color palettes only.

Table of contents


This article is intended for those who have basic understanding of WordPress block themes and some familiarity of using Full Site Editor (FSE) interface. If you’re new to block themes and the FSE, you can get started here on CSS-Tricks with this deep introduction to WordPress block themes and site editor documentation. This Full Site Editing website is one of the most up-to-date tutorial guides to learn all FSE features including block themes and styles variations discussed in this article.

Global style variations

For some background, let’s briefly overview global style variation. Twenty Twenty-Two (TT2) theme lead and Automattic design director Kjell Reigstad introduced global styles variations with this tweet and GitHub ticket #292 as child themes. In the ticket, Kjell notes that they were initially intended as alternate color patterns and fonts combinations, but they can be used for building simple child themes.

This example from Kjell demonstrates how different style combinations could be selected from options available in the sidebar.

Since then, the Automattic theme team has been experimenting with the concept to create variable child themes (variable color and fonts only), including the following:

  • geologist with blue, cream, slate, yellow variations
  • quadrat with black, green, red, white, and yellow versions

Global style switcher

The Gutenberg 12.5 release has introduced a global styles switcher which would allow users quickly and easily switch between different looks in the same theme via different theme.json files stored under a /styles folder.

The concept of allowing switching global style variation via theme.json has been discussed on GitHub for a while now. Gutenberg lead engineer Matias Ventura gave renewed importance to it by adding it to the WordPress 6.0 roadmap recently.

Embrace style alternates driven by json variations. This was teased in various videos around the new default theme and should be fully unveiled and presented in 6.0. One of the parallel goals is to create a few distinct variations of TT2 made just with styles. (35619)

Matias Ventura, “Preliminary Roadmap to 6.0”

The latest development iteration of theme style variation switcher is available with Gutenberg 13.0 and included in WordPress 6.0. In this Exploring WordPress 6.0 video, Automattic product liaison Anne McCarthy provides an overview of its major features, including style variations and Webfonts API (starting 5:18) discussed in this article.

Theme style variation versus child theme

In my previous article, I briefly covered building block child themes. Global style variations have blurred the line between alternate-theme.json and child themes. For example, the only difference between a recently released alante-dark child theme and its parent theme is an alternate.json file in the child theme that overrides the global theme styles like this:

Screenshot of the Visual Studio Code UI displaying the contents of alante-dark.
The alante-dark theme.

Likewise, the two recent Alara child themes in the WordPress directoryFramboise and Richmond — differ only in their single theme.json file.

Section 1: Creating theme style variations

At the root of your child theme folder, create a /styles folder, which holds style variations as JSON files. For this demo example, I created three variations of Twenty Twenty-Two’s theme.json color palettes — blue.json, maroon.json, and pink.json — by swapping the foreground and background colors:

Screenshot of the Visual Studio Code UI displaying the child theme file structure of "blue.json", "maroon.json", and "pink.json" in the styles directory.
The child theme file structure of “blue.json”, “maroon.json”, and “pink.json” in the styles directory.

Here is the final result after clicking the styles icon from the admin dashboard (located at Appearance → Editor):

Animated GIF showing the theme variations in WordPress.
Walking through the WordPress admin interface to select the “blue”, “maroon”, and “pink” styles.

Click the Other Styles button (recently revised to Browser styles), which displays “blue”, “maroon”, and “pink” color style icons in addition to its original styles.

To change and choose a style, select your preferred variation and click the Save button (top-right), which is displayed on the front end of your browser.

Adding labels to alternate style variations and file name with hover animation effect are available in Gutenberg 13.0.

Step 1: Setup and installation

First, install and set up a WordPress site with some dummy content. For this demo, I made a fresh WordPress install, activated Twenty Twenty-Two theme, and added Gutenberg test data.

The theme style variations and WebFonts API discussed in this article require installation and activation of the Gutenberg 13.0 plugin or WordPress 6.0.

Step 2: Create a TT2 child theme

In this demo child theme example, let’s slightly vary the body color from the header and footer color, with all site content centered:

The lower part of the site design are not visible because it is not scrolled into view. Site navigation is present in the header. A large banner image with a bird is visible. A date and title for the latest blog entry is also visible.
Screenshot of the default appearance of the demo theme in a browser window.

Step 3: Create JSON files

Create /styles in your child theme’s root folder with blue, maroon, and pink.json files:

__ style.css __ theme.json __ functions.php __ index.php __ templates __ ... __ parts __ ... __ styles __ blue.json __ maroon.json __ pink.json

Step 4: Create alternate theme JSON files

Next up, create your alternate-theme.json files with desired color pallets under /styles folder. For this demo example, I created three color palettes (blue, maroon, and pink). Here is the code for maroon.json:

{   "version": 2,   "title": "Maroon",   "settings": {     "color": {       "palette": [         { "slug": "foreground", "color": "#7C290F", "name": "Foreground" },         { "slug": "background", "color": "#ffffff", "name": "Background" },         { "slug": "foreground-dark", "color": "#000000", "name": "Foreground Dark" },         { "slug": "background-body", "color": "#ffd8be", "name": "Background Body" },         { "slug": "primary", "color": "#000000", "name": "Primary" },         { "slug": "secondary", "color": "#ffe2c7", "name": "Secondary" },         { "slug": "tertiary", "color": "#55ACEE", "name": "Tertiary" }       ]   },   "typography": {} }, "styles": {   "color":       {         "background": "var(--wp--preset--color--background-body)",         "text": "var(--wp--preset--color--foreground-dark)"       },   "elements": {       "link": {         "color": { "text": "var(--wp--preset--color--primary)" }       }     }   } }

The other two alternate blue.json and pink.json files swap values of foreground and background-body, foreground-dark and primary color properties with their respective blue and pink hex color values.

Section 2: An example of a use case

As I noted in my previous article, I have been working on block themes and using them for my own personal project site. Inspired by the theme style variations and Webfonts API features in Gutenberg plugin, I started tweaking my work-in-progress block theme with an alternate dark color mode and by configuring the Webfonts API.

In this section, I will walk you through how I created TT2 Gopher Blocks, a demo sibling of my work-in-progress block theme created for this article. The theme includes maroon, dark, and light color modes created using theme style variations and Webfonts API that became available with the Gutenberg 12.8 release.

Showing the homepage we are creating with style variations in WordPress.
Screenshot displaying a sample site using the TT2 Gopher theme with maroon default color.

Some highlights of the TT2 Gopher theme include centered, single-column content display, distinct header and footer, more user-friendly archive and search pages.

A copy of TT2 Gopher Blocks is available at the GitHub repository, which you can fork and customize.

Creating dark mode on WordPress

First, some background on dark mode. Dark mode is a personal preference and developers offer it or other mode toggle switches like on this site, which is not a small job for most regular developers. Creating dark mode is well-covered here at CSS-Tricks, including this complete guide to dark mode and dark mode typography.

In a WordPress site, we can add a dark mode toggle using the WP Dark Mode plugin. Erin Myers of WP Engine and WPBeginner describe how to use the WP Dark Mode plugin, while Brenda Barron lists other dark mode plugin options in this WPExplorer post.

Creating a dark mode in WordPress block themes without a plugin involves several steps. Over a year ago, Ari Stathopoulos created a dark support for the TT1 Blocks theme at the GitHub. Looking at the example here, it involves some JavaScript knowledge to create assets (e.g., toggler, customize, editor-mode-support), dark color CSS variables, and expanded functions.php files.

In this short video, Automattic’s Anne McCarthy demonstrates how simple it is to create a dark mode of TT2 block theme with global style variation by adding kllejr’s gist of JSON snippets in the TT2 /styles folder.

Creating the demo TT2 Gopher blocks theme

The TT2 Gopher is a very simple and modified version of the default Twenty Twenty-Two theme. It includes three theme style variations — maroon, dark, and white.

Describing each customization step is beyond the scope of this article, but you can learn more from my deep introduction to WordPress block themes as well as the Block Editor Handbook over at WordPress.org.

A brief overview of the TT2 Gopher theme color and font combinations include:

  • Light mode
    • The header is white and the footer has a smoky body background color.
    • Open Sans is the primary font.
  • Dark mode
    • The header and footer are black with lighter dark colors for the body backgrounds.
    • Source Serif Pro is the primary font.
  • Maroon mode
    • The header and footer are both a dark maroon color, with a lighter yellowish body background.
    • Work Sans is the primary font.

Let me briefly walk you through how I created theme style variations.

Adding and configuring webfonts

The Gutenberg 12.8 plugin introduced a new Webfonts API that allows the authors to load local (bundled) fonts “in a performance-friendly, privacy-friendly, and future-proof manner.” This feature can be implemented in a block theme the PHP way or the theme.json way.

Currently this feature works only with fonts bundled with block themes and does not support Google-hosted fonts because of privacy concerns. More details on the current status of Webfonts API development are covered in this make WordPress core article and this WP Tavern article.

Step 1: Download and add fonts in block theme

The TT2 theme adds Source Serif Pro font files to the theme’s assets/fonts folder. Two additional fonts — Work Sans and Public Sans — are also provided in he GitHub repository.

Step 2: Registering webfonts

In the TT2 theme, local Source Serif Pro webfonts are registered with PHP in its functions.php file:

function twentytwentytwo_get_font_face_styles() {   return "   @font-face{     font-family: 'Source Serif Pro';     font-weight: 200 900;     font-style: normal;     font-stretch: normal;     font-display: swap;     src: url('" . get_theme_file_uri( 'assets/fonts/SourceSerif4Variable-Roman.ttf.woff2' ) . "') format('woff2');   }   @font-face{     font-family: 'Source Serif Pro';     font-weight: 200 900;     font-style: italic;     font-stretch: normal;     font-display: swap;     src: url('" . get_theme_file_uri( 'assets/fonts/SourceSerif4Variable-Italic.ttf.woff2' ) . "') format('woff2');   }   "; }

Gutenberg 12.8 introduced the ability to register local web fonts with theme.json file. The following theme.json snippets from the demo TT2 Gopher theme show how local Work Sans web fonts are registered in the maroon theme style variation:

"typography": {   "fontFamilies": [     {       "fontFamily": "'Work Sans', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Helvetica', sans-serif",       "slug": "work-sans",       "name": "Work Sans",       "fontFace": [         { "fontFamily": "Work Sans", "fontDisplay": "block", "fontWeight": "400", "fontStyle": "normal", "fontStretch": "normal", "src": [ "file:./assets/fonts/work-sans/WorkSans-VariableFont_wght.ttf" ] },         { "fontFamily": "Work Sans", "fontDisplay": "block", "fontWeight": "700", "fontStyle": "normal", "fontStretch": "normal", "src": [ "file:./assets/fonts/work-sans/WorkSans-VariableFont_wght.ttf" ] },         { "fontFamily": "Work Sans", "fontDisplay": "block", "fontWeight": "400", "fontStyle": "italic", "fontStretch": "normal", "src": [ "file:./assets/fonts/work-sans/WorkSans-Italic-VariableFont_wght.ttf" ] },         { "fontFamily": "Work Sans", "fontDisplay": "block", "fontWeight": "700", "fontStyle": "italic", "fontStretch": "normal", "src": [ "file:./assets/fonts/work-sans/WorkSans-Italic-VariableFont_wght.ttf" ] }       ]     }   ] }

Additional information on how to register and use local webfonts in block themes is described in this tutorial and this WP Tavern article.

Creating theme style variations

Following the steps described in the previous section, I created two alternate versions of the theme.json file — white.json and black.json — with different color and fonts combinations inside the child theme’s /styles folder.

This feature requires version 2 of theme.json. Since Gutenberg 12.5, title can also be added at theme.json to display style label in the site editor or file name (without extension) will be displayed by default.

Here is an example of white.json:

{   "version": 2,   "title": "White",   "settings": {     "color": {       "palette": [         { "slug": "foreground", "color": "#000000", "name": "Foreground" },         { "slug": "background", "color": "#f2f2f2", "name": "Background" },         { "slug": "background-header", "color": "#ffffff", "name": "Background header" },         { "slug": "primary", "color": "#0d0d0d", "name": "Primary" },         { "slug": "secondary", "color": "#F0EAE6", "name": "Secondary" },         { "slug": "tertiary", "color": "#eb3425", "name": "Tertiary" },         { "slug": "quaternary", "color": "#7c7e83", "name": "Quaternary" }       ]     },     "typography": {       "fontFamilies": [         {         "fontFamily": ""Public Sans", sans-serif",         "name": "Public Sans",         "slug": "public-sans",         "fontFace": [           { "fontFamily": "Public Sans", "fontDisplay": "block", "fontStyle": "normal", "fontStretch": "normal", "src": [ "file:.assets/fonts/publicSans/PublicSans-VariableFont_wght.ttf.woff2" ] },           { "fontFamily": "Public Sans", "fontDisplay": "block", "fontStyle": "italic", "fontStretch": "normal", "src": [ "file:./assets/fonts/publicSans/PublicSans-Italic-VariableFont_wght.ttf.woff2" ] }         ]       }     ]   } }, "styles": {   "blocks": {     "core/image": {       "filter": { "duotone": "var(--wp--preset--duotone--default-filter)" }     },     "core/post-title": {       "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "700", "fontSize": "var(--wp--custom--typography--font-size--gigantic)" }     },     "core/query-title": {       "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "300", "fontSize": "var(--wp--custom--typography--font-size--gigantic)" }     },     "core/post-featured-image": {       "filter": { "duotone": "var(--wp--preset--duotone--default-filter)" }     },     "core/site-logo": {       "filter": { "duotone": "var(--wp--preset--duotone--default-filter)" }     },     "core/site-title": {       "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontSize": "var(--wp--preset--font-size--normal)", "fontWeight": "normal" }     }     },     "color": { "background": "var(--wp--preset--color--background)", "text": "var(--wp--preset--color--foreground)" },     "elements": {       "h1": {         "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "600", "fontSize": "var(--wp--custom--typography--font-size--colossal)" }       },       "h2": {         "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "600", "fontSize": "var(--wp--custom--typography--font-size--gigantic)" }       },       "h3": {         "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "300", "fontSize": "var(--wp--custom--typography--font-size--huge)" }       },       "h4": {         "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "300", "fontSize": "var(--wp--preset--font-size--x-large)" }       },       "h5": {         "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "700", "textTransform": "uppercase", "fontSize": "var(--wp--preset--font-size--medium)" }       },       "h6": {         "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontWeight": "400", "textTransform": "uppercase", "fontSize": "var(--wp--preset--font-size--medium)" }       },       "link": {         "color": { "text": "var(--wp--custom--color--foreground)" }       }     },     "typography": { "fontFamily": "var(--wp--preset--font-family--public-sans)", "fontSize": "var(--wp--preset--font-size--normal)" }   } }

This code swaps color palettes from theme.json and also registers and defines the local Public Sans font files.

The black.json is also very similar and uses Source Serif Pro fonts registered in the functions.php file.

Screenshot of the light color theme on the left. And screenshot of the dark color theme on the right. The heading navigation and first blog entry are visible.
Side-by-side comparison of the light (left) and dark (right) color themes for TT2 Gopher.

Example of block themes with theme styles variations

  • Twenty Twenty-Two – the first default theme to include style variations. Its updated 1.2, bundled with WordPress 6.0 includes three style variations — “Blue”, “Pink”, and “Swiss” — allowing users to quickly swap between different visual styles.
  • Frost – an experimental block theme with dark theme style variation.
  • Alara – has above 100 active installs and includes 7 style variations.
  • Wabi– which powers Rich Tabor website contains 3 style variants and 300+ active installations.
  • Brisky – has more than 600 installs and one dark theme style variation.
  • Pendant – a theme by Automattic theme team under development at GitHub contains 3 theme style variation.

In this WP Tavern article, Justin speculates that this new feature may be utilized by theme authors by tying to the site visitor’s settings, while some users may prefer to tweak their site giving a seasonal or event-based design look. This is probably a little early, but only time will tell how this powerful feature would be utilized by both theme authors and users.

Wrapping up

Creating style variations of a block theme with different typography and color combination has been greatly simplified, without using plugins. It’s one of my favorite feature of the block editor that I plan to apply in my personal projects.

In my opinion, theme style variations are definitely a game changer for block themes and with this handy feature there might not be a need for child themes or even many cooky-cutter block themes. A few well-designed base block themes, similar to Automattic theme team’s block-canvas or blockbase (work-in-progress base block themes at GitHub), could be customized with theme style variation.


Dark Mode

Creating Style Variations in WordPress Block Themes originally published on CSS-Tricks. You should get the newsletter.


, , , , ,

A Deep Introduction to WordPress Block Themes

The relatively new WordPress editor, also known as the WordPress Block Editor, always under development via the Gutenberg plugin, has been with us since 2018. You can use the block editor on any WordPress theme, provided the theme loads CSS that the blocks use. But there are new themes that lean into the Block Editor much more deeply.

WordPress Block Themes allow you to build out the entire site using blocks, meaning the theme’s responsibly is mostly design guidelines, and less about controlling the pages and the content on them. This is referred to as Full-Site Editing in WordPress and the themes that are built for this are called Block Themes, because you build out everything with blocks.

Let’s dig into all this.

Illustration of a black vinyl record coming out of a record sleep sleeve from the left that contains a blue tinted image of jazz singer Joséphine Baker's profile looking right with a soft smile and parted lips. The image includes white text that says WordPress 5.9 and code is poetry.
Credit: WordPress.org

Table of Contents


Except for those who follow its day-to-day development iterations at GitHub, most development surrounding the block editor is largely visible to users — and that’s not necessarily a bad thing. I have been personally trying to keep myself updated with the block editor through WP Tavern and Gutenberg posts, and have been using both the legacy — or “Classic” editor — as well as the block editor in my personal learning project sites.

After taking a detour to learn and experience headless WordPress sites with Gatsby and Frontity frameworks, I am now back to my native WordPress home.

Though I have been aware of the WordPress theme-experiment GitHub repository for a while — themes made completely out of blocks! — I have only started digging into block themes recently. In fact, I have been using an experimental block-based theme here in this project site.

WordPress 5.9 is now out in the wild and with it comes block-based theming for the masses. This release, dubbed Joséphine, is the formal introduction to WordPress full site editing and Block Themes.

Even though the block-based theming functionality has been available in various iterative forms in previous releases, this is a big deal for the WordPress platform and the ecosystem that relies on it. I’ve had my hands on it and thought I’d share what I’ve learned about block themes in my hands-on experience, as well as some personal thoughts on how it works.

Disclaimer: I am not a block themes expert by any stretch. I am well-versed in WordPress and a major fan of the content management system. My goal here is not to critique WordPress 5.9 or steer you in the direction of whether or not you should like it or want to use it. I’m merely coming from the perspective of an open-minded learner who is building personal sites with fairly deep understanding and familiarity with the WordPress Block Editor.

Before we dive straight into block themes, I think it’s a good idea to form a baseline understanding of just what we’re talking about when we’re tossing around terms, like blocks and site editing, as they’re so incredibly new and game-changing relative to what we’ve known and loved about WordPress for decades.

Block Editor

This is really what we mean any time we refer to the “WordPress Editor.” We call the WordPress Editor the Block Editor because it allows us to create pages and posts where each element— including text, images, videos, headers, footers, etc. — is inserted into the post using blocks that can be arranged modularly to complete page layouts. It evolved from what’s now called the “classic” editor, which was more squarely based on entering content to be published on a page or post in a predefined layout.

A full screenshot of the WordPress Block editor split into three numbers parts that are highlighted in red.
WordPress Block Editor including the block inserter (1), block editor content area (2), and the document and block settings (3)
Credit: WordPress Block Editor Handbook.

It’s sort of like content and layout coming together, where both are managed in the WordPress Editor. So, where we used to rely on the editor for content and (more or less) theme templates to define layout, both are directly editable in the WordPress Editor interface.

You can find more detail here on using the Block Editor.

Block Theme

As explained in the WordPress docs:

A block theme is a WordPress theme with templates entirely composed of blocks so that in addition to the post content of the different post types (pages, posts, …), the block editor can also be used to edit all areas of the site: headers, footers, sidebars, etc.

This WordPress documentation provides an overview of block themes in its knowledgebase, including how to create block themes and styling in this primer.

The bottom line: Block themes are different than “classic” WordPress themes. Rather than relying strictly on PHP files that conform to the WordPress Template Hierarchy, a WordPress Block Theme consists of block-based HTML templates — assembled groups of blocks that can be styled and arranged in the WordPress Site Editor (that’s coming up next) as well as using a theme.json file for global styling tokens.

Site Editor

This is the crown jewel of WordPress 5.9. While it is officially called the WordPress Site Editor, it’s largely been referred to as Full-Site Editing** (FSE) during development and is described as “the cohesive experience that allows you to directly edit and navigate between various templates, template parts, styling options, and more.” Phew, that’s a lot!

Credit: WordPress Support

The WordPress Site Editor allows us to create and editing templates that are made of blocks. So the idea is that we can assemble a group of blocks that can be applied globally to a site. Like a header component, for example. That might consist of blocks for a site logo, a primary menu, and a tagline. The site editor allows us to create a new block theme or modify an existing theme to give the site’s global appearance a completely new look without writing a line of code.

So, you know how you’ve had to build a theme in the past with a bunch of PHP templates? That’s no longer the case. Theme “development” now has a UI that’s available directly in WordPress.

More detail on using site editor is in the WordPress documentation.

The official WordPress Glossary has additional terms and definitions you may want to explore as we dig deeper into WordPress Block Themes and FSE.

Using the block editor with classic themes

The WordPress Block Editor can be used in both the classic and block themes. When the Gutenberg editor project began, the classic TinyMCE-based editor was detached from WordPress Core into the Classic Editor plugin. As long as the Classic Editor plugin is installed and active, content writing is pretty normal as it was before blocks were introduced.

Prior to the formal introduction of block editor features, we had to install the experimental Gutenberg plugin. By simply switching plugins, individual page or post contents could be created with either editor. The WordPress 5.0 release introduced the block editor alongside the default Twenty Nineteen theme, demonstrating how to add block editor features and explore its power.

In other words, the evolution toward FSE has been building for a while. And because of that, we get to enjoy a high level of backwards compatibility that allows us all to adopt block-based features when we’re good and ready.

The anatomy of block-based themes

Experimental block-based themes have been in development since early 2020. At the time I’m writing this, the GitHub theme experiment repository lists 12 block themes that explore some aspect of creating themes using blocks or block templates.

But it was probably the Twenty Twenty-One theme that was the first “default” theme to make blocks a first-class citizen, introducing block styles and block patterns, though the recently updated versions of Twenty Nineteen, and Twenty Twenty also include bundled block styling and block patterns. Currently, there are more than 130 themes from the community with bundled block editor patterns, block styles feature, including my favorite, Anders Noren’s Eksell theme.

With the ongoing development of the WordPress Block Editor’s FSE features, even more block-based themes are also being introduced.

So, what does the development of block-based themes mean for those of us who are deeply entrenched in the “classic” way of building WordPress themes? That’s what I want to look at in this section.

The file structure of block themes

In classic PHP-powered theming, markup elements are generated with PHP and JavaScript, while in block themes those templates are entirely composed of HTML blocks and structural CSS provided by the block editor. This might sound scary for lots of folks, but it’s easy to imagine just how liberating it is for others as it lowers the bar when it comes to developing a WordPress theme.

The structure of a block theme is drastically different from the classic WordPress Template Hierarchy that we all are used to. In classic PHP-based themes, page element markup has to be generated with PHP and JavaScript, whereas in block themes, the WordPress Core provides both the markup and basic styling. For example, the default Twenty Twenty-One theme contains 48 PHP files and 11 JavaScript files weighing in at 4.5 MB. Its block-based sibling, the experimental TT1 Blocks theme, contains only four PHP files, one JavaScript file, and eight HTML files at 3.5 MB.

Screenshot of a Mac window open to the default Twenty Twenty-One WordPress theme, displaying a long list of files.
Twenty Twenty-One theme folder

Screenshot of a Mac window open to the TT1 theme folder, showing that WordPress Block Themes contain fewer files.
TT1 theme folder

A block theme structure can be very simple with just a few required files : index.php, style.css and template/index.html. The following is a typical block theme file structure, pulled from the WordPress Editor Handbook:

#! basic block-theme structure theme |__ style.css |__ functions.php |__ index.php |__ theme.json |__ templates     |__ index.html     |__ single.html     |__ archive.html     |__ ... |__ parts     |__ header.html     |__ footer.html     |__ sidebar.html     |__ ...
  • styles.css: Contains theme’s style sheet
  • functions.php: Contains theme setup and may include additional files, enable an editor style sheet, and enqueue style.css, if there are any
  • index.php: An empty file to switch to default file in case the block theme is activated without the WordPress Block Editor.
  • theme.json: Optional configuration file used to enable or disable features and set default styles for both the website and blocks
  • templates: Contains page templates that are composed of blocks. These files follow the same template hierarchy as traditional themes.
    • index.html: The primary template to generate a post or page, analogous to index.php in classic themes
    • single.html: The template to generate single posts or pages
    • archive.html: The template to generate archive lists of posts
  • parts: The common collections of blocks to be used in block templates
    • header.html: The global header block
    • footer.html: The global footer block
    • sidebar.html: An optional global sidebar block

A list of theme blocks including that are specific to block themes is available in WordPress Block Editor Handbook.

Templates and template parts

Templates are basically group of assembled blocks that might include reusable block parts, like a site header or footer. Different blocks are used to compose a page template. For example, that might be a list of blog posts, a list of products, or even a widget.

Here’s an example of a block template pulled from the WordPress Block Editor Handbook.

 <!-- wp:site-title /-->  <!-- wp:image {"sizeSlug":"large"} --> <figure class="wp-block-image size-large">     <img src="https://cldup.com/0BNcqkoMdq.jpg" alt="" /> </figure> <!-- /wp:image -->  <!-- wp:group --> <div class="wp-block-group">     <!-- wp:post-title /-->     <!-- wp:post-content /--> </div> <!-- /wp:group -->  <!-- wp:group --> <div class="wp-block-group">     <!-- wp:heading -->     <h2>Footer</h2>     <!-- /wp:heading --> </div> <!-- /wp:group -->

Creating WordPress Block Themes

The WordPress Site Editor is now the primary tool for defining the look and feel of a WordPress website. You may be used to using the WordPress Customizer to do these things — and some themes have heavily tapped into that to do what the site editor is now designed to do.

So, no longer is the block editor for pages and posts; it’s the way WordPress themes are created.

I’m assuming that many of you have already used the block editor, and don’t really need a deep lesson on what it is or how to use it. That said, it’s worth poking at it a bit since it’s the impetus for everything related to WordPress theming moving forward, now that WordPress 5.9 is in the wild.

In fact, when we talk about block editing and theming, yes, we’re talking about the block editor. But really what we’re talking about is the WordPress Site Editor.

The WordPress Site Editor interface

Even as an early adopter of the Gutenberg plugin, I find the experience of the site editor intimidating and frustrating. It changes frequently and often drastically with each new release. I am hopeful, though, that WordPress 5.9 is a sort of line in the sand that helps stabilize that rocky feeling.

The site editor is accessed the same way you’re already used to accessing the WordPress Customizer. It’s located under Appearance in the dashboard menu, called Editor.

Screenshots of the WordPress admin Themes screen side-by-side, the first showing the classic WordPress menu items like Customize, Widgets, and Menus, while the second shows how a WordPress Block Themes only displays a single Editor menu item.
The site editor option is available only when a block theme is activated. If you’re using a classic theme, you’ll get the classic UI to go with it.

Let’s briefly walk-through the new Editor interface.

First, navigate to the site editor by clicking Appearance → Editor from the WordPress admin menu. That menu item may have a red “beta” label on it, like it currently does in WordPress 5.9.

That takes you to the site editor, which displays either your homepage or post archive, depending on what you have your homepage set to in Settings → Reading. From there it sort of looks like the fullscreen version of the block editor when creating or editing a page or post. But click on the WordPress logo in the top-left of the screen, and a left panel opens up revealing the WordPress Site Editor and its menu to navigate between different parts of the site. This includes Site, Templates, and Template Parts.

Screenshot of the WordPress Site Editor. There is a dark gray left panel open with an Editor heading and three links for Site, Templates, and Template Parts. The main content shows a preview of the site homepage in the WordPress Block Editor.

Let’s click into Templates. This shows us a list of the available templates provided by the theme, complete with a description of each one and where it is registered (e.g. the parent or a child theme).

Screenshot of the site editor's Templates screen which shows a two-column table listing template on the left and who a template was added by on the right.

The other way to get to this screen is from the initial page we landed on when entering the site editor. Click the name of the template in the top admin bar to reveal a button that takes you directly to the same Templates screen.

Screenshot of the Home template open in the WordPress Site Editor. The template name is at the top of the screen in a white toolbar and is expanded with a submenu that describes the template and provides a black button with white text to view all templates.

Any of templates can be edited just like any page or post in the block editor. Let’s say I don’t like to have a featured image on my index page and want to remove it. Simply delete the featured image block and save the template.

The other key part of the site editor UI is a list view that outlines the current blocks that are placed in the template. This has been a feature in WordPress since the introduction of the block editor, but what’s new this time around is that you can open and close parent blocks that contain child blocks like an accordion. Not only that, but it supports dragging and dropping blocks to change the layout directly from there.

The WordPress Site Editor with a white left panel expanded revealing an outline of the current blocks that are applied to the template.

One more thing in the site editor UI: you can clear out customizations with the click of a button. From the Templates screen, click the kebob menu next to a template and select the option to Clear customizations. This is a nice way to reset and start from scratch, should you need to.

Screenshot of the Template Parts screen in the WordPress Site Editor, showing a two-column able with a column that displays template names, and a column that identifies the location of the template part.

The WordPress Core team publishes regular updates on what’s new at Make WordPress Core. It’s worth bookmarking that to stay posted on the latest changes to the WordPress Block Editor and Site Editor.

Creating Templates and Template Parts

Templates, as you know, are core to WordPress theming. They enforce consistent and reusable layouts. That doesn’t change in WordPress 5.9. And neither does the fact that we can create template parts that are like module pieces that can be used in multiple template, say a post query that lives in an archive template and the home template.

What’s different in WordPress 5.9 is that they are created and managed with the site editor rather than PHP files that live in the theme folder.

The Block Editor Handbook lists three ways to create templates and template parts: (a) manually, by creating HTML files containing block markup, (b) using the site editor, and (c) using the template editing mode in the block editor.

Brief descriptions of creating template in the site editor and template editing mode are available in the Block Theme handbook. The WordPress 5.9 allows to create a new template using editor mode.

Screenshot of the Template Parts screen open in the WordPress Site Editor. A modal is open above the UI that contains an interface to create a template part, including the part's name and area.

The customized templates can then be exported to include in a block theme. So, yeah, we now have the ability to create a fully functioning WordPress theme without writing a line of code! The exported folder currently does not contain theme.json file, however there is a proposal over at GitHub to allow exporting both block themes and styles.

Screenshot of the WordPress Site Editor preferences panel open as a white panel to the left of the screen.

But for those who prefer working more closely with code, then manually creating WordPress templates and template parts is still a thing. You can still crack open a code editor and create HTML files containing block markup.

Global settings and styles (theme.json)

In classic themes, we write the styling rules in a style.css file. In block themes, styling is more challenging because CSS comes from different sources (e.g. core blocks, themes, and users). WordPress 5.8 introduced a concept of Global Styles — which is essentially a theme.json file — that, according to the docs, consolidate “the various APIs related to styles into a single point – a theme.json file that should be located inside the root of the theme directory.“

Screenshot of a theme dot jayson file open in the VS Code editor. The file contains objects for version and settings. The settings object contains a color object. The color object contains a palette objects which contains properties for slightly, color, name, and default.

The theme.json file is said to have been designed to offer more granular styling structure for theme authors with options to manage and customize the CSS styles coming from various origins. For example, a theme author may set certain styling features that are hidden from users, define default colors, font sizes and other features available to the user, and may set the default layout of the editor as well. Plus, theme.json allows you to customize styling on a per-block basis. It’s powerful, flexible, and super maintainable!

The block editor is expected to provide all the basic styling that theme authors are allowed to customize style, as defined by the theme.json file. However, the theme.json file could get quite long for a complex theme, and currently there is no way to partition it in a more digestible way. There is a GitHub ticket to restructure it so that different theme.json files map to theme hierarchy to /styles folder. That would be a nice enhancement for developer experience.

The default Twenty Twenty-Two theme is a good example of how WordPress full-site editing features use theme.json for global settings and styling blocks.

WordPress Block Theme approaches

Maybe you’ve always made WordPress themes from scratch. Perhaps you’ve relied on the Underscores theme as a starting point. Or maybe you have a favorite theme you extend with a child theme. The new features of the WordPress Site Editor really change the way we make themes.

Following are a few emerging strategies for block-based theme development that are deeply integrated with the WordPress Site Editor.

Universal themes

The Automattic team has built a Blockbase universal theme that’s dubbed as a new way to build themes, sort of similar to the Underscores starter theme. The Blockbase theme provides temporary “ponyfill” styles that the block editor “does not yet take into account on theme.json ‘custom’ properties” and that may eventually become obsolete once the Gutenberg plugin fully matures and is integrated into WordPress Core.

Using the universal parent theme approach, the Automattic has already released eight Blockbase child themes, and several others are in progress over at GitHub.

Twenty Twenty-Two default theme

The Twenty Twenty-Two default theme is another excellent starting point, as it’s really the first WordPress theme that ships with WordPress that is designed to work with the site editor.

In my opinion, this theme is excellent for theme developers who are already familiar with FSE features to showcase what is possible. For others users who are not developers and are not familiar with FSE features, customizations it in the block editor, then exporting it as a child theme could be painfully frustrating and overwhelming.

Hybrid themes

The concept of “Hybrid” themes in the context of FSE is discussed in this GitHub ticket. The idea is to provide paths for any user to use the site or template editor to override traditional theme templates.

Justin Tadlock in this WP Tavern post predicts four types of themes — block only, universal, hybrid, and classic — and speculates that theme authors may split between “block themes and a mashup of classic/hybrid themes.”

Proof in the pudding is provided by Frank Klein in “What I Learned Building a Hybrid Theme”:

A hybrid theme mixes the traditional theming approach with full-site editing features. A key component here is the theme.json file. It offers more control over the block editor’s settings, and simplifies styling blocks. A hybrid theme can use block templates as well, but that’s optional.

Frank is the author of the Block-Based Bosco theme and has expanded further on what a “hybrid theme” is by creating a hybrid version of the default Twenty Twenty theme. The theme is available on GitHub. Currently, there are no hybrid themes in the WordPres Theme Directory.

WordPress community themes

At the time of writing, there are 47 block-based themes with FSE features available in the theme directory. As expected, this approach is widely varied.

For example, in this post, Aino block theme author Ellen Bower discusses how they converted their classic theme into a block theme, detailing what makes a theme a “block” theme. The file structure of this approach looks different from the standard block theme structure we covered earlier.

Another popular block theme, Tove by Andars Noren, is described as a flexible base theme that follows the standard block theme file structure.

There’s also a very simple single page proof of the concept theme by Carolina Nymark that contains nothing but a single index.html called Miniblock OOAK. It’s already available in the theme directory, as is another one from Justin Tadlock that’s a work in progress (and he wrote up his process in a separate article).

Block Theme Generator app

Even though we’ve already established how friendly WordPress Block Themes are for non-developers, there are tools that help create complete block themes or merely a customized theme.json file.

David Gwyer, an Automattic engineer, has been working on a Block theme generator app which, at the time of writing, is in beta and available for testing by request.

Screenshot of the Block Theme Generator app homepage. It has a bright blue background and dark blue text that welcomes you to the site, and a screenshot of the app.

In my brief testing, the app only allowed me to generate customized theme.json file. But Gwyer told to WP Tavern that the app isn’t fully baked just yet, but features are being added often. Once complete, this could be a very helpful resource for theme authors to create customized block themes.

Block themes that are currently in use

This Twitter thread from Carolina Nymark shows some examples of block themes that are live and in production at the time of this writing. In a recent Yoast article, Carolina listed a bunch of personal and business websites that use block themes.

Personal sites

Business sites

As I mentioned earlier, I also have been using a block theme for one of my personal websites for a while. The default Twenty Twenty-Two theme also currently shows more than 60,000 active installs, which tells me there are many more examples of block-based theme implementations in the wild.

Building Block Child Themes

Child theming is still a thing in this new era of WordPress blocks, though something that’s still in early days. In other words, there is no clear approach to do make a block-based child theme, and there are no existing tools to help at the moment.

That said, a few approaches for creating WordPress child block themes are emerging.

Create Blockbase Theme plugin

The Automattic team is working on a plugin called Create Blockbase Theme. This will make it fairly trivial to create child themes based on the Blockbase universal theme we talked about earlier. Ben Dwyer has discussed how theme authors can build Blockbase child themes with simple six steps and without writing a line of code.

I tested the plugin in my own local environment, making only small changes to my Blockbase theme install, and everything appeared to work. Just note that the plugin is still experimental and under development, though you can follow the roadmap to see what’s up.

Using an alternate theme.json file

Kjell Reigstad, author of the default WordPress Twenty Twenty-Two theme, demonstrates how swapping a single theme.json file with another theme.json file that contains different style configurations can change the look and feel of a block-based theme design.

Kjell has opened a pull request that shows off several experimental child themes that are available for testing at the GitHub theme-experiment GitHub repository.

A three-by-two grid of screenshots of child themes based on the default WordPress Twenty Twenty-Two theme in alternate colors schemes.

Along these same lines, Ryan Welcher is in the process of developing a theme.json builder tool that will generate a customized theme.json file to facilitate non-coders to create similar child themes. More can be found in this WP Tavern post.

The Framboise child theme (available in theme directory) is an early example of that approach which includes only a single theme.json file.

Is there even a need for child themes?

Rich Tabor asks the question:

Indeed, a single theme.json file could serve as a child theme on its own. There is an ongoing discussion about allowing theme authors to ship multiple theme.json files with block themes that offer multiple global style variations. This way, a WordPress user could pick one of the variations to use on the site.

Some features of global style variations are already included in Gutenberg v12. 5 and expected to be available with WordPress 6.0.

Some personal thoughts

I’d be remiss to end this without weighing in on all this from a personal level. I’ll do this briefly in a few points.

Block themes are a WordPress answer to Jamstack criticisms

Jamstack enthusiasts have lobbed criticisms at the WordPress platform, most notably that WordPress themes are bloated with PHP files. Well, that’s no longer the case with WordPress Block Themes.

We saw earlier how an entire theme can be a single index.html file and a theme.json file. No bloat there. And nothing but markup.

I miss the WordPress Customizer

Especially the ability to inject custom code. From here on out, it’s going to require a deep level of familiarity with the WordPress Site Editor UI to accomplish the same thing.

Customizations a site is easy-peasy.

Customizing a classic theme — even something as minimal as changing fonts — can be difficult if you don’t know what you’re doing. That’s changed now with the site editor and the introduction of the theme.json file, where a theme can be customized (and even exported!) without writing a single line of code.

I still hold my opinion, though that the site editor interface is confusing. I think a pleasant user experience is a far ways off but looking forward to the next WordPress 6.0 release for better user experience.

Barriers to designing themes is getting lower.

It’s less about PHP and template files, and more about developing patterns and creating content. That sounds exactly what a content management system should be designed to do! I am already excited with new features being considered for the WordPress 6.0 release.


There is already a ton of other articles that cover WordPress Block Themes, full-site editing, and the block editor. And many of those came before WordPress 5.9 was released!

So, in addition to this article, here’s a collection of others for you to consider as you begin or continue down your journey of WordPress blocks and site editing.

WordPress 5.9

Site editor and block themes

Selected blog posts

As expected in beta testing, the site editor is still intimating and confusing, nevertheless, I am finding it a fun to work with block themes. Indeed, I have been already modifying Twenty Twenty-Two as a child theme and plan to create style alternatives using single theme.json file.

Have you been using block themes in your project, if so, share your experience and thoughts; I love reading any comments and feedback!

A Deep Introduction to WordPress Block Themes originally published on CSS-Tricks. You should get the newsletter and become a supporter.


, , , ,

4 Quality Options for a Table of Contents Block in WordPress

Offering a table of contents block in WordPress for blog posts (or really any other type of long-ish written content) is a good idea for two reasons:

  • It helps users jump around in the post for what they need (and hopefully doesn’t get in the way).
  • It’s provides SEO value.

The RankMath SEO plugin factors it in as part of your page score (suggesting you should have one), because of that second point. See what Google likely gives you if you do it right:

Screenshoot of a typical Google search results item with a breadcrumb above the page title, then a page description. A purple box is drawn around four links below the page description to call out how adding a table of contents block in WordPress can add those links in the search results for additional user convenience,

It makes sense that other WordPress SEO Plugins like Yoast offer a table of contents block as a baked-in additional feature of the plugin. If you’re committed to using Yoast, then I think it’s fine to just use that. But I admit it’s not my favorite to feel locked to a plugin because it offers a microfeature that you then depend on.

So what are the options?

Table of Contents

What to look for in a WordPress Table of Contents Block

Here are some things to look for and think about when choosing a table of contents block:

  • Customizable header — Many options chuck a “Table of Contents” header above the actual Table of Contents, which makes sense. Can you turn it off or customize it? What level header is it? Having the ability to disable the heading might be necessary for layout, and having a choice of heading levels can help ensure proper HTML semantics.
  • Collapsible — In the spirit of making the Table of Contents less annoying, many offer a feature to toggle the Table of Contents block between open and closed states. Do you want that? Are you OK with the fact it likely requires some JavaScript to work? Is it doing toggling accessibly? Can it default to the state that you want?
  • Choose which headings to include — Perhaps you only want all the <h2> elements to form the Table of Contents. Can you do that? Do sub-headers create a “nested’ list? Do you want that? Can you turn off certain levels of headers? Can you tell the block to only include <h2> through <h4>? Are there things other than headers you want to be part of the Table of Contents?
  • Editable links — Many Table of Contents plugins in WordPress typically grab all the headings verbatim. Maybe you want to shorten, lengthen, or otherwise change a specific link in the Table of Contents; as in, not have it be the exact text of the header it links to. Can you do that?
  • Include additional links — Perhaps you want to link to something that isn’t a content heading. Perhaps it’s added to the template with a WordPress custom field, or it’s part of the overall template like the comments section. Can you add (or remove) those as headings in the block?
  • Block Editor support — That’s kind of the point of this blog post. I didn’t include many options that don’t have a block. But surely there are old school versions of this that are [shortcode]-based or that implement it some other way. I’m mostly concerned about blocks, although I could easily see a situation where your goal is to put the Table of Contents elsewhere in a template (sidebar, perhaps?). So, having multiple options and modularity could be useful.
  • Styling options — Personally, I like to bring my own styling (surprise!) and even dequeue any stylesheets (or scripts) that a plugin tries to bring along for the ride. But I can imagine more folks want the Table of Contents to look good and be able to aesthetically control it right from the editor. This means it’d be nice to have block options for colors, fonts, spacing, etc.
  • Semantic markup — Might be worth a peek at the HTML that the Table of Contents block you choose generates to make if it’s sensible. I’ve seen plugins generate HTML lists that don’t actually nest lists, for example, but instead add classes to list items to make them look nested. No, thanks. I’m not sure there is an official HTML format that’s best for SEO, so sematic markup is about the best you can do.
  • Heading IDs — In order for a linked Table of Contents to work, all the headers need to have IDs so there’s something to anchor to. I would think any plugin here that’s worth its salt would add them to headings only in the case that they don’t already have one, but you might wanna veryify that; otherwise, you run the risk of breaking existing links or perhaps even styling and functionality. Also think about what IDs are being generated. For example, I use the Add Anchor Links plugin, which adds a link (🔗) icon beside all headings to offer access to the IDs. The IDs it generates were idential to the Table of Contents-generated IDs, causing a duplicate ID problem. Fixable, but just be aware of things like that.

Option 1: Use a Dedicated Table of Contents Plugin

A dedicated Table of Contents plugin is a plugin that focuses on nothing but a Table of Contents. Nothing else. Here are some solid options where that’s the case.

Heroic Table of Contents

The ability to edit/add/remove headers from the table of contents — even after it’s been automatically generated — is pretty powerful and unique to this plugin. It allows you to open and close it (optionally) as well, which is nice as a goal for these, as they should make the links useful rather than content that gets in the way. But beware that this puts you in the territory of enqueuing additional scripts as well as styles which may or may not be ideal or something you’re comfortable doing.

Screenshot of Heroic Table of Contents Block in WordPress
(Recommended by Deborah Edwards-Onoro)

Easy Table of Contents

This is not a Block Editor block! Instead, it only automatically inserts itself, either by content type or through an opt-in checkbox in a metabox.

I find it a little awkward that you can’t control where the Table of Contents goes with this plugin. Looks like it inserts itself near the top of posts, likely right after where the <!-- more --> is located.

Screenshot of Easy Table of Contents Block in WordPress


This is my favorite one.

I like this one because it doesn’t add any scripts or styles by default. It just makes a semantic HTML list out of the headers, links them up, and that’s it. That’s how I like to roll.

Screenshot of SimpleTOC Table of Contents Block in WordPress

LuckyWP Table of Contents

Lots of features, but I find it a bit awkward how it doesn’t have regular block controls. Instead, you get this entirely custom UI for changing the settings — and you can’t preview what it looks like in the block itself.

Screenshot of LuckyWP Table of Contents Block in WordPress


Feels like this Table of Contents plugin embraces the spirit of the WordPress Block Editor quite well, but I find the settings a little awkward. The choices it offers don’t feel terrifically useful (like square bullets for the list? “15” space left?).

Screenshot of the GutenTOC Table of Contents plugin in WordPress.

Option 2: Wait for a Table of Contents feature to be baked into Core WordPress

As I write, there is an open pull request to enable a Table of Contents block in the Gutenberg plugin. Presumably, should that go well, it ultimately makes its way to core. That would be great if you ask me, but it doesn’t help solve the problem of needing a Table of Contents block right this second.

If this feature does drop, I’d lean heavily toward using it. Hopefully, I can do a search or query to find existing Table of Contents blocks on all posts, switch them over to use the native block, and remove whatever plugin I have in place.

Option 3: Use a Table of Contents Block that’s a sub-feature of another WordPress plugin

I would recommend against using a plugin that does a whole slew of things just because you want to use some small part of it. But hey, if it turns out you could use lots of things from the big plugin, it could be a bonus as far as managing fewer plugins overall.

Yoast SEO Premium

The free version of the Yoast SEO plugin doesn’t have it, but for only $ 99 per year, the Yoast SEO Premium plugin does. It has almost no features at all. You just add it as a block, and it pops in. You can edit the title or remove it — it’s almost like a “sub block.”

The list of links isn’t editable, but it does update in real-time as you change headings in the content, which is something most of the others I tested didn’t do. Super basic, no styling or features, but I kinda like that. I wouldn’t run Yoast for this one feature, especially for a paid premium, but if you’re using Yoast anyway (for the long haul), then you might as well go this route.

Screenshot of the Yoast SEO plugin’s table of contents block in WordPress.

Ultimate Addons for Gutenberg

This one is probably the classiest Table of Contents block I’ve come across. Again, I’m weary of using an all-in-one plugin for one specific feature, but the other features that are baked into this plugin are things you can use, then it’s a solid option.

Screenshot of the Ultimate Addons for Gutenberg Tablew of Contents plugin in WordPress.

Option 4: Roll your own DIY Table of Contents Block

Making blocks yourself isn’t out of the question! I’ve done it a few times with create-guten-block, though I’d probably reach for @wordpress/create-block these days. This puts you in JavaScript-land, so you’ll be parsing the content of the post with JavaScript, finding headings in the post content, and building things out from there. Kind of intermediate-to-advanced territory, I’d say. On one hand, it’s extra technical debt, and on the other, at least you have complete control since it’s your own code.

Since we’re focusing on building blocks, Advanced Custom Fields has a very powerful way of building custom blocks that brings that power back to PHP-land. That way, if you’re only concerned with building a Table of Contents from other heading blocks, the code gets a lot easier.

Bill Erickson has a post — “Access block data with PHP using parse_blocks() and render_block() — that ultimately gets into literally building a Table of Contents block. This gist he provides is a pretty useful reference for how to loop through blocks on a post and produce an HTML list.


If I was using Yoast SEO Premium on a site, I’d just use that one. If not, I’d go for SimpleTOC. That’s what we’ve done here on CSS-Tricks. Once the core feature drops (🤞), I’d make a rainy day project of moving all posts that currently use the Table of Contents plugin over to using the core WordPress block (assuming it turns out nice).

4 Quality Options for a Table of Contents Block in WordPress originally published on CSS-Tricks. You should get the newsletter and become a supporter.


, , , , ,

WordPress Admin Warnings in the Block Editor

We sent out an email the other week that ultimately had a <video> in the HTML markup. We send the newsletter by creating it here in the WordPress block editor, which is fetched through RSS-to-Mailchimp. Mailchimp dutifully sent it out, but the HTML was such that it totally borked the layout. This lead to some charming totally fair emails like this:

This email looks like trash in thunderbird, just giving a heads up.

You actually can send <video> in HTML email, but our system just isn’t set up for it. It requires some fancy dancing CSS (e.g. hiding it for non-supporting users with a fallback, and detecting support is super tricky, etc.) and HTML (e.g. making sure the width/height attributes are small-screen friendly). We could do it, but I don’t think it’s worth it for the handful of times we would want to do it.

So instead, to prevent us from doing it again, I used (drumroll)…. CSS.

I have some CSS that gets loaded in the admin area only when the block editor is loaded, which is in a functionality plugin:

wp_register_style(   'css-tricks-code-block-editor-css',   plugins_url('location/of/styles.css', dirname( __FILE__ )),   array('wp-edit-blocks'),   filemtime( plugin_dir_path(__DIR__) . 'location/of/styles.css') );

I can put anything I want in that CSS file and it will effect styles of the block editor but nothing on the public front end of the site.

I also wanted to scope this CSS only to the newsletters page. Fortunately, WordPress has body classes in the editor as well. We have a Custom Post Type for newsletters, and that expresses itself as a class here:

So I chuck these styles in:

/* Warn about videos in newsletters */ .post-type-newsletters .wp-block-video {   border: 5px solid red; } .post-type-newsletters .wp-block-video::before {   content: "WARNING: NO VIDEOS IN EMAILS";   display: block;   color: red; }

And boom, I have styles that warn about this problem before it happens again:

The post WordPress Admin Warnings in the Block Editor appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.


, , , ,

A Crash Course in WordPress Block Filters

Blocks in WordPress are great. Drop some into the page, arrange them how you like, and you’ve got a pretty sweet landing page with little effort. But what if the default blocks in WordPress need a little tweaking? Like, what if we could remove the alignment options in the Cover block settings? Or how about control sizing for the Button block?

There are plenty of options when it comes to extending the functionality of core blocks in WordPress. We can add a custom CSS class to a block in the editor, add a custom style, or create a block variation. But even those might not be enough to get what you need, and you find yourself needing to filter the core block to add or remove features, or building an entirely new block from scratch.

I’ll show you how to extend core blocks with filters and also touch on when it’s best to build a custom block instead of extending a core one.

A quick note on these examples

Before we dive in, I’d like to note that code snippets in this article are taken out of context on purpose to focus on filters rather than build tools and file structure. If I included the full code for the filters, the article would be hard to follow. With that said, I understand that it’s not obvious for someone who is just starting out where to put the snippets or how to run build scripts and make the whole thing work.

To make things easier for you, I made a WordPress plugin with examples from this article available on my GitHub. Feel free to download it and explore the file structure, dependencies and build scripts. There is a README that will help you get started.

Block filters in an nutshell

The concept of filters is not new to WordPress. Most of us are familiar with the add_filter() function in PHP. It allows developers to modify various types of data using hooks.

A simple example of a PHP filter could look something like this:

function filter_post_title( $ title ){   return '<strong>' . $ title . '</strong>'; };  add_filter( 'the_title',  'filter_post_title' );

In this snippet, we create a function that receives a string representing a post title, then wrap it in a <strong> tag and return a modified title. We then use add_filter() to tell WordPress to use that function on a post title.

JavaScript filters work in a similar way. There is a JavaScript function called addFilter() that lives in the wp.hooks package and works almost like its PHP sibling. In its simplest form, a JavaScript filter looks something like this:

function filterSomething(something) {   // Code for modifying something goes here.   return something; }  wp.hooks.addFilter( 'hookName', 'namespace', filterSomething );

Looks pretty similar, right? One notable difference is addFilter() has a namespace as a second argument. As per the WordPress Handbook, “Namespace uniquely identifies a callback in the the form vendor/plugin/function.” However, examples in the handbook follow different patterns: plugin/what-filter-does or plugin/component-name/what-filter-does. I usually follow the latter because it keeps the handles unique throughout the project.

What makes JavaScript filters challenging to understand and use is the different nature of what they can filter. Some filter strings, some filter JavaScript objects, and others filter React components and require understanding the concept of Higher Order Components.

On top of that, you’ll most likely need to use JSX which means you can’t just drop the code into your theme or plugin and expect it to work. You need to transpile it to vanilla JavaScript that browsers understand. All that can be intimidating at the beginning, especially if you are coming from a PHP background and have limited knowledge of ES6, JSX, and React.

But fear not! We have two examples that cover the basics of block filters to help you grasp the idea and feel comfortable working with JavaScript filters in WordPress. As a reminder, if writing this code for the Block Editor is new to you, explore the plugin with examples from this article.

Without any further ado, let’s take a look at the first example.

Removing the Cover block’s alignment options

We’re going to filter the core Cover block and remove the Left, Center, Right, and Wide alignment options from its block settings. This may be useful on projects where the Cover block is only used as a page hero, or a banner of some sort and does not need to be left- or right-aligned.

We’ll use the blocks.registerBlockType filter. It receives the settings of the block and its name and must return a filtered settings object. Filtering settings allows us to update the supports object that contains the array of available alignments. Let’s do it step-by-step.

We’ll start by adding the filter that just logs the settings and the name of the block to the console, to see what we are working with:

const { addFilter } = wp.hooks;  function filterCoverBlockAlignments(settings, name) {   console.log({ settings, name });   return settings; }  addFilter(   'blocks.registerBlockType',   'intro-to-filters/cover-block/alignment-settings',   filterCoverBlockAlignments, );

Let’s break it down. The first line is a basic destructuring of the wp.hooks object. It allows us to write addFilter() in the rest of the file, instead of wp.hooks.addFilter(). This may seem redundant in this case, but it is useful when using multiple filters in the same file (as we’ll get to in the next example).

Next, we defined the filterCoverBlockAlignments() function that does the filtering. For now, it only logs the settings object and the name of the block to the console and returns the settings as is.

All filter functions receive data, and must return filtered data. Otherwise, the editor will break.

And, lastly, we initiated the filter with addFilter() function. We provided it with the name of the hook we are going to use, the filter namespace, and a function that does the filtering.

If we’ve done everything right, we should see a lot of messages in the console. But note that not all of them refer to the Cover block.

This is correct because the filter is applied to all blocks rather than the specific one we want. To fix that, we need to make sure that we apply the filter only to the core/cover block:

function filterCoverBlockAlignments(settings, name) {   if (name === 'core/cover') {     console.log({ settings, name });   }   return settings; }

With that in place, we should see something like this now in the console:

Don’t worry if you see more log statements than Cover blocks on the page. I have yet to figure out why that’s the case. If you happen to know why, please share in the comments!

And here comes the fun part: the actual filtering. If you have built blocks from scratch before, then you know that alignment options are defined with Supports API. Let me quickly remind you how it works — we can either set it to true to allow all alignments, like this:

supports: {   align: true }

…or provide an array of alignments to support. The snippet below does the same thing, as the one above:

supports: {   align: [ 'left', 'right', 'center', 'wide', 'full' ] }

Now let’s take a closer look at the settings object from one of the console messages we have and see what we are dealing with:

All we need to do is replace align: true with align: ['full'] inside the supports property. Here’s how we can do it:

function filterCoverBlockAlignments(settings, name) {   if (name === 'core/cover') {     return assign({}, settings, {       supports: merge(settings.supports, {         align: ['full'],       }),     });   }   return settings; }

I’d like to pause here to draw your attention to the assign and merge lodash methods. We use those to create and return a brand new object and make sure that the original settings object remains intact. The filter will still work if we do something like this:

/* 👎 WRONG APPROACH! DO NOT COPY & PASTE! */ settings.supports.align = ['full']; return settings;

…but that is an object mutation, which is considered a bad practice and should be avoided unless you know what you are doing. Zell Liew discusses why mutation can be scary over at A List Apart.

Going back to our example, there should now only be one alignment option in the block toolbar:

I removed the “center” alignment option because the alignment toolbar allows you to toggle the alignment “on” and “off.” This means that Cover blocks now have default and “Full width” states.

And here’s the full snippet:

const { addFilter } = wp.hooks; const { assign, merge } = lodash;  function filterCoverBlockAlignments(settings, name) {   if (name === 'core/cover') {     return assign({}, settings, {       supports: merge(settings.supports, {         align: ['full'],       }),     }); }   return settings; }  addFilter(   'blocks.registerBlockType',   'intro-to-filters/cover-block/alignment-settings',   filterCoverBlockAlignments, );

This wasn’t hard at all, right? You are now equipped with a basic understanding of how filters work with blocks. Let’s level it up and take a look at a slightly more advanced example.

Adding a size control to the Button block

Now let’s add a size control to the core Button block. It will be a bit more advanced as we will need to make a few filters work together. The plan is to add a control that will allow the user to choose from three sizes for a button: Small, Regular, and Large.

The goal is to get that new “Size settings” section up and running.

It may seem complicated, but once we break it down, you’ll see that it’s actually pretty straightforward.

1. Add a size attribute to the Button block

First thing we need to do is add an additional attribute that stores the size of the button. We’ll use the already familiar blocks.registerBlockType filter from the previous example:

/**  * Add Size attribute to Button block  *  * @param  {Object} settings Original block settings  * @param  {string} name     Block name  * @return {Object}          Filtered block settings  */ function addAttributes(settings, name) {   if (name === 'core/button') {     return assign({}, settings, {       attributes: merge(settings.attributes, {         size: {           type: 'string',           default: '',         },       }),     });   }   return settings; }  addFilter(   'blocks.registerBlockType',   'intro-to-filters/button-block/add-attributes',   addAttributes, );

The difference between what we’re doing here versus what we did earlier is that we’re filtering attributes rather than the supports object. This snippet alone doesn’t do much and you won’t notice any difference in the editor, but having an attribute for the size is essential for the whole thing to work.

2. Add the size control to the Button block

We’re working with a new filter, editor.BlockEdit. It allows us to modify the Inspector Controls panel (i.e. the settings panel on the right of the Block editor).

/**  * Add Size control to Button block  */ const addInspectorControl = createHigherOrderComponent((BlockEdit) => {   return (props) => {     const {       attributes: { size },       setAttributes,       name,     } = props;     if (name !== 'core/button') {       return <BlockEdit {...props} />;     }     return (       <Fragment>         <BlockEdit {...props} />         <InspectorControls>           <PanelBody             title={__('Size settings', 'intro-to-filters')}             initialOpen={false}           >             <SelectControl               label={__('Size', 'intro-to-filters')}               value={size}               options={[                 {                   label: __('Regular', 'intro-to-filters'),                   value: 'regular',                 },                 {                   label: __('Small', 'intro-to-filters'),                   value: 'small'                 },                 {                   label: __('Large', 'intro-to-filters'),                   value: 'large'                 },               ]}               onChange={(value) => {                 setAttributes({ size: value });               }}             />           </PanelBody>       </InspectorControls>       </Fragment>     );   }; }, 'withInspectorControl');  addFilter(   'editor.BlockEdit',   'intro-to-filters/button-block/add-inspector-controls',   addInspectorControl, );

This may look like a lot, but we’ll break it down and see how straightforward it actually is.

The first thing you may have noticed is the createHigherOrderComponent construct. Unlike other filters in this example, editor.BlockEdit receives a component and must return a component. That’s why we need to use a Higher Order Component pattern derived from React.

In its purest form, the filter for adding controls looks something like this:

const addInspectorControl = createHigherOrderComponent((BlockEdit) => {   return (props) => {     // Logic happens here.     return <BlockEdit {...props} />;   }; }, 'withInspectorControl');

This will do nothing but allow you to inspect the <BlockEdit /> component and its props in the console. Hopefully the construct itself makes sense now, and we can keep breaking down the filter.

The next part is destructuring the props:

const {   attributes: { size },   setAttributes,   name, } = props;

This is done so we can use name, setAttributes, and size in the scope of the filter, where:

  • size is the attribute of the block that we’ve added in step 1.
  • setAttributes is a function that lets us update the block’s attribute values.
  • name is a name of the block. which is core/button in our case.

Next, we avoid inadvertantly adding controls to other blocks:

if (name !== 'core/button') {   return <BlockEdit {...props} />; }

And if we are dealing with a Button block, we wrap the settings panel in a <Fragment /> (a component that renders its children without a wrapping element) and add an additional control for picking the button size:

return (   <Fragment>     <BlockEdit {...props} />     {/* Additional controls go here */}   </Fragment> );

Finally, additional controls are created like this:

<InspectorControls>   <PanelBody title={__('Size settings', 'intro-to-filters')} initialOpen={false}>     <SelectControl       label={__('Size', 'intro-to-filters')}       value={size}       options={[         { label: __('Regular', 'intro-to-filters'), value: 'regular' },         { label: __('Small', 'intro-to-filters'), value: 'small' },         { label: __('Large', 'intro-to-filters'), value: 'large' },       ]}       onChange={(value) => {         setAttributes({ size: value });       }}     />   </PanelBody> </InspectorControls>

Again, if you have built blocks before, you may already be familiar with this part. If not, I encourage you to study the library of components that WordPress comes with.

At this point we should see an additional section in the inspector controls for each Button block:

We are also able to save the size, but that won’t reflect in the editor or on the front end. Let’s fix that.

3. Add a size class to the block in the editor

As the title suggests, the plan for this step is to add a CSS class to the Button block so that the selected size is reflected in the editor itself.

We’ll use the editor.BlockListBlock filter. It is similar to editor.BlockEdit in the sense that it receives the component and must return the component; but instead of filtering the block inspector panel, if filters the block component that is displayed in the editor.

import classnames from 'classnames'; const { addFilter } = wp.hooks; const { createHigherOrderComponent } = wp.compose;  /**  * Add size class to the block in the editor  */ const addSizeClass = createHigherOrderComponent((BlockListBlock) => {   return (props) => {     const {       attributes: { size },       className,       name,     } = props;      if (name !== 'core/button') {       return <BlockListBlock {...props} />;     }      return (       <BlockListBlock         {...props}         className={classnames(className, size ? `has-size-$ {size}` : '')}       />     );   }; }, 'withClientIdClassName');  addFilter(    'editor.BlockListBlock',    'intro-to-filters/button-block/add-editor-class',    addSizeClass );

You may have noticed a similar structure already:

  1. We extract the size, className, and name variables from props.
  2. Next, we check if we are working with core/button block, and return an unmodified <BlockListBlock> if we aren’t.
  3. Then we add a class to a block based on selected button size.

I’d like to pause on this line as it may look confusing from the first glance:

className={classnames(className, size ? `has-size-$ {size}` : '')}

I’m using the classnames utility here, and it’s not a requirement — I just find using it a bit cleaner than doing manual concatenations. It prevents me from worrying about forgetting to add a space in front of a class, or dealing with double spaces.

4. Add the size class to the block on the front end

All we have done up to this point is related to the Block Editor view, which is sort of like a preview of what we might expect on the front end. If we change the button size, save the post and check the button markup on the front end, notice that button class is not being applied to the block.

To fix this, we need to make sure we are actually saving the changes and adding the class to the block on the front end. We do it with blocks.getSaveContent.extraProps filter, which hooks into the block’s save() function and allows us to modify the saved properties. This filter receives block props, the type of the block, and block attributes, and must return modified block props.

import classnames from 'classnames'; const { assign } = lodash; const { addFilter } = wp.hooks;  /**  * Add size class to the block on the front end  *  * @param  {Object} props      Additional props applied to save element.  * @param  {Object} block      Block type.  * @param  {Object} attributes Current block attributes.  * @return {Object}            Filtered props applied to save element.  */ function addSizeClassFrontEnd(props, block, attributes) {   if (block.name !== 'core/button') {     return props;   }    const { className } = props;   const { size } = attributes;    return assign({}, props, {     className: classnames(className, size ? `has-size-$ {size}` : ''),   }); }  addFilter(   'blocks.getSaveContent.extraProps',   'intro-to-filters/button-block/add-front-end-class',   addSizeClassFrontEnd, );

In the snippet above we do three things:

  1. Check if we are working with a core/button block and do a quick return if we are not.
  2. Extract the className and size variables from props and attributes objects respectively.
  3. Create a new props object with an updated className property that includes a size class if necessary.

Here’s what we should expect to see in the markup, complete with our size class:

<div class="wp-block-button has-size-large">   <a class="wp-block-button__link" href="#">Click Me</a> </div>

5. Add CSS for the custom button sizes

One more little thing before we’re done! The idea is to make sure that large and small buttons have corresponding CSS styles.

Here are the styles I came up with:

.wp-block-button.has-size-large .wp-block-button__link {   padding: 1.5rem 3rem; } .wp-block-button.has-size-small .wp-block-button__link {   padding: 0.25rem 1rem; }

If you are building a custom theme, you can include these front-end styles in the theme’s stylesheet. I created a plugin for the default Twenty Twenty One theme, so, in my case, I had to create a separate stylesheet and include it using wp_enqueue_style(). You could just as easily work directly in functions.php if that’s where you manage functions.

function frontend_assets() {   wp_enqueue_style(     'intro-to-block-filters-frontend-style',     plugin_dir_url( __FILE__ ) . 'assets/frontend.css',     [],     '0.1.0'   ); } add_action( 'wp_enqueue_scripts', 'frontend_assets' );

Similar to the front end, we need to make sure that buttons are properly styled in the editor. We can include the same styles using the enqueue_block_editor_assets action:

function editor_assets() {   wp_enqueue_style(     'intro-to-block-filters-editor-style',     plugin_dir_url( __FILE__ ) . 'assets/editor.css',     [],     '0.1.0'   ); } add_action( 'enqueue_block_editor_assets', 'editor_assets' );

We should now should have styles for large and small buttons on the front end and in the editor!

As I mentioned earlier, these examples are available in as a WordPress plugin I created just for this article. So, if you want to see how all these pieces work together, download it over at GitHub and hack away. And if something isn’t clear, feel free to ask in the comments.

Use filters or create a new block?

This is a tricky question to answer without knowing the context. But there’s one tip I can offer.

Have you ever seen an error like this?

It usually occurs when the markup of the block on the page is different from the markup that is generated by the block’s save() function. What I’m getting at is it’s very easy to trigger this error when messing around with the markup of a block with filters.

So, if you need to significantly change the markup of a block beyond adding a class, I would consider writing a custom block instead of filtering an existing one. That is, unless you are fine with keeping the markup consistent for the editor and only changing the front-end markup. In that case, you can use PHP filter.

Speaking of which…

Bonus tip: render_block()

This article would not be complete without mentioning the render_block hook. It filters block markup before it’s rendered. It comes in handy when you need to update the markup of the block beyond adding a new class.

The big upside of this approach is that it won’t cause any validation errors in the editor. That said, the downside is that it only works on the front end. If I were to rewrite the button size example using this approach, I would first need to remove the code we wrote in the fourth step, and add this:

/**  * Add button size class.  *  * @param  string $ block_content Block content to be rendered.  * @param  array  $ block         Block attributes.  * @return string  */ function add_button_size_class( $ block_content = '', $ block = [] ) {   if ( isset( $ block['blockName'] ) && 'core/button' === $ block['blockName'] ) {     $ defaults = ['size' => 'regular'];     $ args = wp_parse_args( $ block['attrs'], $ defaults );      $ html = str_replace(       '<div class="wp-block-button',       '<div class="wp-block-button has-size-' . esc_attr( $ args['size']) . ' ',       $ block_content     );      return $ html; }   return $ block_content; }  add_filter( 'render_block', 'add_button_size_class', 10, 2 );

This isn’t the cleanest approach because we are injecting a CSS class using str_replace() — but that’s sometimes the only option. A classic example might be working with a third-party block where we need to add a <div> with a class around it for styling.

Wrapping up

WordPress block filters are powerful. I like how it allows you to disable a lot of unused block options, like we did with the Cover block in the first example. This can reduce the amount of CSS you need to write which, in turn, means a leaner stylesheet and less maintenance — and less cognitive overhead for anyone using the block settings.

But as I mentioned before, using block filters for heavy modifications can become tricky because you need to keep block validation in mind.

That said, I usually reach for block filters if I need to:

  • disable certain block features,
  • add an option to a block and can’t/don’t want to do it with custom style (and that option must not modify the markup of the block beyond adding/removing a custom class), or
  • modify the markup only on the front end (using a PHP filter).

I also usually end up writing custom blocks when core blocks require heavy markup adjustments both on the front end and in the editor.

If you have worked with block filters and have other thoughts, questions, or comments, let me know!


The post A Crash Course in WordPress Block Filters appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , , ,

How to Work With WordPress Block Patterns

Just a little post I wrote up over at The Events Calendar blog. The idea is that a set of blocks can be grouped together in WordPress, then registered in a register_block_pattern() function that makes the group available to use as a “block pattern” in any page or post.

Block patterns are becoming upper-class citizens in the WordPress block editor. They were announced without much fanfare in WordPress 5.5 back in August, but have been given prominent real estate in the block inserter with its own tab next to blocks, including 10 or so default ones right out of the box.

Block patterns are sandwiched between Blocks and Reusable Blocks in the block inserter, which is a perfect metaphor for where it fits in the bigger picture of WordPress editing.

If the 5.6 Beta 3 release notes are any indication, then it looks like more patterns are on the way for default WordPress themes. And, of course, the block registration function has an unregister_block_pattern() companion should you need to opt out of any patterns.

What I find interesting is how the blocks ecosystem is evolving. We started with a set of default blocks that can be inserted into a post. We got reusable blocks that provide a way to assemble a group of blocks with consistent content across all pages of posts. Now we have a way to do the same, but in a much more flexible and editable way. The differences are subtle, but the use cases couldn’t be more different. We’ve actually been using reusable blocks here at CSS-Tricks for post explanations, like this:

We drop some text in here when we think there’s something worth calling out or that warrants a little extra explanation.

Any reusable block can be converted to a “regular” block. The styles are maintained but the content is not. That’s been our hack-y approach for speeding up our process around here, but now that block patterns are a thing, previous reusable blocks we’ve been using now make more sense as patterns.

Direct Link to ArticlePermalink

The post How to Work With WordPress Block Patterns appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , ,

Getting the WordPress Block Editor to Look Like the Front End Design

I’m a WordPress user and, if you’re anything like me, you always have two tabs open when you edit a post: one with the new fancy pants block editor, aka Gutenberg, and another with a preview of the post so you know it won’t look wonky on the front end.

It’s no surprise that a WordPress theme’s styles only affect the front end of your website. The back end posy editor generally looks nothing like the front end result. We’re used to it. But what if I said it’s totally possible for the WordPress editor nearly mirror the front end appearance?

All it takes is a custom stylesheet.

Mind. Blown. Right? Well, maybe it’s not that mind blowing, but it may save you some time if nothing else. 🙂

WordPress gives us a hint of what’s possible here. Fire up the default Twenty Twenty theme that’s packaged with WordPress, fire up the editor, and it sports some light styling.

This whole thing consists of two pretty basic changes:

  1. A few lines of PHP in your theme’s functions.php file that tell the editor you wish to load a custom stylesheet for editor styles
  2. Said custom stylesheet

Right then, enough pre-waffle! Let’s get on with making the WordPress editor look like the front end, shall we?

Step 1: Crack open the functions.php file

OK I was lying, just a little more waffling. If you’re using a WordPress theme that you don’t develop yourself, it’s probably best that you setup a child theme before making any changes to your main theme. </pre-waffle>

Fire up your favorite text editor and open up the theme’s functions.php file that’s usually located in the root of the theme folder. Let’s drop in the following lines at the end of the file:

// Gutenberg custom stylesheet add_theme_support('editor-styles'); add_editor_style( 'style-editor.css' ); // make sure path reflects where the file is located

What this little snippet of code does is tell WordPress to add support for a custom stylesheet to be used with Gutenberg, then points to where that stylesheet (that we’re calling editor-style.css) is located. WordPress has solid documentation for the add_theme_support function if you want to dig into it a little more.

Step 2: CSS tricks (see what I did there?!)

Now we’re getting right into our wheelhouse: writing CSS!

We’ve added editor-styles support to our theme, so the next thing to do is to add the CSS goodness to the stylesheet we defined in functions.php so our styles correctly load up in Gutenberg.

There are thousands of WordPress themes out there, so I couldn’t possibly write a stylesheet that makes the editor exactly like each one. Instead, I will show you an example based off of the theme I use on my website. This should give you an idea of how to build the stylesheet for your site. I’ll also include a template at the end, which should get you started.

OK let’s create a new file called style-editor.css and place it in the root directory of the theme (or again, the child theme if you’re customizing a third-party theme).

Writing CSS for the block editor isn’t quite as simple as using standard CSS elements. For example, if we were to use the following in our editor stylesheet it wouldn’t apply the text size to <h2> elements in the post.

h2 {   font-size: 1.75em; }

Instead of elements, our stylesheet needs to target Block Editor blocks. This way, we know the formatting should be as accurate as possible. That means <h2> elements needs to be scoped to the .rich-text.block-editor-rich-text__editable class to style things up.

Showing the block editor with a light yellow background, a heading that reads Holly Dolly, and a heading 2 with DevTools open to the left in dark mode and a block-editor-rich-text-__editor class highlighted in red.
It just takes a little peek at DevTools to find a class we can latch onto.
h2.rich-text.block-editor-rich-text__editable {   font-size: 1.75em; }

I just so happened to make a baseline CSS file that styles common block editor elements following this pattern. Feel free to snag it over at GitHub and swap out the styles so they complement your theme.

I could go on building the stylesheet here, but I think the template gives you an idea of what you need to populate within your own stylesheet. A good starting point is to go through the stylesheet for your front-end and copy the elements from there, but you will likely need to change some of the element classes so that they apply to the Block Editor window.

If in doubt, play around with elements in your browser’s DevTools to work out what classes apply to which elements. The template linked above should capture most of the elements though.

The results

First of all, let’s take a look at what the WordPress editor looks like without a custom stylesheet:

Showing the WordPress block editor without any custom styling, which is a plain white screen with black text including a heading one paragraph, a blockquote and a black rounded button.
The block editor sports a clean, stark UI in its default appearance. It’s pulling in Noto Serif from Google Fonts but everything else is pretty bare bones.

Let’s compare that to the front end of my test site:

Showing a webpage with the same heading, paragraph, blockquote and button, but with styles that include a red-to-orange gradient that goes left-to-right as a background behind the white heading, a typewriter-like font, the same gradient to style the blockquote borders and text, and to style the button.

Things are pretty different, right? Here we still have a simple design, but I’m using gradients all over, to the max! There’s also a custom font, button styling, and a blockquote. Even the containers aren’t exactly square edges.

Love it or hate it, I think you will agree this is a big departure from the default Gutenberg editor UI. See why I have to have a separate tab open to preview my posts?

Now let’s load up our custom styles and check things out:

The same look as the custom styles on the front end but now displayed in the WordPress block editor.

Well would you look at that! The editor UI now looks pretty much exactly the same as the front end of my website. The content width, fonts, colors and various elements are all the same as the front end. I even have the fancy background against the post title!

Ipso facto — no more previews in another tab. Cool, huh?

Making the WordPress editor look like your front end is a nice convenience. When I’m editing a post, flipping between tabs to see what the posts looks like on the front end ruins my mojo, so I prefer not to do it.

These couple of quick steps should be able to do the same for you, too!

The post Getting the WordPress Block Editor to Look Like the Front End Design appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , , , , , ,