wp_get_layout_style() │ WP 5.9.0
Generates the CSS corresponding to the provided layout.
Internal function — this function is designed to be used by the kernel itself. It is not recommended to use this function in your code.
No Hooks.
Returns
string. CSS styles on success. Else, empty string.
Usage
wp_get_layout_style( $selector, $layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value, $block_spacing, $options );
- $selector(string) (required)
- CSS selector.
- $layout(array) (required)
- Layout object. The one that is passed has already checked the existence of default block layout.
- $has_block_gap_support(true|false)
- Whether the theme has support for the block gap.
Default:false - $gap_value(string|string[]|null)
- The block gap value to apply.
Default:null - $should_skip_gap_serialization(true|false)
- Whether to skip applying the user-defined value set in the editor.
Default:false - $fallback_gap_value(string|array)
- The block gap value to apply. If it's an array expected properties are "top" and/or "left".
Default:'0.5em' - $block_spacing(array|null)
- Custom spacing set on the block.
Default:null - $options(array)
Extra options for internal callers.
Default:
empty array-
viewport_overrides(array)
An array of layout property overrides for the sake of style generation, keyed by property name. -
rules_group(string|null)
Optional group name for the rules.
Default: null - has_block_gap_override(true|false)
Whether the block gap has been overridden.
Default: false
-
Changelog
| Since 5.9.0 | Introduced. |
| Since 6.1.0 | Added $block_spacing param, use style engine to enqueue styles. |
| Since 6.3.0 | Added grid layout type. |
| Since 6.6.0 | Removed duplicated selector from layout styles. Enabled negative margins for alignfull children of blocks with custom padding. |
| Since 7.1.0 | Added options array with options to process responsive styles. |
wp_get_layout_style() wp get layout style code WP 7.1
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;
/*
* 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 );
};
$layout_styles = array();
if ( 'default' === $layout_type ) {
if ( $has_block_gap_support && $should_output_block_gap ) {
if ( is_array( $gap_value ) ) {
$gap_value = $gap_value['top'] ?? null;
}
if ( null !== $gap_value && ! $should_skip_gap_serialization ) {
// Get spacing CSS variable from preset value if provided.
if ( is_string( $gap_value ) && str_contains( $gap_value, 'var:preset|spacing|' ) ) {
$index_to_splice = strrpos( $gap_value, '|' ) + 1;
$slug = _wp_to_kebab_case( substr( $gap_value, $index_to_splice ) );
$gap_value = "var(--wp--preset--spacing--$slug)";
}
array_push(
$layout_styles,
array(
'selector' => "$selector > *",
'declarations' => array(
'margin-block-start' => '0',
'margin-block-end' => '0',
),
),
array(
'selector' => "$selector > * + *",
'declarations' => array(
'margin-block-start' => $gap_value,
'margin-block-end' => '0',
),
)
);
}
}
} elseif ( 'constrained' === $layout_type ) {
$content_size = $layout_for_styles['contentSize'] ?? '';
$wide_size = $layout_for_styles['wideSize'] ?? '';
$justify_content = $layout_for_styles['justifyContent'] ?? 'center';
// 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] );
$wide_max_width_value = safecss_filter_attr( explode( ';', $wide_max_width_value )[0] );
$margin_left = 'left' === $justify_content ? '0 !important' : 'auto !important';
$margin_right = 'right' === $justify_content ? '0 !important' : 'auto !important';
if ( $should_output_constrained_sizes && ( $content_size || $wide_size || $is_resetting_constrained_sizes ) ) {
$content_size_declarations = array(
'max-width' => $all_max_width_value,
);
if ( null === $viewport_overrides || $has_justify_content_override ) {
$content_size_declarations['margin-left'] = $margin_left;
$content_size_declarations['margin-right'] = $margin_right;
}
array_push(
$layout_styles,
array(
'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))",
'declarations' => $content_size_declarations,
),
array(
'selector' => "$selector > .alignwide",
'declarations' => array( 'max-width' => $wide_max_width_value ),
),
array(
'selector' => "$selector .alignfull",
'declarations' => array( 'max-width' => 'none' ),
)
);
}
if ( null === $viewport_overrides && isset( $block_spacing ) ) {
$block_spacing_values = wp_style_engine_get_styles(
array(
'spacing' => $block_spacing,
)
);
/*
* Handle negative margins for alignfull children of blocks with custom padding set.
* They're added separately because padding might only be set on one side.
*/
if ( isset( $block_spacing_values['declarations']['padding-right'] ) ) {
$padding_right = $block_spacing_values['declarations']['padding-right'];
// Add unit if 0.
if ( '0' === $padding_right ) {
$padding_right = '0px';
}
$layout_styles[] = array(
'selector' => "$selector > .alignfull",
'declarations' => array( 'margin-right' => "calc($padding_right * -1)" ),
);
}
if ( isset( $block_spacing_values['declarations']['padding-left'] ) ) {
$padding_left = $block_spacing_values['declarations']['padding-left'];
// Add unit if 0.
if ( '0' === $padding_left ) {
$padding_left = '0px';
}
$layout_styles[] = array(
'selector' => "$selector > .alignfull",
'declarations' => array( 'margin-left' => "calc($padding_left * -1)" ),
);
}
}
if ( $has_justify_content_override && ! $should_output_constrained_sizes ) {
$layout_styles[] = array(
'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))",
'declarations' => array(
'margin-left' => $margin_left,
'margin-right' => $margin_right,
),
);
} elseif ( null === $viewport_overrides ) {
if ( 'left' === $justify_content ) {
$layout_styles[] = array(
'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))",
'declarations' => array( 'margin-left' => '0 !important' ),
);
}
if ( 'right' === $justify_content ) {
$layout_styles[] = array(
'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))",
'declarations' => array( 'margin-right' => '0 !important' ),
);
}
}
if ( $has_block_gap_support && $should_output_block_gap ) {
if ( is_array( $gap_value ) ) {
$gap_value = $gap_value['top'] ?? null;
}
if ( null !== $gap_value && ! $should_skip_gap_serialization ) {
// Get spacing CSS variable from preset value if provided.
if ( is_string( $gap_value ) && str_contains( $gap_value, 'var:preset|spacing|' ) ) {
$index_to_splice = strrpos( $gap_value, '|' ) + 1;
$slug = _wp_to_kebab_case( substr( $gap_value, $index_to_splice ) );
$gap_value = "var(--wp--preset--spacing--$slug)";
}
array_push(
$layout_styles,
array(
'selector' => "$selector > *",
'declarations' => array(
'margin-block-start' => '0',
'margin-block-end' => '0',
),
),
array(
'selector' => "$selector > * + *",
'declarations' => array(
'margin-block-start' => $gap_value,
'margin-block-end' => '0',
),
)
);
}
}
} elseif ( 'flex' === $layout_type ) {
$layout_orientation = $layout_for_styles['orientation'] ?? 'horizontal';
$justify_content_options = array(
'left' => 'flex-start',
'right' => 'flex-end',
'center' => 'center',
);
$vertical_alignment_options = array(
'top' => 'flex-start',
'center' => 'center',
'bottom' => 'flex-end',
);
if ( 'horizontal' === $layout_orientation ) {
$justify_content_options += array( 'space-between' => 'space-between' );
$vertical_alignment_options += array( 'stretch' => 'stretch' );
} else {
$justify_content_options += array( 'stretch' => 'stretch' );
$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' );
$should_output_flex_alignment = null === $viewport_overrides || $has_viewport_property_override( 'verticalAlignment' ) || $has_viewport_property_override( 'orientation' );
if ( $should_output_flex_wrap && ! empty( $layout_for_styles['flexWrap'] ) && 'nowrap' === $layout_for_styles['flexWrap'] ) {
$layout_styles[] = array(
'selector' => $selector,
'declarations' => array( 'flex-wrap' => 'nowrap' ),
);
}
if ( $has_block_gap_support && $should_output_block_gap && isset( $gap_value ) ) {
$combined_gap_value = '';
$gap_sides = is_array( $gap_value ) ? array( 'top', 'left' ) : array( 'top' );
foreach ( $gap_sides as $gap_side ) {
$process_value = $gap_value;
if ( is_array( $gap_value ) ) {
if ( is_array( $fallback_gap_value ) ) {
$fallback_value = $fallback_gap_value[ $gap_side ] ?? reset( $fallback_gap_value );
} else {
$fallback_value = $fallback_gap_value;
}
$process_value = $gap_value[ $gap_side ] ?? $fallback_value;
}
// Get spacing CSS variable from preset value if provided.
if ( is_string( $process_value ) && str_contains( $process_value, 'var:preset|spacing|' ) ) {
$index_to_splice = strrpos( $process_value, '|' ) + 1;
$slug = _wp_to_kebab_case( substr( $process_value, $index_to_splice ) );
$process_value = "var(--wp--preset--spacing--$slug)";
}
$combined_gap_value .= "$process_value ";
}
$gap_value = trim( $combined_gap_value );
if ( null !== $gap_value && ! $should_skip_gap_serialization ) {
$layout_styles[] = array(
'selector' => $selector,
'declarations' => array( 'gap' => $gap_value ),
);
}
}
if ( 'horizontal' === $layout_orientation ) {
/*
* Add this style only if is not empty for backwards compatibility,
* since we intend to convert blocks that had flex layout implemented
* by custom css.
*/
if ( $should_output_flex_justification && ! empty( $layout_for_styles['justifyContent'] ) && array_key_exists( $layout_for_styles['justifyContent'], $justify_content_options ) ) {
$layout_styles[] = array(
'selector' => $selector,
'declarations' => array( 'justify-content' => $justify_content_options[ $layout_for_styles['justifyContent'] ] ),
);
}
if ( $should_output_flex_alignment && ! empty( $layout_for_styles['verticalAlignment'] ) && array_key_exists( $layout_for_styles['verticalAlignment'], $vertical_alignment_options ) ) {
$layout_styles[] = array(
'selector' => $selector,
'declarations' => array( 'align-items' => $vertical_alignment_options[ $layout_for_styles['verticalAlignment'] ] ),
);
}
} else {
if ( $should_output_flex_orientation ) {
$layout_styles[] = array(
'selector' => $selector,
'declarations' => array( 'flex-direction' => 'column' ),
);
}
if ( $should_output_flex_justification && ! empty( $layout_for_styles['justifyContent'] ) && array_key_exists( $layout_for_styles['justifyContent'], $justify_content_options ) ) {
$layout_styles[] = array(
'selector' => $selector,
'declarations' => array( 'align-items' => $justify_content_options[ $layout_for_styles['justifyContent'] ] ),
);
} elseif ( $should_output_flex_justification ) {
$layout_styles[] = array(
'selector' => $selector,
'declarations' => array( 'align-items' => 'flex-start' ),
);
}
if ( $should_output_flex_alignment && ! empty( $layout_for_styles['verticalAlignment'] ) && array_key_exists( $layout_for_styles['verticalAlignment'], $vertical_alignment_options ) ) {
$layout_styles[] = array(
'selector' => $selector,
'declarations' => array( 'justify-content' => $vertical_alignment_options[ $layout_for_styles['verticalAlignment'] ] ),
);
}
}
} elseif ( 'grid' === $layout_type ) {
/*
* If the gap value is an array, we use the "left" value because it represents the vertical gap, which
* is the relevant one for computation of responsive grid columns.
*/
if ( is_array( $fallback_gap_value ) ) {
$responsive_gap_value = $fallback_gap_value['left'] ?? reset( $fallback_gap_value );
} else {
$responsive_gap_value = $fallback_gap_value;
}
if ( $has_block_gap_support && isset( $gap_value ) ) {
$combined_gap_value = '';
$gap_sides = is_array( $gap_value ) ? array( 'top', 'left' ) : array( 'top' );
foreach ( $gap_sides as $gap_side ) {
$process_value = $gap_value;
if ( is_array( $gap_value ) ) {
if ( is_array( $fallback_gap_value ) ) {
$fallback_value = $fallback_gap_value[ $gap_side ] ?? reset( $fallback_gap_value );
} else {
$fallback_value = $fallback_gap_value;
}
$process_value = $gap_value[ $gap_side ] ?? $fallback_value;
}
// Get spacing CSS variable from preset value if provided.
if ( is_string( $process_value ) && str_contains( $process_value, 'var:preset|spacing|' ) ) {
$index_to_splice = strrpos( $process_value, '|' ) + 1;
$slug = _wp_to_kebab_case( substr( $process_value, $index_to_splice ) );
$process_value = "var(--wp--preset--spacing--$slug)";
}
$combined_gap_value .= "$process_value ";
}
$gap_value = trim( $combined_gap_value );
$responsive_gap_value = $gap_value;
}
// Ensure 0 values have a unit so they work in calc().
if ( '0' === $responsive_gap_value || 0 === $responsive_gap_value ) {
$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 ) {
$should_output_grid_columns = true;
}
$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`.
*/
$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'] ) ) {
$max_value = 'max(min(' . $layout_for_styles['minimumColumnWidth'] . ', 100%), (100% - (' . $responsive_gap_value . ' * (' . $layout_for_styles['columnCount'] . ' - 1))) /' . $layout_for_styles['columnCount'] . ')';
$grid_declarations['grid-template-columns'] = 'repeat(' . $auto_placement . ', minmax(' . $max_value . ', 1fr))';
} elseif ( $should_output_grid_columns && ! empty( $layout_for_styles['columnCount'] ) ) {
$grid_declarations['grid-template-columns'] = 'repeat(' . $layout_for_styles['columnCount'] . ', minmax(0, 1fr))';
} elseif ( $should_output_grid_columns ) {
$minimum_column_width = ! empty( $layout_for_styles['minimumColumnWidth'] ) ? $layout_for_styles['minimumColumnWidth'] : '12rem';
$grid_declarations['grid-template-columns'] = 'repeat(' . $auto_placement . ', minmax(min(' . $minimum_column_width . ', 100%), 1fr))';
}
if ( ! empty( $grid_declarations ) ) {
$base_has_container_type = empty( $base_layout['columnCount'] ) || ( ! empty( $base_layout['columnCount'] ) && ! empty( $base_layout['minimumColumnWidth'] ) );
if ( empty( $layout_for_styles['columnCount'] ) || ! empty( $layout_for_styles['minimumColumnWidth'] ) ) {
if ( null === $viewport_overrides || ! $base_has_container_type ) {
$grid_declarations['container-type'] = 'inline-size';
}
}
$layout_styles[] = array(
'selector' => $selector,
'declarations' => $grid_declarations,
);
}
if ( $should_output_grid_rows ) {
$layout_styles[] = array(
'selector' => $selector,
'declarations' => array( 'grid-template-rows' => 'repeat(' . $layout_for_styles['rowCount'] . ', minmax(1rem, auto))' ),
);
}
if ( $has_block_gap_support && $should_output_block_gap && null !== $gap_value && ! $should_skip_gap_serialization ) {
$layout_styles[] = array(
'selector' => $selector,
'declarations' => array( 'gap' => $gap_value ),
);
}
}
if ( ! empty( $layout_styles ) ) {
if ( ! empty( $rules_group ) ) {
foreach ( $layout_styles as $index => $layout_style ) {
$layout_styles[ $index ]['rules_group'] = $rules_group;
}
}
/*
* Add to the style engine store to enqueue and render layout styles.
* Return compiled layout styles to retain backwards compatibility.
* Since https://github.com/WordPress/gutenberg/pull/42452,
* wp_enqueue_block_support_styles is no longer called in this block supports file.
*/
return wp_style_engine_get_stylesheet_from_css_rules(
$layout_styles,
array(
'context' => 'block-supports',
'prettify' => false,
)
);
}
return '';
}