Building a WordPress theme with Gutenberg

Many of the articles I’ve shared recently describe specific features in the Gutenberg block editor and the Genesis theme framework.

I think it would be helpful to take a step back and walk you through my process of building a custom WordPress theme from start to finish. I encourage you to also review my Developer’s Guide to Gutenberg.

I focus on a recent Genesis child theme I built for Her Packing List, but the process applies to any WordPress theme.

In this article:

  1. Start with design
  2. Style Guide
  3. Custom blocks
  4. Gutenberg specific styling
  5. Finish building the base template
  6. Archives
  7. Block Areas
  8. Modular Template

Start with design

Gutenberg has accelerated a change in the way we design and build themes. We still use a three phase process of Discovery, Design and Development, but we now think in more modular terms.

Rather than designing in pages, with each page often being a unique template with its own styling and metaboxes, we design in blocks and assemble the pages using these blocks.

We actually used a modular design approach before Gutenberg, but were constrained on the development side by the classic editor. Our designs used reusable components, but these were often managed with metaboxes and shortcodes. Now with Gutenberg our modular design can be implemented with core and custom blocks.

It’s crucial to work with a designer who understands the Gutenberg block editor. My two design partners, Duane Smith and Andrew Pautler, create incredible web experiences both through their design expertise and by enabling our clients to fully use the features of WordPress.

Thank you! I am just blown away at how well everything is thought through in your development! I LOVE it!

avatarRobyn Stone
Add a Pinch

I won’t go into any more detail on our design process, but I think it’s important to note that a key factor in building an easy-to-manage website is starting with a design that was built for the block editor, rather than trying to squeeze a custom design into the block editor.

Style Guide

After I’ve set up my development environment and download a fresh copy of my starter theme, I start development by building out the Style Guide.

The above is just a sampling from the style guide. Here’s the full style guide: desktop | tablet | mobile.

First I update my _base.scss SASS file with brand colors, Gutenberg color options, grid width, and breakpoints. Here’s the _base.scss file for Her Packing List.

I review the core blocks to see which will need additional block styles. This site had quite a few – underline and fancy styles for headings, arrow and icon styles for lists, and more. Here’s the editor.js file for this project.

In the content editor I build the Style Guide page with all the content from the mockup, up until the “Custom Gutenberg Blocks” section. Then I write the CSS in _blocks.scss so the Style Guide matches the mockup.

Custom Blocks

I build all of my custom blocks using ACF. I avoid using block library plugins like Atomic Blocks and CoBlocks because they contain many blocks that we don’t need, and the ones we would use often allow customizing the styling (ex: specify padding for each block).

I don’t want content creators to worry about design. They should focus on content creation and let the theme handle the styling. ACF makes it incredibly easy to quickly build custom blocks with minimal options, keeping the interface as simple as possible for content creators.

Before I start coding, I review the visual and technical requirements for each custom block and determine how I’ll build it.

The above is just a sampling from the style guide. Here’s the full style guide: desktop | tablet | mobile.

  • Social Media Share Buttons will be implemented with Shared Counts. I’m not actually building a custom block for this since they will automatically be added to the end of every post by Shared Counts. I just have to style them to match the design.
  • Social Media Share Links will be an ACF block with no options. It will pull social links from Yoast SEO.
  • Pinterest CTA will be an ACF block with two image upload fields.
  • Email Subscribe CTA will be a WPForms block with some CSS.
  • HPL World CTA will be an ACF block with no options.
  • Email Contact Form is WPForms.
  • Product Listing is an ACF block with a title and repeatable field for products. Each product has a name, image, URL, and price.
  • Quick Links is an ACF block with a repeatable field for links.
  • Gear We Use and Travel Resources use the WP core group block with a background color set. They are saved as a reusable blocks since they are used on multiple pages.
  • Related Posts is an ACF block with no options. It will be used in the Single Post Block Area.
  • Next Stop is an ACF block with no options. The dropdowns are populated with terms from a custom taxonomy and take you to the term archive.
  • Fact Box is the WP core group block with a background color.

