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

Site Editor: Fix template resolution for templates assigned as home page #56418

Merged
merged 6 commits into from
Nov 23, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -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 ]
);
}
Expand All @@ -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 ]
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
}
Comment on lines +96 to +103
Copy link
Member

Choose a reason for hiding this comment

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

Are there any other values that frontPageTemplateId could be other than undefined|string?

Could we just return frontPageTemplateId; without the two ifs?

Copy link
Contributor

Choose a reason for hiding this comment

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

Further up in the useSelect the value false is used to denote that no templates match the front page template. In this case, a page is set to be the front page, but there's no front page template, so these two if statements (and early returns) should be skipped, with the rest of this function continuing to execute to find the right template to use.

I think that's what's happening, anyway!

}

const editedEntity = getEditedEntityRecord(
'postType',
postTypeToResolve,
Expand Down Expand Up @@ -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 );
Expand All @@ -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( () => {
Expand All @@ -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,
Expand Down
Loading