wp_render_layout_support_flag

The timeline below displays how wordpress function wp_render_layout_support_flag has changed across different WordPress versions. If a version is not listed, refer to the next available version below.

WordPress Version: 6.5

/**
 * Renders the layout config to the block wrapper.
 *
 * @since 5.8.0
 * @since 6.3.0 Adds compound class to layout wrapper for global spacing styles.
 * @since 6.3.0 Check for layout support via the `layout` key with fallback to `__experimentalLayout`.
 * @access private
 *
 * @param string $block_content Rendered block content.
 * @param array  $block         Block object.
 * @return string Filtered block content.
 */
function wp_render_layout_support_flag($block_content, $block)
{
    $block_type = WP_Block_Type_Registry::get_instance()->get_registered($block['blockName']);
    $block_supports_layout = block_has_support($block_type, 'layout', false) || block_has_support($block_type, '__experimentalLayout', false);
    $layout_from_parent = isset($block['attrs']['style']['layout']['selfStretch']) ? $block['attrs']['style']['layout']['selfStretch'] : null;
    if (!$block_supports_layout && !$layout_from_parent) {
        return $block_content;
    }
    $outer_class_names = array();
    if ('fixed' === $layout_from_parent || 'fill' === $layout_from_parent) {
        $container_content_class = wp_unique_id('wp-container-content-');
        $child_layout_styles = array();
        if ('fixed' === $layout_from_parent && isset($block['attrs']['style']['layout']['flexSize'])) {
            $child_layout_styles[] = array('selector' => ".{$container_content_class}", 'declarations' => array('flex-basis' => $block['attrs']['style']['layout']['flexSize'], 'box-sizing' => 'border-box'));
        } elseif ('fill' === $layout_from_parent) {
            $child_layout_styles[] = array('selector' => ".{$container_content_class}", 'declarations' => array('flex-grow' => '1'));
        }
        wp_style_engine_get_stylesheet_from_css_rules($child_layout_styles, array('context' => 'block-supports', 'prettify' => false));
        $outer_class_names[] = $container_content_class;
    }
    // Prep the processor for modifying the block output.
    $processor = new WP_HTML_Tag_Processor($block_content);
    // Having no tags implies there are no tags onto which to add class names.
    if (!$processor->next_tag()) {
        return $block_content;
    }
    /*
     * A block may not support layout but still be affected by a parent block's layout.
     *
     * In these cases add the appropriate class names and then return early; there's
     * no need to investigate on this block whether additional layout constraints apply.
     */
    if (!$block_supports_layout && !empty($outer_class_names)) {
        foreach ($outer_class_names as $class_name) {
            $processor->add_class($class_name);
        }
        return $processor->get_updated_html();
    } elseif (!$block_supports_layout) {
        // Ensure layout classnames are not injected if there is no layout support.
        return $block_content;
    }
    $global_settings = wp_get_global_settings();
    $fallback_layout = isset($block_type->supports['layout']['default']) ? $block_type->supports['layout']['default'] : array();
    if (empty($fallback_layout)) {
        $fallback_layout = isset($block_type->supports['__experimentalLayout']['default']) ? $block_type->supports['__experimentalLayout']['default'] : array();
    }
    $used_layout = isset($block['attrs']['layout']) ? $block['attrs']['layout'] : $fallback_layout;
    $class_names = array();
    $layout_definitions = wp_get_layout_definitions();
    /*
     * Uses an incremental ID that is independent per prefix to make sure that
     * rendering different numbers of blocks doesn't affect the IDs of other
     * blocks. Makes the CSS class names stable across paginations
     * for features like the enhanced pagination of the Query block.
     */
    $container_class = wp_unique_prefixed_id('wp-container-' . sanitize_title($block['blockName']) . '-is-layout-');
    // Set the correct layout type for blocks using legacy content width.
    if (isset($used_layout['inherit']) && $used_layout['inherit'] || isset($used_layout['contentSize']) && $used_layout['contentSize']) {
        $used_layout['type'] = 'constrained';
    }
    $root_padding_aware_alignments = isset($global_settings['useRootPaddingAwareAlignments']) ? $global_settings['useRootPaddingAwareAlignments'] : false;
    if ($root_padding_aware_alignments && isset($used_layout['type']) && 'constrained' === $used_layout['type']) {
        $class_names[] = 'has-global-padding';
    }
    /*
     * The following section was added to reintroduce a small set of layout classnames that were
     * removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is
     * not intended to provide an extended set of classes to match all block layout attributes
     * here.
     */
    if (!empty($block['attrs']['layout']['orientation'])) {
        $class_names[] = 'is-' . sanitize_title($block['attrs']['layout']['orientation']);
    }
    if (!empty($block['attrs']['layout']['justifyContent'])) {
        $class_names[] = 'is-content-justification-' . sanitize_title($block['attrs']['layout']['justifyContent']);
    }
    if (!empty($block['attrs']['layout']['flexWrap']) && 'nowrap' === $block['attrs']['layout']['flexWrap']) {
        $class_names[] = 'is-nowrap';
    }
    // Get classname for layout type.
    if (isset($used_layout['type'])) {
        $layout_classname = isset($layout_definitions[$used_layout['type']]['className']) ? $layout_definitions[$used_layout['type']]['className'] : '';
    } else {
        $layout_classname = isset($layout_definitions['default']['className']) ? $layout_definitions['default']['className'] : '';
    }
    if ($layout_classname && is_string($layout_classname)) {
        $class_names[] = sanitize_title($layout_classname);
    }
    /*
     * Only generate Layout styles if the theme has not opted-out.
     * Attribute-based Layout classnames are output in all cases.
     */
    if (!current_theme_supports('disable-layout-styles')) {
        $gap_value = isset($block['attrs']['style']['spacing']['blockGap']) ? $block['attrs']['style']['spacing']['blockGap'] : null;
        /*
         * Skip if gap value contains unsupported characters.
         * Regex for CSS value borrowed from `safecss_filter_attr`, and used here
         * to only match against the value, not the CSS attribute.
         */
        if (is_array($gap_value)) {
            foreach ($gap_value as $key => $value) {
                $gap_value[$key] = ($value && preg_match('%[\\\\(&=}]|/\*%', $value)) ? null : $value;
            }
        } else {
            $gap_value = ($gap_value && preg_match('%[\\\\(&=}]|/\*%', $gap_value)) ? null : $gap_value;
        }
        $fallback_gap_value = isset($block_type->supports['spacing']['blockGap']['__experimentalDefault']) ? $block_type->supports['spacing']['blockGap']['__experimentalDefault'] : '0.5em';
        $block_spacing = isset($block['attrs']['style']['spacing']) ? $block['attrs']['style']['spacing'] : null;
        /*
         * If a block's block.json skips serialization for spacing or spacing.blockGap,
         * don't apply the user-defined value to the styles.
         */
        $should_skip_gap_serialization = wp_should_skip_block_supports_serialization($block_type, 'spacing', 'blockGap');
        $block_gap = isset($global_settings['spacing']['blockGap']) ? $global_settings['spacing']['blockGap'] : null;
        $has_block_gap_support = isset($block_gap);
        $style = wp_get_layout_style(".{$container_class}.{$container_class}", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value, $block_spacing);
        // Only add container class and enqueue block support styles if unique styles were generated.
        if (!empty($style)) {
            $class_names[] = $container_class;
        }
    }
    // Add combined layout and block classname for global styles to hook onto.
    $block_name = explode('/', $block['blockName']);
    $class_names[] = 'wp-block-' . end($block_name) . '-' . $layout_classname;
    // Add classes to the outermost HTML tag if necessary.
    if (!empty($outer_class_names)) {
        foreach ($outer_class_names as $outer_class_name) {
            $processor->add_class($outer_class_name);
        }
    }
    /**
     * Attempts to refer to the inner-block wrapping element by its class attribute.
     *
     * When examining a block's inner content, if a block has inner blocks, then
     * the first content item will likely be a text (HTML) chunk immediately
     * preceding the inner blocks. The last HTML tag in that chunk would then be
     * an opening tag for an element that wraps the inner blocks.
     *
     * There's no reliable way to associate this wrapper in $block_content because
     * it may have changed during the rendering pipeline (as inner contents is
     * provided before rendering) and through previous filters. In many cases,
     * however, the `class` attribute will be a good-enough identifier, so this
     * code finds the last tag in that chunk and stores the `class` attribute
     * so that it can be used later when working through the rendered block output
     * to identify the wrapping element and add the remaining class names to it.
     *
     * It's also possible that no inner block wrapper even exists. If that's the
     * case this code could apply the class names to an invalid element.
     *
     * Example:
     *
     *     $block['innerBlocks']  = array( $list_item );
     *     $block['innerContent'] = array( '<ul class="list-wrapper is-unordered">', null, '</ul>' );
     *
     *     // After rendering, the initial contents may have been modified by other renderers or filters.
     *     $block_content = <<<HTML
     *         <figure>
     *             <ul class="annotated-list list-wrapper is-unordered">
     *                 <li>Code</li>
     *             </ul><figcaption>It's a list!</figcaption>
     *         </figure>
     *     HTML;
     *
     * Although it is possible that the original block-wrapper classes are changed in $block_content
     * from how they appear in $block['innerContent'], it's likely that the original class attributes
     * are still present in the wrapper as they are in this example. Frequently, additional classes
     * will also be present; rarely should classes be removed.
     *
     * @todo Find a better way to match the first inner block. If it's possible to identify where the
     *       first inner block starts, then it will be possible to find the last tag before it starts
     *       and then that tag, if an opening tag, can be solidly identified as a wrapping element.
     *       Can some unique value or class or ID be added to the inner blocks when they process
     *       so that they can be extracted here safely without guessing? Can the block rendering function
     *       return information about where the rendered inner blocks start?
     *
     * @var string|null
     */
    $inner_block_wrapper_classes = null;
    $first_chunk = isset($block['innerContent'][0]) ? $block['innerContent'][0] : null;
    if (is_string($first_chunk) && count($block['innerContent']) > 1) {
        $first_chunk_processor = new WP_HTML_Tag_Processor($first_chunk);
        while ($first_chunk_processor->next_tag()) {
            $class_attribute = $first_chunk_processor->get_attribute('class');
            if (is_string($class_attribute) && !empty($class_attribute)) {
                $inner_block_wrapper_classes = $class_attribute;
            }
        }
    }
    /*
     * If necessary, advance to what is likely to be an inner block wrapper tag.
     *
     * This advances until it finds the first tag containing the original class
     * attribute from above. If none is found it will scan to the end of the block
     * and fail to add any class names.
     *
     * If there is no block wrapper it won't advance at all, in which case the
     * class names will be added to the first and outermost tag of the block.
     * For cases where this outermost tag is the only tag surrounding inner
     * blocks then the outer wrapper and inner wrapper are the same.
     */
    do {
        if (!$inner_block_wrapper_classes) {
            break;
        }
        $class_attribute = $processor->get_attribute('class');
        if (is_string($class_attribute) && str_contains($class_attribute, $inner_block_wrapper_classes)) {
            break;
        }
    } while ($processor->next_tag());
    // Add the remaining class names.
    foreach ($class_names as $class_name) {
        $processor->add_class($class_name);
    }
    return $processor->get_updated_html();
}

