Skip to content

Block Bindings: Support Image block's caption attribute, remove <figcaption> if empty#9702

Closed
ockham wants to merge 4 commits intoWordPress:trunkfrom
ockham:try/block-binding-conditional-image-caption-take-two
Closed

Block Bindings: Support Image block's caption attribute, remove <figcaption> if empty#9702
ockham wants to merge 4 commits intoWordPress:trunkfrom
ockham:try/block-binding-conditional-image-caption-take-two

Conversation

@ockham
Copy link
Contributor

@ockham ockham commented Sep 2, 2025

Implement "conditional" Block Bindings, using the example of the Image block's caption attribute. The following cases need to be supported when that attribute is bound to a Block Bindings source:

  • If the block was saved with a caption, and the Block Bindings source value is not empty, the caption is replaced with the latter.
  • If the block was saved with a caption, and the Block Bindings source value is empty, the <figcaption> element is removed.
  • If the block was saved without a caption, and the Block Bindings source value is not empty, a <figcaption> element is added (with the caption set to the Block Bindings source value).

The logic implemented in this PR isn't specific to the Image block; it can be extended to any block that conditionally includes an HTML element that corresponds to a rich-text block attribute (e.g. the Pullquote block's citation attribute, which corresponds to a <cite> element). See here for some discussion related to this solution.

See the screenshots in the "Testing Instructions" section for an illustrative example.

Testing Instructions

The first two cases from the above list are covered by unit tests.

To test manually, follow these instructions:

Create a new post, and paste the following markup:

<!-- wp:group {"layout":{"type":"flex","flexWrap":"nowrap"}} -->
<div class="wp-block-group"><!-- wp:image {"width":"126px","height":"auto","sizeSlug":"large","metadata":{"bindings":{"__default":{"source":"core/pattern-overrides"}},"name":"Bulbasur Override"}} -->
<figure class="wp-block-image size-large is-resized"><img src="https://img.pokemondb.net/artwork/large/bulbasaur.jpg" alt="" style="width:126px;height:auto"/><figcaption class="wp-element-caption">Replace</figcaption></figure>
<!-- /wp:image -->

<!-- wp:image {"width":"107px","height":"auto","sizeSlug":"large","metadata":{"bindings":{"__default":{"source":"core/pattern-overrides"}},"name":"Charmander Override"}} -->
<figure class="wp-block-image size-large is-resized"><img src="https://img.pokemondb.net/artwork/large/charmander.jpg" alt="" style="width:107px;height:auto"/><figcaption class="wp-element-caption"></figcaption></figure>
<!-- /wp:image -->

<!-- wp:image {"width":"118px","height":"auto","sizeSlug":"large","metadata":{"bindings":{"__default":{"source":"core/pattern-overrides"}},"name":"Squirtle Override"}} -->
<figure class="wp-block-image size-large is-resized"><img src="https://img.pokemondb.net/artwork/large/squirtle.jpg" alt="" style="width:118px;height:auto"/><figcaption class="wp-element-caption">Remove</figcaption></figure>
<!-- /wp:image --></div>
<!-- /wp:group -->

The resulting content should look like this:

image

In the Visual Editor, select all three image blocks. Then, from the block toolbar, select "Create Pattern". Assign a name of your choice to the pattern (e.g. "Pokemons").

Below the three image blocks that now form a pattern, insert another instance of the "Pokemons" pattern. Then, edit the newly inserted instance as follows:

  1. Change the caption of the first image to "Bulbasaur".
  2. Add a caption to the second image ("Charmander").
  3. Remove the caption of third image.

Publish the post, and verify that the result looks like this:

image

(Testing instructions largely copied from WordPress/gutenberg#70642.)

Supersedes ockham#5.

Trac ticket: https://core.trac.wordpress.org/ticket/63919


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.

@ockham ockham self-assigned this Sep 2, 2025
@github-actions
Copy link

github-actions bot commented Sep 2, 2025

Test using WordPress Playground

The 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

  • The Plugin and Theme Directories cannot be accessed within Playground.
  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

@github-actions
Copy link

github-actions bot commented Sep 3, 2025

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 props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props bernhard-reiter.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

return true;
}

public function remove_node() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing function doc.

Comment on lines +530 to +532
// Find matching tag closer.
while ( $this->next_token() && $this->get_current_depth() >= $depth ) {
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need these condition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is needed. It's a loop that advances the internal cursor until a matching tag closer is found for the opener that we started from.

,
'<div class="wp-block-button"><a class="wp-block-button__link wp-element-button">test source value</a></div>',
),
'image block' => array(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on my testing experience described in WordPress/gutenberg#71483 (comment), we might need some coverage when replacing HTML attributes, too. In that particular case, src in the <img /> didn't get replaced for unknown reasons with the Pattern Overrides mechanism.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see it's covered in test_update_block_with_value_from_source_image_placeholder test:

$this->assertSame(
'https://example.com/image.jpg',
$block->attributes['url'],
"The 'url' attribute should be updated with the value returned by the source."
);
$this->assertSame(
'<figure class="wp-block-image"><img src="https://example.com/image.jpg" alt=""/></figure>',
trim( $result ),
'The block content should be updated with the value returned by the source.'
);

That might be an issue in the Gutenberg implementation. However, adding more diverse cases here could still be beneficial.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on my testing experience described in WordPress/gutenberg#71483 (comment), we might need some coverage when replacing HTML attributes, too. In that particular case, src in the <img /> didn't get replaced for unknown reasons with the Pattern Overrides mechanism.

Test coverage for this scenario was added on the GB side as part of the fix to the bug you mentioned (src not being replaced).

The bug was specific to GB's compat layer (and can't manifest in Core in the same way), but we can carry over the test coverage to Core just for parity's sake.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done over at the new PR: 339fbe8

@ockham
Copy link
Contributor Author

ockham commented Sep 18, 2025

Closing this due to reasons laid out in this comment.

I'll follow-up with a trimmed-down PR that only adds support for the Image block's caption attribute (but doesn't remove <figcaption> if it's empty).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants