In a similar vein as [58291], this changeset introduces a new `insert_hooked_blocks_into_rest_response` function and hooks it to the `rest_prepare_wp_navigation` filter.
This is part of an ongoing effort to move Block Hooks related code out of the Navigation block. Specifically, `insert_hooked_blocks_into_rest_response` is based on `block_core_navigation_insert_hooked_blocks_into_rest_response`. Eventually, it will be possible to deprecate the latter.
Follow-up to [58291].
See #60759.
Built from https://develop.svn.wordpress.org/trunk@58292
git-svn-id: http://core.svn.wordpress.org/trunk@57752 1a063a9b-81f0-0310-95a4-ce76da25c4cd
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes#60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
The Block Hooks UI relies on the `ignoredHookedBlocks` metadata when determining whether to show the toggle in the Site Editor. The problem is that for uncustomized templates we don't add this metadata.
Currently the visitor functions have a default callback of `insert_hooked_blocks` and we only add the metadata when we're writing to the database via an available filter in the template controller.
This changeset creates a new callback which both inserts the hooked blocks and adds the `ignoredHookedBlocks` metadata to the anchor block, and uses this new callback explicitly in the visitor functions that are run upon reading from the database.
We continue to set the `ignoredHookedBlocks` metadata when writing to the database, i.e. this operation happens twice. Although not ideal, this is necessary to cover the following scenarios:
* When the user adds an anchor block within the editor, we still need to add the `ignoredHookedBlocks` meta to it to prevent hooked blocks hooking on to it unexpectedly on the frontend. This is required to keep parity between the frontend and editor.
* When a user writes template data to the database directly through the API (instead of the editor), we need to again ensure we're not inserting hooked blocks unexpectedly.
It is worth noting that with this change, the first hooked block to insert relative to its anchor block will be accepted. Any additional blocks of the same type (e.g. a second `core/loginout` block) trying to hook onto the same anchor block will be ignored, irrespective of the position.
Props tomjcafferkey, bernhard-reiter, gziolo.
Fixes#59574.
Built from https://develop.svn.wordpress.org/trunk@58186
git-svn-id: http://core.svn.wordpress.org/trunk@57649 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This changeset allows using symbolic links for `editorScript` and `editorStyle` in `register_block_type()`. This adds `realpath` to template and stylesheet in `get_block_asset_url()` to ensure returning canonicalized absolute pathnames.
Follow-up to [56683].
Props antonlukin, spacedmonkey, maxpertici.
Fixes#59175.
See #58525.
Built from https://develop.svn.wordpress.org/trunk@57675
git-svn-id: http://core.svn.wordpress.org/trunk@57176 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Allow returning null from the `hooked_block` and `hooked_block_{$hooked_block_type}` filters to suppress a hooked block from being inserted. This is required to allow extenders conditionally inserting a hooked block based on e.g. the value of an attribute of the anchor block.
Props swissspidy, gziolo, joshuatf, tomjcafferkey.
Fixes 60580.
Built from https://develop.svn.wordpress.org/trunk@57668
git-svn-id: http://core.svn.wordpress.org/trunk@57169 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This is a counterpart to the dynamic `hooked_block_{$block_type}` filter introduced in [57354],
which makes it easier to modify all hooked blocks prior to insertion.
Also adds the hooked block type as an additional argument to both filters for consistency.
Props bernhard-reiter, swissspidy.
Fixes#60574.
Built from https://develop.svn.wordpress.org/trunk@57660
git-svn-id: http://core.svn.wordpress.org/trunk@57161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Decouple hooked blocks insertion from setting the `metadata.ignoredHookedBlocks` attribute on anchor blocks, and perform the latter step upon saving a template or template part to the database. This ensures that anchor blocks that have been newly added to a template (or part) on the client side will also get `ignoredHookedBlocks` metadata set correctly, thus preserving editor/front-end parity. Hooked block insertion, on the other hand, will continue to happen upon ''reading'' a template (or part).
Props gziolo, tomjcafferkey.
Fixes#60506.
Built from https://develop.svn.wordpress.org/trunk@57627
git-svn-id: http://core.svn.wordpress.org/trunk@57128 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Add a new `hooked_block_{$block_type}` filter that allows modifying a hooked block (in parsed block format) prior to insertion, while providing read access to its anchor block (in the same format).
This allows block authors to e.g. set a hooked block's attributes, or its inner blocks; the filter can peruse information about the anchor block when doing so. As such, this filter provides a solution to both #59572 and #60126.
The new filter is designed to strike a good balance and separation of concerns with regard to the existing [https://developer.wordpress.org/reference/hooks/hooked_block_types/ `hooked_block_types` filter], which allows addition or removal of a block to the list of hooked blocks for a given anchor block -- all of which are identified only by their block ''types''. This new filter, on the other hand, only applies to ''one'' hooked block at a time, and allows modifying the entire (parsed) hooked block; it also gives (read) access to the parsed anchor block.
Props gziolo, tomjcafferkey, andrewserong, isabel_brison, timbroddin, yansern.
Fixes#59572, #60126.
Built from https://develop.svn.wordpress.org/trunk@57354
git-svn-id: http://core.svn.wordpress.org/trunk@56860 1a063a9b-81f0-0310-95a4-ce76da25c4cd
The biggest tradeoff that was made in the implementation of Block Hooks was that they were limited to layouts (i.e. templates, template parts, and patterns) that ''didn't have any user modifications'' (see #59313 for the reason). This changeset is a preparatory step to remove this limitation, so they’ll eventually also work with user-modified layouts.
The crucial problem to solve is how to acknowledge that a user has opted to remove or persist a hooked block, so that the auto-insertion mechanism won't run again and inject an extraneous hooked block on the frontend when none is solicited.
This is achieved by storing all known blocks hooked to a given anchor block in the `metadata` attribute on that anchor block; specifically in a field called `ignoredHookedBlocks` inside of the `metadata`. Hooked blocks are only rendered on the frontend if they're absent from that field; OTOH, they're injected into that field (via the REST API) when first loaded in the editor.
This simple logic guarantees that once a user modifies a given layout, those changes are respected on the frontend; yet if a plugin that includes a hooked block is activated after those modifications have taken place, the hooked block will be rendered on the frontend. This new technique supplants the one previously used (i.e. rendering hooked blocks on the frontend only if a layout doesn't have any modifications) in a rather direct way.
Note that this changeset only introduces the new metadata field and relevant logic; it does not yet enable hooked block insertion into modified layouts. That will be done in a subsequent step (see #59646).
Props gziolo.
Closes#60008.
Built from https://develop.svn.wordpress.org/trunk@57157
git-svn-id: http://core.svn.wordpress.org/trunk@56668 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Documents the 4 new 6.4 Block Hooks global functions as private and for Core-only internal usage:
* `make_before_block_visitor()`
* `make_after_block_visitor()`
* `traverse_and_serialize_block()`
* `traverse_and_serialize_blocks()`
This is being done as the architectural design of these new functions may change in the next cycle. Further denoting them as private / Core only can help to avoid extender churn if any of these functions are deprecated.
Follow up to [56649], [56620].
Props azaozz, hellofromTonya, bernhard-reiter, gziolo, mikeschroder.
Fixes#59783.
See #59313.
Built from https://develop.svn.wordpress.org/trunk@57066
git-svn-id: http://core.svn.wordpress.org/trunk@56577 1a063a9b-81f0-0310-95a4-ce76da25c4cd
The callbacks returned by `make_before_block_visitor` and `make_after_block_visitor`, respectively, (which are passed as arguments to `traverse_and_serialize_block(s)`) currently accept three arguments, all of which are block arrays (i.e. with properties `blockName`, `attrs`, etc.):
- A ''reference'' to the block they're currently visiting, `&$block`;
- the block's `$parent_block`; and
- the `$prev`ious block (for `make_before_block_visitor`), or the `$next` block (for `make_after_block_visitor`), respectively.
Those arguments are passed to the "block visitor" callbacks by `traverse_and_serialize_block(s)` during traversal. The block that the callback is currently visiting is passed ''by reference'' to allow modifying it, which is e.g. used to inject the `theme` attribute into Template Part blocks.
One major limitation of Block Hooks is that they currently only work with templates, parts, and patterns that ''don't have any user modifications'' (i.e. that come straight from the corresponding theme files, rather than from the database). For WordPress 6.5, it is planned to change that to make Block Hooks work for templates, parts, and patterns that ''do'' have user modifications: #59646.
This will be implemented by storing an attribute on the "anchor" block. While working on that feature, it was found that the aforementioned callbacks will need to modify not only the currently visited `$block`, but also the `$parent_block` -- i.e. that the latter argument needs to be passed by reference as well. This is consistent with the requirement of adding an attribute to an anchor block, as it's not only the currently visited block that can serve as an anchor block (in the case of `before` or `after` sibling insertion), but also its parent (for `first_child` and `last_child` insertion).
If the `$parent_block` argument were to be changed to become a reference in a later WordPress version, this could be considered a backwards-compatibility breaking change. For this reason, this change is instead proposed for 6.4 already, which is the cycle during which the relevant functions were first introduced. This should have no impact on existing code, since nothing currently relies on `$parent_block` remaining unmodified by the respective callback, nor is anything currently modifying that argument.
Props hellofromTonya.
Fixes#59776.
Built from https://develop.svn.wordpress.org/trunk@57038
git-svn-id: http://core.svn.wordpress.org/trunk@56549 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This makes it possible to register a block by passing an array of arguments, without the presence of a `block.json` file.
Follow-up to [48141], [49948].
Props aristath, spacedmonkey, mukesh27, costdev, audrasjb, oglekler, felipeelia, hellofromTonya.
Fixes#56865.
Built from https://develop.svn.wordpress.org/trunk@57026
git-svn-id: http://core.svn.wordpress.org/trunk@56537 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Both the `$pre_callback` and `$post_callback` functions that are given as arguments to `traverse_and_serialize_block(s)` receive a reference to the current block as their first argument. However, while any changes that the "pre" callback makes to the block are reflected by the serialized markup, the same wasn't true for the "post" callback: Any changes that it made were only applied ''after'' the block had already been serialized.
This commit changes the behavior such that `$post_callback`'s changes to the current block are also reflected in the serialized markup.
See #59646.
Props gziolo.
Fixes#59669.
Built from https://develop.svn.wordpress.org/trunk@56970
git-svn-id: http://core.svn.wordpress.org/trunk@56481 1a063a9b-81f0-0310-95a4-ce76da25c4cd
It was found that Template Part blocks were broken in the Site Editor, showing the `Template part has been deleted or is unavailable` message, due to a missing `theme` attribute.
This bug seems to have been introduced by [56896], whose goal was to only inject that attribute into the markup returned by the templates and patterns REST API endpoints but not on the frontend, in order to improve performance. It has been demonstrated locally that reverting that changeset fixes the bug.
Reverts [56896].
Props mmcalister, swisspidy, thelovelist, hellofromTonya, pbiron, Pauthake015, richtabor, nicolefurlan, huzaifaalmesbah, annezazu, kafleg, aegkr, sunitarai, shresthaaman, andraganescu, onemaggie, gziolo.
Fixes#59629.
Built from https://develop.svn.wordpress.org/trunk@56960
git-svn-id: http://core.svn.wordpress.org/trunk@56471 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Having the patterns registry inject the `theme` attribute into all Template Part blocks inside every pattern was found to negatively impact performance. It turns out that it's only required for the editor (i.e. in the REST API) but not on the frontend; there, it's instead possible to fall back to the currently active theme.
The latter change was made to the Pattern and Template Part blocks in https://github.com/WordPress/gutenberg/pull/55217, which was sync'ed to Core in [56849]. Consequently, this changeset removes `theme` attribute insertion from the frontend.
Props flixos90, gziolo, dmsnell, hellofromtonya.
Fixes#59583.
Built from https://develop.svn.wordpress.org/trunk@56896
git-svn-id: http://core.svn.wordpress.org/trunk@56407 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Prior to this changeset, `get_hooked_blocks` was called four times ''for every parsed block'' in each template, template part, and pattern. With this changeset applied, `get_hooked_blocks` is called only once per template, template part, or pattern.
Additionally, `get_hooked_blocks` is called only once when returning the list of all registered patterns. (The latter modification brings the implementation closer to its state prior to Block Hooks.)
Finally, when there are no registered hooked blocks or `hooked_block_types` filters, parsing, hooked block insertion, and re-serializing is skipped altogether.
Props gziolo, flixos90, joemcgill, dmsnell, spacedmonkey, hellofromtonya.
Fixes#59383.
Built from https://develop.svn.wordpress.org/trunk@56805
git-svn-id: http://core.svn.wordpress.org/trunk@56317 1a063a9b-81f0-0310-95a4-ce76da25c4cd
In the context of register_block_script_handle, the get_block_asset_url function may return false when an empty string is provided as the input. This behavior is intended to prevent the generation of invalid URLs. However, when the script loading strategy is set to "defer" while passing false, it triggers a "doing it wrong" message.
This situation becomes problematic, especially for scenarios where the scripts haven't been built yet. In such cases, the realpath call returns an empty string because the file doesn't exist. To address this issue, we now perform a simple check to ensure that the script URI is not empty before applying the "defer" loading strategy. This adjustment prevents unnecessary deferral of loading for scripts with empty URIs.
Follow on from [56683] and [56033].
Props kebbet, mukesh27, swissspidy, westonruter, spacedmonkey.
Fixes#59475
Built from https://develop.svn.wordpress.org/trunk@56744
git-svn-id: http://core.svn.wordpress.org/trunk@56256 1a063a9b-81f0-0310-95a4-ce76da25c4cd
`_wp_array_get()` is an expensive function, and it's called thousands of times on each page view on the front end. While the function performance was slightly improved in #58376, it is still called more times than it should be.
This commit aims to further optimize its usage:
* In many cases, `_wp_array_get()` can be replaced with a much simpler and faster `isset()` check.
* The `isset()` function is capable of checking nested arrays, so `isset( $foo['a']['b']['c'] )` will return false even if `$foo['a']` is unset, without throwing any errors or warnings.
* When `_wp_array_get()` cannot be directly replaced with `isset()`, it would be good practice to wrap it in an `isset()` function so that `_wp_array_get()` only runs when it needs to.
Original PR from Gutenberg repository:
* [https://github.com/WordPress/gutenberg/pull/51116#51116 Performance improvement: Reduce the use of the _wp_array_get() function]
Follow-up to [55851], [56382].
Props aristath, jrf, spacedmonkey, mukesh27, swissspidy, hellofromTonya.
Fixes#59405.
Built from https://develop.svn.wordpress.org/trunk@56709
git-svn-id: http://core.svn.wordpress.org/trunk@56221 1a063a9b-81f0-0310-95a4-ce76da25c4cd
All existing calls of `get_hooked_blocks()` in non-test code are currently wrapped in an extra `array_keys()` call. This changeset absorbs that logic into the function and changes the structure of the return value accordingly.
Furthermore, this allows us to remove the extra `$relative_position` argument (introduced in [56673]) from the function again, as the same data can now be simply fetched via array access.
Props gziolo, spacedmonkey, mukesh27.
See #59383.
Built from https://develop.svn.wordpress.org/trunk@56704
git-svn-id: http://core.svn.wordpress.org/trunk@56216 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit introduces a valuable utility function, get_block_asset_url, designed to simplify the retrieval of block asset URLs, such as those for CSS and JavaScript files. This utility eliminates redundancy in both register_block_script_handle and register_block_style_handle. Additionally, `get_block_asset_url` incorporates an early exit mechanism to optimize performance.
This update includes comprehensive unit tests, covering various scenarios, including asset registration from core (wp-includes), themes, child themes, plugins, and mu-plugins.
Props spacedmonkey, joemcgill, flixos90, gziolo.
Fixes#58525.
Built from https://develop.svn.wordpress.org/trunk@56683
git-svn-id: http://core.svn.wordpress.org/trunk@56195 1a063a9b-81f0-0310-95a4-ce76da25c4cd
In [50761], the block_has_support function was introduced. However, using `property_exists` within this function negatively impacted its performance. This commit replaces the `property_exists` function call with `instanceof WP_Block_Type`, resulting in improved performance.
Props mukesh27, gziolo, spacedmonkey.
Fixes#59441.
Built from https://develop.svn.wordpress.org/trunk@56678
git-svn-id: http://core.svn.wordpress.org/trunk@56190 1a063a9b-81f0-0310-95a4-ce76da25c4cd
In [56610], the get_hooked_blocks function was introduced. However, using property_exists within this function negatively impacted its performance. This commit replaces the property_exists function call with instanceof WP_Block_Type, resulting in improved performance.
Props gziolo, spacedmonkey.
See #59383.
Built from https://develop.svn.wordpress.org/trunk@56677
git-svn-id: http://core.svn.wordpress.org/trunk@56189 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Per discussion in #59424, there's agreement that the new `hooked_block_types` filter (introduced in [56673]) covers conditional addition and removal of hooked blocks better and at a higher level than the `inject_hooked_block_markup` filter that was originally added in [56649] for that same purpose.
Consequently, this changeset removes the latter filter.
Props gziolo.
Fixes#59439.
Built from https://develop.svn.wordpress.org/trunk@56674
git-svn-id: http://core.svn.wordpress.org/trunk@56186 1a063a9b-81f0-0310-95a4-ce76da25c4cd
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 underlying idea is 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.
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 (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to 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.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be 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, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes#59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
During work on #59399, it was discovered that ''sibling'' block insertion wasn't likely going to work the way it was planned, which required devising an alternative solution. This new solution requires some changes to `traverse_and_serialize_block(s)`:
- Change the signature of the existing callback such that:
- the return value is a string that will be prepended to the result of the inner block traversal and serialization;
- the function arguments are: a ''reference'' to the current block (so it can be modified inline, which is important e.g. for `theme` attribute insertion), the parent block, and the previous block (instead of the block index and chunk index).
- Add a second callback argument to `traverse_and_serialize_block(s)`, which is called ''after'' the block is traversed and serialized.
- Its function arguments are a reference to the current block, the parent block, and the next block.
Props gziolo.
Fixes#59412. See #59313.
Built from https://develop.svn.wordpress.org/trunk@56644
git-svn-id: http://core.svn.wordpress.org/trunk@56156 1a063a9b-81f0-0310-95a4-ce76da25c4cd
In [56618], three functions (`insert_inner_block`, `prepend_inner_block`, and `append_inner_block`) were introduced. They were meant to be used for insertion of hooked blocks; however, it was discovered that the original idea wouldn't work for sibling insertion. Instead, a different approach will be taken (see #59412), and these functions are no longer needed and can thus be removed.
Reverts [56618].
See #59412, #59385, #59313.
Built from https://develop.svn.wordpress.org/trunk@56634
git-svn-id: http://core.svn.wordpress.org/trunk@56146 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Introduces two new functions `traverse_and_serialize_blocks` and `traverse_and_serialize_block` with the additional `$callback` argument. It is possible to pass parent block, block index, chunk index to the callback argument.
Reverts changes applied to `serialize_blocks` and `serialize_block` in #59327 with [56557].
Props ockham, mukesh27.
See #59313.
Built from https://develop.svn.wordpress.org/trunk@56620
git-svn-id: http://core.svn.wordpress.org/trunk@56132 1a063a9b-81f0-0310-95a4-ce76da25c4cd
For #59313, we need to implement functions to insert a given parsed block into another parsed block's inner blocks, and to prepend and append to that array, respectively.
We will use those functions in combination with `traverse_and_serialize_blocks` (see #59327) to implement automatic insertion of hooked blocks into block templates and patterns.
Props gziolo.
Fixes#59385.
Built from https://develop.svn.wordpress.org/trunk@56618
git-svn-id: http://core.svn.wordpress.org/trunk@56130 1a063a9b-81f0-0310-95a4-ce76da25c4cd