-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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 Supports: Re-use instance of Tag Processor when adding layout classes. #54075
Block Supports: Re-use instance of Tag Processor when adding layout classes. #54075
Conversation
This pull request has changed or added PHP files. Please confirm whether these changes need to be synced to WordPress Core, and therefore featured in the next release of WordPress. If so, it is recommended to create a new Trac ticket and submit a pull request to the WordPress Core Github repository soon after this pull request is merged. If you're unsure, you can always ask for help in the #core-editor channel in WordPress Slack. Thank you! ❤️ View changed files❔ lib/block-supports/layout.php |
83c2b9d
to
7d86181
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR, code changes LGTM! Just left a couple minor comments about the comments 😄
Testing with several different layout blocks shows everything working as expected:
- Cover block - which has multiple wrappers - has layout classes applied to its inner wrapper;
- Navigation block still has classes applied to its outer wrapper, which is expected as it has its own render callback;
- Other single-wrapper blocks such as Group and Buttons have layout classes applied correctly.
lib/block-supports/layout.php
Outdated
/* | ||
* Return early if only child layout exists. | ||
* | ||
* In other words, if there is nothing more complicated, add |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can be a bit more specific here with something like "In other words, if the block itself doesn't support layout..." instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain the original comment in different words? I think my ambiguity here comes from my inability to understand what "if only child layout exists" means.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
specifically, what does has_child_layout
mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm yeah I could have done a better job with the original comment 😅
has_child_layout
means that the block is inside a block with flex layout that has allowSizingOnChildren
set to true, so it has access to certain layout properties, even if the block doesn't itself support layout.
Currently the only properties applied to flex children are selfStretch
and flexSize
, but more might be added in the future. Any block at all that is a child of a flex block with allowSizingOnChildren
(currently the only core blocks that support it are Group variations and Navigation) has access to those properties, through a set of controls in the Dimensions panel:
So at this point in the code we're checking if the block supports layout, because if it doesn't we can just add whatever child layout properties it has and skip all the logic below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for clarifying; I've attempted to explain this in comments in the latest version of the patch.
/*
* A block may not support layout but still be affected by a parent block's layout.
*
* In these cases add the appropriate class names and then return early; there's
* no need to investigate on this block whether additional layout constraints apply.
*/
lib/block-supports/layout.php
Outdated
* | ||
* @TODO: Find a better way to match the first inner block. Can some unique | ||
* value or class or ID be added to the inner blocks when they process | ||
* so that they can be extracted here safely without guessing? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding this super detailed explanation!
I'd just clarify here that what we're trying to match is the innermost wrapper for the inner blocks, not the first inner block.
(From what I recall the problem was that when processing the inner blocks we don't have access to the wrapper. It would be great to find a better way of doing this though!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aha, well I was actually intending on leaving the note about matching the inner block because then we can tell when we've crossed into it. identifying a block wrapper can work when there is a wrapper and when a block indicates it, but there is no general concept of an inner block wrapper, whereas there is a concept of an inner block.
I'll clarify the comment to make this clearer why we would want to identify the inner block and not the wrapper.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see, that makes sense!
lib/block-supports/layout.php
Outdated
$content->add_class( $class_name ); | ||
/* | ||
* Find where to add the remaining class names. If there was a last tag identified before | ||
* the inner blocks then they belong on that tag. Otherwise, they belong on the outermost tag. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the last tag identified before the inner blocks will actually be the outermost tag if the block only has a single wrapper element for its inner blocks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah. thanks for clarifying. it was incredibly difficult for me to figure out what the goals of this code was, so my comments have been more or less a record of my attempts to do so, and a document for the future developer who comes in and wants to understand the logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry about that, this should have had some more inline comments for clarity. Thanks for adding them!
bd4c446
to
92f5293
Compare
Flaky tests detected in 196747eb8cfdd353e76cac7ba9ef36a167c5e569. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/6053826558
|
196747e
to
1943ac6
Compare
…lasses. In #45364 (WordPress/wordpress-develop#3976) the Block Supports was extended to add layout class names using the HTML API, new in WordPress 6.2. The initial patch opened up two opportunities to refine the code, however: - There are multiple instances of the `WP_HTML_Tag_Processor` created when a single one suffices. (There is an exception in that a second processor is necessary in order to find an inner block wrapper). - The code relies on the incidental fact that searching by a whitespace-separated list of class names works if the class names in the target tag are in the same order. In this patch the use of the HTML API is refactored to address these opportunities and clean up a few places where there could be stronger consistency with other use patterns of the HTML API: - Multiple instances of the Tag Processor have been combined to remove overhead, extra variables, and code confusion. The new flow is more linear throughout the function instead of branching. - Updated HTML is returned via `get_updated_html()` instead of casting to a string. - The matching logic to find the inner block wrapper has been commented and the condition uses the null-coalescing operator now that WordPress requires PHP 7.0+. - When attempting to find the inner block wrapper at the end, a custom comparison is made against the `class` attribute instead of relying on `next_tag()` to find a tag with the given set of class names. The last refactor is important as a preliminary step to WordPress/wordpress-develop#5096 where `has_class()` and `class_list()` methods are being introduced to the Tag Processor. In that patch the implicit functionality of matching `'class_name' => 'more than one class'` is removed since that's not a single class name, but many.
1943ac6
to
b49f67b
Compare
See WordPress/gutenberg#54075 Refactors block supports to use a single Tag Processor instance and to only send a single class at a time to `add_class()`.
@dmsnell 👋 I'm working on backports for WP 6.4 and it looks like this PR is already included. This is the backport branch for 6.4 Beta 2, and all these changes are present. I wanted to confirm with you as this PR isn't marked for any Gutenberg release milestone which confused me, although I am confident that the changes are in the 6.4 branch! Edit: Actually, I think this needs to be listed in #54177, as it's a PHP change. Do we already have a trac ticket for this? |
@mikachan we'll have to talk about release milestones in Gutenberg another time - it's new to me. thankfully this change was backported into Core four days ago by @tellthemachines in WordPress/wordpress-develop#5252 so there should be nothing more that needs to be done in either repo. please let me know if you find that something isn't right about that. the code on each side remains different but I believe that may be because of other changes done around that file. when I backported the change I only brought this change and not any others. |
@dmsnell Thanks for confirming! Yeah you're right, looks like there's nothing else that needs to be done for this PR. I've removed the I think milestones are usually added automatically by GitHub when a PR is merged to make sure the PR is automatically assigned to a release version, and the biggest reason for a PR to be tagged is so it's listed in the correct changelog. So I don't think anything needs to be changed here either, but I guess it was probably missed off a changelog 😅 |
What?
Refactors the use of the HTML API in Block Supports for layout. Resolves an issue that accidentally works today but will break in future iteration of the HTML API.
Why?
While searching for multiple class names with
$processor->next_tag( array( 'class_name' => 'many class names' ) )
may seem convenient, it only incidentally works today in the Tag Processor because of partial support for matching class names. This can lead to unexpected results, for instance, when class names on the tag are reordered. A more proper method of searching would be resilient to ordering and whitespace in theclass
attribute, which is what is introduced in WordPress/wordpress-develop#5096. Unfortunately, this code must be changed before that merges otherwise it will break layout support.How?
In #45364 (WordPress/wordpress-develop#3976) the Block Supports was extended to add layout class names using the HTML API, new in WordPress 6.2. The initial patch opened up two opportunities to refine the code, however:
There are multiple instances of the
WP_HTML_Tag_Processor
created when a single one suffices. (There is an exception in that a second processor is necessary in order to find an inner block wrapper).The code relies on the incidental fact that searching by a whitespace-separated list of class names works if the class names in the target tag are in the same order.
In this patch the use of the HTML API is refactored to address these opportunities and clean up a few places where there could be stronger consistency with other use patterns of the HTML API:
Multiple instances of the Tag Processor have been combined to remove overhead, extra variables, and code confusion. The new flow is more linear throughout the function instead of branching.
Updated HTML is returned via
get_updated_html()
instead of casting to a string.The matching logic to find the inner block wrapper has been commented and the condition uses the null-coalescing operator now that WordPress requires PHP 7.0+.
When attempting to find the inner block wrapper at the end, a custom comparison is made against the
class
attribute instead of relying onnext_tag()
to find a tag with the given set of class names.The last refactor is important as a preliminary step to WordPress/wordpress-develop#5096 where
has_class()
andclass_list()
methods are being introduced to the Tag Processor. In that patch the implicit functionality of matching'class_name' => 'more than one class'
is removed since that's not a single class name, but many.Testing Instructions
Review the code changes, ensure tests pass.
There should be no functional or visual changes in this patch.