Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
websevendev opened this issue Sep 10, 2018 · 25 comments · Fixed by #34299
Assignees
Labels
[Feature] Block API API that allows to express the block paradigm. [Feature] Extensibility The ability to extend blocks or the editing experience [Priority] High Used to indicate top priority items that need quick attention [Status] In Progress Tracking issues with work in progress [Type] Discussion For issues that are high-level and not yet ready to implement. [Type] Enhancement A suggestion for improvement.

Comments

@websevendev
Copy link

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?

@ianbelanger79 ianbelanger79 added [Type] Enhancement A suggestion for improvement. [Feature] Block API API that allows to express the block paradigm. labels Sep 10, 2018
@designsimply designsimply added the Needs Technical Feedback Needs testing from a developer perspective. label Sep 10, 2018
@youknowriad
Copy link
Contributor

Does your script depend on wp-editor?

@youknowriad
Copy link
Contributor

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.

@websevendev
Copy link
Author

@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.

@notnownikki
Copy link
Member

notnownikki commented Mar 21, 2019

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 Automattic/jetpack#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

@gziolo gziolo added the [Feature] Extensibility The ability to extend blocks or the editing experience label Apr 16, 2019
@aduth
Copy link
Member

aduth commented Apr 17, 2019

@phpbits
Copy link
Contributor

phpbits commented Apr 23, 2019

@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!

@adamsilverstein
Copy link
Member

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

@gziolo
Copy link
Member

gziolo commented Apr 24, 2019

@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

@phpbits
Copy link
Contributor

phpbits commented Apr 24, 2019

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!

@nerrad
Copy link
Contributor

nerrad commented Apr 29, 2019

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.

@adamsilverstein
Copy link
Member

adamsilverstein commented May 1, 2019

@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.

@gziolo gziolo added [Type] Tracking Issue Tactical breakdown of efforts across the codebase and/or tied to Overview issues. and removed Needs Technical Feedback Needs testing from a developer perspective. labels May 24, 2019
@gziolo gziolo changed the title Block API: should wp.blocks.registerBlockType be delayed until wp.domReady? Block API: Ensure filters are properly applied to blocks regardless when they are registered May 24, 2019
@youknowriad youknowriad added [Type] Discussion For issues that are high-level and not yet ready to implement. and removed [Type] Tracking Issue Tactical breakdown of efforts across the codebase and/or tied to Overview issues. labels Jun 4, 2020
@munirkamal
Copy link
Contributor

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

@gziolo
Copy link
Member

gziolo commented Jun 23, 2020

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

@munirkamal
Copy link
Contributor

@gziolo

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

TIA

@gziolo
Copy link
Member

gziolo commented Jun 23, 2020

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.

@munirkamal
Copy link
Contributor

@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

@websevendev
Copy link
Author

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

@munirkamal
Copy link
Contributor

@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. 🙂

@gziolo
Copy link
Member

gziolo commented Jun 23, 2020

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.

@munirkamal
Copy link
Contributor

@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.

🙌

@munirkamal
Copy link
Contributor

@gziolo

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

Looking forward for a fix for this.

richardtape added a commit to richardtape/content-visibility-date-and-time that referenced this issue Dec 16, 2020
…in. This means when the WordPress/gutenberg#9757 gutenberg bug (feature?!) is fixed, we can perhaps use a standard action in our core plugin, and our add-ons will fall in place automatically.
richardtape added a commit to richardtape/content-visibility-user-role that referenced this issue Dec 16, 2020
…in. This means when the WordPress/gutenberg#9757 gutenberg bug (feature?!) is fixed, we can perhaps use a standard action in our core plugin, and our add-ons will fall in place automatically.
@vielhuber
Copy link

vielhuber commented Feb 14, 2021

As a current workaround, I had to leave wp.domReady(() => {}) out for the filter working on non core blocks.

@landwire
Copy link

landwire commented Aug 17, 2021

After hours of debugging I have landed here. Actually the workaround from #9757 (comment) worked in my case.

Still it would be nice to have a proper solution and especially have this mentioned somewhere in the documentation of the hook/filter to save people some time.

@gziolo
Copy link
Member

gziolo commented Aug 17, 2021

I agree that it requires more attention. It will become even more pressing once we have several screens using the block editor. Setting a script dependency to wp-edit-post or wp-editor will no longer be a good way to mitigate this issue outside of the post editor screen.

@gziolo gziolo added the [Priority] High Used to indicate top priority items that need quick attention label Aug 17, 2021
@gziolo gziolo self-assigned this Aug 24, 2021
@gziolo gziolo added the [Status] In Progress Tracking issues with work in progress label Aug 24, 2021
@gziolo
Copy link
Member

gziolo commented Aug 26, 2021

I'm exploring whether we can re-apply filters (when necessary) to the registered blocks just before the block editor starts the parsing step in #34299.

Ideally, we should be able to apply those filters at any time and all block definitions should magically update, but there are some architectural shortcomings that we would have to address first:

  • in many places access to blocks isn't reactive, meaning we fetch the block definitions and assume they won't change
  • we never reparse the block editor content after the initial render, in the case when a filter gets added or removed, then any changes to save, attributes or supports might impact the result of parsing the same block

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block API API that allows to express the block paradigm. [Feature] Extensibility The ability to extend blocks or the editing experience [Priority] High Used to indicate top priority items that need quick attention [Status] In Progress Tracking issues with work in progress [Type] Discussion For issues that are high-level and not yet ready to implement. [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging a pull request may close this issue.