Make WordPress Core


Ignore:
Timestamp:
06/13/2024 08:55:47 AM (3 months 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.

File:
1 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':
Note: See TracChangeset for help on using the changeset viewer.