diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php
index b26ed9df659c2..838327c626f20 100644
--- a/lib/block-supports/layout.php
+++ b/lib/block-supports/layout.php
@@ -241,15 +241,18 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) {
$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 = gutenberg_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' );
- $style = gutenberg_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;
- wp_enqueue_block_support_styles( $style );
+ // Only generate Layout styles if the theme has not opted-out.
+ if ( ! current_theme_supports( 'disable-layout-styles' ) ) {
+ // 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( ".$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;
+ wp_enqueue_block_support_styles( $style );
+ }
}
// This assumes the hook only applies to blocks with a single wrapper.
diff --git a/lib/compat/wordpress-6.1/block-editor-settings.php b/lib/compat/wordpress-6.1/block-editor-settings.php
index de61109ed3ac7..5512390db5910 100644
--- a/lib/compat/wordpress-6.1/block-editor-settings.php
+++ b/lib/compat/wordpress-6.1/block-editor-settings.php
@@ -171,6 +171,7 @@ function gutenberg_get_block_editor_settings( $settings ) {
}
$settings['localAutosaveInterval'] = 15;
+ $settings['disableLayoutStyles'] = current_theme_supports( 'disable-layout-styles' );
return $settings;
}
diff --git a/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php b/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php
index 1679e87c5a8a9..0261adb267035 100644
--- a/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php
+++ b/lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php
@@ -1252,6 +1252,11 @@ protected function get_layout_styles( $block_metadata ) {
$block_rules = '';
$block_type = null;
+ // Skip outputting layout styles if explicitly disabled.
+ if ( current_theme_supports( 'disable-layout-styles' ) ) {
+ return $block_rules;
+ }
+
if ( isset( $block_metadata['name'] ) ) {
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_metadata['name'] );
if ( ! block_has_support( $block_type, array( '__experimentalLayout' ), false ) ) {
diff --git a/lib/experimental/class-wp-rest-block-editor-settings-controller.php b/lib/experimental/class-wp-rest-block-editor-settings-controller.php
index d9b726f1158da..777e193ffe70a 100644
--- a/lib/experimental/class-wp-rest-block-editor-settings-controller.php
+++ b/lib/experimental/class-wp-rest-block-editor-settings-controller.php
@@ -204,6 +204,12 @@ public function get_item_schema() {
'context' => array( 'post-editor', 'site-editor', 'widgets-editor' ),
),
+ 'disableLayoutStyles' => array(
+ 'description' => __( 'Disables output of layout styles.', 'gutenberg' ),
+ 'type' => 'boolean',
+ 'context' => array( 'post-editor', 'site-editor', 'widgets-editor' ),
+ ),
+
'enableCustomLineHeight' => array(
'description' => __( 'Enables custom line height.', 'gutenberg' ),
'type' => 'boolean',
diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js
index 4db7ac3b6ef05..d7df54ea3c614 100644
--- a/packages/block-editor/src/hooks/layout.js
+++ b/packages/block-editor/src/hooks/layout.js
@@ -84,6 +84,22 @@ function useLayoutClasses( layout, layoutDefinitions ) {
return layoutClassnames;
}
+/**
+ * Determines whether or not the theme has disabled all layout styles output.
+ *
+ * This feature only disables the output of layout styles,
+ * the controls for adjusting layout will still be available in the editor.
+ * Themes that use this feature commit to providing their own styling for layout features.
+ *
+ * @return {boolean} Whether or not the theme opts-in to disable all layout styles.
+ */
+function useThemeHasDisabledLayoutStyles() {
+ return useSelect( ( select ) => {
+ const { getSettings } = select( blockEditorStore );
+ return !! getSettings().disableLayoutStyles;
+ } );
+}
+
function LayoutPanel( { setAttributes, attributes, name: blockName } ) {
const { layout } = attributes;
const defaultThemeLayout = useSetting( 'layout' );
@@ -264,10 +280,12 @@ export const withInspectorControls = createHigherOrderComponent(
export const withLayoutStyles = createHigherOrderComponent(
( BlockListBlock ) => ( props ) => {
const { name, attributes } = props;
- const shouldRenderLayoutStyles = hasBlockSupport(
+ const hasLayoutBlockSupport = hasBlockSupport(
name,
layoutBlockSupportKey
);
+ const shouldRenderLayoutStyles =
+ hasLayoutBlockSupport && ! useThemeHasDisabledLayoutStyles();
const id = useInstanceId( BlockListBlock );
const defaultThemeLayout = useSetting( 'layout' ) || {};
const element = useContext( BlockList.__unstableElementContext );
@@ -277,7 +295,7 @@ export const withLayoutStyles = createHigherOrderComponent(
const usedLayout = layout?.inherit
? defaultThemeLayout
: layout || defaultBlockLayout || {};
- const layoutClasses = shouldRenderLayoutStyles
+ const layoutClasses = hasLayoutBlockSupport
? useLayoutClasses( usedLayout, defaultThemeLayout?.definitions )
: null;
const selector = `.${ getBlockDefaultClassName(
diff --git a/packages/edit-post/src/components/visual-editor/index.js b/packages/edit-post/src/components/visual-editor/index.js
index 77054884472a6..0f351f0148c0e 100644
--- a/packages/edit-post/src/components/visual-editor/index.js
+++ b/packages/edit-post/src/components/visual-editor/index.js
@@ -118,13 +118,15 @@ export default function VisualEditor( { styles } ) {
( select ) => select( editPostStore ).hasMetaBoxes(),
[]
);
- const { themeSupportsLayout, assets } = useSelect( ( select ) => {
- const _settings = select( blockEditorStore ).getSettings();
- return {
- themeSupportsLayout: _settings.supportsLayout,
- assets: _settings.__unstableResolvedAssets,
- };
- }, [] );
+ const { themeHasDisabledLayoutStyles, themeSupportsLayout, assets } =
+ useSelect( ( select ) => {
+ const _settings = select( blockEditorStore ).getSettings();
+ return {
+ themeHasDisabledLayoutStyles: _settings.disableLayoutStyles,
+ themeSupportsLayout: _settings.supportsLayout,
+ assets: _settings.__unstableResolvedAssets,
+ };
+ }, [] );
const { clearSelectedBlock } = useDispatch( blockEditorStore );
const { setIsEditingTemplate } = useDispatch( editPostStore );
const desktopCanvasStyles = {
@@ -241,13 +243,17 @@ export default function VisualEditor( { styles } ) {
assets={ assets }
style={ { paddingBottom } }
>
- { themeSupportsLayout && ! isTemplateMode && (
-