Skip to content
Merged
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
3 changes: 3 additions & 0 deletions backport-changelog/7.0/11686.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
https://github.com/WordPress/wordpress-develop/pull/11686

* https://github.com/WordPress/gutenberg/pull/78217
62 changes: 48 additions & 14 deletions lib/block-supports/custom-css.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,28 @@
*
* @param array $parsed_block The parsed block.
* @return array The same parsed block with custom CSS class name added if appropriate.
*
* @phpstan-param array{
* blockName: string|null,
* attrs: array{
* className?: string,
* style?: array{
* css?: string,
* ...
* },
* ...
* },
* ...
* } $parsed_block
*/
function gutenberg_render_custom_css_support_styles( $parsed_block ) {
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $parsed_block['blockName'] );

if ( ! block_has_support( $block_type, 'customCSS', true ) ) {
$custom_css = $parsed_block['attrs']['style']['css'] ?? null;
if ( ! is_string( $custom_css ) || '' === trim( $custom_css ) ) {
return $parsed_block;
}

$custom_css = trim( $parsed_block['attrs']['style']['css'] ?? '' );

if ( empty( $custom_css ) ) {
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $parsed_block['blockName'] );
if ( ! block_has_support( $block_type, 'customCSS', true ) ) {
return $parsed_block;
}

Expand All @@ -30,9 +41,10 @@ function gutenberg_render_custom_css_support_styles( $parsed_block ) {
}

// Generate a unique class name for this block instance.
$class_name = wp_unique_id_from_values( $parsed_block, 'wp-custom-css-' );
$updated_class_name = isset( $parsed_block['attrs']['className'] )
? $parsed_block['attrs']['className'] . " $class_name"
$class_name = wp_unique_id_from_values( $parsed_block, 'wp-custom-css-' );
$existing_class_name = $parsed_block['attrs']['className'] ?? null;
$updated_class_name = is_string( $existing_class_name )
? "$existing_class_name $class_name"
: $class_name;

_wp_array_set( $parsed_block, array( 'attrs', 'className' ), $updated_class_name );
Expand Down Expand Up @@ -64,26 +76,48 @@ function gutenberg_enqueue_block_custom_css() {
/**
* Applies the custom CSS class name to the block's rendered HTML.
*
* The class name is generated in `gutenberg_render_custom_css_support_styles`
* The class name is generated in {@see gutenberg_render_custom_css_support_styles()}
* and stored in block attributes. This filter adds it to the actual markup.
*
* @param string $block_content Rendered block content.
* @param array $block Block object.
* @return string Filtered block content.
*
* @phpstan-param array{
* attrs: array{
* className?: string,
* ...
* },
* ...
* } $block
*/
function gutenberg_render_custom_css_class_name( $block_content, $block ) {
$class_string = $block['attrs']['className'] ?? '';
preg_match( '/\bwp-custom-css-\S+\b/', $class_string, $matches );
$class_name_attr = $block['attrs']['className'] ?? null;

if ( ! is_string( $class_name_attr ) || ! str_contains( $class_name_attr, 'wp-custom-css-' ) ) {
return $block_content;
}

if ( empty( $matches ) ) {
// Parse out the 'wp-custom-css-*' class name added by gutenberg_render_custom_css_support_styles().
$custom_class_name = null;
$token_delimiter = " \t\f\r\n";
$class_token = strtok( $class_name_attr, $token_delimiter );
Comment thread
sirreal marked this conversation as resolved.
while ( false !== $class_token ) {
if ( str_starts_with( $class_token, 'wp-custom-css-' ) ) {
$custom_class_name = $class_token;
break;
}
$class_token = strtok( $token_delimiter );
}
if ( null === $custom_class_name ) {
return $block_content;
}

$tags = new WP_HTML_Tag_Processor( $block_content );

if ( $tags->next_tag() ) {
$tags->add_class( 'has-custom-css' );
$tags->add_class( $matches[0] );
$tags->add_class( $custom_class_name );
}

return $tags->get_updated_html();
Expand Down
38 changes: 38 additions & 0 deletions phpunit/block-supports/custom-css-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,44 @@ public function test_render_custom_css_class_name_extracts_class_from_mixed_clas
$this->assertStringContainsString( 'wp-custom-css-mixed123', $result, 'Custom CSS class should be extracted and added.' );
}

/**
* Tests that custom CSS class surrounded by ASCII whitespace (other than space) is extracted.
*
* @covers ::gutenberg_render_custom_css_class_name
*/
public function test_render_custom_css_class_name_extracts_class_between_whitespace() {
$block_content = '<div class="wp-block-paragraph">Test content</div>';
$block = array(
'blockName' => 'core/paragraph',
'attrs' => array(
'className' => "\twp-custom-css-123abc\t",
),
);

$result = gutenberg_render_custom_css_class_name( $block_content, $block );

$this->assertStringContainsString( 'wp-custom-css-123abc', $result, 'Custom CSS class should be extracted from between whitespace.' );
}

/**
* Tests that a class merely prefixed with wp-custom-css- (e.g. via a hyphen) is not treated as the custom CSS class.
*
* @covers ::gutenberg_render_custom_css_class_name
*/
public function test_render_custom_css_class_name_returns_unchanged_for_prefixed_class() {
$block_content = '<div class="wp-block-paragraph">Test content</div>';
$block = array(
'blockName' => 'core/paragraph',
'attrs' => array(
'className' => 'my-wp-custom-css-456def',
),
);

$result = gutenberg_render_custom_css_class_name( $block_content, $block );

$this->assertSame( $block_content, $result, 'Block content should remain unchanged when wp-custom-css- only appears as a substring of another class.' );
}

/**
* Tests that custom CSS support is enabled by default.
*
Expand Down
Loading