WordPress Version: 6.4

/**
 * Renders the layout config to the block wrapper.
 *
 * @since 5.8.0
 * @since 6.3.0 Adds compound class to layout wrapper for global spacing styles.
 * @since 6.3.0 Check for layout support via the `layout` key with fallback to `__experimentalLayout`.
 * @access private
 *
 * @param string $block_content Rendered block content.
 * @param array  $block         Block object.
 * @return string Filtered block content.
 */
function wp_render_layout_support_flag($block_content, $block)
{
    $block_type = WP_Block_Type_Registry::get_instance()->get_registered($block['blockName']);
    $block_supports_layout = block_has_support($block_type, 'layout', false) || block_has_support($block_type, '__experimentalLayout', false);
    $layout_from_parent = isset($block['attrs']['style']['layout']['selfStretch']) ? $block['attrs']['style']['layout']['selfStretch'] : null;
    if (!$block_supports_layout && !$layout_from_parent) {
        return $block_content;
    }
    $outer_class_names = array();
    if ('fixed' === $layout_from_parent || 'fill' === $layout_from_parent) {
        $container_content_class = wp_unique_id('wp-container-content-');
        $child_layout_styles = array();
        if ('fixed' === $layout_from_parent && isset($block['attrs']['style']['layout']['flexSize'])) {
            $child_layout_styles[] = array('selector' => ".{$container_content_class}", 'declarations' => array('flex-basis' => $block['attrs']['style']['layout']['flexSize'], 'box-sizing' => 'border-box'));
        } elseif ('fill' === $layout_from_parent) {
            $child_layout_styles[] = array('selector' => ".{$container_content_class}", 'declarations' => array('flex-grow' => '1'));
        }
        wp_style_engine_get_stylesheet_from_css_rules($child_layout_styles, array('context' => 'block-supports', 'prettify' => false));
        $outer_class_names[] = $container_content_class;
    }
    // Prep the processor for modifying the block output.
    $processor = new WP_HTML_Tag_Processor($block_content);
    // Having no tags implies there are no tags onto which to add class names.
    if (!$processor->next_tag()) {
        return $block_content;
    }
    /*
     * A block may not support layout but still be affected by a parent block's layout.
     *
     * In these cases add the appropriate class names and then return early; there's
     * no need to investigate on this block whether additional layout constraints apply.
     */
    if (!$block_supports_layout && !empty($outer_class_names)) {
        foreach ($outer_class_names as $class_name) {
            $processor->add_class($class_name);
        }
        return $processor->get_updated_html();
    }
    $global_settings = wp_get_global_settings();
    $fallback_layout = isset($block_type->supports['layout']['default']) ? $block_type->supports['layout']['default'] : array();
    if (empty($fallback_layout)) {
        $fallback_layout = isset($block_type->supports['__experimentalLayout']['default']) ? $block_type->supports['__experimentalLayout']['default'] : array();
    }
    $used_layout = isset($block['attrs']['layout']) ? $block['attrs']['layout'] : $fallback_layout;
    $class_names = array();
    $layout_definitions = wp_get_layout_definitions();
    /*
     * Uses an incremental ID that is independent per prefix to make sure that
     * rendering different numbers of blocks doesn't affect the IDs of other
     * blocks. Makes the CSS class names stable across paginations
     * for features like the enhanced pagination of the Query block.
     */
    $container_class = wp_unique_prefixed_id('wp-container-' . sanitize_title($block['blockName']) . '-layout-');
    // Set the correct layout type for blocks using legacy content width.
    if (isset($used_layout['inherit']) && $used_layout['inherit'] || isset($used_layout['contentSize']) && $used_layout['contentSize']) {
        $used_layout['type'] = 'constrained';
    }
    $root_padding_aware_alignments = isset($global_settings['useRootPaddingAwareAlignments']) ? $global_settings['useRootPaddingAwareAlignments'] : false;
    if ($root_padding_aware_alignments && isset($used_layout['type']) && 'constrained' === $used_layout['type']) {
        $class_names[] = 'has-global-padding';
    }
    /*
     * The following section was added to reintroduce a small set of layout classnames that were
     * removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is
     * not intended to provide an extended set of classes to match all block layout attributes
     * here.
     */
    if (!empty($block['attrs']['layout']['orientation'])) {
        $class_names[] = 'is-' . sanitize_title($block['attrs']['layout']['orientation']);
    }
    if (!empty($block['attrs']['layout']['justifyContent'])) {
        $class_names[] = 'is-content-justification-' . sanitize_title($block['attrs']['layout']['justifyContent']);
    }
    if (!empty($block['attrs']['layout']['flexWrap']) && 'nowrap' === $block['attrs']['layout']['flexWrap']) {
        $class_names[] = 'is-nowrap';
    }
    // Get classname for layout type.
    if (isset($used_layout['type'])) {
        $layout_classname = isset($layout_definitions[$used_layout['type']]['className']) ? $layout_definitions[$used_layout['type']]['className'] : '';
    } else {
        $layout_classname = isset($layout_definitions['default']['className']) ? $layout_definitions['default']['className'] : '';
    }
    if ($layout_classname && is_string($layout_classname)) {
        $class_names[] = sanitize_title($layout_classname);
    }
    /*
     * Only generate Layout styles if the theme has not opted-out.
     * Attribute-based Layout classnames are output in all cases.
     */
    if (!current_theme_supports('disable-layout-styles')) {
        $gap_value = isset($block['attrs']['style']['spacing']['blockGap']) ? $block['attrs']['style']['spacing']['blockGap'] : null;
        /*
         * Skip if gap value contains unsupported characters.
         * Regex for CSS value borrowed from `safecss_filter_attr`, and used here
         * to only match against the value, not the CSS attribute.
         */
        if (is_array($gap_value)) {
            foreach ($gap_value as $key => $value) {
                $gap_value[$key] = ($value && preg_match('%[\\\\(&=}]|/\*%', $value)) ? null : $value;
            }
        } else {
            $gap_value = ($gap_value && preg_match('%[\\\\(&=}]|/\*%', $gap_value)) ? null : $gap_value;
        }
        $fallback_gap_value = isset($block_type->supports['spacing']['blockGap']['__experimentalDefault']) ? $block_type->supports['spacing']['blockGap']['__experimentalDefault'] : '0.5em';
        $block_spacing = isset($block['attrs']['style']['spacing']) ? $block['attrs']['style']['spacing'] : null;
        /*
         * If a block's block.json skips serialization for spacing or spacing.blockGap,
         * don't apply the user-defined value to the styles.
         */
        $should_skip_gap_serialization = wp_should_skip_block_supports_serialization($block_type, 'spacing', 'blockGap');
        $block_gap = isset($global_settings['spacing']['blockGap']) ? $global_settings['spacing']['blockGap'] : null;
        $has_block_gap_support = isset($block_gap);
        $style = wp_get_layout_style(".{$container_class}.{$container_class}", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value, $block_spacing);
        // Only add container class and enqueue block support styles if unique styles were generated.
        if (!empty($style)) {
            $class_names[] = $container_class;
        }
    }
    // Add combined layout and block classname for global styles to hook onto.
    $block_name = explode('/', $block['blockName']);
    $class_names[] = 'wp-block-' . end($block_name) . '-' . $layout_classname;
    // Add classes to the outermost HTML tag if necessary.
    if (!empty($outer_class_names)) {
        foreach ($outer_class_names as $outer_class_name) {
            $processor->add_class($outer_class_name);
        }
    }
    /**
     * Attempts to refer to the inner-block wrapping element by its class attribute.
     *
     * When examining a block's inner content, if a block has inner blocks, then
     * the first content item will likely be a text (HTML) chunk immediately
     * preceding the inner blocks. The last HTML tag in that chunk would then be
     * an opening tag for an element that wraps the inner blocks.
     *
     * There's no reliable way to associate this wrapper in $block_content because
     * it may have changed during the rendering pipeline (as inner contents is
     * provided before rendering) and through previous filters. In many cases,
     * however, the `class` attribute will be a good-enough identifier, so this
     * code finds the last tag in that chunk and stores the `class` attribute
     * so that it can be used later when working through the rendered block output
     * to identify the wrapping element and add the remaining class names to it.
     *
     * It's also possible that no inner block wrapper even exists. If that's the
     * case this code could apply the class names to an invalid element.
     *
     * Example:
     *
     *     $block['innerBlocks']  = array( $list_item );
     *     $block['innerContent'] = array( '<ul class="list-wrapper is-unordered">', null, '</ul>' );
     *
     *     // After rendering, the initial contents may have been modified by other renderers or filters.
     *     $block_content = <<<HTML
     *         <figure>
     *             <ul class="annotated-list list-wrapper is-unordered">
     *                 <li>Code</li>
     *             </ul><figcaption>It's a list!</figcaption>
     *         </figure>
     *     HTML;
     *
     * Although it is possible that the original block-wrapper classes are changed in $block_content
     * from how they appear in $block['innerContent'], it's likely that the original class attributes
     * are still present in the wrapper as they are in this example. Frequently, additional classes
     * will also be present; rarely should classes be removed.
     *
     * @TODO: Find a better way to match the first inner block. If it's possible to identify where the
     *        first inner block starts, then it will be possible to find the last tag before it starts
     *        and then that tag, if an opening tag, can be solidly identified as a wrapping element.
     *        Can some unique value or class or ID be added to the inner blocks when they process
     *        so that they can be extracted here safely without guessing? Can the block rendering function
     *        return information about where the rendered inner blocks start?
     *
     * @var string|null
     */
    $inner_block_wrapper_classes = null;
    $first_chunk = isset($block['innerContent'][0]) ? $block['innerContent'][0] : null;
    if (is_string($first_chunk) && count($block['innerContent']) > 1) {
        $first_chunk_processor = new WP_HTML_Tag_Processor($first_chunk);
        while ($first_chunk_processor->next_tag()) {
            $class_attribute = $first_chunk_processor->get_attribute('class');
            if (is_string($class_attribute) && !empty($class_attribute)) {
                $inner_block_wrapper_classes = $class_attribute;
            }
        }
    }
    /*
     * If necessary, advance to what is likely to be an inner block wrapper tag.
     *
     * This advances until it finds the first tag containing the original class
     * attribute from above. If none is found it will scan to the end of the block
     * and fail to add any class names.
     *
     * If there is no block wrapper it won't advance at all, in which case the
     * class names will be added to the first and outermost tag of the block.
     * For cases where this outermost tag is the only tag surrounding inner
     * blocks then the outer wrapper and inner wrapper are the same.
     */
    do {
        if (!$inner_block_wrapper_classes) {
            break;
        }
        if (false !== strpos($processor->get_attribute('class'), $inner_block_wrapper_classes)) {
            break;
        }
    } while ($processor->next_tag());
    // Add the remaining class names.
    foreach ($class_names as $class_name) {
        $processor->add_class($class_name);
    }
    return $processor->get_updated_html();
}

