From 996004b796d606a575c6252afc713e2f256dd556 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 23 Nov 2023 21:12:43 +0100 Subject: [PATCH] Site Editor: Fix template resolution for templates assigned as home page (#56418) Co-authored-by: ntsekouras Co-authored-by: Ramon --- .../sidebar-edit-mode/page-panels/hooks.js | 29 +++++-- .../page-panels/reset-default-template.js | 6 +- .../use-init-edited-entity-from-url.js | 86 +++++++++++++++---- 3 files changed, 92 insertions(+), 29 deletions(-) diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/hooks.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/hooks.js index 92fad17cd1d3e4..1071479b2f9f22 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/hooks.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/hooks.js @@ -18,13 +18,25 @@ export function useEditedPostContext() { ); } -export function useIsPostsPage() { +export function useAllowSwitchingTemplates() { const { postId } = useEditedPostContext(); return useSelect( - ( select ) => - +postId === - select( coreStore ).getEntityRecord( 'root', 'site' ) - ?.page_for_posts, + ( select ) => { + const { getEntityRecord, getEntityRecords } = select( coreStore ); + const siteSettings = getEntityRecord( 'root', 'site' ); + const templates = getEntityRecords( + 'postType', + TEMPLATE_POST_TYPE, + { per_page: -1 } + ); + const isPostsPage = +postId === siteSettings?.page_for_posts; + // If current page is set front page or posts page, we also need + // to check if the current theme has a template for it. If not + const isFrontPage = + +postId === siteSettings?.page_on_front && + templates?.some( ( { slug } ) => slug === 'front-page' ); + return ! isPostsPage && ! isFrontPage; + }, [ postId ] ); } @@ -46,19 +58,18 @@ function useTemplates() { export function useAvailableTemplates() { const currentTemplateSlug = useCurrentTemplateSlug(); - const isPostsPage = useIsPostsPage(); + const allowSwitchingTemplate = useAllowSwitchingTemplates(); const templates = useTemplates(); return useMemo( () => - // The posts page template cannot be changed. - ! isPostsPage && + allowSwitchingTemplate && templates?.filter( ( template ) => template.is_custom && template.slug !== currentTemplateSlug && !! template.content.raw // Skip empty templates. ), - [ templates, currentTemplateSlug, isPostsPage ] + [ templates, currentTemplateSlug, allowSwitchingTemplate ] ); } diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/reset-default-template.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/reset-default-template.js index 0f29292274546b..795477cc8fc7c6 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/reset-default-template.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/reset-default-template.js @@ -10,18 +10,18 @@ import { store as coreStore } from '@wordpress/core-data'; * Internal dependencies */ import { + useAllowSwitchingTemplates, useCurrentTemplateSlug, useEditedPostContext, - useIsPostsPage, } from './hooks'; export default function ResetDefaultTemplate( { onClick } ) { const currentTemplateSlug = useCurrentTemplateSlug(); - const isPostsPage = useIsPostsPage(); + const allowSwitchingTemplate = useAllowSwitchingTemplates(); const { postType, postId } = useEditedPostContext(); const { editEntityRecord } = useDispatch( coreStore ); // The default template in a post is indicated by an empty string. - if ( ! currentTemplateSlug || isPostsPage ) { + if ( ! currentTemplateSlug || ! allowSwitchingTemplate ) { return null; } return ( diff --git a/packages/edit-site/src/components/sync-state-with-url/use-init-edited-entity-from-url.js b/packages/edit-site/src/components/sync-state-with-url/use-init-edited-entity-from-url.js index 64eb3778a99c70..46079cbce8efd5 100644 --- a/packages/edit-site/src/components/sync-state-with-url/use-init-edited-entity-from-url.js +++ b/packages/edit-site/src/components/sync-state-with-url/use-init-edited-entity-from-url.js @@ -28,21 +28,46 @@ const postTypesWithoutParentTemplate = [ ]; function useResolveEditedEntityAndContext( { postId, postType } ) { - const { isRequestingSite, homepageId, url } = useSelect( ( select ) => { - const { getSite, getUnstableBase } = select( coreDataStore ); - const siteData = getSite(); - const base = getUnstableBase(); - - return { - isRequestingSite: ! base, - homepageId: - siteData?.show_on_front === 'page' - ? siteData.page_on_front - : null, - url: base?.home, - }; - }, [] ); + const { hasLoadedAllDependencies, homepageId, url, frontPageTemplateId } = + useSelect( ( select ) => { + const { getSite, getUnstableBase, getEntityRecords } = + select( coreDataStore ); + const siteData = getSite(); + const base = getUnstableBase(); + const templates = getEntityRecords( + 'postType', + TEMPLATE_POST_TYPE, + { + per_page: -1, + } + ); + let _frontPateTemplateId; + if ( templates ) { + const frontPageTemplate = templates.find( + ( t ) => t.slug === 'front-page' + ); + _frontPateTemplateId = frontPageTemplate + ? frontPageTemplate.id + : false; + } + return { + hasLoadedAllDependencies: !! base && !! siteData, + homepageId: + siteData?.show_on_front === 'page' + ? siteData.page_on_front.toString() + : null, + url: base?.home, + frontPageTemplateId: _frontPateTemplateId, + }; + }, [] ); + + /** + * This is a hook that recreates the logic to resolve a template for a given WordPress postID postTypeId + * in order to match the frontend as closely as possible in the site editor. + * + * It is not possible to rely on the server logic because there maybe unsaved changes that impact the template resolution. + */ const resolvedTemplateId = useSelect( ( select ) => { // If we're rendering a post type that doesn't have a template @@ -62,6 +87,22 @@ function useResolveEditedEntityAndContext( { postId, postType } ) { postTypeToResolve, postIdToResolve ) { + // For the front page, we always use the front page template if existing. + if ( + postTypeToResolve === 'page' && + homepageId === postIdToResolve + ) { + // We're still checking whether the front page template exists. + // Don't resolve the template yet. + if ( frontPageTemplateId === undefined ) { + return undefined; + } + + if ( !! frontPageTemplateId ) { + return frontPageTemplateId; + } + } + const editedEntity = getEditedEntityRecord( 'postType', postTypeToResolve, @@ -91,6 +132,10 @@ function useResolveEditedEntityAndContext( { postId, postType } ) { } ); } + if ( ! hasLoadedAllDependencies ) { + return undefined; + } + // If we're rendering a specific page, post... we need to resolve its template. if ( postType && postId ) { return resolveTemplateForPostTypeAndId( postType, postId ); @@ -102,12 +147,19 @@ function useResolveEditedEntityAndContext( { postId, postType } ) { } // If we're not rendering a specific page, use the front page template. - if ( ! isRequestingSite && url ) { + if ( url ) { const template = __experimentalGetTemplateForLink( url ); return template?.id; } }, - [ homepageId, isRequestingSite, url, postId, postType ] + [ + homepageId, + hasLoadedAllDependencies, + url, + postId, + postType, + frontPageTemplateId, + ] ); const context = useMemo( () => { @@ -130,7 +182,7 @@ function useResolveEditedEntityAndContext( { postId, postType } ) { return { isReady: true, postType, postId, context }; } - if ( ( postType && postId ) || homepageId || ! isRequestingSite ) { + if ( hasLoadedAllDependencies ) { return { isReady: resolvedTemplateId !== undefined, postType: TEMPLATE_POST_TYPE,