diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 15a7a131f8a9b..b61311362893a 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -291,6 +291,23 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support return ''; } +/** + * Gets classname from last tag in a string of HTML. + * + * @param string $html markup to be processed. + * @return string String of inner wrapper classnames. + */ +function gutenberg_get_classnames_from_last_tag( $html ) { + $tags = new WP_HTML_Tag_Processor( $html ); + $last_classnames = ''; + + while ( $tags->next_tag() ) { + $last_classnames = $tags->get_attribute( 'class' ); + } + + return $last_classnames; +} + /** * Renders the layout config to the block wrapper. * @@ -320,7 +337,6 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { $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 = ''; @@ -397,7 +413,7 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { $should_skip_gap_serialization = gutenberg_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' ); $style = gutenberg_get_layout_style( - ".$block_classname.$container_class", + ".$container_class.$container_class", $used_layout, $has_block_gap_support, $gap_value, @@ -412,16 +428,22 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { } } - /* - * 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 - ); + /** + * The first chunk of innerContent contains the block markup up until the inner blocks start. + * We want to target the opening tag of the inner blocks wrapper, which is the last tag in that chunk. + */ + $inner_content_classnames = isset( $block['innerContent'][0] ) && 'string' === gettype( $block['innerContent'][0] ) ? gutenberg_get_classnames_from_last_tag( $block['innerContent'][0] ) : ''; + + $content = 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(); + $content->add_class( implode( ' ', $class_names ) ); + } return $content; } @@ -433,6 +455,7 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { 'register_attribute' => 'gutenberg_register_layout_support', ) ); + if ( function_exists( 'wp_render_layout_support_flag' ) ) { remove_filter( 'render_block', 'wp_render_layout_support_flag' ); } diff --git a/packages/block-editor/src/components/block-edit/index.js b/packages/block-editor/src/components/block-edit/index.js index 9b2875b3018a3..747e25b820847 100644 --- a/packages/block-editor/src/components/block-edit/index.js +++ b/packages/block-editor/src/components/block-edit/index.js @@ -20,11 +20,12 @@ import { BlockEditContextProvider, useBlockEditContext } from './context'; export { useBlockEditContext }; export default function BlockEdit( props ) { - const { name, isSelected, clientId } = props; + const { name, isSelected, clientId, __unstableLayoutClassNames } = props; const context = { name, isSelected, clientId, + __unstableLayoutClassNames, }; return ( ); diff --git a/packages/block-editor/src/components/inner-blocks/index.js b/packages/block-editor/src/components/inner-blocks/index.js index 4105d7291957e..8afc6482eb33f 100644 --- a/packages/block-editor/src/components/inner-blocks/index.js +++ b/packages/block-editor/src/components/inner-blocks/index.js @@ -150,7 +150,9 @@ const ForwardedInnerBlocks = forwardRef( ( props, ref ) => { * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/inner-blocks/README.md */ export function useInnerBlocksProps( props = {}, options = {} ) { - const { clientId } = useBlockEditContext(); + const { __unstableDisableLayoutClassNames } = options; + const { clientId, __unstableLayoutClassNames: layoutClassNames = '' } = + useBlockEditContext(); const isSmallScreen = useViewportMatch( 'medium', '<' ); const { __experimentalCaptureToolbars, hasOverlay } = useSelect( ( select ) => { @@ -200,12 +202,14 @@ export function useInnerBlocksProps( props = {}, options = {} ) { innerBlocksProps.value && innerBlocksProps.onChange ? ControlledInnerBlocks : UncontrolledInnerBlocks; + return { ...props, ref, className: classnames( props.className, 'block-editor-block-list__layout', + __unstableDisableLayoutClassNames ? '' : layoutClassNames, { 'has-overlay': hasOverlay, } diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index 73d655c57c2ac..eeea8f3df2c8c 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -9,11 +9,7 @@ import { kebabCase } from 'lodash'; */ import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose'; import { addFilter } from '@wordpress/hooks'; -import { - getBlockDefaultClassName, - getBlockSupport, - hasBlockSupport, -} from '@wordpress/blocks'; +import { getBlockSupport, hasBlockSupport } from '@wordpress/blocks'; import { useSelect } from '@wordpress/data'; import { Button, @@ -366,9 +362,8 @@ export const withLayoutStyles = createHigherOrderComponent( const layoutClasses = hasLayoutBlockSupport ? useLayoutClasses( block ) : null; - const selector = `.${ getBlockDefaultClassName( - name - ) }.wp-container-${ id }`; + // Higher specificity to override defaults from theme.json. + const selector = `.wp-container-${ id }.wp-container-${ id }`; const blockGapSupport = useSetting( 'spacing.blockGap' ); const hasBlockGapSupport = blockGapSupport !== null; @@ -413,7 +408,10 @@ export const withLayoutStyles = createHigherOrderComponent( />, element ) } - + ); } diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index 9a551b6e0d9f7..e6176cc8a7256 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -26,6 +26,7 @@ export const Gallery = ( props ) => { mediaPlaceholder, insertBlocksAfter, blockProps, + __unstableLayoutClassNames: layoutClassNames, } = props; const { align, columns, caption, imageCrop } = attributes; @@ -42,6 +43,7 @@ export const Gallery = ( props ) => { { ...innerBlocksProps } className={ classnames( blockProps.className, + layoutClassNames, 'blocks-gallery-grid', { [ `align${ align }` ]: align, diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js index 9d43c4339ba1f..efe0d0ede9ebc 100644 --- a/packages/block-library/src/group/edit.js +++ b/packages/block-library/src/group/edit.js @@ -35,7 +35,12 @@ const htmlElementMessages = { ), }; -function GroupEdit( { attributes, setAttributes, clientId } ) { +function GroupEdit( { + attributes, + setAttributes, + clientId, + __unstableLayoutClassNames: layoutClassNames, +} ) { const { hasInnerBlocks, themeSupportsLayout } = useSelect( ( select ) => { const { getBlock, getSettings } = select( blockEditorStore ); @@ -55,7 +60,9 @@ function GroupEdit( { attributes, setAttributes, clientId } ) { const { type = 'default' } = usedLayout; const layoutSupportEnabled = themeSupportsLayout || type === 'flex'; - const blockProps = useBlockProps(); + const blockProps = useBlockProps( { + className: ! layoutSupportEnabled ? layoutClassNames : null, + } ); const innerBlocksProps = useInnerBlocksProps( layoutSupportEnabled @@ -67,6 +74,7 @@ function GroupEdit( { attributes, setAttributes, clientId } ) { ? undefined : InnerBlocks.ButtonBlockAppender, __experimentalLayout: layoutSupportEnabled ? usedLayout : undefined, + __unstableDisableLayoutClassNames: ! layoutSupportEnabled, } ); diff --git a/packages/block-library/src/post-content/edit.js b/packages/block-library/src/post-content/edit.js index 1949553b2540f..e190101aa0515 100644 --- a/packages/block-library/src/post-content/edit.js +++ b/packages/block-library/src/post-content/edit.js @@ -84,8 +84,8 @@ function Content( props ) { ); } -function Placeholder() { - const blockProps = useBlockProps(); +function Placeholder( { layoutClassNames } ) { + const blockProps = useBlockProps( { className: layoutClassNames } ); return (

@@ -118,7 +118,11 @@ function RecursionError() { ); } -export default function PostContentEdit( { context, attributes } ) { +export default function PostContentEdit( { + context, + attributes, + __unstableLayoutClassNames: layoutClassNames, +} ) { const { postId: contextPostId, postType: contextPostType } = context; const { layout = {} } = attributes; const hasAlreadyRendered = useHasRecursion( contextPostId ); @@ -132,7 +136,7 @@ export default function PostContentEdit( { context, attributes } ) { { contextPostId && contextPostType ? ( ) : ( - + ) } );