WordPress Version: 6.3

/**
 * Renders the layout config to the block wrapper.
 *
 * @since 5.8.0
 * @since 6.3.0 Adds compound class to layout wrapper for global spacing styles.
 * @since 6.3.0 Check for layout support via the `layout` key with fallback to `__experimentalLayout`.
 * @access private
 *
 * @param string $block_content Rendered block content.
 * @param array  $block         Block object.
 * @return string Filtered block content.
 */
function wp_render_layout_support_flag($block_content, $block)
{
    $block_type = WP_Block_Type_Registry::get_instance()->get_registered($block['blockName']);
    $support_layout = block_has_support($block_type, array('layout'), false) || block_has_support($block_type, array('__experimentalLayout'), false);
    $has_child_layout = isset($block['attrs']['style']['layout']['selfStretch']);
    if (!$support_layout && !$has_child_layout) {
        return $block_content;
    }
    $outer_class_names = array();
    if ($has_child_layout && ('fixed' === $block['attrs']['style']['layout']['selfStretch'] || 'fill' === $block['attrs']['style']['layout']['selfStretch'])) {
        $container_content_class = wp_unique_id('wp-container-content-');
        $child_layout_styles = array();
        if ('fixed' === $block['attrs']['style']['layout']['selfStretch'] && isset($block['attrs']['style']['layout']['flexSize'])) {
            $child_layout_styles[] = array('selector' => ".{$container_content_class}", 'declarations' => array('flex-basis' => $block['attrs']['style']['layout']['flexSize'], 'box-sizing' => 'border-box'));
        } elseif ('fill' === $block['attrs']['style']['layout']['selfStretch']) {
            $child_layout_styles[] = array('selector' => ".{$container_content_class}", 'declarations' => array('flex-grow' => '1'));
        }
        wp_style_engine_get_stylesheet_from_css_rules($child_layout_styles, array('context' => 'block-supports', 'prettify' => false));
        $outer_class_names[] = $container_content_class;
    }
    // Return early if only child layout exists.
    if (!$support_layout && !empty($outer_class_names)) {
        $content = new WP_HTML_Tag_Processor($block_content);
        $content->next_tag();
        $content->add_class(implode(' ', $outer_class_names));
        return (string) $content;
    }
    $global_settings = wp_get_global_settings();
    $fallback_layout = (!empty(_wp_array_get($block_type->supports, array('layout', 'default'), array()))) ? _wp_array_get($block_type->supports, array('layout', 'default'), array()) : _wp_array_get($block_type->supports, array('__experimentalLayout', 'default'), array());
    $used_layout = isset($block['attrs']['layout']) ? $block['attrs']['layout'] : $fallback_layout;
    $class_names = array();
    $layout_definitions = wp_get_layout_definitions();
    $container_class = wp_unique_id('wp-container-');
    $layout_classname = '';
    // Set the correct layout type for blocks using legacy content width.
    if (isset($used_layout['inherit']) && $used_layout['inherit'] || isset($used_layout['contentSize']) && $used_layout['contentSize']) {
        $used_layout['type'] = 'constrained';
    }
    $root_padding_aware_alignments = _wp_array_get($global_settings, array('useRootPaddingAwareAlignments'), false);
    if ($root_padding_aware_alignments && isset($used_layout['type']) && 'constrained' === $used_layout['type']) {
        $class_names[] = 'has-global-padding';
    }
    /*
     * The following section was added to reintroduce a small set of layout classnames that were
     * removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is
     * not intended to provide an extended set of classes to match all block layout attributes
     * here.
     */
    if (!empty($block['attrs']['layout']['orientation'])) {
        $class_names[] = 'is-' . sanitize_title($block['attrs']['layout']['orientation']);
    }
    if (!empty($block['attrs']['layout']['justifyContent'])) {
        $class_names[] = 'is-content-justification-' . sanitize_title($block['attrs']['layout']['justifyContent']);
    }
    if (!empty($block['attrs']['layout']['flexWrap']) && 'nowrap' === $block['attrs']['layout']['flexWrap']) {
        $class_names[] = 'is-nowrap';
    }
    // Get classname for layout type.
    if (isset($used_layout['type'])) {
        $layout_classname = _wp_array_get($layout_definitions, array($used_layout['type'], 'className'), '');
    } else {
        $layout_classname = _wp_array_get($layout_definitions, array('default', 'className'), '');
    }
    if ($layout_classname && is_string($layout_classname)) {
        $class_names[] = sanitize_title($layout_classname);
    }
    /*
     * Only generate Layout styles if the theme has not opted-out.
     * Attribute-based Layout classnames are output in all cases.
     */
    if (!current_theme_supports('disable-layout-styles')) {
        $gap_value = _wp_array_get($block, array('attrs', 'style', 'spacing', 'blockGap'));
        /*
         * Skip if gap value contains unsupported characters.
         * Regex for CSS value borrowed from `safecss_filter_attr`, and used here
         * to only match against the value, not the CSS attribute.
         */
        if (is_array($gap_value)) {
            foreach ($gap_value as $key => $value) {
                $gap_value[$key] = ($value && preg_match('%[\\\\(&=}]|/\*%', $value)) ? null : $value;
            }
        } else {
            $gap_value = ($gap_value && preg_match('%[\\\\(&=}]|/\*%', $gap_value)) ? null : $gap_value;
        }
        $fallback_gap_value = _wp_array_get($block_type->supports, array('spacing', 'blockGap', '__experimentalDefault'), '0.5em');
        $block_spacing = _wp_array_get($block, array('attrs', 'style', 'spacing'), null);
        /*
         * If a block's block.json skips serialization for spacing or spacing.blockGap,
         * don't apply the user-defined value to the styles.
         */
        $should_skip_gap_serialization = wp_should_skip_block_supports_serialization($block_type, 'spacing', 'blockGap');
        $block_gap = _wp_array_get($global_settings, array('spacing', 'blockGap'), null);
        $has_block_gap_support = isset($block_gap);
        $style = wp_get_layout_style(".{$container_class}.{$container_class}", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value, $block_spacing);
        // Only add container class and enqueue block support styles if unique styles were generated.
        if (!empty($style)) {
            $class_names[] = $container_class;
        }
    }
    // Add combined layout and block classname for global styles to hook onto.
    $block_name = explode('/', $block['blockName']);
    $class_names[] = 'wp-block-' . end($block_name) . '-' . $layout_classname;
    $content_with_outer_classnames = '';
    if (!empty($outer_class_names)) {
        $content_with_outer_classnames = new WP_HTML_Tag_Processor($block_content);
        $content_with_outer_classnames->next_tag();
        foreach ($outer_class_names as $outer_class_name) {
            $content_with_outer_classnames->add_class($outer_class_name);
        }
        $content_with_outer_classnames = (string) $content_with_outer_classnames;
    }
    /**
     * The first chunk of innerContent contains the block markup up until the inner blocks start.
     * This targets the opening tag of the inner blocks wrapper, which is the last tag in that chunk.
     */
    $inner_content_classnames = '';
    if (isset($block['innerContent'][0]) && 'string' === gettype($block['innerContent'][0]) && count($block['innerContent']) > 1) {
        $tags = new WP_HTML_Tag_Processor($block['innerContent'][0]);
        $last_classnames = '';
        while ($tags->next_tag()) {
            $last_classnames = $tags->get_attribute('class');
        }
        $inner_content_classnames = (string) $last_classnames;
    }
    $content = $content_with_outer_classnames ? new WP_HTML_Tag_Processor($content_with_outer_classnames) : new WP_HTML_Tag_Processor($block_content);
    if ($inner_content_classnames) {
        $content->next_tag(array('class_name' => $inner_content_classnames));
        foreach ($class_names as $class_name) {
            $content->add_class($class_name);
        }
    } else {
        $content->next_tag();
        foreach ($class_names as $class_name) {
            $content->add_class($class_name);
        }
    }
    return (string) $content;
}

