Gutenberg: Block API: Ensure filters are properly applied to blocks regardless when they are registered

Created on 10 Sep 2018  路  21Comments  路  Source: WordPress/gutenberg

Is your feature request related to a problem? Please describe.
I'm utilizing the blocks.registerBlockType filter to add a custom attribute to all blocks, much like the Custom CSS Class feature does it here.

I noticed the core blocks received the custom attribute, but my custom blocks didn't.

The reason being that the plugin with my custom blocks is loaded earlier and calls wp.blocks.registerBlockType() before the plugin with the filter is loaded. Both plugins' scripts are hooked to enqueue_block_editor_assets action so I believe it comes down to alphabetical plugin naming or similar.

I looked at how Gutenberg registers it's core blocks and found that they are registered inside a wp.domReady() call.
It never occurred to me to do this because in the docs the registerBlockType() is used as-is. But I wrapped my wp.blocks.registerBlockType() in wp.domReady() and sure enough, the attributes are now successfully applied.

But then I tried a third-party plugin that also registers blocks and the same issue arose.
It just calls registerBlockType() and there's nothing(?) I can do to guarantee my plugin with the filter is loaded before that, since they both depend on the same wp-* script dependencies.

So my question is, could the registerBlockType() function pool all the calls and set them up to be called after the DOM is ready, so that all scripts have a chance to add their filters? (And after DOM is ready it should register the block immediately.) Or should plugin developers be instructed to not register their blocks before DOM is ready to guarantee compatibility with any plugins that may wish to filter the registration process? Or do blocks.registerBlockType filter users simply need to take extra measures to ensure their scrips are loaded as early as possible?

[Feature] Block API [Feature] Extensibility [Type] Discussion [Type] Enhancement

Most helpful comment

Hi Everyone,

I've finally found a workaround and seems to be working perfectly. Use init instead of enqueue_block_editor_assets with wp_enqueue_script and use false on in_footer.

https://github.com/phpbits/block-options/blob/a3a10f7845273b1e89f2c6f768821d882a46d833/includes/class-editorskit-block-assets.php#L70

I hope this helps!

Cheers!

All 21 comments

Does your script depend on wp-editor?

