Skip to content
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
13 changes: 12 additions & 1 deletion src/wp-includes/block-supports/elements.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,18 @@
* @return string The unique class name.
*/
function wp_get_elements_class_name( $block ) {
return 'wp-elements-' . md5( serialize( $block ) );
static $seen_hashes = array();

$hash = md5( serialize( $block ) );

if ( isset( $seen_hashes[ $hash ] ) ) {
++$seen_hashes[ $hash ];
return 'wp-elements-' . md5( $hash . $seen_hashes[ $hash ] );
}

$seen_hashes[ $hash ] = 0;

return 'wp-elements-' . $hash;
}

/**
Expand Down
68 changes: 68 additions & 0 deletions tests/phpunit/tests/block-supports/wpRenderElementsSupport.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,74 @@ public function test_elements_block_support_class_with_invalid_elements_prefix()
);
}

/**
* Tests that duplicate blocks get distinct elements class names
* on their rendered markup to avoid CSS cascade conflicts.
*
* @ticket 65435
*
* @covers ::wp_get_elements_class_name
*/
public function test_elements_block_support_class_with_duplicate_blocks() {
$this->test_block_name = 'test/element-block-supports';

register_block_type(
$this->test_block_name,
array(
'api_version' => 3,
'attributes' => array(
'style' => array(
'type' => 'object',
),
),
'supports' => array(
'color' => array(
'link' => true,
),
),
)
);

$block = array(
'blockName' => $this->test_block_name,
'attrs' => array(
'style' => array(
'elements' => array(
'link' => array(
'color' => array(
'text' => 'var:preset|color|vivid-red',
),
),
),
),
),
);

$block_markup = '<p>Hello <a href="http://www.wordpress.org/">WordPress</a>!</p>';
$block_one = wp_render_elements_support_styles( $block );
$block_two = wp_render_elements_support_styles( $block );
$markup_one = wp_render_elements_class_name( $block_markup, $block_one );
$markup_two = wp_render_elements_class_name( $block_markup, $block_two );

$this->assertMatchesRegularExpression(
'/^<p class="wp-elements-[a-f0-9]{32}">Hello <a href="http:\/\/www.wordpress.org\/">WordPress<\/a>!<\/p>$/',
$markup_one,
'First block should have wp-elements class applied'
);
$this->assertMatchesRegularExpression(
'/^<p class="wp-elements-[a-f0-9]{32}">Hello <a href="http:\/\/www.wordpress.org\/">WordPress<\/a>!<\/p>$/',
$markup_two,
'Second block should also have wp-elements class applied'
);

// Extract class names and verify they are different.
preg_match( '/wp-elements-([a-f0-9]{32})/', $markup_one, $match_one );
preg_match( '/wp-elements-([a-f0-9]{32})/', $markup_two, $match_two );
$this->assertNotEmpty( $match_one, 'First block class name should be extractable' );
$this->assertNotEmpty( $match_two, 'Second block class name should be extractable' );
$this->assertNotSame( $match_one[1], $match_two[1], 'Class names for identical blocks should be unique' );
}

/**
* Data provider.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,71 @@ public function test_elements_block_support_styles( $color_settings, $elements_s
);
}

/**
* Tests that identical blocks with different elements styles
* generate distinct class names to avoid CSS cascade conflicts.
*
* @ticket 65435
*
* @covers ::wp_get_elements_class_name
*/
public function test_elements_block_support_styles_with_duplicate_blocks() {
$this->test_block_name = 'test/element-block-supports';

register_block_type(
$this->test_block_name,
array(
'api_version' => 3,
'attributes' => array(
'style' => array(
'type' => 'object',
),
),
'supports' => array(
'color' => array(
'link' => true,
),
),
)
);

$block = array(
'blockName' => $this->test_block_name,
'attrs' => array(
'style' => array(
'elements' => array(
'link' => array(
'color' => array(
'text' => 'blue',
),
),
),
),
),
);

// Process two identical blocks with the same elements styles.
wp_render_elements_support_styles( $block );
wp_render_elements_support_styles( $block );
$actual_stylesheet = wp_style_engine_get_stylesheet_from_context( 'block-supports', array( 'prettify' => false ) );

// Both rules should be present with distinct class names.
$this->assertMatchesRegularExpression(
'/\.wp-elements-[a-f0-9]{32} a:where\(:not\(\.wp-element-button\)\)\{color:blue;\}/',
$actual_stylesheet,
'First block element style should be present'
);
$this->assertMatchesRegularExpression(
'/\.wp-elements-[a-f0-9]{32} a:where\(:not\(\.wp-element-button\)\)\{color:blue;\}/',
$actual_stylesheet,
'Second block element style should also be present'
);
// Count the number of distinct class names to confirm uniqueness.
preg_match_all( '/\.wp-elements-([a-f0-9]{32})/', $actual_stylesheet, $matches );
$unique_classes = array_unique( $matches[1] );
$this->assertCount( 2, $unique_classes, 'Both blocks should produce distinct class names' );
}

/**
* Data provider.
*
Expand Down
Loading