WordPress Version: 6.2

/**
 * Renders the layout config to the block wrapper.
 *
 * @since 5.8.0
 * @access private
 *
 * @param string $block_content Rendered block content.
 * @param array  $block         Block object.
 * @return string Filtered block content.
 */
function wp_render_layout_support_flag($block_content, $block)
{
    $block_type = WP_Block_Type_Registry::get_instance()->get_registered($block['blockName']);
    $support_layout = block_has_support($block_type, array('__experimentalLayout'), false);
    $has_child_layout = isset($block['attrs']['style']['layout']['selfStretch']);
    if (!$support_layout && !$has_child_layout) {
        return $block_content;
    }
    $outer_class_names = array();
    if ($has_child_layout && ('fixed' === $block['attrs']['style']['layout']['selfStretch'] || 'fill' === $block['attrs']['style']['layout']['selfStretch'])) {
        $container_content_class = wp_unique_id('wp-container-content-');
        $child_layout_styles = array();
        if ('fixed' === $block['attrs']['style']['layout']['selfStretch'] && isset($block['attrs']['style']['layout']['flexSize'])) {
            $child_layout_styles[] = array('selector' => ".{$container_content_class}", 'declarations' => array('flex-basis' => $block['attrs']['style']['layout']['flexSize'], 'box-sizing' => 'border-box'));
        } elseif ('fill' === $block['attrs']['style']['layout']['selfStretch']) {
            $child_layout_styles[] = array('selector' => ".{$container_content_class}", 'declarations' => array('flex-grow' => '1'));
        }
        wp_style_engine_get_stylesheet_from_css_rules($child_layout_styles, array('context' => 'block-supports', 'prettify' => false));
        $outer_class_names[] = $container_content_class;
    }
    // Return early if only child layout exists.
    if (!$support_layout && !empty($outer_class_names)) {
        $content = new WP_HTML_Tag_Processor($block_content);
        $content->next_tag();
        $content->add_class(implode(' ', $outer_class_names));
        return (string) $content;
    }
    $global_settings = wp_get_global_settings();
    $block_gap = _wp_array_get($global_settings, array('spacing', 'blockGap'), null);
    $has_block_gap_support = isset($block_gap);
    $global_layout_settings = _wp_array_get($global_settings, array('layout'), null);
    $root_padding_aware_alignments = _wp_array_get($global_settings, array('useRootPaddingAwareAlignments'), false);
    $default_block_layout = _wp_array_get($block_type->supports, array('__experimentalLayout', 'default'), array());
    $used_layout = isset($block['attrs']['layout']) ? $block['attrs']['layout'] : $default_block_layout;
    if (isset($used_layout['inherit']) && $used_layout['inherit'] && !$global_layout_settings) {
        return $block_content;
    }
    $class_names = array();
    $layout_definitions = _wp_array_get($global_layout_settings, array('definitions'), array());
    $container_class = wp_unique_id('wp-container-');
    $layout_classname = '';
    // Set the correct layout type for blocks using legacy content width.
    if (isset($used_layout['inherit']) && $used_layout['inherit'] || isset($used_layout['contentSize']) && $used_layout['contentSize']) {
        $used_layout['type'] = 'constrained';
    }
    if ($root_padding_aware_alignments && isset($used_layout['type']) && 'constrained' === $used_layout['type']) {
        $class_names[] = 'has-global-padding';
    }
    /*
     * The following section was added to reintroduce a small set of layout classnames that were
     * removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is
     * not intended to provide an extended set of classes to match all block layout attributes
     * here.
     */
    if (!empty($block['attrs']['layout']['orientation'])) {
        $class_names[] = 'is-' . sanitize_title($block['attrs']['layout']['orientation']);
    }
    if (!empty($block['attrs']['layout']['justifyContent'])) {
        $class_names[] = 'is-content-justification-' . sanitize_title($block['attrs']['layout']['justifyContent']);
    }
    if (!empty($block['attrs']['layout']['flexWrap']) && 'nowrap' === $block['attrs']['layout']['flexWrap']) {
        $class_names[] = 'is-nowrap';
    }
    // Get classname for layout type.
    if (isset($used_layout['type'])) {
        $layout_classname = _wp_array_get($layout_definitions, array($used_layout['type'], 'className'), '');
    } else {
        $layout_classname = _wp_array_get($layout_definitions, array('default', 'className'), '');
    }
    if ($layout_classname && is_string($layout_classname)) {
        $class_names[] = sanitize_title($layout_classname);
    }
    /*
     * Only generate Layout styles if the theme has not opted-out.
     * Attribute-based Layout classnames are output in all cases.
     */
    if (!current_theme_supports('disable-layout-styles')) {
        $gap_value = _wp_array_get($block, array('attrs', 'style', 'spacing', 'blockGap'));
        /*
         * Skip if gap value contains unsupported characters.
         * Regex for CSS value borrowed from `safecss_filter_attr`, and used here
         * to only match against the value, not the CSS attribute.
         */
        if (is_array($gap_value)) {
            foreach ($gap_value as $key => $value) {
                $gap_value[$key] = ($value && preg_match('%[\\\\(&=}]|/\*%', $value)) ? null : $value;
            }
        } else {
            $gap_value = ($gap_value && preg_match('%[\\\\(&=}]|/\*%', $gap_value)) ? null : $gap_value;
        }
        $fallback_gap_value = _wp_array_get($block_type->supports, array('spacing', 'blockGap', '__experimentalDefault'), '0.5em');
        $block_spacing = _wp_array_get($block, array('attrs', 'style', 'spacing'), null);
        /*
         * If a block's block.json skips serialization for spacing or spacing.blockGap,
         * don't apply the user-defined value to the styles.
         */
        $should_skip_gap_serialization = wp_should_skip_block_supports_serialization($block_type, 'spacing', 'blockGap');
        $style = wp_get_layout_style(".{$container_class}.{$container_class}", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value, $block_spacing);
        // Only add container class and enqueue block support styles if unique styles were generated.
        if (!empty($style)) {
            $class_names[] = $container_class;
        }
    }
    $content_with_outer_classnames = '';
    if (!empty($outer_class_names)) {
        $content_with_outer_classnames = new WP_HTML_Tag_Processor($block_content);
        $content_with_outer_classnames->next_tag();
        foreach ($outer_class_names as $outer_class_name) {
            $content_with_outer_classnames->add_class($outer_class_name);
        }
        $content_with_outer_classnames = (string) $content_with_outer_classnames;
    }
    /**
     * The first chunk of innerContent contains the block markup up until the inner blocks start.
     * This targets the opening tag of the inner blocks wrapper, which is the last tag in that chunk.
     */
    $inner_content_classnames = '';
    if (isset($block['innerContent'][0]) && 'string' === gettype($block['innerContent'][0]) && count($block['innerContent']) > 1) {
        $tags = new WP_HTML_Tag_Processor($block['innerContent'][0]);
        $last_classnames = '';
        while ($tags->next_tag()) {
            $last_classnames = $tags->get_attribute('class');
        }
        $inner_content_classnames = (string) $last_classnames;
    }
    $content = $content_with_outer_classnames ? new WP_HTML_Tag_Processor($content_with_outer_classnames) : new WP_HTML_Tag_Processor($block_content);
    if ($inner_content_classnames) {
        $content->next_tag(array('class_name' => $inner_content_classnames));
        foreach ($class_names as $class_name) {
            $content->add_class($class_name);
        }
    } else {
        $content->next_tag();
        foreach ($class_names as $class_name) {
            $content->add_class($class_name);
        }
    }
    return (string) $content;
}

