-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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 bindings: Add support for image caption #6838
base: trunk
Are you sure you want to change the base?
Block bindings: Add support for image caption #6838
Conversation
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
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.
@SantosGuillamot this is a fine use of sub-classing, though I do want us to be extra careful here, as by adding subclassing code into Core we are setting an example to others, and this is not the example we want to send more broadly, especially since it's coming later.
To that end there are a few things to start with on this. I hope it's okay to extra resilient here.
-
There's no need to create the anonymous class outside of the
if ( 'core/image' … ) {}
block. It's probably fine, but since all of the processing happens within, its scope might be more clear if left inside of it instead of outside of it. -
let's follow all of Core's documentation requirements, such as a docblock for the added method.
-
one thing I think is essential for "exceptional cases" like this in Core is full checking to ensure we're not trying to replace the wrong tokens. for example, here we might check that the processor is paused on an opening tag. it would be ideal if we also put a terse but scary warning right at the top indicating that this is a stop-gap measure in Core not to be emulated.
public function set_inner_text( $raw_text_content ) {
if (
WP_HTML_Tag_Processor::STATE_MATCHED_TAG !== $this->parser_state ||
$this->is_tag_closer()
) {
return false;
}
}
-
It might be ideal to wait to grab the bookmark until the end. The greater the distance between binding the bookmark offsets and its use, the greater the danger. That is, it's fine to set the bookmark at the top, but we shouldn't read it until we add the
lexical_updates[]
. -
This one isn't important, but since this processor dies immediately we don't need to release the bookmarks.
-
The comment on "Visit the closing tag" is nice, but I think it could really help to indicate that this is a best-effort guess and that code should rely on the HTML Processor for this kind of operation.
To that end, we expect to get image blocks here don't we? Is there anything in the image block that the HTML Processor doesn't support? Maybe we should start instead with it and see if we can skip the Tag Processor.
Thanks a lot for all the feedback, @dmsnell ! That's really helpful 🙂 I totally agree we should be really careful, so please share any more suggestions you have. Going to your points:
Yes, I think it should be safe to use the HTML Processor. I've just changed the code to extend that class instead of the Tag Processor: link. I had to pass the
I've moved it into the conditional now. At first, I kept it outside because I was considering using it for other blocks like the paragraph, heading, or button. But we can move it out if we decide to take that approach.
I added a comment to the function here. I added a warning notice trying to push back users from replicating that code. Let me know if that's what you had in mind.
I added this check as well: link.
I moved this logic just before using lexical updates as suggested: link.
I've removed the bookmarks now.
I added another comment trying to clarify this: link. Please let me know further improvements! |
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN:
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
I'm quite worried about introducing caption support this late in the release cycle. Imo it deserves some testing as a feature in the GB plugin first. I've made this alternative PR that disallows overrides for an image with caption: WordPress/gutenberg#62747. |
I totally understand the concerns. And thanks a lot for the feedback. I agree that if support for image caption is not added, code to disallowing overrides in images with captions for 6.6 could be a good alternative. |
src/wp-includes/class-wp-block.php
Outdated
@@ -333,6 +333,74 @@ private function replace_html( string $block_content, string $attribute_name, $s | |||
switch ( $block_type->attributes[ $attribute_name ]['source'] ) { | |||
case 'html': | |||
case 'rich-text': | |||
if ( 'core/image' === $this->name && 'caption' === $attribute_name ) { | |||
// Create private anonymous class until the HTML API provides `set_inner_html` method. | |||
$bindings_processor = new class( $block_content, WP_HTML_Processor::CONSTRUCTOR_UNLOCK_CODE ) extends WP_HTML_Processor { |
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.
this is an interesting side-effect of that choice. I think we should rename that constant to something scarier, like what its value is.
I kind of like that it makes anonymous classes stand out more.
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.
@sirreal I think this is a really good example of a part of the HTML Processor we're going to have to improve.
not only is the unlock code ugly here (ugly, because it shouts how this is work-around territory), but also by calling the constructor directly we bypass setting up the context node and the HTML node. in effect, this is starting as a full parser instead of a fragment parser.
I wonder how we can better allow subclassing without this hassle and risk.
Co-authored-by: Luis Herranz <[email protected]>
43ecd61
to
ac43482
Compare
src/wp-includes/class-wp-block.php
Outdated
} | ||
}; | ||
|
||
$block_reader = $bindings_processor::create_fragment( $block_content ); |
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.
whoah. this is unrelated to your changes @SantosGuillamot, but this line really confuses me, purely based on how PHP's anonymous classes work. @sirreal maybe what I wrote above is fine, and when we call new class( ...$args )
they don't matter?
yes, I just tested and this is odd. calling $bindings_processor->next_token()
will crash because it never finds the context node. this means that it looks like an HTML Processor but isn't. it's better as a HTML Processor Builder.
@SantosGuillamot I wonder if we could take advantage of this in line 338 and instead of passing $block_content
pass something like "do not use this, it will not work. it's only here to create a subclass and call the static creator method"
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 am not 100% this is what you meant, but I made this change to address the feedback. Let me know if that's not what you were suggesting.
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 @SantosGuillamot for all your adjustments. I think this is worth giving it a try. I'd prefer the name of the method be scarier, like seriously_wait_for_core_to_replace_inner_html()
but that's just a personal preference. This will be I think the first subclass going into Core doing dangerous operations; it makes me nervous is all.
While I agree we could change the name to prevent users even more from copying it,
Apart from that, we could always wait to support the image caption until the HTML Processor provides its own method. Any thoughts? |
I would go with |
What's the status on this? it seems reasonable at the moment, unless there are concerns still about it coming late in the cycle. |
It wasn't considered a priority, and I personally didn't find time to push it. It would probably need a small refactor and testing in Gutenberg as well: link. Taking into account that the last Gutenberg version included in 6.7 beta will be on Sep 18th, I personally don't have the bandwidth to work on it, but I'm happy to help if needed. |
@SantosGuillamot and I did some work on an implementation leveraging the HTML processor and using a |
Trac ticket: https://core.trac.wordpress.org/ticket/61466
This pull request should be tested together with this other one from Gutenberg, because it needs changes in the image render file.
What?
Add support for the image caption attribute in block bindings.
Why?
There is an issue with pattern overrides caused by this: WordPress/gutenberg#62287.
Additionally, it is a good enhancement.
How?
I created an anonymous class to extend the tag processor and include
set_inner_text
until there is a similar method provided by default.Additionally, in Gutenberg pull request, I'm modifying the render file of the image to:
figcaption
element when it exists, and the binding value is empty.figcaption
element when it doesn't exist, and the binding value is not empty.This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.