Getting Started with Block Themes: Patterns

Block Patterns, or simply patterns, enable theme developers to create custom blocks that are compositions of blocks provided by the standard block library, and if desired, with additional design flourishes. For example, Twenty Twenty One includes support for blocks designed with overlapping images and text, among others. In the blocks version of Twenty Twenty One, these will be registered as patterns within the theme.

Repeatable design patterns

Unlike templates, patterns are defined in PHP in a way that might be more familiar to experienced theme developers. We can define them in the functions.php file of our theme, or a file that is included there.

First up, as a matter of good practice, we register a category for our patterns using the register_block_pattern_category function. By categorising our patterns, we can separate them from other patterns such as those registered by WordPress core, and other third-party plugins:

register_block_pattern_category(
    'theme_blocks',
        array( 'label' => esc_html__( 'Theme Blocks', 'theme-blocks' ) )
);

Now we can start adding our patterns with the `register_block_pattern` function. The parameters for this function are the pattern name as a string, and an array of properties to be associated with the pattern. This array comprises a title, content, description, categories, keywords and viewport width. Putting this together, a simple pattern can be registered like this:

register_block_pattern(
    'theme-blocks/pattern-name',
        array(
            'title'         => esc_html__( 'Pattern Title', 'theme-blocks' ),
                'categories'    => array( 'theme-blocks' ),
                'viewportWidth' => 1024,
                'description'   => esc_html_x( 'A description of what is in the pattern', 'Block pattern description', 'theme-blocks' ),
                'content'       => '<!-- wp:columns ... -->'
        )
);

Most of what we’re doing here is self-explanatory, however the content property may look less familiar. This property contains the raw HTML content for the pattern. What we add here follows the same convention as template parts.

Getting real

It’s easier to think about what this contains if we work with a real pattern, so let’s take Twenty Twenty One’s Overlapping Images pattern. The content looks like this:

