Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions packages/block-editor/src/components/block-toolbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export function PrivateBlockToolbar( {
const {
blockClientId,
blockClientIds,
isContentOnlyMode,
isDefaultEditingMode,
blockType,
toolbarKey,
Expand All @@ -75,7 +76,6 @@ export function PrivateBlockToolbar( {
showLockButtons,
showSwitchSectionStyleButton,
hasFixedToolbar,
isNavigationMode,
} = useSelect( ( select ) => {
const {
getBlockName,
Expand All @@ -90,7 +90,6 @@ export function PrivateBlockToolbar( {
getSettings,
getParentSectionBlock,
isZoomOut,
isNavigationMode: _isNavigationMode,
isSectionBlock,
} = unlock( select( blockEditorStore ) );
const selectedBlockClientIds = getSelectedBlockClientIds();
Expand All @@ -101,8 +100,8 @@ export function PrivateBlockToolbar( {
const parentBlockName = getBlockName( parentClientId );
const parentBlockType = getBlockType( parentBlockName );
const editingMode = getBlockEditingMode( selectedBlockClientId );
const isNavigationModeEnabled = _isNavigationMode();
const _isDefaultEditingMode = editingMode === 'default';
const _isContentOnlyMode = editingMode === 'contentOnly';
const _blockName = getBlockName( selectedBlockClientId );
const isValid = selectedBlockClientIds.every( ( id ) =>
isBlockValid( id )
Expand Down Expand Up @@ -138,7 +137,7 @@ export function PrivateBlockToolbar( {
showParentSelector:
! _isZoomOut &&
parentBlockType &&
editingMode !== 'contentOnly' &&
! _isContentOnlyMode &&
getBlockEditingMode( parentClientId ) !== 'disabled' &&
hasBlockSupport(
parentBlockType,
Expand All @@ -153,13 +152,12 @@ export function PrivateBlockToolbar( {
showSlots: ! _isZoomOut,
showGroupButtons: ! _isZoomOut,
showLockButtons: ! _isZoomOut,
isContentOnlyMode: _isContentOnlyMode,
showSwitchSectionStyleButton:
_isZoomOut ||
( isNavigationModeEnabled &&
editingMode === 'contentOnly' &&
( _isContentOnlyMode &&
isSectionBlock( selectedBlockClientId ) ), // Zoom out or Write Mode Section Blocks
hasFixedToolbar: getSettings().hasFixedToolbar,
isNavigationMode: isNavigationModeEnabled,
};
}, [] );

Expand All @@ -186,7 +184,7 @@ export function PrivateBlockToolbar( {
// Shifts the toolbar to make room for the parent block selector.
const classes = clsx( 'block-editor-block-contextual-toolbar', {
'has-parent': showParentSelector,
'is-inverted-toolbar': isNavigationMode && ! hasFixedToolbar,
'is-inverted-toolbar': isContentOnlyMode && ! hasFixedToolbar,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

contentOnly is also used outside of navigation (write) mode:

  • block overrides in synced patterns
  • templateLock contentOnly
  • Post content blocks when editing a post with the 'Show Template'

Those all now have the inverted toolbar after this change, whereas my understanding is that it's only for navigation mode to indicate the different mode.

Before:
Screenshot 2025-08-08 at 5 37 13 pm

After:
Screenshot 2025-08-08 at 5 37 36 pm

Copy link
Contributor Author

@jeryj jeryj Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was my understanding that we'd surface if a block was contentOnly with the toolbar color, but maybe I misunderstood. @richtabor, can you clarify? I could go either way on if the toolbar should turn black or not if it's contentOnly. It'd be surprising to see the black toolbar, but also nice to have a visual indicator to know why the tools are missing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, that's fine if so.

There might be some contrast issues to work out with the purple icon color (also not sure about the grey text color).

} );

const innerClasses = clsx( 'block-editor-block-toolbar', {
Expand Down
2 changes: 2 additions & 0 deletions packages/block-editor/src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2309,6 +2309,8 @@ function getDerivedBlockEditingModesForTree(
}
}

// If the editor is zoomed out or in navigation mode, all blocks will be set to either contentOnly or disabled.
// The fallback is to set the block editing mode to disabled.
if ( isZoomedOut || isNavMode ) {
// If the root block is the section root set its editing mode to contentOnly.
if ( clientId === sectionRootClientId ) {
Expand Down
68 changes: 14 additions & 54 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -3040,62 +3040,22 @@ export function __unstableIsWithinBlockOverlay( state, clientId ) {
* @return {BlockEditingMode} The block editing mode. One of `'disabled'`,
* `'contentOnly'`, or `'default'`.
*/
export const getBlockEditingMode = createRegistrySelector(
( select ) =>
( state, clientId = '' ) => {
// Some selectors that call this provide `null` as the default
// rootClientId, but the default rootClientId is actually `''`.
if ( clientId === null ) {
clientId = '';
}

const isNavMode = isNavigationMode( 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 &&
state.derivedBlockEditingModes?.has( clientId )
) {
return state.derivedBlockEditingModes.get( clientId );
}

// If the editor *is* in navigation mode, the block editing mode states
// are stored in the derivedNavModeBlockEditingModes map.
if (
isNavMode &&
state.derivedNavModeBlockEditingModes?.has( clientId )
) {
return state.derivedNavModeBlockEditingModes.get( clientId );
}

// In normal mode, consider that an explicitly set editing mode takes over.
const blockEditingMode = state.blockEditingModes.get( clientId );
if ( blockEditingMode ) {
return blockEditingMode;
}
export const getBlockEditingMode = ( state, clientId = '' ) => {
// Some selectors that call this provide `null` as the default
// rootClientId, but the default rootClientId is actually `''`.
if ( clientId === null ) {
clientId = '';
}

// In normal mode, top level is default mode.
if ( clientId === '' ) {
return 'default';
}
const isNavMode = isNavigationMode( state );

const rootClientId = getBlockRootClientId( state, clientId );
const templateLock = getTemplateLock( state, rootClientId );
// If the parent of the block is contentOnly locked, check whether it's a content block.
if ( templateLock === 'contentOnly' ) {
const name = getBlockName( state, clientId );
const { hasContentRoleAttribute } = unlock(
select( blocksStore )
);
const isContent = hasContentRoleAttribute( name );
return isContent ? 'contentOnly' : 'disabled';
}
return 'default';
}
);
if ( isNavMode ) {
// If the editor *is* in navigation mode, the block editing mode states
// are stored in the derivedNavModeBlockEditingModes map.
return state.derivedNavModeBlockEditingModes.get( clientId );
}
return state.derivedBlockEditingModes.get( clientId );
};
Comment on lines +3052 to +3058
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was curious if everything was stored in derivedBlockEditingModes. It appears not 😅 . It looks like derivedBlockEditingModes does handle most everything though. I think we can simplify this overall to be clearer. For example, do we need the templateLock section? derivedBlockEditingMode handles a ton of this too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think derivedNavModeBlockEditingModes should almost handle everything for nav mode.

derivedBlockEditingModes handles lots for regular mode.

For the template locking code I have another PR that I was working on - #67606.

IIRC, block editing modes don't handle every type of template lock, only contentOnly. I think there are a few things block editing modes can't do, so other types of template lock use completely different APIs.

An example of something block editing modes can't do is enable a block, but prevent inner blocks from being added/moved/removed from that enabled block.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll close this PR in favor of #67606. That seems like it's further ahead on the refactor.


/**
* Indicates if a block is ungroupable.
Expand Down
11 changes: 6 additions & 5 deletions packages/block-library/src/social-link/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
InspectorControls,
URLPopover,
URLInput,
useBlockEditingMode,
useBlockProps,
store as blockEditorStore,
} from '@wordpress/block-editor';
Expand Down Expand Up @@ -138,16 +137,18 @@ const SocialLinkEdit = ( {
// Use internal state instead of a ref to make sure that the component
// re-renders when the popover's anchor updates.
const [ popoverAnchor, setPopoverAnchor ] = useState( null );
const isContentOnlyMode = useBlockEditingMode() === 'contentOnly';

const { activeVariation } = useSelect(
const { activeVariation, isContentOnlyMode } = useSelect(
( select ) => {
const { getActiveBlockVariation } = select( blocksStore );
const { getActiveBlockVariation, getBlockEditingMode } =
select( blocksStore );
return {
activeVariation: getActiveBlockVariation( name, attributes ),
isContentOnlyMode:
getBlockEditingMode( clientId ) === 'contentOnly',
};
},
[ name, attributes ]
[ name, attributes, clientId ]
);

const { icon, label: socialLinkName } = getSocialService( activeVariation );
Expand Down
Loading