Render a dynamic Gutenberg Block with Twig and Timber
Recently, I decided to delve into the "new" Gutenberg editor of WordPress to finally adopt it and offer a better editing experience to my clients. This epiphany came when I watched the case study videos by 10up about the development of the White House website.
Finally, I realized that Gutenberg was not just a tedious assembly of atomic components that were laborious to evolve and maintain. Instead, it could be used to produce broader components like site sections, cards, page layouts, and more.
Initially confused by the data model used to save blocks in the database and its fragility when modifying existing blocks, I discovered that by using the dynamic variant of blocks, it's possible to make rendering changes site-wide by modifying associated templates without having to edit each page individually.
The Benefits of Gutenberg
The advantage of this solution is clear compared to using ACF and its flexible field: the client can simply click on the elements they want to edit on the page and see the result live – a true WYSIWYG in its purest sense.
ACF does allow for the creation of server-side rendered blocks in the admin. However, I find this solution less ideal due to the difference in user experience for the end client between editing content directly where it appears on the page versus using fields in the editor's sidebar, along with the associated loading times due to the use of the WordPress API for client-server communication in rendering these blocks.
However, even though using Gutenberg this way is great for usability, I was somewhat put off by the development of its blocks during my initial experiments.
Indeed, to produce a result as high-quality as that of the White House website mentioned earlier, you first need to develop the component once with React for editing in the editor, and then a second time in PHP for front-end rendering.
PHP? What about my Twig templates? What about template reuse?
WordPress Theme Development with Timber and Twig
Timber is a module that allows the use of Twig with WordPress. It enables a clear separation between logic (fetching posts with WP_Query, custom functionalities, etc.) and front-end display, thus aligning with an MVC-like architecture.
Since I started using it 5 years ago, I have developed all my WordPress themes with it and even transitioned some of my agency clients to use it, given the superior development experience compared to the basic PHP templates often scattered with logic snippets that are difficult to maintain over time.
Initially used as a rendering engine for Symfony projects and then adopted by Drupal, Twig allows for great flexibility in front-end development by facilitating layout reuse, the creation of components cherished by front-end developers, and generally practices that have become standards across all technologies.
Using Timber and Twig with Gutenberg
Wanting to maintain my good development practices and an ecosystem I am well-acquainted with, I sought a way to develop custom and dynamic Gutenberg blocks with a Twig rendering engine.
By digging into the core code of WordPress and Gutenberg, I found this solution that integrates perfectly with my use of Timber:
add_filter('block_type_metadata_settings', function ($settings, $metadata) {
if (! empty($metadata['render'])) {
$template_path = wp_normalize_path(
realpath(
dirname($metadata['file']) . '/' .
remove_block_asset_path_prefix($metadata['render'])
)
);
if (str_ends_with($template_path, '.twig')) {
$settings['render_callback'] = function ($attributes, $content, $block) use ($template_path) {
$content = Timber::compile($template_path, [
'attributes' => $attributes,
'content' => $content,
'block' => $block,
]);
return $content;
};
};
};
return $settings;
}, 10, 2);
This piece of code is based on the block metadata defined in their block.json
file, the recommended method by WordPress for declaring blocks.
One of the entries in this file allows specifying the template to use for rendering, in most cases "render": "file:./render.php"
.
For my blocks, I simply change this line to "render": "file:./render.twig"
. The above code thus recognizes the use of a Twig template, modifying the block's render_callback to compile its rendering template with Twig using the Timber::compile method.
In practice, I can now render in Twig using the same methods defined in PHP, utilizing attributes, InnerBlocks, wrapper functions, etc.
<section {{
function(
'get_block_wrapper_attributes',
{
class: 'alignfull p-8'
}
)
}}>
<p class="text-2xl font-semibold">
{{ attributes.content }}
</p>
</section>
My Starter Project for Gutenberg Theme Development with Twig and TailwindCSS
As you may have noticed, I use TailwindCSS classes in my Twig templates. Another technology I haven't left since its discovery, I integrated it into my base theme to enable faster development without having to worry about different style files for front-end and editor with Gutenberg.
Since my needs are quite custom and go beyond what is natively possible with WordPress, I had to write a custom webpack configuration rather than using @wordpress/scripts
to compile my blocks, their templates, and their assets.
Given that setting this up was tedious, I decided to create a public starter theme that can be used as an open-source template.
You can find it at this address on GitHub
In addition to Twig rendering for blocks, it includes other features to further modernize WordPress theme development:
- Use of TailwindCSS for styling
- Use of Timber and Twig for template rendering
- Use of dependency injection and classes for organizing theme functionalities
- Addition of services for easy creation of new Custom Post Types and Menus
- Use of Symfony’s error handling component
- Creation of customized blocks using Twig with the
@wordpress/create-block
CLI and a local template
I have had the opportunity to use this stack professionally, and it provides a development velocity comparable to developing themes with the classic editor, with the added benefit of offering my clients an unparalleled editing experience.
I hope this template will finally convince you to switch to (or at least give a second chance to) Gutenberg while maintaining the good practices we’ve built over the years of development and evolution of WordPress.