diff --git a/src/wp-includes/block-supports/layout.php b/src/wp-includes/block-supports/layout.php index c10da1f8db04b..db96f3c56f113 100644 --- a/src/wp-includes/block-supports/layout.php +++ b/src/wp-includes/block-supports/layout.php @@ -497,13 +497,16 @@ function wp_register_layout_support( $block_type ) { * @return string CSS styles on success. Else, empty string. */ function wp_get_layout_style( $selector, $layout, $has_block_gap_support = false, $gap_value = null, $should_skip_gap_serialization = false, $fallback_gap_value = '0.5em', $block_spacing = null, $options = array() ) { - $base_layout = is_array( $layout ) ? $layout : array(); - $viewport_overrides = $options['viewport_overrides'] ?? null; - $layout_for_styles = null === $viewport_overrides ? $base_layout : array_replace( $base_layout, $viewport_overrides ); - $layout_type = $base_layout['type'] ?? 'default'; - $rules_group = $options['rules_group'] ?? null; - $has_block_gap_override = ! empty( $options['has_block_gap_override'] ); - $should_output_block_gap = null === $viewport_overrides || $has_block_gap_override; + $base_layout = is_array( $layout ) ? $layout : array(); + $viewport_overrides = $options['viewport_overrides'] ?? null; + $layout_for_styles = null === $viewport_overrides ? $base_layout : array_replace( $base_layout, $viewport_overrides ); + $layout_type = $base_layout['type'] ?? 'default'; + $rules_group = $options['rules_group'] ?? null; + $has_block_gap_override = ! empty( $options['has_block_gap_override'] ); + $should_output_block_gap = null === $viewport_overrides || $has_block_gap_override; + // Viewport styles only store changed fields. If a field is present with null, + // the user cleared a value inherited from the default viewport, so check + // whether the key exists rather than whether the value is truthy. $has_viewport_property_override = static function ( $property ) use ( $viewport_overrides ) { return array_key_exists( $property, $viewport_overrides ); }; @@ -546,8 +549,29 @@ function wp_get_layout_style( $selector, $layout, $has_block_gap_support = false $wide_size = $layout_for_styles['wideSize'] ?? ''; $justify_content = $layout_for_styles['justifyContent'] ?? 'center'; - $all_max_width_value = $content_size ? $content_size : $wide_size; - $wide_max_width_value = $wide_size ? $wide_size : $content_size; + // Check if viewport-specific ("override") values exist. Null values are valid and mean the user cleared a value inherited from the default viewport. + $has_justify_content_override = null !== $viewport_overrides && $has_viewport_property_override( 'justifyContent' ); + $has_content_size_override = null !== $viewport_overrides && $has_viewport_property_override( 'contentSize' ); + $has_wide_size_override = null !== $viewport_overrides && $has_viewport_property_override( 'wideSize' ); + + /* + * Styles should be output either if there are no viewport overrides (this is the default case), or if the user has set a new viewport-specific + * value for contentSize or wideSize. If a viewport clears a custom constrained size, reset to the global layout variable. + */ + $should_output_constrained_sizes = null === $viewport_overrides || $has_content_size_override || $has_wide_size_override; + $is_resetting_constrained_sizes = null !== $viewport_overrides && + ( + ( $has_content_size_override && ! $content_size ) || + ( $has_wide_size_override && ! $wide_size ) + ); + + // If a viewport clears a custom constrained size, reset to the global layout variable. + $all_max_width_value = $content_size + ? $content_size + : ( $wide_size && ! $has_content_size_override ? $wide_size : 'var(--wp--style--global--content-size, none)' ); + $wide_max_width_value = $wide_size + ? $wide_size + : ( $content_size && ! $has_wide_size_override ? $content_size : 'var(--wp--style--global--wide-size, none)' ); // Make sure there is a single CSS rule, and all tags are stripped for security. $all_max_width_value = safecss_filter_attr( explode( ';', $all_max_width_value )[0] ); @@ -556,9 +580,7 @@ function wp_get_layout_style( $selector, $layout, $has_block_gap_support = false $margin_left = 'left' === $justify_content ? '0 !important' : 'auto !important'; $margin_right = 'right' === $justify_content ? '0 !important' : 'auto !important'; - $has_justify_content_override = null !== $viewport_overrides && $has_viewport_property_override( 'justifyContent' ); - $should_output_constrained_sizes = null === $viewport_overrides || $has_viewport_property_override( 'contentSize' ) || $has_viewport_property_override( 'wideSize' ); - if ( $should_output_constrained_sizes && ( $content_size || $wide_size ) ) { + if ( $should_output_constrained_sizes && ( $content_size || $wide_size || $is_resetting_constrained_sizes ) ) { $content_size_declarations = array( 'max-width' => $all_max_width_value, ); @@ -698,6 +720,10 @@ function wp_get_layout_style( $selector, $layout, $has_block_gap_support = false $vertical_alignment_options += array( 'space-between' => 'space-between' ); } + /* + * Styles should be output either if there are no viewport overrides (this is the default case), or if the user has set a new viewport-specific + * value for any of the flex properties. + */ $should_output_flex_wrap = null === $viewport_overrides || $has_viewport_property_override( 'flexWrap' ); $should_output_flex_orientation = null === $viewport_overrides || $has_viewport_property_override( 'orientation' ); $should_output_flex_justification = null === $viewport_overrides || $has_viewport_property_override( 'justifyContent' ) || $has_viewport_property_override( 'orientation' ); @@ -828,6 +854,10 @@ function wp_get_layout_style( $selector, $layout, $has_block_gap_support = false $responsive_gap_value = '0px'; } + /* + * Styles should be output either if there are no viewport overrides (this is the default case), or if the user has set a new viewport-specific + * value for any of the grid properties. + */ $should_output_grid_columns = null === $viewport_overrides || $has_viewport_property_override( 'minimumColumnWidth' ) || $has_viewport_property_override( 'columnCount' ) || $has_viewport_property_override( 'autoFit' ); $uses_gap_in_grid_columns = ! empty( $layout_for_styles['columnCount'] ) && ! empty( $layout_for_styles['minimumColumnWidth'] ); if ( $has_block_gap_override && $uses_gap_in_grid_columns ) { @@ -837,8 +867,10 @@ function wp_get_layout_style( $selector, $layout, $has_block_gap_support = false $should_output_grid_rows = ( null === $viewport_overrides || $has_viewport_property_override( 'rowCount' ) ) && ! empty( $layout_for_styles['columnCount'] ) && ! empty( $layout_for_styles['rowCount'] ); $grid_declarations = array(); - // When enabled, columns stretch to fill the available space using - // `auto-fit`; otherwise empty tracks are preserved with `auto-fill`. + /* + * When enabled, columns stretch to fill the available space using + * `auto-fit`; otherwise empty tracks are preserved with `auto-fill`. + */ $auto_placement = ! empty( $layout_for_styles['autoFit'] ) ? 'auto-fit' : 'auto-fill'; if ( $should_output_grid_columns && ! empty( $layout_for_styles['columnCount'] ) && ! empty( $layout_for_styles['minimumColumnWidth'] ) ) { diff --git a/tests/phpunit/tests/block-supports/wpGetLayoutStyle.php b/tests/phpunit/tests/block-supports/wpGetLayoutStyle.php index 190170be1d933..4088a260fc157 100644 --- a/tests/phpunit/tests/block-supports/wpGetLayoutStyle.php +++ b/tests/phpunit/tests/block-supports/wpGetLayoutStyle.php @@ -13,6 +13,7 @@ class Tests_Block_Supports_WpGetLayoutStyle extends WP_UnitTestCase { 'should_skip_gap_serialization' => false, 'fallback_gap_value' => '0.5em', 'block_spacing' => null, + 'options' => array(), ); /** @@ -32,7 +33,8 @@ public function test_wp_get_layout_style( array $args, $expected_output ) { $args['gap_value'], $args['should_skip_gap_serialization'], $args['fallback_gap_value'], - $args['block_spacing'] + $args['block_spacing'], + $args['options'] ); $this->assertSame( $expected_output, $layout_styles ); @@ -120,6 +122,21 @@ public function data_wp_get_layout_style() { ), 'expected_output' => '.wp-layout > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width:800px;margin-left:auto !important;margin-right:auto !important;}.wp-layout > .alignwide{max-width:1200px;}.wp-layout .alignfull{max-width:none;}.wp-layout > .alignfull{margin-right:calc(10px * -1);margin-left:calc(20px * -1);}', ), + 'constrained layout with content size unset in viewport' => array( + 'args' => array( + 'selector' => '.wp-layout', + 'layout' => array( + 'type' => 'constrained', + 'contentSize' => '800px', + ), + 'options' => array( + 'viewport_overrides' => array( + 'contentSize' => null, + ), + ), + ), + 'expected_output' => '.wp-layout > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width:var(--wp--style--global--content-size, none);}.wp-layout > .alignwide{max-width:var(--wp--style--global--wide-size, none);}.wp-layout .alignfull{max-width:none;}', + ), 'constrained layout with block gap support' => array( 'args' => array( 'selector' => '.wp-layout',