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
51 changes: 51 additions & 0 deletions src/wp-includes/class-wp-theme-json.php
Original file line number Diff line number Diff line change
Expand Up @@ -3497,6 +3497,44 @@ private static function update_button_width_declarations( $feature_declarations,
return $feature_declarations;
}

/**
* Converts `width` declarations to `flex-basis` for column blocks.
*
* The column block sizes itself with `flex-basis` rather than `width`
* because it lives in a flex container. This post-processes the computed
* style declarations so the correct CSS property is output.
*
* @since 7.2.0
*
* @param array $declarations An array of CSS declarations.
* @return array The updated declarations.
*/
private static function update_column_width_declarations( $declarations ) {
$has_width = false;

foreach ( $declarations as &$declaration ) {
if ( 'width' === $declaration['name'] ) {
$declaration['name'] = 'flex-basis';
$has_width = true;
}
}
unset( $declaration );

/*
* Columns without a width divide the remaining space between them via
* `flex-grow`. A column given a width should keep it instead, matching
* the behaviour of a width set on the block itself.
*/
if ( $has_width ) {
$declarations[] = array(
'name' => 'flex-grow',
'value' => '0',
);
}

return $declarations;
}

/**
* An internal method to get the block nodes from a theme.json file.
*
Expand Down Expand Up @@ -3860,6 +3898,10 @@ public function get_styles_for_block( $block_metadata ) {
// Compute declarations for remaining styles not covered by feature level selectors.
$style_variation_declarations[ $style_variation['selector'] ] = static::compute_style_properties( $style_variation_node, $settings, null, $this->theme_json );

if ( 'core/column' === ( $block_metadata['name'] ?? null ) ) {
$style_variation_declarations[ $style_variation['selector'] ] = self::update_column_width_declarations( $style_variation_declarations[ $style_variation['selector'] ] );
}

// Process pseudo-selectors for this variation (e.g., :hover, :focus)
if ( isset( $block_metadata['name'] ) ) {
$block_name = $block_metadata['name'];
Expand Down Expand Up @@ -3913,6 +3955,11 @@ public function get_styles_for_block( $block_metadata ) {

// Process base properties for this breakpoint.
$breakpoint_declarations = static::compute_style_properties( $breakpoint_node, $settings, null, $this->theme_json );

if ( 'core/column' === $block_name ) {
$breakpoint_declarations = self::update_column_width_declarations( $breakpoint_declarations );
}

if ( ! empty( $breakpoint_declarations ) ) {
$base_ruleset = static::to_ruleset( ':root :where(' . $style_variation['selector'] . ')', $breakpoint_declarations );
$variation_responsive_css .= $breakpoint_media . '{' . $base_ruleset . '}';
Expand Down Expand Up @@ -4081,6 +4128,10 @@ static function ( $pseudo_selector ) use ( $selector ) {
}
}

if ( 'core/column' === $block_name ) {
$declarations = self::update_column_width_declarations( $declarations );
}

/*
* If root styles has a background-image or a background (gradient) set,
* set the min-height to '100%'. Minus `--wp-admin--admin-bar--height` for logged-in view.
Expand Down
246 changes: 246 additions & 0 deletions tests/phpunit/tests/theme/wpThemeJson.php
Original file line number Diff line number Diff line change
Expand Up @@ -6872,6 +6872,252 @@ public function data_update_button_width_declarations() {
);
}

/**
* Tests that column block width declarations are output as `flex-basis`.
*
* @ticket 66055
*
* @dataProvider data_update_column_width_declarations
*
* @param array $theme_json_args Theme JSON arguments including styles and optional settings.
* @param string $expected_output Expected CSS output.
*/
public function test_update_column_width_declarations( $theme_json_args, $expected_output ) {
$theme_json = new WP_Theme_JSON(
array_merge(
array( 'version' => WP_Theme_JSON::LATEST_SCHEMA ),
$theme_json_args
),
'default'
);

$column_node = array(
'name' => 'core/column',
'path' => array( 'styles', 'blocks', 'core/column' ),
'selector' => '.wp-block-column',
'selectors' => array(
'root' => '.wp-block-column',
),
'duotone' => null,
'variations' => array(),
'css' => '.wp-block-column',
);

$this->assertSame( $expected_output, $theme_json->get_styles_for_block( $column_node ) );
}

