diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index e239ed023bd62e..871cad2c20022a 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -30,6 +30,7 @@ function gutenberg_register_layout_support( $block_type ) { * * @param string $selector CSS selector. * @param array $layout Layout object. The one that is passed has already checked the existence of default block layout. + * @param array|null $padding Padding applied to the current block. * @param boolean $has_block_gap_support Whether the theme has support for the block gap. * @param string $gap_value The block gap value to apply. * @param boolean $should_skip_gap_serialization Whether to skip applying the user-defined value set in the editor. @@ -37,7 +38,7 @@ function gutenberg_register_layout_support( $block_type ) { * * @return string CSS style. */ -function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support = false, $gap_value = null, $should_skip_gap_serialization = false, $fallback_gap_value = '0.5em' ) { +function gutenberg_get_layout_style( $selector, $layout, $padding, $has_block_gap_support = false, $gap_value = null, $should_skip_gap_serialization = false, $fallback_gap_value = '0.5em' ) { $layout_type = isset( $layout['type'] ) ? $layout['type'] : 'default'; $style = ''; @@ -54,14 +55,29 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $wide_max_width_value = wp_strip_all_tags( explode( ';', $wide_max_width_value )[0] ); if ( $content_size || $wide_size ) { - $style = "$selector > :where(:not(.alignleft):not(.alignright)) {"; + $style = "$selector {"; + // Using important here to override the inline padding that could be potentially + // applied using the custom padding control before the layout inheritance is applied. + $style .= sprintf( + 'padding: %s %s %s %s !important', + isset( $padding['top'] ) ? $padding['top'] : 0, + isset( $padding['right'] ) ? $padding['right'] : 0, + isset( $padding['bottom'] ) ? $padding['bottom'] : 0, + isset( $padding['left'] ) ? $padding['left'] : 0 + ); + $style .= '}'; + $style .= "$selector > :where(:not(.alignleft):not(.alignright)) {"; $style .= 'max-width: ' . esc_html( $all_max_width_value ) . ';'; $style .= 'margin-left: auto !important;'; $style .= 'margin-right: auto !important;'; $style .= '}'; $style .= "$selector > .alignwide { max-width: " . esc_html( $wide_max_width_value ) . ';}'; - $style .= "$selector .alignfull { max-width: none; }"; + $style .= "$selector > .alignfull {"; + $style .= 'max-width: none;'; + $style .= isset( $padding['left'] ) ? sprintf( 'margin-left: calc( -1 * %s ) !important;', $padding['left'] ) : ''; + $style .= isset( $padding['right'] ) ? sprintf( 'margin-right: calc( -1 * %s ) !important;', $padding['right'] ) : ''; + $style .= '}'; } $style .= "$selector > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }"; @@ -162,6 +178,7 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { $block_gap = gutenberg_get_global_settings( array( 'spacing', 'blockGap' ) ); $default_layout = gutenberg_get_global_settings( array( 'layout' ) ); + $padding = _wp_array_get( $block, array( 'attrs', 'style', 'spacing', 'padding' ), null ); $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; @@ -170,6 +187,7 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { return $block_content; } $used_layout = $default_layout; + $padding = isset( $default_layout['padding'] ) ? $default_layout['padding'] : null; } $class_names = array(); @@ -209,7 +227,7 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { // 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 = gutenberg_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' ); - $style = gutenberg_get_layout_style( ".$container_class", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value ); + $style = gutenberg_get_layout_style( ".$container_class", $used_layout, $padding, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_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( diff --git a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php index 77d731b9d45442..cb8015beec604d 100644 --- a/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php +++ b/lib/compat/wordpress-6.0/class-wp-theme-json-6-0.php @@ -227,6 +227,7 @@ class WP_Theme_JSON_6_0 extends WP_Theme_JSON_5_9 { 'layout' => array( 'contentSize' => null, 'wideSize' => null, + 'padding' => null, ), 'spacing' => array( 'blockGap' => null, diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index c5072200869ed2..eeb01a45f5b519 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -2,7 +2,7 @@ * External dependencies */ import classnames from 'classnames'; -import { has, kebabCase } from 'lodash'; +import { has, get, kebabCase } from 'lodash'; /** * WordPress dependencies @@ -77,23 +77,14 @@ function getLayoutClasses( attributes ) { function LayoutPanel( { setAttributes, attributes, name: blockName } ) { const { layout } = attributes; - const defaultThemeLayout = useSetting( 'layout' ); - const themeSupportsLayout = useSelect( ( select ) => { - const { getSettings } = select( blockEditorStore ); - return getSettings().supportsLayout; - }, [] ); - const layoutBlockSupport = getBlockSupport( - blockName, - layoutBlockSupportKey, - {} - ); + const { supportsFlowLayout, config } = useLayout( blockName ); const { allowSwitching, allowEditing = true, allowInheriting = true, default: defaultBlockLayout, - } = layoutBlockSupport; + } = config; if ( ! allowEditing ) { return null; @@ -104,18 +95,14 @@ function LayoutPanel( { setAttributes, attributes, name: blockName } ) { // and that the default / flow layout type is in use, as this is the only one that supports inheritance. const showInheritToggle = !! ( allowInheriting && - !! defaultThemeLayout && + !! supportsFlowLayout && ( ! layout?.type || layout?.type === 'default' || layout?.inherit ) ); const usedLayout = layout || defaultBlockLayout || {}; const { inherit = false, type = 'default' } = usedLayout; - /** - * `themeSupportsLayout` is only relevant to the `default/flow` - * layout and it should not be taken into account when other - * `layout` types are used. - */ - if ( type === 'default' && ! themeSupportsLayout ) { + + if ( type === 'default' && ! supportsFlowLayout ) { return null; } const layoutType = getLayoutType( type ); @@ -163,7 +150,7 @@ function LayoutPanel( { setAttributes, attributes, name: blockName } ) { ) } @@ -172,7 +159,7 @@ function LayoutPanel( { setAttributes, attributes, name: blockName } ) { ) } @@ -197,6 +184,26 @@ function LayoutTypeSwitcher( { type, onChange } ) { ); } +export function useLayout( blockName ) { + const defaultThemeLayout = useSetting( 'layout' ); + const themeSupportsLayout = useSelect( ( select ) => { + const { getSettings } = select( blockEditorStore ); + return getSettings().supportsLayout; + }, [] ); + + const layoutBlockSupport = getBlockSupport( + blockName, + layoutBlockSupportKey, + {} + ); + + return { + supportsFlowLayout: themeSupportsLayout, + defaultLayout: defaultThemeLayout, + config: layoutBlockSupport, + }; +} + /** * Filters registered block settings, extending attributes to include `layout`. * @@ -276,6 +283,9 @@ export const withLayoutStyles = createHigherOrderComponent( }, layoutClasses ); + const padding = layout?.inherit + ? usedLayout?.padding + : get( attributes, [ 'style', 'spacing', 'padding' ] ); return ( <> @@ -286,6 +296,7 @@ export const withLayoutStyles = createHigherOrderComponent( blockName={ name } selector={ `.wp-container-${ id }` } layout={ usedLayout } + padding={ padding } style={ attributes?.style } />, element diff --git a/packages/block-editor/src/hooks/padding.js b/packages/block-editor/src/hooks/padding.js index 02a371db0d6a33..495ea70570e594 100644 --- a/packages/block-editor/src/hooks/padding.js +++ b/packages/block-editor/src/hooks/padding.js @@ -28,6 +28,7 @@ import { } from './dimensions'; import { cleanEmptyObject } from './utils'; import BlockPopover from '../components/block-popover'; +import { useLayout } from './layout'; /** * Determines if there is padding support. @@ -80,11 +81,19 @@ export function resetPadding( { attributes = {}, setAttributes } ) { * * @return {boolean} Whether padding setting is disabled. */ -export function useIsPaddingDisabled( { name: blockName } = {} ) { +export function useIsPaddingDisabled( { name: blockName, attributes } = {} ) { + const { supportsFlowLayout, config } = useLayout( blockName ); + const hasInheritedLayout = + supportsFlowLayout && !! config && attributes?.layout?.inherit; const isDisabled = ! useSetting( 'spacing.padding' ); const isInvalid = ! useIsDimensionsSupportValid( blockName, 'padding' ); - return ! hasPaddingSupport( blockName ) || isDisabled || isInvalid; + return ( + ! hasPaddingSupport( blockName ) || + hasInheritedLayout || + isDisabled || + isInvalid + ); } /** diff --git a/packages/block-editor/src/layouts/flow.js b/packages/block-editor/src/layouts/flow.js index 82851cb0150756..84c3a5ec2fbb2d 100644 --- a/packages/block-editor/src/layouts/flow.js +++ b/packages/block-editor/src/layouts/flow.js @@ -112,6 +112,7 @@ export default { layout = {}, style, blockName, + padding, } ) { const { contentSize, wideSize } = layout; const blockGapSupport = useSetting( 'spacing.blockGap' ); @@ -126,10 +127,17 @@ export default { ! shouldSkipSerialization( blockName, 'spacing', 'blockGap' ) ? blockGapStyleValue?.top : 'var( --wp--style--block-gap )'; + // Using important here for the padding to override the inline padding that could be potentially + // applied using the custom padding control before the layout inheritance is applied. let output = !! contentSize || !! wideSize ? ` + ${ appendSelectors( selector ) } { + padding: ${ padding?.top || 0 } ${ padding?.right || 0 } ${ + padding?.bottom || 0 + } ${ padding?.left || 0 } !important; + } ${ appendSelectors( selector, '> :where(:not(.alignleft):not(.alignright))' @@ -143,6 +151,16 @@ export default { } ${ appendSelectors( selector, '> .alignfull' ) } { max-width: none; + ${ + padding?.left + ? `margin-left: calc( -1 * ${ padding?.left } ) !important;` + : '' + } + ${ + padding?.right + ? `margin-right: calc( -1 * ${ padding?.right } ) !important;` + : '' + } } ` : ''; diff --git a/packages/edit-post/src/components/visual-editor/index.js b/packages/edit-post/src/components/visual-editor/index.js index b5a2b0a4a4b971..a0ef01533a92ee 100644 --- a/packages/edit-post/src/components/visual-editor/index.js +++ b/packages/edit-post/src/components/visual-editor/index.js @@ -198,6 +198,14 @@ export default function VisualEditor( { styles } ) { titleRef?.current?.focus(); }, [ isWelcomeGuideVisible, isCleanNewPost ] ); + const padding = useMemo( () => { + if ( isTemplateMode || ! themeSupportsLayout ) { + return undefined; + } + + return defaultLayout?.padding; + } ); + return ( ) } { ! isTemplateMode && (