diff --git a/lib/block-supports/dimensions.php b/lib/block-supports/dimensions.php index f858136a595080..55b4d6dbe9407d 100644 --- a/lib/block-supports/dimensions.php +++ b/lib/block-supports/dimensions.php @@ -117,6 +117,50 @@ function gutenberg_skip_spacing_serialization( $block_type ) { $spacing_support['__experimentalSkipSerialization']; } +/** + * Renders the dimensions support to the block wrapper, for supports that + * require block-level server-side rendering, for example blockGap support + * which uses CSS variables. + * + * @param string $block_content Rendered block content. + * @param array $block Block object. + * @return string Filtered block content. + */ +function gutenberg_render_dimensions_support( $block_content, $block ) { + $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); + $has_gap_support = gutenberg_block_has_support( $block_type, array( 'spacing', 'blockGap' ), false ); + if ( ! $has_gap_support || ! isset( $block['attrs']['style']['spacing']['blockGap'] ) ) { + return $block_content; + } + + $id = uniqid(); + $style = sprintf( + '.wp-container-%s { --wp--style--block-gap: %s; }', + $id, + esc_attr( $block['attrs']['style']['spacing']['blockGap'] ) + ); + + // This assumes the hook only applies to blocks with a single wrapper. + $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', + function () use ( $style ) { + echo ''; + } + ); + + return $content; +} + // Register the block support. WP_Block_Supports::get_instance()->register( 'dimensions', @@ -125,3 +169,5 @@ function gutenberg_skip_spacing_serialization( $block_type ) { 'apply' => 'gutenberg_apply_dimensions_support', ) ); + +add_filter( 'render_block', 'gutenberg_render_dimensions_support', 10, 2 ); diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index 87bf4685d50d42..cd39b112e796aa 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -144,7 +144,7 @@ function addAttribute( settings ) { return settings; } -const skipSerializationPaths = { +const skipSerializationPathsEdit = { [ `${ BORDER_SUPPORT_KEY }.__experimentalSkipSerialization` ]: [ 'border' ], [ `${ COLOR_SUPPORT_KEY }.__experimentalSkipSerialization` ]: [ COLOR_SUPPORT_KEY, @@ -157,23 +157,34 @@ const skipSerializationPaths = { ], }; +const skipSerializationPathsSave = { + ...skipSerializationPathsEdit, + [ `${ SPACING_SUPPORT_KEY }` ]: [ 'spacing', 'blockGap' ], +}; + /** * Override props assigned to save component to inject the CSS variables definition. * * @param {Object} props Additional props applied to save element. * @param {Object} blockType Block type. * @param {Object} attributes Block attributes. + * @param {Object} skipPaths An object of keys and paths to skip serialization. * * @return {Object} Filtered props applied to save element. */ -export function addSaveProps( props, blockType, attributes ) { +export function addSaveProps( + props, + blockType, + attributes, + skipPaths = skipSerializationPathsSave +) { if ( ! hasStyleSupport( blockType ) ) { return props; } let { style } = attributes; - forEach( skipSerializationPaths, ( path, indicator ) => { + forEach( skipPaths, ( path, indicator ) => { if ( getBlockSupport( blockType, indicator ) ) { style = omit( style, path ); } @@ -207,7 +218,12 @@ export function addEditProps( settings ) { props = existingGetEditWrapperProps( attributes ); } - return addSaveProps( props, settings, attributes ); + return addSaveProps( + props, + settings, + attributes, + skipSerializationPathsEdit + ); }; return settings;