<!-- wp:columns {"verticalAlignment":"center","align":"wide","className":"is-style-twentytwentyone-columns-overlap"} -->
    <div class="wp-block-columns alignwide are-vertically-aligned-center is-style-twentytwentyone-columns-overlap">
            <!-- wp:column {"verticalAlignment":"center"} -->
                <div class="wp-block-column is-vertically-aligned-center">
                            <!-- wp:image {"align":"full","sizeSlug":"full"} -->
                                    <figure class="wp-block-image alignfull size-full">
                                            <img src="' . esc_url( get_template_directory_uri() ) . '/assets/images/roses-tremieres-hollyhocks-1884.jpg" alt="' . esc_attr__( '“Roses Tremieres” by Berthe Morisot', 'tt1-blocks' ) . '"/>
                                        </figure>
                                <!-- /wp:image -->
                                <!-- wp:spacer -->
                                    <div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>
                                <!-- /wp:spacer -->
                                <!-- wp:image {"align":"full","sizeSlug":"full"} -->
                                    <figure class="wp-block-image alignfull size-full">
                                            <img src="' . esc_url( get_template_directory_uri() ) . '/assets/images/in-the-bois-de-boulogne.jpg" alt="' . esc_attr__( '“In the Bois de Boulogne” by Berthe Morisot', 'tt1-blocks' ) . '"/>
                                        </figure>
                                <!-- /wp:image -->
                        </div>
                <!-- /wp:column -->
                <!-- wp:column {"verticalAlignment":"center"} -->
                    <div class="wp-block-column is-vertically-aligned-center">
                            <!-- wp:spacer -->
                            <div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>
                            <!-- /wp:spacer -->
                            <!-- wp:image {"align":"full",sizeSlug":"full"} -->
                                <figure class="wp-block-image alignfull size-full">
                                        <img src="' . esc_url( get_template_directory_uri() ) . '/assets/images/young-woman-in-mauve.jpg" alt="' . esc_attr__( '“Young Woman in Mauve” by Berthe Morisot', 'tt1-blocks' ) . '"/>
                                    </figure>
                            <!-- /wp:image -->
                    </div>
            <!-- /wp:column -->
    </div>
<!-- /wp:columns -->

To ease readability, we have added line breaks and indentation, but it’s worth noting that as this is ultimately just a string, when we come to registering our pattern, we can paste it in as a long line of text.

What we can see in this block is a mix of regular HTML, with the Block Editor’s pseudo HTML expressed as comments. Boiling it down, this markup contains two columns, with each one containing an image and some stylistic spacing. The images used here are just placeholders that can be modified by users in the editor, but it’s worth noting that any placeholder images used in a pattern must also be included in the theme assets.

You may note that in the markup above, it’s not entirely clear where the magic that makes these columns overlap occurs. This is achieved via a block style, and applied using the is-style-twentytwentyone-columns-overlap class.

Putting it all together

With all of this in place, here’s how we can now interact with our pattern in the site editor.

As you can see, we can find it by searching for “overlap” in the block editor. We can also browse all of our patterns in the block browser which is accessed by clicking “browse all” when selecting a block in the inline editor.

Why should I use patterns?

Hopefully this has helped you gain some understanding of what patterns are and how they work. Don’t worry if you’re still a little confused. There’s a lot to take in here and it’s something that makes more sense once you start making patterns. However, you may still be wondering why we’re talking about this and what the advantages are of using patterns.

Patterns are very helpful when users are trying to create more advanced layouts that have a greater sense of art direction than WordPress has traditionally provided. They’re a great way of breaking the monotony that can set in with long-form content, as well as helping users break the sense of creative block that is often felt when confronted with a blank page. As you can see in the patterns included with Twenty Twenty One, users have easy access to more versatile and visually interesting ways of presenting their content.

Next steps

To help consolidate your understanding, check out the full implementation of Twenty Twenty One’s patterns in the experimental block-based version of the theme.

Getting Started with Block Themes: Global Styles

Global Styles is a new mechanism for a theme to define a site’s styles. An important goal of Global Styles is to make it easier for users to change how their site looks without having to know or write any CSS.  These theme styles are defined via a json configuration file.  Importantly, it opens the way for users to modify those settings themselves in the Global Style Editor. 

Here you can find an empty theme JSON file to check out.  There’s a “Global” object with a “settings” block and a “styles” block.  You’ll find plenty of details about this JSON file here in the Gutenberg docs. Remember, work is ongoing so those details will change and grow. Q has built this very handy tool to get started with some generated JSON and get a head start on building your own theme.

Let’s take a look at some of those settings.

Global Settings

An important thing that we define at the global level is the palette of a theme. These are the colors that will be used throughout.
This will be in our settings portion of the JSON in the global.settings.color.palette collection and looks like this.

{“global”: { “settings”: {
	"color": {
		"palette": [
			{
				"slug": "blue",
				"color": "#0000FF",
				"name": "Blue"
			}
			…

With that defined there’s now a CSS variable –wp–preset–color–blue to be used throughout the theme.  And since it’s defined at the :root level you can use it throughout your theme’s JSON and CSS.  

This portion of the docs outlines the details of how that gets translated from JSON objects to CSS variable names. It follows the –wp-preset–{category}–{slug} pattern. 

And all of the colors in that palette are now at the disposal of users to apply across any block that supports colors.

A quick note regarding naming conventions:

It creates an easier time for users when switching themes if the palette names are descriptive of what they ARE rather than what they are FOR.  For instance “light-blue” or “canary-yellow” is more helpful than “secondary” or “accent”. 

This is because when users switch themes, if a palette color that they have chosen has the same name in the new theme then that palette color will still be used.   So if they picked a blue color, but it was labeled “secondary” and the new theme has a “secondary” color that is actually orange then suddenly something is orange that used to be blue and the poor user is very confused as to why. 

Whereas if they choose a color labeled “light-blue” and switch to another theme where there is also a “light-blue” palette color (even if it is a slightly different shade of blue) then their choice of color holds and is less likely to be confused about the color of their elements.

This also holds true for font size names: ‘small’ and ‘normal’ are a cleaner choice than ‘primary’ and ‘secondary’.

Global Styles

With this palette in hand you can associate those colors to your site at the global level or per-block to get the theme styled right.  Looking toward the styles portion of the configuration we can adjust what colors we use for things like the background.  This setting for global.styles.color.background shows us how to leverage the color value we just created:

{“global”:{
	"styles": {
	    	"color": {
			"background": "var(--wp--preset--color--blue)"
		}
	}
	…

There are a lot more important things like typography that we can use these global styles and settings for (and even some custom values) and I’ll mention more below. But for now let’s go a little deeper…

Block Styles

Now we can get extra fancy.  The above showed us settings at a global level.  But using JSON we can now also assign these styles to blocks, simply by targeting the block’s ‘context’ instead of ‘global’ context:

…
“core/heading/h1”:{
	"styles": {
	    	"color": {
			"background": "var(--wp--preset--color--blue)"
		}
	}
	…

These values are rendered into CSS which applies that style to every h1 element.

h1 {
	background-color: var(--wp--preset--color--blue);
}

Though for some blocks these values are rendered into a class which is applied to blocks of that type.  For instance, Gutenberg turns the configuration for a “core/site-title” into:

.wp-block-site-title {
	background-color: var(--wp--preset--color--blue);
}

And should a user want to customize that further…

User Block Styles with the Global Style Editor

And finally the Global Style Editor in the Full Site Editor can be used to customize aspects of a block at the site level.  These values will supersede whatever is set in the theme’s JSON. 

Here a user is changing the Site Title’s background style via the Global Styles Editor.

Typography

Just like colors, defining typography for a theme has moved from the realm of PHP to some simple configuration.

Adding some objects to global.settings.typography.fontSizes looks like this:

{“global”: { “settings”: { “typography”: {
	"fontSizes": [
		{
			"slug": "small",
			"size": "15px",
			"name": "Small"
		},
	]
	…

And just like colors, defining the font sizes for the theme in this way will give users access to these same values in the editor. This makes it easier for them to reuse the sizes the theme designer defines. 

Font families can be defined in the same way:

{“global”: { “settings”: { “typography”: {
	"fontFamilies": [
		{
			"fontFamily": "sans-serif",
			"slug": "noserifsplease",
			"name": "Sans"
		}
	]
	…

Of course for non-system fonts you’ll also need to load the fonts.  This can still be done in the function.php file with wp_enqueue_style and should seem familiar.

…
wp_enqueue_style( 'mytheme-fonts', 'https://url/for/font-face/definitions' , array(), null );
…

Or include the font face in your style.css

@font-face {
  font-family: 'Epilogue';
  font-style: normal;
  font-weight: 300;
  src: url(https://url/for/font-file.woff) format('woff');
}

Now that the font is loaded it can be used in the theme.json file:

{“global”: { “settings”: { “typography”: {
	"fontFamilies": [
		{
			"fontFamily": "\”Epilogue\”, sans-serif",
			"slug": "epilogue",
			"name": "Epilogue"
		}
	]
	…

And now these font values can be leveraged either at the global level or at the block level in your configuration, crafting the look and style of the theme:

{“global”:{ 
	"styles": { 
		"typography": {
			"fontSize": "var(--wp--preset--font-size--normal)"
			“fontFamily”: “Epilogue”
			…

…
“core/site-title”:{ 
	"styles": {
		"typography": {
			"fontSize": "var(--wp--preset--font-size--normal)"
			“fontFamily”: “Epilogue”
			…

CSS

Not all styles can be expressed in the theme JSON. In time we hope that all common styles will be available, but there will always be some things that will only live in CSS (like animations). 

The theme’s style.css file will continue to be available as a way to express the style of a block-based theme.  Blocks can continue to be styled in CSS with classes.  But now you can use all of the swatches defined in your theme JSON throughout.  You can even define custom values like a global vertical spacer value.

Theme JSON
{“global”: { “settings”: { “custom”: {
	“spacing”: {
		“vertical”: “20px”
		…
Theme CSS
.wp-block-of-some-kind {
	padding-top: var(--wp--custom--spacing--vertical);
	…

Buy Why?

Defining styles in this way has some important advantages.  

JSON configuration is more accessible than writing PHP code and CSS.  There’s less to understand, less to type and less to potentially mess up.  This doesn’t “re-invent CSS as JSON” and the concepts of CSS certainly don’t go away because of this new tooling.  Nor will PHP.  But key concepts present in every WordPress theme can be expressed simply and in ways that can be leveraged in more ways than CSS alone.  This will make Theme development a simpler and faster process.

But perhaps one of the most important aspects of this new Global Styles system is the power it puts in the hands of people USING a Theme.  By using a Theme as a starting place and providing the tools to tweak things to suit their needs, without custom CSS and in a visually clear way is incredibly powerful.  This makes ALL themes leveraging these tools immediately more powerful.

Creating a Block-based Landing Page Theme

Kjell Reigstad details how to build a single-page block-based theme.

The other day, my colleague Ian Stewart and I were discussing homepage templates, and this Carrd layout came up in conversation:

Layout from Carrd.co

Its two-column design is friendly and simple. It’s also drastically different than most WordPress themes we see these days — it doesn’t have a traditional header and footer, or even a menu for that matter. It really doesn’t look like a WordPress site (partly because it isn’t. 😄).

It does however look like a relatively simple pattern that could be built with Gutenberg blocks. With block-based themes on the horizon, Ian suggested I see how easy it would be to build a block-based theme featuring a similar homepage layout. I took him up on the challenge.

In about an hour, I had a fully functional version of the theme. Read on for details on how it all came together.


The Structure

The first thing I did was set up the basic theme files, and get them all hooked up to each other. Most of the theme files are more or less boilerplate — aside from a little CSS and some experimental-theme.json value changes, they aren’t going to change much from theme to theme. Here’s how that looked:

- assets
 	- (font files)
- block-templates
 	- index.html
- experimental-theme.json
- functions.php
- index.php
- style.css
- style-shared.css

HTML

  • block-templates/index.html was left empty to start with. As explained below, I populated this using Gutenberg.

JSON

PHP Files

  • index.php is empty, but needs to be there.
  • functions.php contains a standard function to enqueue the stylesheet. Aside from that, it just sets some theme options. Since this is an experimental block-based theme, I opted-in to just about all of the experimental options from the Block Editor handbook.

Stylesheets

  • style.css is enqueued only on the front-end. It includes a standard theme header docblock, plus barebones alignment styles, courtesy of Ari Stathopoulos. These styles just replicate the editor alignment rules from Gutenberg (standard, wide, and full) in the front-end. Hopefully Gutenberg can provide these styles one day, eliminating the need for this standalone CSS file.
  • style-shared.css houses the basic font and color rules, plus just a few theme-specific spacing overrides. This is loaded in both the editor and the front-end.

Building the Front Page Template

Once I had those files in place, I was ready to build the block template in block-templates/index.html.

First, I installed and activated my theme. With the empty HTML file created, I opened up the site editor, and was presented with a blank slate:

The Gutenberg site editor, with no content.

From here, I added a full-width columns block. On the left, I used a Cover block and uploaded my image. I used a columns block because I wanted to take advantage of two great Cover block features: its ability to take up the full height of the screen, and also its focal point picker which would ensure that the image is always centered on the model’s face.

The Gutenberg site editor with a cover block inserted into the left two thirds of the screen.

After that, I added a few center-aligned blocks to the right column: Site Title and Site Tagline blocks, a Button block, and a Social Links block:

The Gutenberg site editor with a Cover block on the left side, and a site title, description, button, and a set of social links on the right.

From there, I hit “Update Design” and used the Gutenberg plugin’s “Export” tool to download a zip file containing this template:

The "Export" option in the Gutenberg Plugin.

The resulting zip file included an index.html file containing the block markup I had just built. I replaced my empty block-templates/index.html file with this new one, and I had a fully functional single-page block-based theme! 🎉


Viewing the Final Result

The only thing left to do was check out the site in the front end. I was pleased with how similar everything looked to the editor, and how the whole layout was responsive by default.


This exercise made me truly excited about the future of theming. It took very little time to assemble the boilerplate necessary to get started, and I constructed most of the theme the editor itself. I imagine whole process will only get faster (and the boilerplate will be whittled down further) as full-site editing progresses.

The theme is available to test by visiting the Theme Experiments repository. There, you’ll find this as well as other themes like the new block-based version of Twenty Twenty-One.

For more in-depth details on building a block-based theme, visit the official tutorial in the Block Editor Handbook.