[wp-trac] [WordPress Trac] #59313: Implement Block Hooks
WordPress Trac
noreply at wordpress.org
Thu Sep 7 19:15:03 UTC 2023
#59313: Implement Block Hooks
-----------------------------+--------------------
Reporter: Bernhard Reiter | Owner: (none)
Type: enhancement | Status: new
Priority: high | Milestone: 6.4
Component: Editor | Version:
Severity: normal | Keywords:
Focuses: |
-----------------------------+--------------------
This ticket is about porting Gutenberg PHP code that implemented Block
Hooks to Core. Skip to the bottom of this ticket for a TODO list.
== Synopsis
First implemented in Gutenberg under the name
[https://make.wordpress.org/core/2023/08/10/whats-new-in-
gutenberg-16-4-9-august/#auto-inserting-blocks "Auto-inserting Blocks"]
and recently [https://github.com/WordPress/gutenberg/pull/54147 renamed]
to "Block Hooks", this feature is meant to provide an extensibility
mechanism for Block Themes, in analogy to WordPress'
[https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has
allowed extending Classic Themes through filters and actions.
Specifically, Block Hooks allow a third-party block to specify a position
relative to a given block into which it will then be automatically
inserted (e.g. a "Like" button block can ask to be inserted after the Post
Content block, or an eCommerce shopping cart block can ask to be inserted
after the Navigation block).
The two core tenets for block hooks are:
1. Insertion into the frontend should happen right after a plugin
containing a hooked block is activated (i.e. the user isn't required to
insert the block manually in the editor first); similarly, disabling the
plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion:
The hooked block is also visible in the editor, and the user's decision to
persist, dismiss, customize, or move it will be respected (and reflected
on the frontend).
To account for both tenets, we've made the **tradeoff** that automatic
block insertion only works for unmodified templates (and template parts,
respectively). The reason for this is that the simplest way of storing the
information whether a block has been persisted to (or dismissed from) a
given template (or part) is right in the template markup. This was first
suggested
[https://github.com/WordPress/gutenberg/issues/39439#issuecomment-1150278043
here].
To accommodate for that tradeoff, we've
[https://github.com/WordPress/gutenberg/pull/52969 added UI controls
(toggles)] to increase visibility of hooked blocks, and to allow their
later insertion into templates (or parts) that already have been modified
by the user.
== Implementation
Since we wanted hooked blocks to appear both in the frontend and in the
editor (see tenet number 2), we had to make sure they were inserted into
both the frontend markup and the REST API (templates and patterns
endpoints) equally. As a consequence, this means that automatic insertion
couldn't only be implemented at block ''render'' stage, as for the editor,
we needed to modify the ''serialized'' (but ''unrendered'') markup.
However, thanks to the tradeoff we made (see above), we could at least
limit ourselves to only inserting hooked blocks into unmodified templates
(and parts), i.e. those that were coming directly from a Block Theme's
template (or parts) file, rather than the database.
It turns out that there's a rather natural stage for automatic insertion
of hooked blocks to happen, which is during template file retrieval.
While we had to leverage the `get_block_templates` and
`get_block_file_template` hooks in Gutenberg to insert those blocks, we'll
be able to directly modify the `_build_block_template_result_from_file`
function in Core.
Furthermore, hooked blocks also have to be inserted into block patterns.
Since almost no filters exist for the patterns registry, this was done in
the patterns REST API controller in the Gutenberg codebase; for Core,
we'll likely want to this at a lower level.
== Core merge
Based on an early exploration in this [https://github.com/WordPress
/wordpress-develop/pull/5158 experimental PR], I believe that we can break
down the implementation of Block Hooks in Core into the following steps.
Note that due to the nature of the existing code, the first steps might
appear somewhat surprising and unrelated; however, they are very much
relevant and will allow us to extend existing functionality through a
series of self-contained steps.
- Add proper unit test coverage to verify that
`_build_block_template_result_from_file` injects the `theme` attribute.
- While we have coverage for
`_inject_theme_attribute_in_block_template_content`, those tests only
verify that ''that'' function does what is supposed to do; there's however
no guarantee that `_build_block_template_result_from_file` uses that
function (or whatever other technique) to actually inject the theme
attribute ([https://github.com/WordPress/wordpress-develop/pull/5155
see]).
- Add a `$callback` argument to `serialize_block()`
([https://github.com/WordPress/wordpress-
develop/pull/5158/commits/b926b86f1585bebcc71efae4819cb8b4593e8714 see])
and `serialize_blocks()` ([https://github.com/WordPress/wordpress-
develop/pull/5158/commits/7fda6f56ef2c49ccdc687e15c3c5bb914290d94c see]).
- In order to insert our hooked blocks, we need to traverse the parsed
block tree (before it is eventually serialized). In order to minimize the
number of tree traversals (which is a potentially costly operation), it
seems that adding a callback function argument to `serialize_block()` --
which inevitable has to traverse the entire tree anyway -- is a natural
fit.
- Use the latter to replace the call to
`_inject_theme_attribute_in_block_template_content` in
`_build_block_template_result_from_file` with a newly written
`_inject_theme_attribute_in_template_part_block`
([https://github.com/WordPress/wordpress-
develop/pull/5158/commits/f7465b97001313ec525215b1e768f9142f252d56 see]).
- Note that `_inject_theme_attribute_in_block_template_content` is still
used in another spot: The Template Part block’s render.php (i.e. in GB).
We might also want to replace that with
`_inject_theme_attribute_in_template_part_block` so that we can deprecate
`_inject_theme_attribute_in_block_template_content`.
- Add `block_hooks` field to `WP_Block_Type`, `block.json` loading, REST
API endpoint, etc ([https://github.com/WordPress/wordpress-
develop/pull/5158/commits/3ad1fd7caac337e10d385fee2619b53ceb4f7c0a see]).
- Implement `get_hooked_blocks()` to receive a list of blocks hooked into
a given "anchor" block ([https://github.com/WordPress/wordpress-
develop/pull/5158/commits/cdcfbcc1117566df0b608f1875d50480b92111ad see]).
- Use that to implement `insert_hooked_blocks`, and call the latter
alongside `_inject_theme_attribute_in_template_part_block` in a newly
written visitor function that's passed as `$callback` to
`serialize_blocks` ([https://github.com/WordPress/wordpress-
develop/pull/5158/commits/c897d86393c2b434421894a776c6e2b75209a186 see]).
- Apply automatic insertion of hooked blocks to block patterns
([https://github.com/WordPress/gutenberg/blob/7b68e34bb04d18619dbe4140e870a4d6bb28873d/lib/experimental
/class-gutenberg-rest-block-patterns-controller.php#L20-L21 see]).
- Add a filter to allow people to e.g. limit automatic insertion of hooked
blocks to a certain template or template part type only
([https://github.com/WordPress/wordpress-
develop/pull/5158/commits/c897d86393c2b434421894a776c6e2b75209a186 also
see]).
- This somewhat informs the architecture of the code (e.g. function
signatures, passing of `$block_template` context) and goes beyond what is
currently in Gutenberg.
- Note that this hasn't been implemented in the code sync PR yet and is
thus still a bit more tentative.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/59313>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list