diff --git a/packages/block-editor/src/components/block-toolbar/index.js b/packages/block-editor/src/components/block-toolbar/index.js
index 083d77a694a7b..dd31abc71d65a 100644
--- a/packages/block-editor/src/components/block-toolbar/index.js
+++ b/packages/block-editor/src/components/block-toolbar/index.js
@@ -70,7 +70,6 @@ export function PrivateBlockToolbar( {
hasParentPattern,
hasContentOnlyLocking,
showShuffleButton,
- showSlots,
showGroupButtons,
showLockButtons,
showSwitchSectionStyleButton,
@@ -148,7 +147,6 @@ export function PrivateBlockToolbar( {
hasParentPattern: _hasParentPattern,
hasContentOnlyLocking: _hasTemplateLock,
showShuffleButton: _isZoomOut,
- showSlots: ! _isZoomOut,
showGroupButtons: ! _isZoomOut,
showLockButtons: ! _isZoomOut,
showSwitchSectionStyleButton: _isZoomOut,
@@ -239,7 +237,7 @@ export function PrivateBlockToolbar( {
{ showSwitchSectionStyleButton && (
) }
- { shouldShowVisualToolbar && showSlots && (
+ { shouldShowVisualToolbar && (
<>
{
const {
getSettings,
getBlockOrder,
- getSelectionStart,
getSelectedBlockClientId,
getSectionRootClientId,
+ isSectionBlock,
+ getParentSectionBlock,
} = unlock( select( blockEditorStore ) );
const root = getSectionRootClientId();
+ const selectionBlockClientId = getSelectedBlockClientId();
+ const _selectedSectionClientId =
+ ! selectionBlockClientId || isSectionBlock( selectionBlockClientId )
+ ? selectionBlockClientId
+ : getParentSectionBlock( selectionBlockClientId );
return {
- hasSelection: !! getSelectionStart().clientId,
+ selectedSectionClientId: _selectedSectionClientId,
blockOrder: getBlockOrder( root ),
sectionRootClientId: root,
setInserterIsOpened:
@@ -54,13 +59,13 @@ function ZoomOutModeInserters() {
};
}, [] );
- if ( ! isReady || ! hasSelection ) {
+ if ( ! isReady || ! selectedSectionClientId ) {
return null;
}
- const previousClientId = selectedBlockClientId;
+ const previousClientId = selectedSectionClientId;
const index = blockOrder.findIndex(
- ( clientId ) => selectedBlockClientId === clientId
+ ( clientId ) => selectedSectionClientId === clientId
);
const nextClientId = blockOrder[ index + 1 ];
diff --git a/packages/block-editor/src/components/inner-blocks/index.js b/packages/block-editor/src/components/inner-blocks/index.js
index ae58772027820..1684f2c1bc33f 100644
--- a/packages/block-editor/src/components/inner-blocks/index.js
+++ b/packages/block-editor/src/components/inner-blocks/index.js
@@ -73,13 +73,11 @@ function UncontrolledInnerBlocks( props ) {
layout,
name,
blockType,
- parentLock,
defaultLayout,
} = props;
useNestedSettingsUpdate(
clientId,
- parentLock,
allowedBlocks,
prioritizedInserterBlocks,
defaultBlock,
@@ -196,7 +194,6 @@ export function useInnerBlocksProps( props = {}, options = {} ) {
const {
getBlockName,
isZoomOut,
- getTemplateLock,
getBlockRootClientId,
getBlockEditingMode,
getBlockSettings,
@@ -239,7 +236,6 @@ export function useInnerBlocksProps( props = {}, options = {} ) {
),
name: blockName,
blockType: getBlockType( blockName ),
- parentLock: getTemplateLock( parentClientId ),
parentClientId,
isDropZoneDisabled: _isDropZoneDisabled,
defaultLayout,
@@ -251,7 +247,6 @@ export function useInnerBlocksProps( props = {}, options = {} ) {
__experimentalCaptureToolbars,
name,
blockType,
- parentLock,
parentClientId,
isDropZoneDisabled,
defaultLayout,
@@ -278,7 +273,6 @@ export function useInnerBlocksProps( props = {}, options = {} ) {
layout,
name,
blockType,
- parentLock,
defaultLayout,
...options,
};
diff --git a/packages/block-editor/src/components/inner-blocks/index.native.js b/packages/block-editor/src/components/inner-blocks/index.native.js
index 1398a5abd51e4..5717ac2c96a1e 100644
--- a/packages/block-editor/src/components/inner-blocks/index.native.js
+++ b/packages/block-editor/src/components/inner-blocks/index.native.js
@@ -105,13 +105,11 @@ function UncontrolledInnerBlocks( props ) {
const context = useBlockContext( clientId );
- const { nestingLevel, parentLock } = useSelect(
+ const { nestingLevel } = useSelect(
( select ) => {
- const { getBlockParents, getTemplateLock, getBlockRootClientId } =
- select( blockEditorStore );
+ const { getBlockParents } = select( blockEditorStore );
return {
nestingLevel: getBlockParents( clientId )?.length,
- parentLock: getTemplateLock( getBlockRootClientId( clientId ) ),
};
},
[ clientId ]
@@ -119,7 +117,6 @@ function UncontrolledInnerBlocks( props ) {
useNestedSettingsUpdate(
clientId,
- parentLock,
allowedBlocks,
prioritizedInserterBlocks,
defaultBlock,
diff --git a/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js b/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js
index bc07a5a1829e2..773c9f70cd23a 100644
--- a/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js
+++ b/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js
@@ -41,7 +41,6 @@ function useShallowMemo( value ) {
* came from props.
*
* @param {string} clientId The client ID of the block to update.
- * @param {string} parentLock
* @param {string[]} allowedBlocks An array of block names which are permitted
* in inner blocks.
* @param {string[]} prioritizedInserterBlocks Block names and/or block variations to be prioritized in the inserter, in the format {blockName}/{variationName}.
@@ -63,7 +62,6 @@ function useShallowMemo( value ) {
*/
export default function useNestedSettingsUpdate(
clientId,
- parentLock,
allowedBlocks,
prioritizedInserterBlocks,
defaultBlock,
@@ -90,16 +88,11 @@ export default function useNestedSettingsUpdate(
prioritizedInserterBlocks
);
- const _templateLock =
- templateLock === undefined || parentLock === 'contentOnly'
- ? parentLock
- : templateLock;
-
useLayoutEffect( () => {
const newSettings = {
allowedBlocks: _allowedBlocks,
prioritizedInserterBlocks: _prioritizedInserterBlocks,
- templateLock: _templateLock,
+ templateLock,
};
// These values are not defined for RN, so only include them if they
@@ -176,7 +169,7 @@ export default function useNestedSettingsUpdate(
clientId,
_allowedBlocks,
_prioritizedInserterBlocks,
- _templateLock,
+ templateLock,
defaultBlock,
directInsert,
__experimentalDefaultBlock,
diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js
index c46778d889b3e..f811e5d1a92da 100644
--- a/packages/block-editor/src/store/private-selectors.js
+++ b/packages/block-editor/src/store/private-selectors.js
@@ -15,8 +15,9 @@ import {
getBlockName,
getTemplateLock,
getClientIdsWithDescendants,
- isNavigationMode,
getBlockRootClientId,
+ __unstableGetEditorMode,
+ getBlockListSettings,
} from './selectors';
import {
checkAllowListRecursive,
@@ -506,8 +507,13 @@ export function isSectionBlock( state, clientId ) {
const sectionClientIds = getBlockOrder( state, sectionRootClientId );
return (
getBlockName( state, clientId ) === 'core/block' ||
- getTemplateLock( state, clientId ) === 'contentOnly' ||
- ( isNavigationMode( state ) && sectionClientIds.includes( clientId ) )
+ // This is different than getTemplateLock
+ // because children of sections are not sections automatically.
+ getBlockListSettings( state, clientId )?.templateLock ===
+ 'contentOnly' ||
+ ( ( __unstableGetEditorMode( state ) === 'navigation' ||
+ isZoomOut( state ) ) &&
+ sectionClientIds.includes( clientId ) )
);
}
diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js
index edae9c392c37d..e48dd68c39aba 100644
--- a/packages/block-editor/src/store/reducer.js
+++ b/packages/block-editor/src/store/reducer.js
@@ -2250,8 +2250,6 @@ function getDerivedBlockEditingModesForTree(
isNavMode = false,
treeClientId = ''
) {
- const isZoomedOut =
- state?.zoomLevel < 100 || state?.zoomLevel === 'auto-scaled';
const derivedBlockEditingModes = new Map();
// When there are sections, the majority of blocks are disabled,
@@ -2267,7 +2265,7 @@ function getDerivedBlockEditingModesForTree(
traverseBlockTree( state, treeClientId, ( block ) => {
const { clientId, name: blockName } = block;
- if ( isZoomedOut || isNavMode ) {
+ if ( isNavMode ) {
// If the root block is the section root set its editing mode to contentOnly.
if ( clientId === sectionRootClientId ) {
derivedBlockEditingModes.set( clientId, 'contentOnly' );
@@ -2289,7 +2287,6 @@ function getDerivedBlockEditingModesForTree(
// disabled.
// If the tree root is not in a section, set its editing mode to disabled.
if (
- isZoomedOut ||
! findParentInClientIdsList( state, clientId, sectionClientIds )
) {
derivedBlockEditingModes.set( clientId, 'disabled' );
diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js
index ed9e859f028a9..cd8dadb72947b 100644
--- a/packages/block-editor/src/store/selectors.js
+++ b/packages/block-editor/src/store/selectors.js
@@ -38,10 +38,10 @@ import {
getContentLockingParent,
getTemporarilyEditingAsBlocks,
getTemporarilyEditingFocusModeToRevert,
- getSectionRootClientId,
isSectionBlock,
getParentSectionBlock,
isZoomOut,
+ getSectionRootClientId,
} from './private-selectors';
/**
@@ -1572,7 +1572,17 @@ export function getTemplateLock( state, rootClientId ) {
return state.settings.templateLock ?? false;
}
- return getBlockListSettings( state, rootClientId )?.templateLock ?? false;
+ const currentLock = getBlockListSettings(
+ state,
+ rootClientId
+ )?.templateLock;
+ if ( currentLock !== undefined ) {
+ return currentLock;
+ }
+ return getTemplateLock(
+ state,
+ getBlockRootClientId( state, rootClientId )
+ );
}
/**
@@ -2941,36 +2951,21 @@ export const __unstableGetVisibleBlocks = createSelector(
);
export function __unstableHasActiveBlockOverlayActive( state, clientId ) {
- // Prevent overlay on blocks with a non-default editing mode. If the mdoe is
- // 'disabled' then the overlay is redundant since the block can't be
- // selected. If the mode is 'contentOnly' then the overlay is redundant
- // since there will be no controls to interact with once selected.
- if ( getBlockEditingMode( state, clientId ) !== 'default' ) {
- return false;
- }
-
// If the block editing is locked, the block overlay is always active.
if ( ! canEditBlock( state, clientId ) ) {
return true;
}
- // In zoom-out mode, the block overlay is always active for section level blocks.
- if ( isZoomOut( state ) ) {
- const sectionRootClientId = getSectionRootClientId( state );
- if ( sectionRootClientId ) {
- const sectionClientIds = getBlockOrder(
- state,
- sectionRootClientId
- );
- if ( sectionClientIds?.includes( clientId ) ) {
- return true;
- }
- } else if ( clientId && ! getBlockRootClientId( state, clientId ) ) {
- return true;
- }
+ // Section blocks need to be selected first before being able to select their children.
+ if (
+ isSectionBlock( state, clientId ) &&
+ ! isBlockSelected( state, clientId ) &&
+ ! hasSelectedInnerBlock( state, clientId, true )
+ ) {
+ return true;
}
- // In navigation mode, the block overlay is active when the block is not
+ // For sections, the block overlay is active when the block is not
// selected (and doesn't contain a selected child). The same behavior is
// also enabled in all modes for blocks that have controlled children
// (reusable block, template part, navigation), unless explicitly disabled
@@ -2982,7 +2977,8 @@ export function __unstableHasActiveBlockOverlayActive( state, clientId ) {
);
const shouldEnableIfUnselected = blockSupportDisable
? false
- : areInnerBlocksControlled( state, clientId );
+ : areInnerBlocksControlled( state, clientId ) &&
+ clientId !== getSectionRootClientId( state, clientId );
return (
shouldEnableIfUnselected &&
@@ -3043,14 +3039,15 @@ export const getBlockEditingMode = createRegistrySelector(
clientId = '';
}
- const isNavMode = isNavigationMode( state );
+ const isNavModeLike =
+ isNavigationMode( state ) || isZoomOut( state );
// If the editor is currently not in navigation mode, check if the clientId
// has an editing mode set in the regular derived map.
// There may be an editing mode set here for synced patterns or in zoomed out
// mode.
if (
- ! isNavMode &&
+ ! isNavModeLike &&
state.derivedBlockEditingModes?.has( clientId )
) {
return state.derivedBlockEditingModes.get( clientId );
@@ -3059,7 +3056,7 @@ export const getBlockEditingMode = createRegistrySelector(
// If the editor *is* in navigation mode, the block editing mode states
// are stored in the derivedNavModeBlockEditingModes map.
if (
- isNavMode &&
+ isNavModeLike &&
state.derivedNavModeBlockEditingModes?.has( clientId )
) {
return state.derivedNavModeBlockEditingModes.get( clientId );
diff --git a/packages/block-editor/src/store/test/selectors.js b/packages/block-editor/src/store/test/selectors.js
index 51949bfd468ca..9f7875b60119e 100644
--- a/packages/block-editor/src/store/test/selectors.js
+++ b/packages/block-editor/src/store/test/selectors.js
@@ -3828,28 +3828,45 @@ describe( 'selectors', () => {
it( 'should return false if the specified clientId was not found', () => {
const state = {
- settings: { templateLock: 'all' },
+ settings: {},
blockListSettings: {
chicken: {
templateLock: 'insert',
},
+ ribs: {},
+ },
+ blocks: {
+ parents: new Map(
+ Object.entries( {
+ chicken: '',
+ ribs: '',
+ } )
+ ),
},
};
expect( getTemplateLock( state, 'ribs' ) ).toBe( false );
} );
- it( 'should return false if template lock was not set on the specified block', () => {
+ it( 'should return the parent lock if the specified clientId was not found', () => {
const state = {
settings: { templateLock: 'all' },
blockListSettings: {
chicken: {
- test: 'tes1t',
+ templateLock: 'insert',
},
},
+ blocks: {
+ parents: new Map(
+ Object.entries( {
+ chicken: '',
+ ribs: '',
+ } )
+ ),
+ },
};
- expect( getTemplateLock( state, 'chicken' ) ).toBe( false );
+ expect( getTemplateLock( state, 'ribs' ) ).toBe( 'all' );
} );
it( 'should return the template lock for the specified clientId', () => {
@@ -3860,6 +3877,14 @@ describe( 'selectors', () => {
templateLock: 'insert',
},
},
+ blocks: {
+ parents: new Map(
+ Object.entries( {
+ chicken: '',
+ ribs: '',
+ } )
+ ),
+ },
};
expect( getTemplateLock( state, 'chicken' ) ).toBe( 'insert' );
diff --git a/test/e2e/specs/editor/various/content-only-lock.spec.js b/test/e2e/specs/editor/various/content-only-lock.spec.js
index 9784aea1ee068..03f70b6c8d270 100644
--- a/test/e2e/specs/editor/various/content-only-lock.spec.js
+++ b/test/e2e/specs/editor/various/content-only-lock.spec.js
@@ -24,6 +24,13 @@ test.describe( 'Content-only lock', () => {
` );
await pageUtils.pressKeys( 'secondary+M' );
+
+ // First click selects the section.
+ await editor.canvas
+ .locator( 'role=document[name="Block: Group"i]' )
+ .click();
+
+ // Second click selects the content.
await editor.canvas
.locator( 'role=document[name="Block: Paragraph"i]' )
.click();
@@ -50,9 +57,18 @@ test.describe( 'Content-only lock', () => {
` );
await pageUtils.pressKeys( 'secondary+M' );
+
+ // First click selects the section.
+ await editor.canvas
+ .locator( 'role=document[name="Block: Group"i]' )
+ .first()
+ .click();
+
+ // Second click selects the content.
await editor.canvas
.locator( 'role=document[name="Block: Paragraph"i]' )
.click();
+
await page.keyboard.type( ' WP' );
await expect.poll( editor.getBlocks ).toMatchObject( [
{