WordPress Version: 6.1

/**
 * Renders the layout config to the block wrapper.
 *
 * @since 5.8.0
 * @access private
 *
 * @param string $block_content Rendered block content.
 * @param array  $block         Block object.
 * @return string Filtered block content.
 */
function wp_render_layout_support_flag($block_content, $block)
{
    $block_type = WP_Block_Type_Registry::get_instance()->get_registered($block['blockName']);
    $support_layout = block_has_support($block_type, array('__experimentalLayout'), false);
    if (!$support_layout) {
        return $block_content;
    }
    $block_gap = wp_get_global_settings(array('spacing', 'blockGap'));
    $global_layout_settings = wp_get_global_settings(array('layout'));
    $has_block_gap_support = isset($block_gap) ? null !== $block_gap : false;
    $default_block_layout = _wp_array_get($block_type->supports, array('__experimentalLayout', 'default'), array());
    $used_layout = isset($block['attrs']['layout']) ? $block['attrs']['layout'] : $default_block_layout;
    if (isset($used_layout['inherit']) && $used_layout['inherit']) {
        if (!$global_layout_settings) {
            return $block_content;
        }
    }
    $class_names = array();
    $layout_definitions = _wp_array_get($global_layout_settings, array('definitions'), array());
    $block_classname = wp_get_block_default_classname($block['blockName']);
    $container_class = wp_unique_id('wp-container-');
    $layout_classname = '';
    // Set the correct layout type for blocks using legacy content width.
    if (isset($used_layout['inherit']) && $used_layout['inherit'] || isset($used_layout['contentSize']) && $used_layout['contentSize']) {
        $used_layout['type'] = 'constrained';
    }
    if (wp_get_global_settings(array('useRootPaddingAwareAlignments')) && isset($used_layout['type']) && 'constrained' === $used_layout['type']) {
        $class_names[] = 'has-global-padding';
    }
    /*
     * The following section was added to reintroduce a small set of layout classnames that were
     * removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is
     * not intended to provide an extended set of classes to match all block layout attributes
     * here.
     */
    if (!empty($block['attrs']['layout']['orientation'])) {
        $class_names[] = 'is-' . sanitize_title($block['attrs']['layout']['orientation']);
    }
    if (!empty($block['attrs']['layout']['justifyContent'])) {
        $class_names[] = 'is-content-justification-' . sanitize_title($block['attrs']['layout']['justifyContent']);
    }
    if (!empty($block['attrs']['layout']['flexWrap']) && 'nowrap' === $block['attrs']['layout']['flexWrap']) {
        $class_names[] = 'is-nowrap';
    }
    // Get classname for layout type.
    if (isset($used_layout['type'])) {
        $layout_classname = _wp_array_get($layout_definitions, array($used_layout['type'], 'className'), '');
    } else {
        $layout_classname = _wp_array_get($layout_definitions, array('default', 'className'), '');
    }
    if ($layout_classname && is_string($layout_classname)) {
        $class_names[] = sanitize_title($layout_classname);
    }
    /*
     * Only generate Layout styles if the theme has not opted-out.
     * Attribute-based Layout classnames are output in all cases.
     */
    if (!current_theme_supports('disable-layout-styles')) {
        $gap_value = _wp_array_get($block, array('attrs', 'style', 'spacing', 'blockGap'));
        /*
         * Skip if gap value contains unsupported characters.
         * Regex for CSS value borrowed from `safecss_filter_attr`, and used here
         * to only match against the value, not the CSS attribute.
         */
        if (is_array($gap_value)) {
            foreach ($gap_value as $key => $value) {
                $gap_value[$key] = ($value && preg_match('%[\\\\(&=}]|/\*%', $value)) ? null : $value;
            }
        } else {
            $gap_value = ($gap_value && preg_match('%[\\\\(&=}]|/\*%', $gap_value)) ? null : $gap_value;
        }
        $fallback_gap_value = _wp_array_get($block_type->supports, array('spacing', 'blockGap', '__experimentalDefault'), '0.5em');
        $block_spacing = _wp_array_get($block, array('attrs', 'style', 'spacing'), null);
        /*
         * If a block's block.json skips serialization for spacing or spacing.blockGap,
         * don't apply the user-defined value to the styles.
         */
        $should_skip_gap_serialization = wp_should_skip_block_supports_serialization($block_type, 'spacing', 'blockGap');
        $style = wp_get_layout_style(".{$block_classname}.{$container_class}", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value, $block_spacing);
        // Only add container class and enqueue block support styles if unique styles were generated.
        if (!empty($style)) {
            $class_names[] = $container_class;
        }
    }
    /*
     * This assumes the hook only applies to blocks with a single wrapper.
     * A limitation of this hook is that nested inner blocks wrappers are not yet supported.
     */
    $content = preg_replace('/' . preg_quote('class="', '/') . '/', 'class="' . esc_attr(implode(' ', $class_names)) . ' ', $block_content, 1);
    return $content;
}

