Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editor: Persist user's 'Show Template' preference #69286

Merged
merged 8 commits into from
Feb 26, 2025
Merged
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
29 changes: 19 additions & 10 deletions packages/edit-post/src/components/layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ function Layout( {
const {
mode,
isFullscreenActive,
hasResolvedMode,
hasActiveMetaboxes,
hasBlockSelected,
showIconLabels,
Expand All @@ -390,7 +391,7 @@ function Layout( {
} = useSelect(
( select ) => {
const { get } = select( preferencesStore );
const { isFeatureActive } = select( editPostStore );
const { isFeatureActive, hasMetaBoxes } = select( editPostStore );
const { canUser, getPostType, getTemplateId } = unlock(
select( coreStore )
);
Expand All @@ -402,22 +403,29 @@ function Layout( {
kind: 'postType',
name: 'wp_template',
} );
const { isZoomOut } = unlock( select( blockEditorStore ) );
const { getEditorMode, getRenderingMode } = select( editorStore );
const { getBlockSelectionStart, isZoomOut } = unlock(
select( blockEditorStore )
);
const { getEditorMode, getRenderingMode, getDefaultRenderingMode } =
unlock( select( editorStore ) );
const isRenderingPostOnly = getRenderingMode() === 'post-only';
const isNotDesignPostType =
! DESIGN_POST_TYPES.includes( currentPostType );
const isDirectlyEditingPattern =
currentPostType === 'wp_block' &&
! onNavigateToPreviousEntityRecord;
const _templateId = getTemplateId( currentPostType, currentPostId );
const defaultMode = getDefaultRenderingMode( currentPostType );

return {
mode: getEditorMode(),
isFullscreenActive:
select( editPostStore ).isFeatureActive( 'fullscreenMode' ),
hasActiveMetaboxes: select( editPostStore ).hasMetaBoxes(),
hasBlockSelected:
!! select( blockEditorStore ).getBlockSelectionStart(),
isFullscreenActive: isFeatureActive( 'fullscreenMode' ),
hasActiveMetaboxes: hasMetaBoxes(),
hasResolvedMode:
defaultMode === 'template-locked'
? !! _templateId
: defaultMode !== undefined,
hasBlockSelected: !! getBlockSelectionStart(),
showIconLabels: get( 'core', 'showIconLabels' ),
isDistractionFree: get( 'core', 'distractionFree' ),
showMetaBoxes:
Expand All @@ -429,7 +437,7 @@ function Layout( {
isViewable &&
canViewTemplate &&
! isEditingTemplate
? getTemplateId( currentPostType, currentPostId )
? _templateId
: null,
enablePaddingAppender:
! isZoomOut() && isRenderingPostOnly && isNotDesignPostType,
Expand All @@ -443,7 +451,8 @@ function Layout( {
onNavigateToPreviousEntityRecord,
]
);
useMetaBoxInitialization( hasActiveMetaboxes );

useMetaBoxInitialization( hasActiveMetaboxes && hasResolvedMode );

const [ paddingAppenderRef, paddingStyle ] = usePaddingAppender(
enablePaddingAppender
Expand Down
14 changes: 8 additions & 6 deletions packages/editor/src/components/post-template/block-theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ export default function BlockThemeControl( { id } ) {
id
);
const { createSuccessNotice } = useDispatch( noticesStore );
const { setRenderingMode } = useDispatch( editorStore );
const { setRenderingMode, setDefaultRenderingMode } = unlock(
useDispatch( editorStore )
);

const canCreateTemplate = useSelect(
( select ) =>
Expand Down Expand Up @@ -149,11 +151,11 @@ export default function BlockThemeControl( { id } ) {
isSelected={ ! isTemplateHidden }
role="menuitemcheckbox"
onClick={ () => {
setRenderingMode(
isTemplateHidden
? 'template-locked'
: 'post-only'
);
const newRenderingMode = isTemplateHidden
? 'template-locked'
: 'post-only';
setRenderingMode( newRenderingMode );
setDefaultRenderingMode( newRenderingMode );
} }
>
{ __( 'Show template' ) }
Expand Down
14 changes: 8 additions & 6 deletions packages/editor/src/components/preview-dropdown/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ export default function PreviewDropdown( { forceIsAutosaveable, disabled } ) {
templateId: getCurrentTemplateId(),
};
}, [] );
const { setDeviceType, setRenderingMode } = useDispatch( editorStore );
const { setDeviceType, setRenderingMode, setDefaultRenderingMode } = unlock(
useDispatch( editorStore )
);
const { resetZoomLevel } = unlock( useDispatch( blockEditorStore ) );

const handleDevicePreviewChange = ( newDeviceType ) => {
Expand Down Expand Up @@ -160,11 +162,11 @@ export default function PreviewDropdown( { forceIsAutosaveable, disabled } ) {
isSelected={ ! isTemplateHidden }
role="menuitemcheckbox"
onClick={ () => {
setRenderingMode(
isTemplateHidden
? 'template-locked'
: 'post-only'
);
const newRenderingMode = isTemplateHidden
? 'template-locked'
: 'post-only';
setRenderingMode( newRenderingMode );
setDefaultRenderingMode( newRenderingMode );
} }
>
{ __( 'Show template' ) }
Expand Down
50 changes: 19 additions & 31 deletions packages/editor/src/components/provider/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,6 @@ const NON_CONTEXTUAL_POST_TYPES = [
'wp_template_part',
];

/**
* These are rendering modes that the editor supports.
*/
const RENDERING_MODES = [ 'post-only', 'template-locked' ];

/**
* Depending on the post, template and template mode,
* returns the appropriate blocks and change handlers for the block editor provider.
Expand Down Expand Up @@ -183,37 +178,28 @@ export const ExperimentalEditorProvider = withRegistryProvider(
getEditorSelection,
getRenderingMode,
__unstableIsEditorReady,
} = select( editorStore );
const {
getEntitiesConfig,
getPostType,
hasFinishedResolution,
} = select( coreStore );

const postTypeSupports = getPostType( post.type )?.supports;
const hasLoadedPostObject = hasFinishedResolution(
'getPostType',
[ post.type ]
);

const _defaultMode = Array.isArray( postTypeSupports?.editor )
? postTypeSupports.editor.find(
( features ) => 'default-mode' in features
)?.[ 'default-mode' ]
: undefined;
const hasDefaultMode = RENDERING_MODES.includes( _defaultMode );

// Wait for template resolution when rendering in a `template-locked` mode.
getDefaultRenderingMode,
} = unlock( select( editorStore ) );
const { getEntitiesConfig } = select( coreStore );

const _defaultMode = getDefaultRenderingMode( post.type );
/**
* To avoid content "flash", wait until rendering mode has been resolved.
* This is important for the initial render of the editor.
*
* - Wait for template to be resolved if the default mode is 'template-locked'.
* - Wait for default mode to be resolved otherwise.
*/
const hasResolvedMode =
hasLoadedPostObject && _defaultMode === 'template-locked'
_defaultMode === 'template-locked'
? hasTemplate
: true;
: _defaultMode !== undefined;

return {
editorSettings: getEditorSettings(),
isReady: __unstableIsEditorReady() && hasResolvedMode,
mode: getRenderingMode(),
defaultMode: hasDefaultMode ? _defaultMode : 'post-only',
defaultMode: _defaultMode,
selection: getEditorSelection(),
postTypeEntities:
post.type === 'wp_template'
Expand All @@ -224,7 +210,7 @@ export const ExperimentalEditorProvider = withRegistryProvider(
[ post.type, hasTemplate ]
);

const shouldRenderTemplate = !! template && mode !== 'post-only';
const shouldRenderTemplate = hasTemplate && mode !== 'post-only';
const rootLevelPost = shouldRenderTemplate ? template : post;
const defaultBlockContext = useMemo( () => {
const postContext = {};
Expand Down Expand Up @@ -341,7 +327,9 @@ export const ExperimentalEditorProvider = withRegistryProvider(

// Sets the right rendering mode when loading the editor.
useEffect( () => {
setRenderingMode( defaultMode );
if ( defaultMode ) {
setRenderingMode( defaultMode );
}
}, [ defaultMode, setRenderingMode ] );

useHideBlocksFromInserter( post.type, mode );
Expand Down
33 changes: 33 additions & 0 deletions packages/editor/src/store/private-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -492,3 +492,36 @@ export const removeTemplates =
.createErrorNotice( errorMessage, { type: 'snackbar' } );
}
};

/**
* Set the default rendering mode preference for the current post type.
*
* @param {string} mode The rendering mode to set as default.
*/
export const setDefaultRenderingMode =
( mode ) =>
( { select, registry } ) => {
const postType = select.getCurrentPostType();
const theme = registry
.select( coreStore )
.getCurrentTheme()?.stylesheet;
const renderingModes =
registry
.select( preferencesStore )
.get( 'core', 'renderingModes' )?.[ theme ] ?? {};

if ( renderingModes[ postType ] === mode ) {
return;
}

const newModes = {
[ theme ]: {
...renderingModes,
[ postType ]: mode,
},
};

registry
.dispatch( preferencesStore )
.set( 'core', 'renderingModes', newModes );
};
57 changes: 57 additions & 0 deletions packages/editor/src/store/private-selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
verse,
} from '@wordpress/icons';
import { store as coreStore } from '@wordpress/core-data';
import { store as preferencesStore } from '@wordpress/preferences';

/**
* Internal dependencies
Expand All @@ -34,6 +35,11 @@ const EMPTY_INSERTION_POINT = {
filterValue: undefined,
};

/**
* These are rendering modes that the editor supports.
*/
const RENDERING_MODES = [ 'post-only', 'template-locked' ];

/**
* Get the inserter.
*
Expand Down Expand Up @@ -215,3 +221,54 @@ export const getPostBlocksByName = createRegistrySelector( ( select ) =>
() => [ select( blockEditorStore ).getBlocks() ]
)
);

/**
* Returns the default rendering mode for a post type by user preference or post type configuration.
*
* @param {Object} state Global application state.
* @param {string} postType The post type.
*
* @return {string} The default rendering mode. Returns `undefined` while resolving value.
*/
export const getDefaultRenderingMode = createRegistrySelector(
( select ) => ( state, postType ) => {
const { getPostType, getCurrentTheme, hasFinishedResolution } =
select( coreStore );

// This needs to be called before `hasFinishedResolution`.
// eslint-disable-next-line @wordpress/no-unused-vars-before-return
const currentTheme = getCurrentTheme();
// eslint-disable-next-line @wordpress/no-unused-vars-before-return
const postTypeEntity = getPostType( postType );

// Wait for the post type and theme resolution.
if (
! hasFinishedResolution( 'getPostType', [ postType ] ) ||
! hasFinishedResolution( 'getCurrentTheme' )
) {
return undefined;
}
Comment on lines +244 to +250
Copy link
Member Author

Choose a reason for hiding this comment

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

Waiting for a resolution seems like a better approach. In rare cases when selectors resolve but return undefined, this allows using a post-only fallback.


const theme = currentTheme?.stylesheet;
const defaultModePreference = select( preferencesStore ).get(
'core',
'renderingModes'
)?.[ theme ]?.[ postType ];
const postTypeDefaultMode = Array.isArray(
postTypeEntity?.supports?.editor
)
? postTypeEntity.supports.editor.find(
( features ) => 'default-mode' in features
)?.[ 'default-mode' ]
: undefined;

const defaultMode = defaultModePreference || postTypeDefaultMode;

// Fallback gracefully to 'post-only' when rendering mode is not supported.
if ( ! RENDERING_MODES.includes( defaultMode ) ) {
return 'post-only';
}

return defaultMode;
}
);
3 changes: 3 additions & 0 deletions test/e2e/specs/site-editor/preload.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ test.describe( 'Preload', () => {
expect( requests ).toEqual( [
// Seems to be coming from `enableComplementaryArea`.
'/wp/v2/users/me',
// There are two separate settings OPTIONS requests. We should fix
// so the one for canUser and getEntityRecord are reused.
'/wp/v2/settings',
Comment on lines +49 to +51
Copy link
Member Author

Choose a reason for hiding this comment

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

I had to remove this in #69228 after merging #69173. I'm guessing the editor "is ready" a bit faster now, so the preloading test picks up /wp/v2/settings again.

This isn't a regression. As noted in the tests, both requests should be removed eventually.

] );
} );
} );
2 changes: 1 addition & 1 deletion test/native/integration-test-helpers/initialize-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export async function initializeEditor( props, { component } = {} ) {
resolutionSpy.mockImplementation( ( selectorName, args ) => {
// The mobile editor only supports the `post-only` rendering mode, so we
// presume a resolved `getPostType` selector to unblock editor rendering.
if ( 'getPostType' === selectorName ) {
if ( [ 'getPostType', 'getCurrentTheme' ].includes( selectorName ) ) {
Copy link
Member Author

Choose a reason for hiding this comment

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

This one was annoying to track down 😄

return true;
}

Expand Down
Loading