Hooks are not delayed, so in theory (unless I'm missing something), it should work if your script is loaded after the wp-editor script.

@youknowriad Yes the script depends on wp-editor.

I'm not saying hooks are delayed, I'm saying when the script is this:

wp.blocks.registerBlockType('custom/block', {...});
wp.hooks.addFilter('blocks.registerBlockType', 'custom/filter', function() {...});

then the filter is not applied when registerBlockType() executes. These 2 lines can be in separate 3rd-party plugins, both loaded at the same hook, so there's no knowing in which order they get executed depending on the plugin names.

In this case, the filter does get applied:

wp.domReady(function() {
  wp.blocks.registerBlockType('custom/block', {...});
});
wp.hooks.addFilter('blocks.registerBlockType', 'custom/filter', function() {...});

So I'm thinking maybe it should be the default behavior of registerBlockType() unless there's a good reason to be registering blocks before DOM is ready.

I'm having problems with this type of behaviour too, in #14050 i can use the filters, but when other plugins are active that change the enqueuing behaviour, it can affect when plugins get loaded in relation to wp-blocks, and so my code doesn't run in time for the filters it relies on. I opened a jetpack issue at https://github.com/Automattic/jetpack/issues/11464 (because it was Jetpack activating that showed up the behaviour, and that issue has reproduction instructions) but it seems like something we should fix in Gutenberg

@aduth I'm having trouble with regards to this issue too. Custom attributes are being applied only on the core blocks. Third party plugins were not affected by the filters. Thanks!

would it be possible to listen for plugins adding hooks on 'blocks.registerBlockType' and then re-register all registered blocks, similar to how withFilters works? This would eliminate the timing issues: you could add the filters late and they would still work. cc: @gziolo

@adamsilverstein to your point. I think it is technically possible to achieve. I tried to investigate that in #10554. We should revisit it again when Block Registration API RFC is finalized. It shouldn't be that difficult to change the flow of blocks registration if we do for example this:

  • blocks.registerBlockType would register block's definition in the new store's reducer
  • there would be a single event happening just before the editor is rendered where all filters get applied and based on it blocks store computes initial state
  • any further filter changes would trigger re-compute of the initial state of blocks using the stored block definitions

Hi Everyone,

I've finally found a workaround and seems to be working perfectly. Use init instead of enqueue_block_editor_assets with wp_enqueue_script and use false on in_footer.

https://github.com/phpbits/block-options/blob/a3a10f7845273b1e89f2c6f768821d882a46d833/includes/class-editorskit-block-assets.php#L70

I hope this helps!

Cheers!

I linked #6092 to this issue. There are some similar points made:

To successfully register a Gutenberg block type, the wp.blocks.registerBlockType() function MUST be run AFTER Gutenberg has included it's JS and BEFORE the wp.editPost.initializeEditor() function is called.

The problem is that both of these events occur in the 'admin_footer' without an easy way to run code in between.

With the proposed solution being:

A simple solution to this issue is to fire an action during the registerCoreBlocks() function...

More details in the issue, I just posted this to bring the two together.

@nerrad Thanks for cross-linking. I think the additional action suggestion by @elliotcondon there makes sense. Its essentially a timing based hook that fires at exactly the right time developers can count on and feels like a direct solution to the issue at hand, although I suspect others here will not feel as comfortable with this type of approach.

I also do still see a use case for exploring the more dynamic re-registering of blocks when filters are added (or removed) which could enable dynamically adding new block types into a running Gutenberg session for example, or enabling an extension/plugin that uses a registration filter.

I am getting this issue as well. I am trying to add attributes to Gutenberg blocks using block filters. It works fine for the core blocks, but not for any 3rd party block. Here is my code.

addFilter(
    "blocks.registerBlockType",
    "my-plugin/custom-attributes",
    addAttributes // callback function 
  );

This filter only works for the core blocks. Any workaround to this?

TIA

We discussed the same issue today during the weekly Core JS chat. It's a very difficult issue to solve that's on our radar:

https://wordpress.slack.com/archives/C5UNMSU4R/p1592922624105100

@gziolo

That's great to hear that it's on the radar. In the meantime, is there a workaround for this?

TIA

It's tough, usually what happens is that blocks have only a few dependencies so it registers earlier and they can't use the filters that are applied later. One thing that could help is to use as little dependencies as possible for your filters, so probably extract the logic that modifies blocks to their own file.

I feel really bad giving this type of answer, but we really need to rethink how blocks are registered on the client. I'm talking mostly about internal implementation. It's doable but it needs some deep understanding of all use cases when the current approach fails.

@gziolo

I see. What if that 3rd party block is also our own plugin? And we need to modify it from another plugin ( I know this may sound silly, but I do have a use-case ). Any suggestions or pointers to head me in the right direction, please?

I appreciate your responses.

TIA

@munirkamal Does wrapping your block registration in wp.domReady not work for you? Example here.

@munirkamal Does wrapping your block registration in wp.domReady not work for you? Example here.

Oh, I haven't tried that yet. I will try and get back here. Thanks for the reference, I did not notice it earlier. 馃檪

You can try wp.domReady or put wp-edit-post as a dependency when registering blocks to ensure they load at the last point when all filters are already registered.

@gziolo

You can try wp.domReady or put wp-edit-post as a dependency when registering blocks to ensure they load at the last point when all filters are already registered.

Awesome, thank you for the suggestion. I will try it out and get back with the result here.

馃檶

@gziolo

Just to update you, unable to make it work that way (as you suggested). 馃檨

Looking forward for a fix for this.

Was this page helpful?
0 / 5 - 0 ratings