WordPress Version: 9.3

/**
 * Renders the layout config to the block wrapper.
 *
 * @since 5.8.0
 * @access private
 *
 * @param string $block_content Rendered block content.
 * @param array  $block         Block object.
 * @return string Filtered block content.
 */
function wp_render_layout_support_flag($block_content, $block)
{
    $block_type = WP_Block_Type_Registry::get_instance()->get_registered($block['blockName']);
    $support_layout = block_has_support($block_type, array('__experimentalLayout'), false);
    if (!$support_layout) {
        return $block_content;
    }
    $block_gap = wp_get_global_settings(array('spacing', 'blockGap'));
    $default_layout = wp_get_global_settings(array('layout'));
    $has_block_gap_support = isset($block_gap) ? null !== $block_gap : false;
    $default_block_layout = _wp_array_get($block_type->supports, array('__experimentalLayout', 'default'), array());
    $used_layout = isset($block['attrs']['layout']) ? $block['attrs']['layout'] : $default_block_layout;
    if (isset($used_layout['inherit']) && $used_layout['inherit']) {
        if (!$default_layout) {
            return $block_content;
        }
        $used_layout = $default_layout;
    }
    $class_name = wp_unique_id('wp-container-');
    $gap_value = _wp_array_get($block, array('attrs', 'style', 'spacing', 'blockGap'));
    // Skip if gap value contains unsupported characters.
    // Regex for CSS value borrowed from `safecss_filter_attr`, and used here
    // because we only want to match against the value, not the CSS attribute.
    $gap_value = preg_match('%[\\\\(&=}]|/\*%', $gap_value) ? null : $gap_value;
    $style = wp_get_layout_style(".{$class_name}", $used_layout, $has_block_gap_support, $gap_value);
    // This assumes the hook only applies to blocks with a single wrapper.
    // I think this is a reasonable limitation for that particular hook.
    $content = preg_replace('/' . preg_quote('class="', '/') . '/', 'class="' . esc_attr($class_name) . ' ', $block_content, 1);
    wp_enqueue_block_support_styles($style);
    return $content;
}

