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/10906.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
https://github.com/WordPress/wordpress-develop/pull/10906

* https://github.com/WordPress/gutenberg/pull/75360
48 changes: 46 additions & 2 deletions lib/block-supports/layout.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,36 @@
* @package gutenberg
*/

/**
* Get the first style variation name from a className string that matches a registered style.
*
* @param string $class_name CSS class string for a block.
* @param array $registered_styles Currently registered block styles.
*
* @return string|null The name of the first registered variation, or null if none found.
*/
function gutenberg_get_variation_name_from_class( $class_name, $registered_styles = array() ) {
if ( empty( $class_name ) ) {
return null;
}

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

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

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

return null;
}

/**
* Returns layout definitions, keyed by layout type.
*
Expand Down Expand Up @@ -898,12 +928,26 @@ function gutenberg_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 = gutenberg_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 ( ! empty( $block_class_name ) && str_contains( $block_class_name, 'is-style-' ) && ! empty( $block_name ) ) {
$styles_registry = WP_Block_Styles_Registry::get_instance();
$registered_styles = $styles_registry->get_registered_styles_for_block( $block_name );
$variation_name = gutenberg_get_variation_name_from_class( $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
2 changes: 1 addition & 1 deletion packages/block-editor/src/hooks/block-style-variation.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function getVariationMatches( className ) {
*
* @return {string|null} The name of the first registered variation.
*/
function getVariationNameFromClass( className, registeredStyles = [] ) {
export function getVariationNameFromClass( className, registeredStyles = [] ) {
// The global flag affects how capturing groups work in JS. So the regex
// below will only return full CSS classes not just the variation name.
const matches = getVariationMatches( className );
Expand Down
33 changes: 30 additions & 3 deletions packages/block-editor/src/hooks/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import clsx from 'clsx';
*/
import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose';
import { addFilter } from '@wordpress/hooks';
import { getBlockSupport, hasBlockSupport } from '@wordpress/blocks';
import {
getBlockSupport,
hasBlockSupport,
store as blocksStore,
} from '@wordpress/blocks';
import { useSelect } from '@wordpress/data';
import {
__experimentalToggleGroupControl as ToggleGroupControl,
Expand All @@ -31,6 +35,9 @@ import { LAYOUT_DEFINITIONS } from '../layouts/definitions';
import { useBlockSettings, useStyleOverride } from './utils';
import { unlock } from '../lock-unlock';
import { globalStylesDataKey } from '../store/private-keys';
import { getVariationNameFromClass } from './block-style-variation';

const VARIATION_PREFIX = 'is-style-';

const layoutBlockSupportKey = 'layout';
const { kebabCase } = unlock( componentsPrivateApis );
Expand Down Expand Up @@ -452,15 +459,35 @@ export const withLayoutStyles = createHigherOrderComponent(
);

// 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.
const globalStyles = settings[ globalStylesDataKey ];

// 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.
let variationBlockGapValue;
const className = attributes?.className;
if ( className?.includes( VARIATION_PREFIX ) ) {
const { getBlockStyles } = select( blocksStore );
const registeredStyles = getBlockStyles( name );
const variationName = getVariationNameFromClass(
className,
registeredStyles
);
variationBlockGapValue = variationName
? globalStyles?.blocks?.[ name ]?.variations?.[
variationName
]?.spacing?.blockGap
: undefined;
}

const globalBlockGapValue =
variationBlockGapValue ??
globalStyles?.blocks?.[ name ]?.spacing?.blockGap ??
globalStyles?.spacing?.blockGap;

return { blockGapSupport, globalBlockGapValue };
},
[ blockSupportsLayout, clientId ]
[ blockSupportsLayout, clientId, attributes?.className, name ]
);

if ( ! extraProps ) {
Expand Down
65 changes: 65 additions & 0 deletions phpunit/block-supports/layout-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,34 @@ 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.
*/
Comment on lines +41 to +43
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doc format

register_block_style(
'core/group',
array(
'name' => 'custom-gap',
'label' => 'Custom Gap',
'style_data' => array(
'spacing' => array(
'blockGap' => '99px',
),
),
)
);
}

public function tear_down() {
$GLOBALS['wp_theme_directories'] = $this->orig_theme_dir;
wp_clean_themes_cache();
unset( $GLOBALS['wp_themes'] );
WP_Style_Engine_CSS_Rules_Store_Gutenberg::remove_all_stores();

// 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 @@ -777,4 +798,48 @@ public function data_layout_support_flag_renders_consistent_container_hash() {
),
);
}

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

$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>',
),
);

gutenberg_render_layout_support_flag( $block_content, $block );

// Get the generated CSS from the style engine.
$actual_stylesheet = gutenberg_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.'
);

// Clean up.
remove_theme_support( 'appearance-tools' );
}
}
Loading