Skip to content
Start a Mission

Building Custom Gutenberg Blocks That Editors Actually Love

Our approach to building custom WordPress blocks: when to build one, static versus dynamic rendering, block.json, attributes, testing and the editor experience.

Building Custom Gutenberg Blocks That Editors Actually Love

Core blocks cover a lot. Paragraphs, images, columns, groups and the Query Loop can produce most layouts. But every serious WordPress build eventually needs something core does not provide: an event card pulled from an API, a pricing table tied to a product, a faceted directory, or a branded callout that must look identical on every page. That is where custom blocks come in.

We have built a lot of custom blocks for publishers, retailers, schools and public agencies. Here is the process we follow.

First, decide whether you need a block at all

Before writing code, we ask three questions. Can a pattern of core blocks do this? Can a block style or a block variation do it? Does the data belong in a custom field instead? A variation of the Query Loop, for example, can deliver a styled list of upcoming events with no custom JavaScript. Only when the answer to all three is no do we build a new block.

Start from block.json

Every block we ship has a block.json file. It declares the name, title, category, icon, attributes, supports and asset files. WordPress uses it to register the block on the server and in the editor, and to load scripts and styles only when the block is on the page. We scaffold new blocks with the official @wordpress/create-block package so build tooling is consistent across projects.

Static or dynamic rendering

A static block saves its HTML into post content when you click save. A dynamic block saves only its attributes and renders HTML in PHP each time the page loads. Our rule of thumb:

  • Use static blocks for presentational content that rarely changes, like a callout or a stat row
  • Use dynamic blocks when output depends on other data, such as the latest posts, prices, an external API or the current user
  • Use dynamic blocks when you expect the markup to evolve, because changing a static block's markup requires deprecations

Dynamic blocks avoid the familiar "unexpected or invalid content" warning after a redesign, which alone makes them the right default for many enterprise builds.

Design the attributes carefully

Attributes are the block's data model. Keep them few and meaningful. Store IDs instead of full objects, and look the object up at render time so it never goes stale. Use the supports API for spacing, color and typography so editors get familiar controls and values flow from theme.json rather than hard coded options.

Build a great editor experience

Editors judge a block by how it feels in the editor. We aim for a preview that matches the front end, inline editing with RichText where text appears, and only essential controls in the sidebar. Placeholder states explain what to do. If a block needs an API key or a selection, it says so plainly instead of rendering an empty box.

We also use InnerBlocks generously. A card block that accepts a heading, paragraph and button as inner blocks is more flexible than one with three hard coded fields, and you can still lock the template so the structure stays intact.

Interactivity without heavy JavaScript

For front end behavior such as tabs, accordions, filters and load more buttons, the Interactivity API in core gives blocks a shared, lightweight way to add state and events. It renders on the server first, so content is visible and indexable before any script runs. We reach for it before adding a framework to a single block.

Test and version

Custom blocks get unit tests for transformation logic, end to end tests for the editor flow and visual checks on the front end. When static markup must change, we write deprecations so older content still validates. Blocks live in a plugin, not the theme, so they survive a redesign.

Server side rendering and caching

Dynamic blocks render in PHP on every request, so expensive work inside a render callback can slow a page. We treat render callbacks like any other performance sensitive code. Results that depend on slow queries or external APIs are cached in the object cache with keys that include the block attributes, and invalidated when the underlying content changes. Blocks that show the same output to every visitor work perfectly with full page caching, while blocks that personalize for logged in users are designed so the rest of the page can still be cached. We also keep markup lean: no wrapper divs without purpose, no inline styles that the supports API could handle, and no scripts loaded unless the block needs interactivity. The result is a block library that editors can use freely without anyone worrying that adding a few more blocks will make the page sluggish.

Custom block checklist

  • Confirm a pattern, style or variation cannot do the job
  • Scaffold with create-block and register through block.json
  • Choose static or dynamic rendering deliberately
  • Keep attributes minimal and use supports for design controls
  • Match the editor preview to the front end
  • Escape all output in render callbacks
  • Ship in a plugin with tests and deprecations

Real examples

The instant faceted search on Visit Mercer County and many interactive pieces in our case studies are built on this approach, so editors can place them anywhere while the data stays live.

Frequently asked questions

Do custom blocks slow down a site?

Not when built correctly. With block.json, assets load only on pages that use the block, and dynamic output can be cached like any other.

Can editors break a custom block?

Locking, sensible defaults and validation make that hard. Dynamic blocks are also more forgiving because the HTML is generated fresh.

Can you convert our shortcodes to blocks?

Yes. We build blocks with transforms so existing shortcodes can be converted in the editor or in bulk with a script.

Need custom blocks for your team? Talk to our WordPress development group or request a quote.

Brian Messenlehner

Written by

Brian Messenlehner

Founder of AlphaWeb and owner of AppPresser. A former U.S. Marine Corps Sergeant and computer programmer, Brian has more than 25 years of experience leading software teams and co-wrote Building Web Apps with WordPress for O'Reilly.

Currently booking projects

Ready to start your mission?

Tell us what you are building. A veteran-owned team of WordPress specialists will scope it, plan it and ship it.