Skip to content
Closed
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
49 changes: 47 additions & 2 deletions src/wp-includes/block-supports/layout.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,37 @@
* @since 5.8.0
*/

/**
* Gets the first style variation name from a className string that matches a registered style.
*
* @since 7.0.0
*
* @param string $class_name CSS class string for a block.
* @param array<string, array<string, mixed>> $registered_styles Currently registered block styles.
* @return string|null The name of the first registered variation, or null if none found.
*/
function wp_get_block_style_variation_name_from_registered_style( string $class_name, array $registered_styles = array() ): ?string {
if ( ! $class_name ) {
return null;
}

$registered_names = array_filter( array_column( $registered_styles, 'name' ) );

$prefix = 'is-style-';
$length = strlen( $prefix );

foreach ( explode( ' ', $class_name ) as $class ) {
if ( str_starts_with( $class, $prefix ) ) {
$variation = substr( $class, $length );
if ( 'default' !== $variation && in_array( $variation, $registered_names, true ) ) {
return $variation;
}
}
}

return null;
}

/**
* Returns layout definitions, keyed by layout type.
*
Expand Down Expand Up @@ -854,12 +885,26 @@ function wp_render_layout_support_flag( $block_content, $block ) {
$has_block_gap_support = isset( $block_gap );

// Get default blockGap value from global styles for use in layouts like grid.
// Check block-specific styles first, then fall back to root styles.
// Check style variation first, then block-specific styles, then fall back to root styles.
$block_name = $block['blockName'] ?? '';
if ( null === $global_styles ) {
$global_styles = wp_get_global_styles();
}
$global_block_gap_value = $global_styles['blocks'][ $block_name ]['spacing']['blockGap'] ?? ( $global_styles['spacing']['blockGap'] ?? null );

// Check if the block has an active style variation with a blockGap value.
// Only check the registry if the className contains a variation class to avoid unnecessary lookups.
$variation_block_gap_value = null;
$block_class_name = $block['attrs']['className'] ?? '';
if ( $block_class_name && str_contains( $block_class_name, 'is-style-' ) && $block_name ) {
$styles_registry = WP_Block_Styles_Registry::get_instance();
$registered_styles = $styles_registry->get_registered_styles_for_block( $block_name );
$variation_name = wp_get_block_style_variation_name_from_registered_style( $block_class_name, $registered_styles );
if ( $variation_name ) {
$variation_block_gap_value = $global_styles['blocks'][ $block_name ]['variations'][ $variation_name ]['spacing']['blockGap'] ?? null;
}
}

$global_block_gap_value = $variation_block_gap_value ?? $global_styles['blocks'][ $block_name ]['spacing']['blockGap'] ?? $global_styles['spacing']['blockGap'] ?? null;

if ( null !== $global_block_gap_value ) {
$fallback_gap_value = $global_block_gap_value;
Expand Down
148 changes: 148 additions & 0 deletions tests/phpunit/tests/block-supports/layout.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,22 @@ public function set_up() {
// Clear caches.
wp_clean_themes_cache();
unset( $GLOBALS['wp_themes'] );

/*
* Register a style variation with a custom blockGap value for testing.
*/
register_block_style(
'core/group',
array(
'name' => 'custom-gap',
'label' => 'Custom Gap',
'style_data' => array(
'spacing' => array(
'blockGap' => '99px',
),
),
)
);
}

public function tear_down() {
Expand All @@ -54,6 +70,11 @@ public function tear_down() {

wp_clean_themes_cache();
unset( $GLOBALS['wp_themes'] );

// Clean up variation test data.
unregister_block_style( 'core/group', 'custom-gap' );
WP_Theme_JSON_Resolver::clean_cached_data();

parent::tear_down();
}

Expand Down Expand Up @@ -727,4 +748,131 @@ public function data_layout_classname_with_custom_blocks() {
),
);
}

