JI
Skip to content
All posts
WordPressJune 18, 2026·8 min read

Building Gutenberg blocks that last

The block editor moves fast. Here's how I structure custom blocks so they survive a year of WordPress core updates without a rewrite.

Every WordPress release nudges the block editor forward. Blocks written against internal APIs age badly — they break on the next major. After shipping blocks for commercial plugins, I've settled on a few rules that keep them alive across updates.

Register with block.json

Metadata-driven registration is the single biggest win. Declare attributes, supports, and assets in block.json and let WordPress wire them up. Core reads the same file for the editor and the front end, so you stop duplicating config.

{
  "apiVersion": 3,
  "name": "portfolio/callout",
  "title": "Callout",
  "category": "widgets",
  "attributes": {
    "message": { "type": "string", "source": "html", "selector": "p" }
  },
  "supports": { "html": false, "spacing": { "padding": true } }
}

Lean on supports, not custom UI

Before you build a color picker or spacing control, check whether a supports flag already gives it to you. Core-provided controls inherit theme.json settings, respect global styles, and keep working when the design system changes underneath you.

Rules I don't break

  • Use apiVersion 3 and the @wordpress/scripts build — never hand-roll the JSX transform.
  • Store markup with attribute sources so content survives a validation error.
  • Add a deprecation entry before you change saved markup, not after users complain.
  • Import from @wordpress/* packages only; reaching into internals is how blocks break.

Do this and a block written today still validates two years and six core releases later. That reliability is the whole point.