WordPress Version: 9.1

/**
 * Renders the layout config to the block wrapper.
 *
 * @since 5.8.0
 * @access private
 *
 * @param string $block_content Rendered block content.
 * @param array  $block         Block object.
 * @return string Filtered block content.
 */
function wp_render_layout_support_flag($block_content, $block)
{
    $block_type = WP_Block_Type_Registry::get_instance()->get_registered($block['blockName']);
    $support_layout = block_has_support($block_type, array('__experimentalLayout'), false);
    if (!$support_layout) {
        return $block_content;
    }
    $block_gap = wp_get_global_settings(array('spacing', 'blockGap'));
    $default_layout = wp_get_global_settings(array('layout'));
    $has_block_gap_support = isset($block_gap) ? null !== $block_gap : false;
    $default_block_layout = _wp_array_get($block_type->supports, array('__experimentalLayout', 'default'), array());
    $used_layout = isset($block['attrs']['layout']) ? $block['attrs']['layout'] : $default_block_layout;
    if (isset($used_layout['inherit']) && $used_layout['inherit']) {
        if (!$default_layout) {
            return $block_content;
        }
        $used_layout = $default_layout;
    }
    $id = uniqid();
    $gap_value = _wp_array_get($block, array('attrs', 'style', 'spacing', 'blockGap'));
    // Skip if gap value contains unsupported characters.
    // Regex for CSS value borrowed from `safecss_filter_attr`, and used here
    // because we only want to match against the value, not the CSS attribute.
    $gap_value = preg_match('%[\\\\(&=}]|/\*%', $gap_value) ? null : $gap_value;
    $style = wp_get_layout_style(".wp-container-{$id}", $used_layout, $has_block_gap_support, $gap_value);
    // This assumes the hook only applies to blocks with a single wrapper.
    // I think this is a reasonable limitation for that particular hook.
    $content = preg_replace('/' . preg_quote('class="', '/') . '/', 'class="wp-container-' . $id . ' ', $block_content, 1);
    wp_enqueue_block_support_styles($style);
    return $content;
}

