Choosing Dynamic Blocks (part one)

Note: This post is a little different than what we normally post here; it contains details of the inner workings of Gutenberg. The information is not entirely relevant for most WordPress users, but if you’re creating your own blocks or just interested in what goes into it, read on.

When creating blocks in WordPress’ new block editor (Gutenblocks, if you will), there are two ways you can choose to have your block rendered to HTML: static and dynamic. In this post, I’ll take a look at the differences between the two and why our team chose to go (almost) all in on dynamic blocks.


With a static block, you write a React component which will receive the attributes as arguments, then have its output saved as HTML in the wp_posts table. Once the page is rendered, that HTML will be input into your page template and served to the client. When you go to edit the page again, the block editor will parse the HTML and pull out the attributes based on how you have defined the source for them. Static blocks may also just store some attributes in HTML comments. The blocks are static because every time they are loaded, they will produce the same output


With a dynamic block, the attributes are saved in the post content table inside of HTML comments. Then, when the page is rendered, those attributes are passed as arguments to a PHP function you declare. The output of that function is put into the page template and served to the user. When you go to edit the page again, those attributes are pulled directly from the comments into the editor. The blocks are dynamic because the output they produce may be different every time they are loaded. Dynamic blocks are very similar in structure and operation to shortcodes.

How to Choose

The key difference between the two is that the output of a static block is determined when the block is saved by the editor, whereas the output of a dynamic block is determined when the client requests the page.

In some situations, such as the Recent Posts Block, you will need a dynamic block. The block cannot know at save time what the content will ultimately be when users view it.

At other times, you do have all the information. When editing a paragraph block, you write the text and pick the color — and you probably don’t want that to change. So, do you create a static block in this situation? Well, maybe. But there are several other reasons why you might still consider making that block a dynamic block.

In fact, you may want all of your blocks to be dynamic blocks. Here’s why:

Benefits of Dynamic Blocks

No Block Validation Errors

This is the biggest gain and was the driving force for us to go all in on dynamic blocks.

What is Block Validation?

When you edit a page that already has content, the block editor goes through a process of turning all of the content on that page into data that the editor will work with. In the case of dynamic blocks, it is simple: the editor sees the HTML comment containing the attributes and it’s done.

With a static block, it will pick up any attributes from the HTML comment, then it will parse over the HTML looking for attributes based on how you have declared their source. It will then take the attributes it gets, pass them back through the save method and compare the output that it gets from that operation and the saved HTML. If the two match then everything goes ahead fine. But if they don’t match, it means something has changed and a validation error will be triggered. The user can resolve the validation issue by converting the saved markup to HTML or letting Gutenberg convert the HTML into blocks, which never really works unless it’s a pretty basic structure.

Why Validation?

I have to admit that for most of my time working with Gutenberg, block validation has been my bane. However, I do know that it’s there for good reason. If there was no validation, blocks could change radically in ways users don’t expect. It could also overwrite changes made by the user that they want to keep. So validation is good! But most times you see a validation issue, it’s because you updated your block and changed a class name or some other small portion of HTML and it invalidated the whole block. That’s very frustrating.

How to Avoid Validation Errors

The way you avoid validation errors is by adding a deprecated version to your block registration. You can add an array of objects where each object contains an old version of the save method and an old version of the attributes object. Now when the block editor goes through the validation process, if it runs into a mismatch, it will check against any deprecated versions before it throws a validation error.

Why That Doesn’t Always Work

Now, I know you’re probably a perfect developer. You write things with no mistakes and get it on the first try. You foresee all use cases and you write functions that win Nobel Prizes. When people use code you’ve written, they feel an unexplained warmth from their bottom of the soul and walk away a fundamentally better person.

But that’s not me. I make a lot of mistakes, and it takes several rounds of dialing things in before they really start working, and then weeks later something comes up and I have to change my approach.

Using a deprecated version requires you to copy both the save method and the attributes. This is not too bad with two or three versions in there. But if you are making a lot of small changes, that will quickly grow.

This issue compounds itself when you are sharing components between blocks. Imagine the following situation:

You have version 1.0 of a  plugin that adds the following blocks: 1, 2, 3 and 4. Each block is importing components Z and Y.

Version 1.0, Blocks 1, 2, 3, and 4 are all using components Z and Y

You have released version 1.0 and it’s great. People love it! But they want some new features, so you are working on version 2.0. You need to update component Z to add these features. This means that all the blocks need a new deprecated version, which would produce the exact output as the component did in version 1.0. You copy and paste all of the markup into the deprecated version, but you change the reference to component Z with the markup of the 1.0 version. This has to be done for each block. Changing one class name on component Z has you duplicating a good chunk of code in four blocks.

Version 2.0, blocks 1, 2, 3, and 4 now have updated versions of component Z, and now have a deprecated version from 1.0

Some time passes and people ask for more features, so you decide to release version 3.0. This time you need to change component Y. You have to do the same thing you did before when updating component Z and add deprecated 2.0 versions to the blocks. But you also have to make sure that the deprecated 1.0 versions no longer contain any references to component Y because now that has changed too.

Version 3.0, blocks 1, 2, 3, and 4 now have updated versions of components Y and Z, and now also have deprecated version from 1.0 and 2.0

You can see how this would quickly get out of hand, especially if the components here also had their own dependencies that might change. Maybe you could write your own versioning system so each block can pass down what it needs, or maybe you copy the raw markup for everything the block depends on (what if it is a third party dependency?), but it’s going to get very difficult to manage.

Or you could just use dynamic blocks and avoid all that. Cowabunga.

Instant Updates

Static blocks will not have their content updated until the post is saved again — even if the block changes. That means that if there was a bug in the markup of one of your blocks, even if you were to fix the block, the error will remain on all pages where that block was used until you go back and save all of those pages again. In the case of very large sites — such as the ones we often deal with — you may have pages that don’t get edited for years at a time and may have very old markup. With dynamic blocks, as soon as the block is updated, all instances of the block will begin serving the updated markup.

Dangerous Markup

As a part of the saving process, WordPress will strip out markup from saved content that presents security issues. Iframe tags, Javascript, SVG and more will be removed — for good reason. Because content from Gutenberg is just saved using the API, WordPress can’t tell what is user input (untrusted) and structural from the blocks themselves (trusted, hopefully) and will just strip all of that content out. Sometimes, however, you might want to use that markup (for example, including an SVG icon with your blocks). Unless you change WordPress’ rules and allow all users to post unfiltered HTML — a bad idea! — you cannot use SVG inside of a static block, unless it’s just as the src of an <img /> tag.

With a dynamic block, you don’t need to save the dangerous markup itself; you just save the name of the icon and let PHP handle the rendering of SVG based on the passed attribute and it won’t be stripped out.

We got embarrassingly far along in building our campus block library before we realized this issue. It was just prior to a user test when we realized that no icons we were adding to the page were displaying. At first we thought it was an issue with a new version of Gutenberg, or we had pulled down the wrong branch, but after some digging we finally realized it was because we were using author accounts for the test and our icons were being stripped out by WordPress. We had only tested before as administrators so we never caught the issue.

In Conclusion

Those three benefits were enough for us to want to go all in on dynamic blocks. But don’t think that there are no challenges with dynamic blocks. There are certainly some trade-offs you will be making. I’ll go over some of those trade-offs next time with part two of this post. Don’t miss it!