diff --git a/packages/e2e-tests/specs/experiments/multi-entity-editing.test.js b/packages/e2e-tests/specs/experiments/multi-entity-editing.test.js
index 2d61fa19729e1..7e1b127b0be67 100644
--- a/packages/e2e-tests/specs/experiments/multi-entity-editing.test.js
+++ b/packages/e2e-tests/specs/experiments/multi-entity-editing.test.js
@@ -204,8 +204,11 @@ describe( 'Multi-entity editor states', () => {
'.wp-block-template-part .block-editor-block-list__layout'
);
- // Our custom template shows up in the " templates > all" menu; let's use it.
- await clickTemplateItem( [ 'Templates', 'All' ], templateName );
+ // Our custom template shows up in the "Templates > General" menu; let's use it.
+ await clickTemplateItem(
+ [ 'Templates', 'General templates' ],
+ templateName
+ );
await page.waitForXPath(
`//h1[contains(@class, "edit-site-document-actions__title") and contains(text(), '${ templateName }')]`
);
diff --git a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/constants.js b/packages/edit-site/src/components/navigation-sidebar/navigation-panel/constants.js
index bf88a77aa4a33..ea6c799bed779 100644
--- a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/constants.js
+++ b/packages/edit-site/src/components/navigation-sidebar/navigation-panel/constants.js
@@ -3,16 +3,43 @@
*/
import { __ } from '@wordpress/i18n';
-export const TEMPLATES_GENERAL = [
- 'front-page',
- 'archive',
- 'singular',
+export const TEMPLATES_PRIMARY = [
'index',
- 'search',
+ 'singular',
+ 'archive',
+ 'single',
+ 'page',
+ 'home',
'404',
+ 'search',
+];
+
+export const TEMPLATES_SECONDARY = [
+ 'author',
+ 'category',
+ 'taxonomy',
+ 'date',
+ 'tag',
+ 'attachment',
+ 'single-post',
+ 'front-page',
+];
+
+export const TEMPLATES_TOP_LEVEL = [
+ ...TEMPLATES_PRIMARY,
+ ...TEMPLATES_SECONDARY,
+];
+
+export const TEMPLATES_GENERAL = [ 'page-home' ];
+
+export const TEMPLATES_POSTS_PREFIXES = [
+ 'post-',
+ 'author-',
+ 'single-post-',
+ 'tag-',
];
-export const TEMPLATES_POSTS = [ 'home', 'single', 'single-post' ];
+export const TEMPLATES_PAGES_PREFIXES = [ 'page-' ];
export const TEMPLATES_NEW_OPTIONS = [
'front-page',
@@ -30,9 +57,10 @@ export const MENU_CONTENT_PAGES = 'content-pages';
export const MENU_CONTENT_POSTS = 'content-posts';
export const MENU_TEMPLATE_PARTS = 'template-parts';
export const MENU_TEMPLATES = 'templates';
-export const MENU_TEMPLATES_ALL = 'templates-all';
+export const MENU_TEMPLATES_GENERAL = 'templates-general';
export const MENU_TEMPLATES_PAGES = 'templates-pages';
export const MENU_TEMPLATES_POSTS = 'templates-posts';
+export const MENU_TEMPLATES_UNUSED = 'templates-unused';
export const SEARCH_DEBOUNCE_IN_MS = 75;
diff --git a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/menus/templates-pages.js b/packages/edit-site/src/components/navigation-sidebar/navigation-panel/menus/templates-pages.js
deleted file mode 100644
index d4816219a0239..0000000000000
--- a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/menus/templates-pages.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * External dependencies
- */
-import { map } from 'lodash';
-
-/**
- * WordPress dependencies
- */
-import {
- __experimentalNavigationGroup as NavigationGroup,
- __experimentalNavigationMenu as NavigationMenu,
-} from '@wordpress/components';
-import { __, _x } from '@wordpress/i18n';
-
-/**
- * Internal dependencies
- */
-import TemplateNavigationItem from '../template-navigation-item';
-import { MENU_TEMPLATES, MENU_TEMPLATES_PAGES } from '../constants';
-
-export default function TemplatesPagesMenu( { templates } ) {
- const defaultTemplate = templates?.find( ( { slug } ) => slug === 'page' );
- const specificTemplates =
- templates?.filter( ( { slug } ) => slug.startsWith( 'page-' ) ) ?? [];
-
- return (
-
-
- { map( specificTemplates, ( template ) => (
-
- ) ) }
-
-
- { defaultTemplate && (
-
-
-
- ) }
-
- );
-}
diff --git a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/menus/templates-posts.js b/packages/edit-site/src/components/navigation-sidebar/navigation-panel/menus/templates-posts.js
deleted file mode 100644
index 02225ee5bfb24..0000000000000
--- a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/menus/templates-posts.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * External dependencies
- */
-import { map } from 'lodash';
-
-/**
- * WordPress dependencies
- */
-import {
- __experimentalNavigationGroup as NavigationGroup,
- __experimentalNavigationMenu as NavigationMenu,
-} from '@wordpress/components';
-import { __, _x } from '@wordpress/i18n';
-
-/**
- * Internal dependencies
- */
-import TemplateNavigationItem from '../template-navigation-item';
-import {
- MENU_TEMPLATES,
- MENU_TEMPLATES_POSTS,
- TEMPLATES_POSTS,
-} from '../constants';
-
-export default function TemplatesPostsMenu( { templates } ) {
- const generalTemplates =
- templates?.filter( ( { slug } ) => TEMPLATES_POSTS.includes( slug ) ) ??
- [];
- const specificTemplates =
- templates?.filter( ( { slug } ) => slug.startsWith( 'post-' ) ) ?? [];
-
- return (
-
-
- { map( specificTemplates, ( template ) => (
-
- ) ) }
-
-
-
- { map( generalTemplates, ( template ) => (
-
- ) ) }
-
-
- );
-}
diff --git a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/menus/templates-all.js b/packages/edit-site/src/components/navigation-sidebar/navigation-panel/menus/templates-sub.js
similarity index 50%
rename from packages/edit-site/src/components/navigation-sidebar/navigation-panel/menus/templates-all.js
rename to packages/edit-site/src/components/navigation-sidebar/navigation-panel/menus/templates-sub.js
index 934a35bd0e0f5..9d6322c25a4f8 100644
--- a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/menus/templates-all.js
+++ b/packages/edit-site/src/components/navigation-sidebar/navigation-panel/menus/templates-sub.js
@@ -7,22 +7,31 @@ import { map } from 'lodash';
* WordPress dependencies
*/
import { __experimentalNavigationMenu as NavigationMenu } from '@wordpress/components';
-import { __ } from '@wordpress/i18n';
+import { useMemo } from '@wordpress/element';
/**
* Internal dependencies
*/
import TemplateNavigationItem from '../template-navigation-item';
-import { MENU_TEMPLATES, MENU_TEMPLATES_ALL } from '../constants';
+import { MENU_TEMPLATES } from '../constants';
+
+export default function TemplatesSubMenu( { menu, title, templates } ) {
+ const templatesFiltered = useMemo(
+ () =>
+ templates
+ ?.filter( ( { location } ) => location === menu )
+ ?.map( ( { template } ) => template ) ?? [],
+ [ menu, templates ]
+ );
-export default function TemplatesAllMenu( { templates } ) {
return (
- { map( templates, ( template ) => (
+ { map( templatesFiltered, ( template ) => (
+ slug.startsWith( prefix )
+ );
+ if ( isPostsTemplate ) {
+ return MENU_TEMPLATES_POSTS;
+ }
+
+ const isPagesTemplate = TEMPLATES_PAGES_PREFIXES.some( ( prefix ) =>
+ slug.startsWith( prefix )
+ );
+ if ( isPagesTemplate ) {
+ return MENU_TEMPLATES_PAGES;
+ }
+
+ return MENU_TEMPLATES_GENERAL;
+}
+
+function getUnusedTemplates( templates, showOnFront ) {
+ const unusedTemplates = [];
+
+ const templateSlugs = map( templates, 'slug' );
+ const supersededTemplates = templates.filter( ( { slug } ) =>
+ isTemplateSuperseded( slug, templateSlugs, showOnFront )
+ );
+
+ return [ ...supersededTemplates, ...unusedTemplates ];
+}
+
+function getTemplatesLocationMap( templates ) {
+ return templates.reduce( ( obj, template ) => {
+ obj[ template.slug ] = getTemplateLocation( template );
+ return obj;
+ }, {} );
+}
export default function TemplatesMenu() {
const [ search, setSearch ] = useState( '' );
@@ -38,14 +90,38 @@ export default function TemplatesMenu() {
setSearch( value );
} );
- const templates = useSelect(
- ( select ) =>
- select( 'core' ).getEntityRecords( 'postType', 'wp_template' ),
- []
- );
+ const { templates, showOnFront } = useSelect( ( select ) => {
+ const { getEntityRecords, getEditedEntityRecord } = select( coreStore );
+ return {
+ templates: getEntityRecords( 'postType', 'wp_template', {
+ per_page: -1,
+ } ),
+ showOnFront: getEditedEntityRecord( 'root', 'site' ).show_on_front,
+ };
+ }, [] );
+
+ const templatesWithLocation = useMemo( () => {
+ if ( ! templates ) {
+ return null;
+ }
- const generalTemplates = templates?.filter( ( { slug } ) =>
- TEMPLATES_GENERAL.includes( slug )
+ const unusedTemplates = getUnusedTemplates( templates, showOnFront );
+ const templateLocations = getTemplatesLocationMap( templates );
+
+ return templates.map( ( template ) => ( {
+ template,
+ location: find( unusedTemplates, { slug: template.slug } )
+ ? MENU_TEMPLATES_UNUSED
+ : templateLocations[ template.slug ],
+ } ) );
+ }, [ templates ] );
+
+ const topLevelTemplates = useMemo(
+ () =>
+ templatesWithLocation
+ ?.filter( ( { location } ) => location === MENU_TEMPLATES )
+ ?.map( ( { template } ) => template ) ?? [],
+ [ templatesWithLocation ]
);
return (
@@ -64,26 +140,32 @@ export default function TemplatesMenu() {
{ ! search && (
<>
+ { map( topLevelTemplates, ( template ) => (
+
+ ) ) }
+
- { map( generalTemplates, ( template ) => (
-
- ) ) }
>
) }
@@ -91,9 +173,26 @@ export default function TemplatesMenu() {
) }
-
-
-
+
+
+
+
);
}
diff --git a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/template-hierarchy.js b/packages/edit-site/src/components/navigation-sidebar/navigation-panel/template-hierarchy.js
new file mode 100644
index 0000000000000..29dba28b9b5aa
--- /dev/null
+++ b/packages/edit-site/src/components/navigation-sidebar/navigation-panel/template-hierarchy.js
@@ -0,0 +1,23 @@
+const TEMPLATE_OVERRIDES = {
+ singular: [ 'single', 'page' ],
+ index: [ 'archive', '404', 'search', 'singular', 'home' ],
+ home: [ 'front-page' ],
+};
+
+export function isTemplateSuperseded( slug, existingSlugs, showOnFront ) {
+ if ( ! TEMPLATE_OVERRIDES[ slug ] ) {
+ return false;
+ }
+
+ // `home` template is unused if it is superseded by `front-page`
+ // or "show on front" is set to show a page rather than blog posts.
+ if ( slug === 'home' && showOnFront !== 'posts' ) {
+ return true;
+ }
+
+ return TEMPLATE_OVERRIDES[ slug ].every(
+ ( overrideSlug ) =>
+ existingSlugs.includes( overrideSlug ) ||
+ isTemplateSuperseded( overrideSlug, existingSlugs, showOnFront )
+ );
+}