Make WordPress Core

Changeset 58398


Ignore:
Timestamp:
06/13/2024 08:55:47 AM (5 weeks ago)
Author:
audrasjb
Message:

HTML API: Revert using regex in block bindings HTML replacement logic.

This changeset reverts part of the changes made in [58298] to avoid using regex that can cause potential bugs. It is indeed safer to revert these changes for now and do the refactoring once the HTML API supports CSS selectors and provides a way to set inner content.

It also adds a unit test to cover the regression experienced in https://github.com/WordPress/gutenberg/issues/62347.

Follow-up to [58298].

Props santosguillamot, gziolo.
Fixes #61385.
See #61351.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-block.php

    r58298 r58398  
    334334            case 'html':
    335335            case 'rich-text':
    336                 // Hardcode the selectors and processing until the HTML API is able to read CSS selectors and replace inner HTML.
    337                 // TODO: Use the HTML API instead.
    338                 if ( 'core/paragraph' === $this->name && 'content' === $attribute_name ) {
    339                     $selector = 'p';
    340                 }
    341                 if ( 'core/heading' === $this->name && 'content' === $attribute_name ) {
    342                     $selector = 'h[1-6]';
    343                 }
    344                 if ( 'core/button' === $this->name && 'text' === $attribute_name ) {
    345                     // Check if it is a <button> or <a> tag.
    346                     if ( preg_match( '/<button[^>]*>.*?<\/button>/', $block_content ) ) {
    347                         $selector = 'button';
    348                     } else {
    349                         $selector = 'a';
     336                $block_reader = new WP_HTML_Tag_Processor( $block_content );
     337
     338                // TODO: Support for CSS selectors whenever they are ready in the HTML API.
     339                // In the meantime, support comma-separated selectors by exploding them into an array.
     340                $selectors = explode( ',', $block_type->attributes[ $attribute_name ]['selector'] );
     341                // Add a bookmark to the first tag to be able to iterate over the selectors.
     342                $block_reader->next_tag();
     343                $block_reader->set_bookmark( 'iterate-selectors' );
     344
     345                // TODO: This shouldn't be needed when the `set_inner_html` function is ready.
     346                // Store the parent tag and its attributes to be able to restore them later in the button.
     347                // The button block has a wrapper while the paragraph and heading blocks don't.
     348                if ( 'core/button' === $this->name ) {
     349                    $button_wrapper                 = $block_reader->get_tag();
     350                    $button_wrapper_attribute_names = $block_reader->get_attribute_names_with_prefix( '' );
     351                    $button_wrapper_attrs           = array();
     352                    foreach ( $button_wrapper_attribute_names as $name ) {
     353                        $button_wrapper_attrs[ $name ] = $block_reader->get_attribute( $name );
    350354                    }
    351355                }
    352                 if ( empty( $selector ) ) {
    353                     return $block_content;
     356
     357                foreach ( $selectors as $selector ) {
     358                    // If the parent tag, or any of its children, matches the selector, replace the HTML.
     359                    if ( strcasecmp( $block_reader->get_tag( $selector ), $selector ) === 0 || $block_reader->next_tag(
     360                        array(
     361                            'tag_name' => $selector,
     362                        )
     363                    ) ) {
     364                        $block_reader->release_bookmark( 'iterate-selectors' );
     365
     366                        // TODO: Use `set_inner_html` method whenever it's ready in the HTML API.
     367                        // Until then, it is hardcoded for the paragraph, heading, and button blocks.
     368                        // Store the tag and its attributes to be able to restore them later.
     369                        $selector_attribute_names = $block_reader->get_attribute_names_with_prefix( '' );
     370                        $selector_attrs           = array();
     371                        foreach ( $selector_attribute_names as $name ) {
     372                            $selector_attrs[ $name ] = $block_reader->get_attribute( $name );
     373                        }
     374                        $selector_markup = "<$selector>" . wp_kses_post( $source_value ) . "</$selector>";
     375                        $amended_content = new WP_HTML_Tag_Processor( $selector_markup );
     376                        $amended_content->next_tag();
     377                        foreach ( $selector_attrs as $attribute_key => $attribute_value ) {
     378                            $amended_content->set_attribute( $attribute_key, $attribute_value );
     379                        }
     380                        if ( 'core/paragraph' === $this->name || 'core/heading' === $this->name ) {
     381                            return $amended_content->get_updated_html();
     382                        }
     383                        if ( 'core/button' === $this->name ) {
     384                            $button_markup  = "<$button_wrapper>{$amended_content->get_updated_html()}</$button_wrapper>";
     385                            $amended_button = new WP_HTML_Tag_Processor( $button_markup );
     386                            $amended_button->next_tag();
     387                            foreach ( $button_wrapper_attrs as $attribute_key => $attribute_value ) {
     388                                $amended_button->set_attribute( $attribute_key, $attribute_value );
     389                            }
     390                            return $amended_button->get_updated_html();
     391                        }
     392                    } else {
     393                        $block_reader->seek( 'iterate-selectors' );
     394                    }
    354395                }
    355                 $pattern = '/(<' . $selector . '[^>]*>).*?(<\/' . $selector . '>)/i';
    356                 return preg_replace( $pattern, '$1' . wp_kses_post( $source_value ) . '$2', $block_content );
     396                $block_reader->release_bookmark( 'iterate-selectors' );
     397                return $block_content;
    357398
    358399            case 'attribute':
  • trunk/tests/phpunit/tests/block-bindings/render.php

    r58289 r58398  
    237237
    238238    /**
     239     * Tests that including symbols and numbers works well with bound attributes.
     240     *
     241     * @ticket 61385
     242     *
     243     * @covers WP_Block::process_block_bindings
     244     */
     245    public function test_using_symbols_in_block_bindings_value() {
     246        $get_value_callback = function () {
     247            return '$12.50';
     248        };
     249
     250        register_block_bindings_source(
     251            self::SOURCE_NAME,
     252            array(
     253                'label'              => self::SOURCE_LABEL,
     254                'get_value_callback' => $get_value_callback,
     255            )
     256        );
     257
     258        $block_content = <<<HTML
     259<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"test/source"}}}} -->
     260<p>Default content</p>
     261<!-- /wp:paragraph -->
     262HTML;
     263        $parsed_blocks = parse_blocks( $block_content );
     264        $block         = new WP_Block( $parsed_blocks[0] );
     265        $result        = $block->render();
     266
     267        $this->assertSame(
     268            '<p>$12.50</p>',
     269            trim( $result ),
     270            'The block content should properly show the symbol and numbers.'
     271        );
     272    }
     273
     274    /**
    239275     * Tests if the `__default` attribute is replaced with real attribues for
    240276     * pattern overrides.
Note: See TracChangeset for help on using the changeset viewer.