Building Custom Gutenberg Blocks with ACF: My Go-To Approach in 2026
Advanced Custom Fields makes custom block development accessible without deep React knowledge. Here's the pattern I use on every project that needs bespoke Gutenberg blocks.
Topics covered
- ACF block registration
- Block templates with PHP
- InnerBlocks for flexible content
- Preview mode and editorial UX
Why ACF Blocks Instead of Native React Blocks
Native Gutenberg block development requires React, build tooling, and a working knowledge of the block editor's JavaScript API. For agencies and freelancers building bespoke client sites, this overhead often isn't justified — particularly when the client needs five or six custom content blocks, not a plugin distributed on WordPress.org. ACF's block API lets you define blocks with PHP and a template file, with ACF fields providing the editing interface. The result is a proper Gutenberg block — draggable, previewable, fully integrated with the editor — built in the time it would take to set up a React block's build configuration.
Registering the Block
Block registration happens in functions.php or a dedicated blocks.php file included from it. You call acf_register_block_type() with an array of arguments: name, title, description, render_template or render_callback, category, icon, keywords, and supports. I use render_template pointing to a PHP template file in a /blocks/ directory — this keeps block templates separate from the rest of the theme and easy to find. The supports array is worth spending time on: enabling align, anchor, and jsx where appropriate gives editors more control without extra development work.
Building the Template
The template file receives $block, $content, $is_preview, and $post_id as variables. ACF fields are retrieved with get_field() exactly as they are on any other template. The key habit is wrapping all output in proper semantic HTML with the block's className applied — generated by get_block_wrapper_attributes() — so editor-side styling via theme.json applies correctly. I always add a block-specific wrapper class too, so individual blocks can be styled independently without specificity battles.
Using InnerBlocks for Flexible Content Areas
InnerBlocks is the ACF/Gutenberg mechanism for allowing editors to insert other blocks inside your custom block — essential for cards, columns, tabs, or any block that needs a flexible content area. In an ACF render template, you output the InnerBlocks placeholder with echo '<InnerBlocks />'. You can restrict which block types are allowed inside using the allowedBlocks attribute, and define a default template that pre-populates the inner area with a sensible starting structure. This is more powerful than a fixed set of ACF repeater fields for layouts where editors need to vary the content structure.
Preview Mode and Editorial UX
One thing many ACF block implementations get wrong is the preview experience. By default, some blocks render as a blank area in the editor until the user clicks into them. Using $is_preview — the variable passed to your template — you can return a simplified but representative preview of the block when $is_preview is true, giving editors a clear visual indication of what the block will look like without needing to publish or preview the page. This is a small detail that makes a significant difference to how clients experience the editing interface.
When to Move to Native Blocks
ACF blocks are the right tool for site-specific custom blocks that won't be distributed as plugins. When you're building a block that will be packaged as a standalone plugin, reused across many projects with full controls in the inspector sidebar, or needs complex interactivity at the editor level — native React blocks are the better choice. The complexity is justified when the block genuinely needs it. For most agency WordPress projects, ACF blocks deliver 90% of the result at 30% of the development time.
Written by Manan Vyas
Senior WordPress Developer · Manchester, UK