See my article Building a block with Advanced Custom Fields for information on building custom blocks. Also take a look at the sample code at the end of ACF with version control to see how I organize the ACF code in the theme.

Gutenberg Specific Styling

After ensuring all of the blocks match the design on the frontend, it’s a good idea to switch back to the Gutenberg block editor and make sure your blocks look the same there too.

The backend editor should match the frontend as close as possible so content editors have a good idea of how the page will look before publishing.

If you’re using SASS, it’s easy to generate an additional stylesheet with only the relevant block styles, then enqueue it as editor styles. My editor-style.scss loads:

  • _base.scss with my variables for colors
  • _blocks.scss with my block-specific styling
  • _gutenberg.scss for Gutenberg-only styling

WordPress loads some CSS only in Gutenberg that can alter the styling of your blocks. I use my Gutenberg-only partial for minor tweaks to get the backend blocks matching the frontend.

I also updated the post title to be white on a red background, and customized the sizes of wide and full blocks. Here’s my _gutenberg.scss for Her Packing List.

Finish building the base template

Now that the blocks in the content area are complete, I focus on everything that’s not in the block editor. This includes building out the site header, navigation menu, sidebar, and site footer.

Once the Style Guide is complete, I move over to the Single Post design and build out the additional post elements, like the comments and author box.

All of the elements after the author box are managed with the After Post Block Area, described in its own section below.

Genesis can now automatically add the featured image to the top of posts, and let writers disable it on a per-post basis. Add the following to your theme’s functions.php file:

add_post_type_support( 'post', 'genesis-singular-images' );

See the “Featured image output options” section of the Genesis 3.1 release notes for more information.

Archives

After building out all the singular content (Style Guide, Single Post, and individual pages), I move on to the dynamic archives.

My approach to archives is a bit different than most Genesis theme developers, but will be familiar to those building custom themes outside of Genesis.

What makes Genesis unique are its hooks and filters. These allow you to customize any aspect in Genesis, and insert your own elements wherever you’d like. Want to add something before the post title? Use the genesis_entry_header hook with a priority less than 10.

These same hooks run when a post is on an archive page, so any customizations you make need to be scoped with conditional tags (ex: is_single() ). If you’re using genesis_custom_loop() for related posts, you need to limit your customizations to the primary post on the page using if( get_the_ID() === get_queried_object_id() ).

Scoping your customizations is even more difficult if you use a modular design approach like we do. We’ll typically have a few different “post summary” styles used throughout the site, on the archive page, in a related posts section on a single post, and in custom “Post Listing” blocks on landing pages.

I prefer to remove the standard genesis loop (and all of its hooks) on archive pages and use template partials instead. I can then design the “post summary” styles as template partials and use them wherever they are needed.

On Her Packing List I built 3 different archive partials, found in /partials/ directory of the theme.

archive.php

echo '<article class="post-summary">';
	echo '<a class="entry-image-link" href="' . get_permalink() . '" tabindex="-1" aria-hidden="true">' . get_the_post_thumbnail( get_the_ID(), 'ea_archive' ) . '</a>';
	echo '<p class="post-summary__meta">' . ea_icon( array( 'icon' => 'chat-circles', 'size' => 16 ) ) . get_comments_number_text() . '</p>';
	echo '<h5 class="entry-title"><a href="' . get_permalink() . '">' . get_the_title() . '</a></h5>';
echo '</article>';

archive-related.php

echo '<article class="post-summary related">';
	echo '<a class="entry-image-link" href="' . get_permalink() . '" tabindex="-1" aria-hidden="true">' . get_the_post_thumbnail( get_the_ID(), 'ea_archive', array( 'class' => 'nopin' ) ) . '</a>';
    echo '<h3><a href="' . get_permalink() . '">' . get_the_title() . '</a></h3>';
echo '</article>';

archive-featured.php