WordPress Version: 5.9

/**
 * Renders the layout config to the block wrapper.
 *
 * @since 5.8.0
 * @access private
 *
 * @param string $block_content Rendered block content.
 * @param array  $block         Block object.
 * @return string Filtered block content.
 */
function wp_render_layout_support_flag($block_content, $block)
{
    $block_type = WP_Block_Type_Registry::get_instance()->get_registered($block['blockName']);
    $support_layout = block_has_support($block_type, array('__experimentalLayout'), false);
    if (!$support_layout) {
        return $block_content;
    }
    $block_gap = wp_get_global_settings(array('spacing', 'blockGap'));
    $default_layout = wp_get_global_settings(array('layout'));
    $has_block_gap_support = isset($block_gap) ? null !== $block_gap : false;
    $default_block_layout = _wp_array_get($block_type->supports, array('__experimentalLayout', 'default'), array());
    $used_layout = isset($block['attrs']['layout']) ? $block['attrs']['layout'] : $default_block_layout;
    if (isset($used_layout['inherit']) && $used_layout['inherit']) {
        if (!$default_layout) {
            return $block_content;
        }
        $used_layout = $default_layout;
    }
    $id = uniqid();
    $gap_value = _wp_array_get($block, array('attrs', 'style', 'spacing', 'blockGap'));
    // Skip if gap value contains unsupported characters.
    // Regex for CSS value borrowed from `safecss_filter_attr`, and used here
    // because we only want to match against the value, not the CSS attribute.
    $gap_value = preg_match('%[\\\\(&=}]|/\*%', $gap_value) ? null : $gap_value;
    $style = wp_get_layout_style(".wp-container-{$id}", $used_layout, $has_block_gap_support, $gap_value);
    // This assumes the hook only applies to blocks with a single wrapper.
    // I think this is a reasonable limitation for that particular hook.
    $content = preg_replace('/' . preg_quote('class="', '/') . '/', 'class="wp-container-' . $id . ' ', $block_content, 1);
    /*
     * Ideally styles should be loaded in the head, but blocks may be parsed
     * after that, so loading in the footer for now.
     * See https://core.trac.wordpress.org/ticket/53494.
     */
    add_action('wp_footer', static function () use ($style) {
        echo '<style>' . $style . '</style>';
    });
    return $content;
}

WordPress Version: 5.8

/**
 * Renders the layout config to the block wrapper.
 *
 * @since 5.8.0
 * @access private
 *
 * @param  string $block_content Rendered block content.
 * @param  array  $block         Block object.
 * @return string                Filtered block content.
 */
function wp_render_layout_support_flag($block_content, $block)
{
    $block_type = WP_Block_Type_Registry::get_instance()->get_registered($block['blockName']);
    $support_layout = block_has_support($block_type, array('__experimentalLayout'), false);
    if (!$support_layout || !isset($block['attrs']['layout'])) {
        return $block_content;
    }
    $used_layout = $block['attrs']['layout'];
    if (isset($used_layout['inherit']) && $used_layout['inherit']) {
        $tree = WP_Theme_JSON_Resolver::get_merged_data();
        $default_layout = _wp_array_get($tree->get_settings(), array('layout'));
        if (!$default_layout) {
            return $block_content;
        }
        $used_layout = $default_layout;
    }
    $id = uniqid();
    $content_size = isset($used_layout['contentSize']) ? $used_layout['contentSize'] : null;
    $wide_size = isset($used_layout['wideSize']) ? $used_layout['wideSize'] : null;
    $all_max_width_value = $content_size ? $content_size : $wide_size;
    $wide_max_width_value = $wide_size ? $wide_size : $content_size;
    // 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]);
    $style = '';
    if ($content_size || $wide_size) {
        $style = ".wp-container-{$id} > * {";
        $style .= 'max-width: ' . esc_html($all_max_width_value) . ';';
        $style .= 'margin-left: auto !important;';
        $style .= 'margin-right: auto !important;';
        $style .= '}';
        $style .= ".wp-container-{$id} > .alignwide { max-width: " . esc_html($wide_max_width_value) . ';}';
        $style .= ".wp-container-{$id} .alignfull { max-width: none; }";
    }
    $style .= ".wp-container-{$id} .alignleft { float: left; margin-right: 2em; }";
    $style .= ".wp-container-{$id} .alignright { float: right; margin-left: 2em; }";
    // This assumes the hook only applies to blocks with a single wrapper.
    // I think this is a reasonable limitation for that particular hook.
    $content = preg_replace('/' . preg_quote('class="', '/') . '/', 'class="wp-container-' . $id . ' ', $block_content, 1);
    return $content . '<style>' . $style . '</style>';
}