diff --git a/packages/edit-site/src/components/add-new-template/new-template.js b/packages/edit-site/src/components/add-new-template/new-template.js index cd615228a915f9..4b1c7eafcb9e8f 100644 --- a/packages/edit-site/src/components/add-new-template/new-template.js +++ b/packages/edit-site/src/components/add-new-template/new-template.js @@ -37,6 +37,7 @@ import { useDefaultTemplateTypes, entitiesConfig, usePostTypes, + usePostTypePage, useTaxonomies, useTaxonomyCategory, useTaxonomyTag, @@ -198,6 +199,7 @@ function useMissingTemplates( setShowCustomTemplateModal ) { const postTypes = usePostTypes(); + const pagePostType = usePostTypePage(); const taxonomies = useTaxonomies(); const categoryTaxonomy = useTaxonomyCategory(); const tagTaxonomy = useTaxonomyTag(); @@ -229,12 +231,17 @@ function useMissingTemplates( entitiesConfig.tag, onClickMenuItem ); + const pageMenuItem = useExtraTemplates( + pagePostType, + entitiesConfig.page, + onClickMenuItem + ); // We need to replace existing default template types with // the create specific template functionality. The original // info (title, description, etc.) is preserved in the // `useExtraTemplates` hook. const enhancedMissingDefaultTemplateTypes = [ ...missingDefaultTemplates ]; - [ categoryMenuItem, tagMenuItem ].forEach( ( menuItem ) => { + [ categoryMenuItem, tagMenuItem, pageMenuItem ].forEach( ( menuItem ) => { if ( ! menuItem?.length ) { return; } diff --git a/packages/edit-site/src/components/add-new-template/utils.js b/packages/edit-site/src/components/add-new-template/utils.js index 725ff6352e125e..555af52b9cfdd5 100644 --- a/packages/edit-site/src/components/add-new-template/utils.js +++ b/packages/edit-site/src/components/add-new-template/utils.js @@ -79,30 +79,34 @@ const taxonomyBaseConfig = { labels.singular_name ), }; +const postTypeBaseConfig = { + entityName: 'postType', + getOrderBy: ( { search } ) => ( search ? 'relevance' : 'modified' ), + recordNamePath: 'title.rendered', + // `icon` is the `menu_icon` property of a post type. We + // only handle `dashicons` for now, even if the `menu_icon` + // also supports urls and svg as values. + getIcon: ( _icon ) => + _icon?.startsWith( 'dashicons-' ) ? _icon.slice( 10 ) : post, + getTitle: ( labels ) => + sprintf( + // translators: %s: Name of the post type e.g: "Post". + __( 'Single item: %s' ), + labels.singular_name + ), + getDescription: ( labels ) => + sprintf( + // translators: %s: Name of the post type e.g: "Post". + __( 'Displays a single item: %s.' ), + labels.singular_name + ), +}; export const entitiesConfig = { postType: { - entityName: 'postType', + ...postTypeBaseConfig, templatePrefix: 'single-', - getOrderBy: ( { search } ) => ( search ? 'relevance' : 'modified' ), - recordNamePath: 'title.rendered', - // `icon` is the `menu_icon` property of a post type. We - // only handle `dashicons` for now, even if the `menu_icon` - // also supports urls and svg as values. - getIcon: ( _icon ) => - _icon?.startsWith( 'dashicons-' ) ? _icon.slice( 10 ) : post, - getTitle: ( labels ) => - sprintf( - // translators: %s: Name of the post type e.g: "Post". - __( 'Single item: %s' ), - labels.singular_name - ), - getDescription: ( labels ) => - sprintf( - // translators: %s: Name of the post type e.g: "Post". - __( 'Displays a single item: %s.' ), - labels.singular_name - ), }, + page: { ...postTypeBaseConfig }, taxonomy: { ...taxonomyBaseConfig, templatePrefix: 'taxonomy-', @@ -129,13 +133,13 @@ export const useDefaultTemplateTypes = () => { ); }; -export const usePostTypes = () => { +const usePublicPostTypes = () => { const postTypes = useSelect( ( select ) => select( coreStore ).getPostTypes( { per_page: -1 } ), [] ); return useMemo( () => { - const excludedPostTypes = [ 'attachment', 'page' ]; + const excludedPostTypes = [ 'attachment' ]; return postTypes?.filter( ( { viewable, slug } ) => viewable && ! excludedPostTypes.includes( slug ) @@ -143,6 +147,22 @@ export const usePostTypes = () => { }, [ postTypes ] ); }; +// `page` post type is a special case in the template hierarchy, +// so we exclude it from the list of post types and we handle it +// separately. +export const usePostTypes = () => { + const postTypes = usePublicPostTypes(); + return useMemo( () => { + return postTypes?.filter( ( { slug } ) => slug !== 'page' ); + }, [ postTypes ] ); +}; +export const usePostTypePage = () => { + const postTypes = usePublicPostTypes(); + return useMemo( () => { + return postTypes?.filter( ( { slug } ) => slug === 'page' ); + }, [ postTypes ] ); +}; + const usePublicTaxonomies = () => { const taxonomies = useSelect( ( select ) => select( coreStore ).getTaxonomies( { per_page: -1 } ),