echo '<article class="post-summary featured">';
	echo '<a class="entry-image-link" href="' . get_permalink() . '" tabindex="-1" aria-hidden="true">' . get_the_post_thumbnail( get_the_ID(), 'large' ) . '</a>';
    echo '<div class="post-summary__content">';
        echo '<h2 class="is-style-underline">Featured Post</h2>';
        echo '<h2 class="entry-title"><a href="' . get_permalink() . '">' . get_the_title() . '</a></h2>';
        the_excerpt();
        echo '<p class="post-summary__meta">' . ea_icon( array( 'icon' => 'chat-circles', 'size' => 16 ) ) . get_comments_number_text() . '</p>';
    echo '</div>';
echo '</article>';

In my archive.php template file, I made the first post on the page use the archive-featured.php partial with:

/**
 * Featured post partial
 *
 */
function ea_archive_featured_post( $context ) {
	global $wp_query;
	if( ! get_query_var( 'paged' ) && 0 === $wp_query->current_post )
		$context = 'featured';
	return $context;
}
add_filter( 'ea_loop_partial_context', 'ea_archive_featured_post' );

For more information on this approach, see Using Template Parts with Genesis.

Block Areas

Our sites often have repeated elements outside the content area, like related posts at the bottom of a single post.

You could hardcode these features into the template file, or create a widget area so your client can edit it.

We prefer creating Block Areas, which are like widget areas but use the block editor.

To include the “After Post” block area to our single posts, I added this to single.php:

/**
 * After Post modules
 *
 */
function ea_after_post_area() {
    if( function_exists( 'ea_block_area' ) )
	   ea_block_area()->show( 'after-post' );
}
add_action( 'genesis_after_entry', 'ea_after_post_area', 9 );

Block Area in Archives

We also provided the ability to insert block areas inside archive pages.

On certain categories, our client wanted to use the “Post Listing” block we created to list recent posts in subcategories of the current category. These would appear after the first (“featured”) post, and before the second post.

I edited the block_area post type registration to include categories and tags as supported taxonomies. Then on archive pages, I do a taxonomy query to see if any block areas have the current category, and if so I output the block area after the first post.

/**
 * Archive block area
 *
 */
function ea_archive_block_area() {

	if( get_query_var( 'paged' ) )
		return;

	global $wp_query;
	if( 1 !== $wp_query->current_post )
		return;

	$tax = is_category() ? 'category' : ( is_tag() ? 'post_tag' : false );
	if( ! $tax )
		return;

	$loop = new WP_Query( array(
		'post_type' => 'block_area',
		'posts_per_page' => 1,
		'tax_query' => array(
			array(
				'taxonomy' => $tax,
				'field'		=> 'term_id',
				'terms'		=> array( get_queried_object_id() )
			)
		)
	));

	if( $loop->have_posts() ): while( $loop->have_posts() ): $loop->the_post();
		echo '<div class="block-area archive-block-area">';
		the_content();
		echo '</div>';
	endwhile; endif; wp_reset_postdata();
}
add_action( 'genesis_before_entry', 'ea_archive_block_area' );

Modular Template

Her Packing List doesn’t include a modular template, but I’m including a note here because many of the sites we build do have them.

I think of Gutenberg as a “rich content builder”, but not a page builder or layout builder. It’s not a good tool for things like displaying content across multiple columns on a grid and adjusting that layout at different breakpoints.

I hope Gutenberg never becomes a full-on page builder because that will drastically increase the complexity of content editing. I’m a firm believer in the separation of content and design.

Some pages are too difficult to implement directly in the Gutenberg block editor. On the sites we build, these are often homepages, landing pages, and category landing pages.

I create a modules.php page template that disables the editor, then loads an ACF metabox with a Flexible Content field. We’ll design and build a dozen or so modules. For more information, see Landing Pages with ACF Flexible Content.

During our discovery and design process we identify the types of blocks/modules needed and their overall complexity. We try to use blocks for everything if possible, like we did with Her Packing List.

If the elements reach a certain level of complexity, we’ll work with our client to either scale back the complexity to something manageable with blocks, or start separating elements into blocks and modules.

The downside to modules is you lose the flexibility and visual editing of a block editor, but it can greatly simplify the content creation process on complex pages.

