Skip to content
Draft
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
5 changes: 4 additions & 1 deletion src/wp-includes/html-api/class-wp-html-tag-processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2970,8 +2970,11 @@ public function get_attribute_names_with_prefix( $prefix ): ?array {
/*
* For the `class` attribute, ensure that enqueued class changes from
* `add_class` and `remove_class` are flushed into attribute updates.
* An enqueued `class` attribute update takes precedence over the
* input document in determining whether the attribute exists.
*/
$has_class = isset( $this->attributes['class'] );
$enqueued_class = $this->get_enqueued_attribute_value( 'class' );
$has_class = false === $enqueued_class ? isset( $this->attributes['class'] ) : null !== $enqueued_class;
if ( '' === $comparable || str_starts_with( 'class', $comparable ) ) {
foreach ( $this->classname_updates as $update ) {
if (
Expand Down
83 changes: 83 additions & 0 deletions tests/phpunit/tests/html-api/wpHtmlTagProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,89 @@ public function test_get_attribute_names_with_prefix_immediately_agrees_with_get
}
}

/**
* Ensures that get_attribute_names_with_prefix() reflects class name updates
* which follow an enqueued update to the `class` attribute.
*
* @ticket 65967
*
* @covers WP_HTML_Tag_Processor::get_attribute_names_with_prefix
*
* @dataProvider data_class_name_updates_after_class_attribute_updates
*
* @param string $html HTML containing a DIV tag.
* @param array[] $updates Method name and arguments of each update to the DIV tag, in order.
* @param string[] $expected_names Attribute names on the DIV tag after the updates.
*/
public function test_get_attribute_names_with_prefix_reflects_class_name_updates_after_class_attribute_updates( string $html, array $updates, array $expected_names ): void {
$processor = new WP_HTML_Tag_Processor( $html );
$processor->next_tag();

foreach ( $updates as $update ) {
$processor->{$update[0]}( ...array_slice( $update, 1 ) );
}

$this->assertSame(
$expected_names,
$processor->get_attribute_names_with_prefix( '' ),
'Failed to report the attribute names resulting from the enqueued updates.'
);

$updated = new WP_HTML_Tag_Processor( $processor->get_updated_html() );
$updated->next_tag();

$this->assertSame(
$expected_names,
$updated->get_attribute_names_with_prefix( '' ),
'Found different attribute names in the updated HTML: check test setup.'
);
}

/**
* Data provider.
*
* @return array<string, array{0: string, 1: list<non-empty-list<string|bool>>, 2: list<string>}>
*/
public static function data_class_name_updates_after_class_attribute_updates(): array {
return array(
'Class added after removing class attribute' => array(
'<div class="a">',
array( array( 'remove_attribute', 'class' ), array( 'add_class', 'b' ) ),
array( 'class' ),
),
'Class added after setting class attribute false' => array(
'<div class="a">',
array( array( 'set_attribute', 'class', false ), array( 'add_class', 'b' ) ),
array( 'class' ),
),
'Class added after removing empty class attribute' => array(
'<div class="">',
array( array( 'remove_attribute', 'class' ), array( 'add_class', 'b' ) ),
array( 'class' ),
),
'Class added after removing boolean class attribute' => array(
'<div class>',
array( array( 'remove_attribute', 'class' ), array( 'add_class', 'b' ) ),
array( 'class' ),
),
'Class added after removing duplicated class attribute' => array(
'<div class="a" class="b">',
array( array( 'remove_attribute', 'class' ), array( 'add_class', 'b' ) ),
array( 'class' ),
),
'Class added after removing class attribute, with other attributes' => array(
'<div id="x" class="a" title="y">',
array( array( 'remove_attribute', 'class' ), array( 'add_class', 'b' ) ),
array( 'id', 'class', 'title' ),
),
'Only class removed after adding class attribute' => array(
'<div>',
array( array( 'set_attribute', 'class', 'a' ), array( 'remove_class', 'a' ) ),
array(),
),
);
}

/**
* @ticket 56299
*
Expand Down
Loading