Make WordPress Core

Changeset 61346


Ignore:
Timestamp:
12/03/2025 05:25:34 PM (less than one hour ago)
Author:
jonsurrell
Message:

HTML API: Ensure correct encoding of modified class names.

Some class names with HTML character references could be mishandled, for example:

  • Failure to remove an existing class like & with ::remove_class( '&' )
  • Double-encoding of an existing class like & after a modification, becoming &

The second case manifested after double-encoding prevention was removed from ::set_attribute() in [60919].

Developed in https://github.com/WordPress/wordpress-develop/pull/10591.

Props jonsurrell, dmsnell.
Fixes #64340.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/html-api/class-wp-html-tag-processor.php

    r61003 r61346  
    23432343
    23442344        if ( false === $existing_class && isset( $this->attributes['class'] ) ) {
    2345             $existing_class = substr(
    2346                 $this->html,
    2347                 $this->attributes['class']->value_starts_at,
    2348                 $this->attributes['class']->value_length
     2345            $existing_class = WP_HTML_Decoder::decode_attribute(
     2346                substr(
     2347                    $this->html,
     2348                    $this->attributes['class']->value_starts_at,
     2349                    $this->attributes['class']->value_length
     2350                )
    23492351            );
    23502352        }
  • trunk/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php

    r61003 r61346  
    28882888            'HTML tag opening inside attribute value'      => array(
    28892889                'input'    => '<pre id="<code" class="wp-block-code <code is poetry&gt;"><code>This &lt;is> a &lt;strong is="true">thing.</code></pre><span>test</span>',
    2890                 'expected' => '<pre foo="bar" id="<code" class="wp-block-code &lt;code is poetry&amp;gt; firstTag"><code class="secondTag">This &lt;is> a &lt;strong is="true">thing.</code></pre><span>test</span>',
     2890                'expected' => '<pre foo="bar" id="<code" class="wp-block-code &lt;code is poetry&gt; firstTag"><code class="secondTag">This &lt;is> a &lt;strong is="true">thing.</code></pre><span>test</span>',
    28912891            ),
    28922892            'HTML tag brackets in attribute values and data markup' => array(
    28932893                'input'    => '<pre id="<code-&gt;-block-&gt;" class="wp-block-code <code is poetry&gt;"><code>This &lt;is> a &lt;strong is="true">thing.</code></pre><span>test</span>',
    2894                 'expected' => '<pre foo="bar" id="<code-&gt;-block-&gt;" class="wp-block-code &lt;code is poetry&amp;gt; firstTag"><code class="secondTag">This &lt;is> a &lt;strong is="true">thing.</code></pre><span>test</span>',
     2894                'expected' => '<pre foo="bar" id="<code-&gt;-block-&gt;" class="wp-block-code &lt;code is poetry&gt; firstTag"><code class="secondTag">This &lt;is> a &lt;strong is="true">thing.</code></pre><span>test</span>',
    28952895            ),
    28962896            'Single and double quotes in attribute value'  => array(
     
    30303030
    30313031    /**
     3032     * @ticket 64340
     3033     */
     3034    public function test_class_changes_produce_correct_html() {
     3035        $processor = new WP_HTML_Tag_Processor( '<div class="&amp;">' );
     3036        $processor->next_tag();
     3037
     3038        $processor->add_class( '"' );
     3039        $processor->get_updated_html();
     3040
     3041        $processor->add_class( 'OK' );
     3042        $processor->get_updated_html();
     3043
     3044        $this->assertTrue( $processor->has_class( '&' ), 'Missing expected "&" class.' );
     3045        $this->assertTrue( $processor->has_class( '"' ), 'Missing expected \'"\' class.' );
     3046        $this->assertTrue( $processor->has_class( 'OK' ), 'Missing expected "OK" class.' );
     3047
     3048        $expected = '<div class="&amp; &quot; OK">';
     3049        $this->assertEqualHTML(
     3050            $expected,
     3051            $processor->get_updated_html(),
     3052            '<body>',
     3053            'HTML was not correctly updated after adding classes.'
     3054        );
     3055
     3056        $processor->remove_class( '&' );
     3057        $processor->get_updated_html();
     3058
     3059        $processor->remove_class( '"' );
     3060        $processor->get_updated_html();
     3061
     3062        $this->assertFalse( $processor->has_class( '&' ) );
     3063        $this->assertFalse( $processor->has_class( '"' ) );
     3064        $this->assertTrue( $processor->has_class( 'OK' ) );
     3065
     3066        $expected = '<div class="OK">';
     3067        $this->assertEqualHTML(
     3068            $expected,
     3069            $processor->get_updated_html(),
     3070            '<body>',
     3071            'HTML was not correctly updated after removing classes.'
     3072        );
     3073    }
     3074
     3075    /**
    30323076     * @covers WP_HTML_Tag_Processor::next_tag
    30333077     */
Note: See TracChangeset for help on using the changeset viewer.