Skip to content
Open
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
80 changes: 45 additions & 35 deletions packages/core-data/src/private-selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,40 +210,48 @@ export const getPostsPageId = createRegistrySelector( ( select ) => () => {

export const getTemplateId = createRegistrySelector(
( select ) => ( state, postType, postId ) => {
const homepage = unlock( select( STORE_NAME ) ).getHomePage();
// `getHomePage()` and `getPostsPageId()` fire a
// `/wp/v2/templates/lookup?slug=front-page` REST request via the
// `getDefaultTemplateId` resolver. The homepage / posts-page
// branches below are guarded by `postType === 'page'`, so resolve
// them only when the post is actually a page — otherwise the
// lookup is wasted work for every non-page post type.
if ( postType === 'page' ) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Changes in this file could be split in a separate PR.

const homepage = unlock( select( STORE_NAME ) ).getHomePage();

if ( ! homepage ) {
return;
}

// For the front page, we always use the front page template if existing.
if (
postType === 'page' &&
postType === homepage?.postType &&
postId.toString() === homepage?.postId
) {
// The /lookup endpoint cannot currently handle a lookup
// when a page is set as the front page, so specifically in
// that case, we want to check if there is a front page
// template, and instead of falling back to the home
// template, we want to fall back to the page template.
const templates = select( STORE_NAME ).getEntityRecords(
'postType',
'wp_template',
{
per_page: -1,
}
);
if ( ! templates ) {
if ( ! homepage ) {
return;
}
const id = templates.find( ( { slug } ) => slug === 'front-page' )
?.id;
if ( id ) {
return id;

// For the front page, we always use the front page template if existing.
if (
postType === homepage?.postType &&
postId.toString() === homepage?.postId
) {
// The /lookup endpoint cannot currently handle a lookup
// when a page is set as the front page, so specifically in
// that case, we want to check if there is a front page
// template, and instead of falling back to the home
// template, we want to fall back to the page template.
const templates = select( STORE_NAME ).getEntityRecords(
'postType',
'wp_template',
{
per_page: -1,
}
);
if ( ! templates ) {
return;
}
const id = templates.find(
( { slug } ) => slug === 'front-page'
)?.id;
if ( id ) {
return id;
}
// If no front page template is found, continue with the
// logic below (fetching the page template).
}
// If no front page template is found, continue with the
// logic below (fetching the page template).
}

const editedEntity = select( STORE_NAME ).getEditedEntityRecord(
Expand All @@ -254,12 +262,14 @@ export const getTemplateId = createRegistrySelector(
if ( ! editedEntity ) {
return;
}
const postsPageId = unlock( select( STORE_NAME ) ).getPostsPageId();
// Check if the current page is the posts page.
if ( postType === 'page' && postsPageId === postId.toString() ) {
return select( STORE_NAME ).getDefaultTemplateId( {
slug: 'home',
} );
if ( postType === 'page' ) {
const postsPageId = unlock( select( STORE_NAME ) ).getPostsPageId();
if ( postsPageId === postId.toString() ) {
return select( STORE_NAME ).getDefaultTemplateId( {
slug: 'home',
} );
}
}
// First see if the post/page has an assigned template and fetch it.
const currentTemplateSlug = editedEntity.template;
Expand Down
89 changes: 11 additions & 78 deletions packages/fields/src/fields/template/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,100 +59,33 @@ export function useTemplateFieldMode(
);
}

/**
* Compute the template slug to look up in the template hierarchy.
*
* In `draft` status we might not have a slug available, so we use the
* `single` post type template slug (e.g. page, single-post,
* single-product, etc.). Pages do not need the `single` prefix to be
* prioritised through template hierarchy.
*
* @param postType The post type.
* @param slug The post slug.
*/
function getTemplateSlugToCheck(
postType: string,
slug: string | undefined
): string {
if ( slug ) {
return postType === 'page'
? `${ postType }-${ slug }`
: `single-${ postType }-${ slug }`;
}
return postType === 'page' ? 'page' : `single-${ postType }`;
}

const NAME_NOT_FOUND = '';

/**
* Hook that resolves the human-readable label for the default template
* that would apply to a post, given its type, ID and slug.
* that would apply to a post, given its type and ID.
*
* Delegates the homepage / posts-page / template-hierarchy resolution to
* the `getTemplateId` private selector in `@wordpress/core-data`, then
* looks up the resolved template's record for its title.
*
* @param postType The post type.
* @param postId The post ID.
* @param slug The post slug.
*/
export function useDefaultTemplateLabel(
postType: string | undefined,
postId: string | number | undefined,
slug: string | undefined
postId: string | number | undefined
): string {
return useSelect(
( select ) => {
if ( ! postType || ! postId ) {
return NAME_NOT_FOUND;
}

const postIdStr = String( postId );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The main difference between the hook and the selector is that the hook would always return the default fallback template and not the assigned one. In this PR you can see that this leads to the below:

Screen.Recording.2026-05-15.at.5.19.42.PM.mov


// Check if the current page is the front page.
const homePage = unlock( select( coreStore ) ).getHomePage();
if (
postType === 'page' &&
homePage?.postType === 'page' &&
homePage?.postId === postIdStr
) {
const templates = select(
coreStore
).getEntityRecords< WpTemplate >( 'postType', 'wp_template', {
per_page: -1,
} );
const frontPage = templates?.find(
( t ) => t.slug === 'front-page'
);
if ( frontPage ) {
return getItemTitle( frontPage );
}

// If no front page template is found, fall back to the page template.
// See @getTemplateId private selector in core-data package.
}

// Check if the current page is the posts page.
const postsPageId = unlock( select( coreStore ) ).getPostsPageId();
if ( postType === 'page' && postsPageId === postIdStr ) {
const templateId = select( coreStore ).getDefaultTemplateId( {
slug: 'home',
} );
if ( ! templateId ) {
return NAME_NOT_FOUND;
}

const template = select(
coreStore
).getEntityRecord< WpTemplate >(
'postType',
'wp_template',
templateId
);
return template ? getItemTitle( template ) : NAME_NOT_FOUND;
}

// Check any other case.
const slugToCheck = getTemplateSlugToCheck( postType, slug );
const templateId = select( coreStore ).getDefaultTemplateId( {
slug: slugToCheck,
} );
const templateId = unlock( select( coreStore ) ).getTemplateId(
postType,
postId
);
if ( ! templateId ) {
return NAME_NOT_FOUND;
}
Expand All @@ -164,6 +97,6 @@ export function useDefaultTemplateLabel(
);
return template ? getItemTitle( template ) : NAME_NOT_FOUND;
},
[ postType, postId, slug ]
[ postType, postId ]
);
}
7 changes: 1 addition & 6 deletions packages/fields/src/fields/template/template-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ function BlockThemeTemplateEdit( {
const postType = data.type;
const postId =
typeof data.id === 'number' ? data.id : parseInt( data.id, 10 );
const slug = data.slug;
const { templates, canSwitchTemplate } = useSelect(
( select ) => {
const allTemplates =
Expand Down Expand Up @@ -108,11 +107,7 @@ function BlockThemeTemplateEdit( {
},
[ postId, postType ]
);
const defaultTemplateLabel = useDefaultTemplateLabel(
postType,
postId,
slug
);
const defaultTemplateLabel = useDefaultTemplateLabel( postType, postId );
const value = field.getValue( { item: data } );
const options = useMemo( () => {
const templateOptions = templates.map( ( template ) => ( {
Expand Down
7 changes: 1 addition & 6 deletions packages/fields/src/fields/template/template-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,10 @@ function BlockThemeTemplateView( {
field,
}: DataViewRenderFieldProps< BasePost > ) {
const postType = item.type;
const slug = item.slug;
const postId = item.id;
const templateSlug = field.getValue( { item } );

const defaultTemplateLabel = useDefaultTemplateLabel(
postType,
postId,
slug
);
const defaultTemplateLabel = useDefaultTemplateLabel( postType, postId );

const templateLabel = useSelect(
( select ) => {
Expand Down
Loading