This is a conversation we have with the client during discovery and design. Our goal is to make their site as easy and enjoyable to manage as possible, so they should be involved in deciding how we build these features.

Bill Erickson

Bill Erickson is a freelance WordPress developer and a contributing developer to the Genesis framework. For the past 14 years he has worked with attorneys, publishers, corporations, and non-profits, building custom websites tailored to their needs and goals.

Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk

Reader Interactions

Comments

  1. Patrick B says

    Fantastic article. I’ve been able to take a lot from it that will improve my workflow. Are you preferring your custom block areas to reusable blocks in widget areas because it’s a nicer unified experience and with this change over have you stopped using widget areas all together? Now that I have been building more all block based sites I find myself annoyed at the widget area for presenting a complete different editing and layout experience for clients.

    • Bill Erickson says

      We still use Reusable Blocks for elements that are reused within the post content, like the listing of practice areas on this homepage and practice areas page.

      I tend to use block areas as a replacement for things I would have used a widget area for in the past (ex: After Post).

      The next phase for Gutenberg is to move navigation menus and widget areas into the block editor, so at some point this functionality will be in core. But for now, I’m with you and think the widget area UI is dated and less usable, so I rarely use it.

      • Patrick B says

        Thanks for the response Bill. That’s what I thought. I’ve been waiting for me details about how the new menu and widget area will work. I’m looking forward to that implementation to bring these various experiences inline. I will definitely use the approach you outline in my next project, hopefuly it will make transitioning easier.

  2. Jane James says

    Hi Bill. This blog has blown my mind and is very different to other ways of wordpress development I have seen. Will you be releasing a course on Udemy on wordpress development with Gutenberg?
    I have done several courses there, as well as WP Shout but they are all old school WP dev and I have never seen anyone teach WP dev specifically around Gutenberg.

    I must need the ‘step back from the step back’ article because whilst I have used ACF and CPTUI I have no idea about where to start developing for blocks.

    Thanks for your post.

  3. Matt says

    I’m trying to build a hero block editor in Gutenberg as a method of replacing some poor work a vendor has done.

    I’m using ACF within the Gutenberg hero block, and that seems fine, but my issue is that I’m trying to use it outside the content area (like most heros), so I’m hooking into a hero function that renders on a page template. If the new Gutenberg hero is present, the page renders that; if not it renders the previous hero version.

    The problem is, however, I don’t know how to render in the header exclusively since Gutenberg wants to render the hero in the content area. I can’t get it via a function other than render_block() which, of course, will render in both areas (header and content).

    I feel like I’m missing something basic here. Any ideas?

    • Bill Erickson says

      I can’t think of a good solution to that. Gutenberg is currently designed for managing the content in the content area. There are proposals to expand Gutenberg beyond the content editor for full site management, but nothing has been done there yet.

      I think the best approach is a custom metabox for managing the data that appears in the header.

  4. Hans Schuijff says

    Great help, Bill, thanks. I’m on the brink of building a new genesis childtheme, so I can try your approach and tips out.

    What perhaps most impresses is the blazing speed in which your pages reach me recently. So fast, as if the website is lean and local to my machine. Impressive. Is that just WPEngines combined with good programming, or is there some other (and perhaps more expensive) magic involved? Just curious off course. We should all thrive to be as fast. Very impressive!

    Cheers, Hans

    • Bill Erickson says

      WPEngine helps, but it’s mostly keeping my code as lean as possible.

      Up until a few weeks ago my site was Native AMP, and implementing that meant keeping CSS to <50kb and no JavaScript.

      I recently switched it to Transitional AMP (AMP only for mobile SERPs) because I realized some old code snippets still used embedded scripts from GitHub which didn't load in AMP. But I kept my CSS as lean as possible and only load a few lines of JS.

      I don't have anything fancy under the hood. I'm on the standard WPEngine hosting plan and using WP Rocket for additional caching. I'd actually like to make it load a bit faster by using a CDN for assets, but that requires me purchasing a wildcard SSL certificate - it won't work with the free Let's Encrypt one I have, and I've been too cheap to sign up for that yet 🙂

Leave A Reply