/**
* Tests that block style variations with blockGap values are applied to layout styles.
*
* @ticket 64624
* @covers ::wp_render_layout_support_flag
*/
public function test_layout_support_flag_uses_variation_block_gap_value() {
switch_theme( 'block-theme' );

$block_content = '<div class="wp-block-group is-style-custom-gap"></div>';
$block = array(
'blockName' => 'core/group',
'attrs' => array(
'className' => 'is-style-custom-gap',
'layout' => array(
'type' => 'grid',
'columnCount' => 3,
'minimumColumnWidth' => '12rem',
),
),
'innerBlocks' => array(),
'innerHTML' => '<div class="wp-block-group is-style-custom-gap"></div>',
'innerContent' => array(
'<div class="wp-block-group is-style-custom-gap"></div>',
),
);

wp_render_layout_support_flag( $block_content, $block );

// Get the generated CSS from the style engine.
$actual_stylesheet = wp_style_engine_get_stylesheet_from_context( 'block-supports', array( 'prettify' => false ) );

// The CSS grid declaration should contain the variation's blockGap value of 99px.
$this->assertStringContainsString(
'grid-template-columns:repeat(auto-fill, minmax(max(min(12rem, 100%), (100% - (99px * (3 - 1))) /3), 1fr))',
$actual_stylesheet,
'Generated CSS should contain the variation blockGap value of 99px.'
);
}

/**
* Tests that wp_get_block_style_variation_name_from_registered_style correctly extracts variation names from class strings.
*
* @ticket 64624
* @covers ::wp_get_block_style_variation_name_from_registered_style
*
* @dataProvider data_get_block_style_variation_name_from_registered_style
*
* @param string $class_name CSS class string to test.
* @param array $registered_styles Registered block styles.
* @param string|null $expected_result Expected variation name or null.
*/
public function test_get_block_style_variation_name_from_registered_style( $class_name, $registered_styles, $expected_result ) {
$result = wp_get_block_style_variation_name_from_registered_style( $class_name, $registered_styles );
$this->assertSame( $expected_result, $result );
}

/**
* Data provider for test_get_block_style_variation_name_from_registered_style.
*
* @return array
*/
public function data_get_block_style_variation_name_from_registered_style() {
return array(
'empty class name' => array(
'class_name' => '',
'registered_styles' => array(),
'expected_result' => null,
),
'no matching registered styles' => array(
'class_name' => 'is-style-shadowed wp-block-button',
'registered_styles' => array(
array( 'name' => 'rounded' ),
array( 'name' => 'outlined' ),
),
'expected_result' => null,
),
'single matching variation found' => array(
'class_name' => 'wp-block-button is-style-rounded',
'registered_styles' => array(
array( 'name' => 'rounded' ),
array( 'name' => 'outlined' ),
),
'expected_result' => 'rounded',
),
'ignores default style only' => array(
'class_name' => 'is-style-default wp-block-button',
'registered_styles' => array(
array( 'name' => 'default' ),
array( 'name' => 'rounded' ),
),
'expected_result' => null,
),
'ignores default and returns next variation' => array(
'class_name' => 'is-style-default is-style-rounded wp-block-button',
'registered_styles' => array(
array( 'name' => 'default' ),
array( 'name' => 'rounded' ),
array( 'name' => 'outlined' ),
),
'expected_result' => 'rounded',
),
'returns first matching variation when multiple present' => array(
'class_name' => 'is-style-shadowed is-style-rounded',
'registered_styles' => array(
array( 'name' => 'rounded' ),
array( 'name' => 'outlined' ),
array( 'name' => 'shadowed' ),
),
'expected_result' => 'shadowed',
),
'empty registered styles array' => array(
'class_name' => 'is-style-rounded',
'registered_styles' => array(),
'expected_result' => null,
),
'registered styles with missing name property' => array(
'class_name' => 'is-style-outlined wp-block-button',
'registered_styles' => array(
array( 'label' => 'Rounded' ),
array( 'name' => 'outlined' ),
),
'expected_result' => 'outlined',
),
);
}
}
Loading