Skip to content
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

Open
wants to merge 18 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 62 additions & 1 deletion src/wp-includes/class-wp-block.php
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ private function process_block_bindings() {
$supported_block_attributes = array(
'core/paragraph' => array( 'content' ),
'core/heading' => array( 'content' ),
'core/image' => array( 'id', 'url', 'title', 'alt' ),
'core/image' => array( 'id', 'url', 'title', 'alt', 'caption' ),
'core/button' => array( 'url', 'text', 'linkTarget', 'rel' ),
);

Expand Down Expand Up @@ -333,6 +333,67 @@ 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_builder = new class(
'Do not use this, it will not work. It is only here to create a subclass and call the static creator method',
WP_HTML_Processor::CONSTRUCTOR_UNLOCK_CODE
) extends WP_HTML_Processor {
/**
* Replace the inner content of a figcaption element with the passed content.
*
* DO NOT COPY THIS METHOD.
* THE HTML PROCESSOR WILL HAVE A PROPER METHOD.
* USE IT INSTEAD.
*
* @since 6.7.0
*
* @param string $new_content New content to insert in the figcaption element.
* @return bool Whether the inner content was properly replaced.
*/
public function set_figcaption_inner_html( $new_content ) {
// Check that the processor is paused on an opener tag.
if ( 'FIGCAPTION' !== $this->get_tag() || $this->is_tag_closer() ) {
return false;
}

// Set position of the opening tag.
$this->set_bookmark( 'opening' );

// Once this element closes the depth will be one shallower than it is now.
$depth = $this->get_current_depth();
while ( $this->next_token() && $this->get_current_depth() >= $depth ) {
// This is inside the FIGCAPTION element.
}

if ( null !== $this->get_last_error() || $this->paused_at_incomplete_token() ) {
return false;
}
SantosGuillamot marked this conversation as resolved.
Show resolved Hide resolved

// Set position of the closing tag.
$this->set_bookmark( 'closing' );

$opening = $this->bookmarks['_opening'];
$closing = $this->bookmarks['_closing'];
$start = $opening->start + $opening->length;

$this->lexical_updates[] = new WP_HTML_Text_Replacement(
$start,
$closing->start - $start,
wp_kses_post( $new_content )
SantosGuillamot marked this conversation as resolved.
Show resolved Hide resolved
);

return true;
}
};

$block_reader = $bindings_processor_builder::create_fragment( $block_content );
if ( $block_reader->next_tag( 'figcaption' ) ) {
$block_reader->set_figcaption_inner_html( $source_value );
}
return $block_reader->get_updated_html();
}

$block_reader = new WP_HTML_Tag_Processor( $block_content );

// TODO: Support for CSS selectors whenever they are ready in the HTML API.
Expand Down
37 changes: 37 additions & 0 deletions tests/phpunit/tests/block-bindings/render.php
Original file line number Diff line number Diff line change
Expand Up @@ -298,4 +298,41 @@ public function test_default_binding_for_pattern_overrides() {
'The `__default` attribute should be replaced with the real attribute prior to the callback.'
);
}

/**
* Tests that replacing inner text for bound attributes works as expected.
*
* @ticket 61466
*
* @covers WP_Block::process_block_bindings
*/
public function test_replacing_inner_text_with_block_bindings_value() {
$get_value_callback = function () {
return '$12.50';
};

register_block_bindings_source(
self::SOURCE_NAME,
array(
'label' => self::SOURCE_LABEL,
'get_value_callback' => $get_value_callback,
)
);

$block_content = <<<HTML
<!-- wp:image {"metadata":{"bindings":{"caption":{"source":"test/source"}}}} -->
<figure class="wp-block-image"><img src="https://example.com/image.jpg" /><figcaption class="wp-element-caption">Default value</figcaption></figure>
<!-- /wp:image -->
HTML;

$parsed_blocks = parse_blocks( $block_content );
$block = new WP_Block( $parsed_blocks[0] );
$result = $block->render();

$this->assertSame(
'<figure class="wp-block-image"><img src="https://example.com/image.jpg" /><figcaption class="wp-element-caption">$12.50</figcaption></figure>',
trim( $result ),
'The image caption should be updated with the value returned by the source.'
);
}
}
Loading