/**
* Data provider for column width declaration tests.
*
* @return array
*/
public function data_update_column_width_declarations() {
return array(
'percentage width' => array(
array(
'styles' => array(
'blocks' => array(
'core/column' => array(
'dimensions' => array(
'width' => '25%',
),
),
),
),
),
'expected_output' => ':root :where(.wp-block-column){flex-basis: 25%;flex-grow: 0;}',
),
'fixed width' => array(
array(
'styles' => array(
'blocks' => array(
'core/column' => array(
'dimensions' => array(
'width' => '200px',
),
),
),
),
),
'expected_output' => ':root :where(.wp-block-column){flex-basis: 200px;flex-grow: 0;}',
),
'preset width' => array(
array(
'settings' => array(
'dimensions' => array(
'dimensionSizes' => array(
array(
'slug' => '50',
'name' => '50%',
'size' => '50%',
),
),
),
),
'styles' => array(
'blocks' => array(
'core/column' => array(
'dimensions' => array(
'width' => 'var:preset|dimension|50',
),
),
),
),
),
'expected_output' => ':root :where(.wp-block-column){flex-basis: var(--wp--preset--dimension--50);flex-grow: 0;}',
),
'width alongside other styles' => array(
array(
'styles' => array(
'blocks' => array(
'core/column' => array(
'color' => array(
'text' => 'red',
),
'dimensions' => array(
'width' => '25%',
),
),
),
),
),
'expected_output' => ':root :where(.wp-block-column){color: red;flex-basis: 25%;flex-grow: 0;}',
),
'no width leaves flex untouched' => array(
array(
'styles' => array(
'blocks' => array(
'core/column' => array(
'color' => array(
'text' => 'red',
),
),
),
),
),
'expected_output' => ':root :where(.wp-block-column){color: red;}',
),
);
}

/**
* Tests that a column width set within a responsive breakpoint is output as
* `flex-basis` within the matching media query.
*
* @ticket 66055
*/
public function test_update_column_width_declarations_for_breakpoints() {
$theme_json = new WP_Theme_JSON(
array(
'version' => WP_Theme_JSON::LATEST_SCHEMA,
'styles' => array(
'blocks' => array(
'core/column' => array(
'@mobile' => array(
'dimensions' => array(
'width' => '100%',
),
),
),
),
),
),
'default'
);

// Mirrors the responsive block node built by get_block_nodes().
$column_breakpoint_node = array(
'name' => 'core/column',
'path' => array( 'styles', 'blocks', 'core/column', '@mobile' ),
'media_query' => '@media (width <= 480px)',
'selector' => '.wp-block-column',
'selectors' => array(
'root' => '.wp-block-column',
),
'variations' => array(),
'css' => '.wp-block-column',
);

$this->assertSame(
'@media (width <= 480px){:root :where(.wp-block-column){flex-basis: 100%;flex-grow: 0;}}',
$theme_json->get_styles_for_block( $column_breakpoint_node )
);
}

/**
* Tests that a column width set on a block style variation is output as
* `flex-basis`, including when set within a responsive breakpoint.
*
* @ticket 66055
*/
public function test_update_column_width_declarations_for_style_variations() {
register_block_style(
'core/column',
array(
'name' => 'foo',
'label' => 'Foo',
)
);

$theme_json = new WP_Theme_JSON(
array(
'version' => WP_Theme_JSON::LATEST_SCHEMA,
'styles' => array(
'blocks' => array(
'core/column' => array(
'variations' => array(
'foo' => array(
'dimensions' => array(
'width' => '25%',
),
'@mobile' => array(
'dimensions' => array(
'width' => '100%',
),
),
),
),
),
),
),
),
'default'
);

$column_node = array(
'name' => 'core/column',
'path' => array( 'styles', 'blocks', 'core/column' ),
'selector' => '.wp-block-column',
'selectors' => array(
'root' => '.wp-block-column',
),
'duotone' => null,
'variations' => array(
array(
'name' => 'foo',
'path' => array( 'styles', 'blocks', 'core/column', 'variations', 'foo' ),
'selector' => '.is-style-foo',
),
),
'css' => '.wp-block-column',
);

$styles = $theme_json->get_styles_for_block( $column_node );

unregister_block_style( 'core/column', 'foo' );

$this->assertStringContainsString(
':root :where(.is-style-foo){flex-basis: 25%;flex-grow: 0;}',
$styles,
'The variation column width should be output as flex-basis.'
);
$this->assertStringContainsString(
'@media (width <= 480px){:root :where(.is-style-foo){flex-basis: 100%;flex-grow: 0;}}',
$styles,
'The responsive variation column width should be output as flex-basis.'
);
}

/**
* @ticket 57559
*/
Expand Down
Loading