From cd22276e890fd611076a64083d964d06e0cfc33f Mon Sep 17 00:00:00 2001
From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com>
Date: Fri, 23 Jun 2023 14:22:10 +1000
Subject: [PATCH] Library: Reinstate sidebar navigation menu editing for
template parts (#51825)
---
.../index.js | 94 +++----------------
...template-part-navigation-menu-list-item.js | 28 ++++++
.../template-part-navigation-menu-list.js | 21 +++++
.../template-part-navigation-menu.js | 30 ++++++
.../template-part-navigation-menus.js | 33 +++++++
.../use-navigation-menu-content.js | 71 ++++++++++++++
.../use-pattern-details.js | 86 +++++++++++++++++
7 files changed, 280 insertions(+), 83 deletions(-)
create mode 100644 packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu-list-item.js
create mode 100644 packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu-list.js
create mode 100644 packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js
create mode 100644 packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menus.js
create mode 100644 packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-navigation-menu-content.js
create mode 100644 packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js
diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/index.js b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/index.js
index 149f420ff6fb9b..279b5a0de298d8 100644
--- a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/index.js
+++ b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/index.js
@@ -1,91 +1,21 @@
/**
* WordPress dependencies
*/
-import { __, sprintf, _x } from '@wordpress/i18n';
-import { useDispatch, useSelect } from '@wordpress/data';
+import { __ } from '@wordpress/i18n';
+import { useDispatch } from '@wordpress/data';
import { pencil } from '@wordpress/icons';
-import {
- __experimentalUseNavigator as useNavigator,
- Icon,
-} from '@wordpress/components';
-import { store as coreStore } from '@wordpress/core-data';
+import { __experimentalUseNavigator as useNavigator } from '@wordpress/components';
/**
* Internal dependencies
*/
+import SidebarButton from '../sidebar-button';
import SidebarNavigationScreen from '../sidebar-navigation-screen';
-import useEditedEntityRecord from '../use-edited-entity-record';
import useInitEditedEntityFromURL from '../sync-state-with-url/use-init-edited-entity-from-url';
-import { unlock } from '../../lock-unlock';
+import usePatternDetails from './use-pattern-details';
+import useNavigationMenuContent from './use-navigation-menu-content';
import { store as editSiteStore } from '../../store';
-import SidebarButton from '../sidebar-button';
-import { useAddedBy } from '../list/added-by';
-
-function usePatternTitleAndDescription( postType, postId ) {
- const { getDescription, getTitle, record } = useEditedEntityRecord(
- postType,
- postId
- );
- const currentTheme = useSelect(
- ( select ) => select( coreStore ).getCurrentTheme(),
- []
- );
- const addedBy = useAddedBy( postType, postId );
- const isAddedByActiveTheme =
- addedBy.type === 'theme' && record.theme === currentTheme?.stylesheet;
- const title = getTitle();
- let descriptionText = getDescription();
-
- if ( ! descriptionText && addedBy.text ) {
- descriptionText = sprintf(
- // translators: %s: pattern title e.g: "Header".
- __( 'This is your %s pattern.' ),
- getTitle()
- );
- }
-
- if ( ! descriptionText && postType === 'wp_block' && record?.title ) {
- descriptionText = sprintf(
- // translators: %s: user created pattern title e.g. "Footer".
- __( 'This is your %s pattern.' ),
- record.title
- );
- }
-
- const description = (
- <>
- { descriptionText }
-
- { addedBy.text && ! isAddedByActiveTheme && (
-
-
-
- { addedBy.imageUrl ? (
-
- ) : (
-
- ) }
-
- { addedBy.text }
-
-
- { addedBy.isCustomized && (
-
- { _x( '(Customized)', 'pattern' ) }
-
- ) }
-
- ) }
- >
- );
-
- return { title, description };
-}
+import { unlock } from '../../lock-unlock';
export default function SidebarNavigationScreenPattern() {
const { params } = useNavigator();
@@ -94,14 +24,11 @@ export default function SidebarNavigationScreenPattern() {
useInitEditedEntityFromURL();
- const { title, description } = usePatternTitleAndDescription(
- postType,
- postId
- );
+ const patternDetails = usePatternDetails( postType, postId );
+ const content = useNavigationMenuContent( postType, postId );
return (
setCanvasMode( 'edit' ) }
@@ -110,7 +37,8 @@ export default function SidebarNavigationScreenPattern() {
/>
}
backPath={ '/library' }
- description={ description }
+ content={ content }
+ { ...patternDetails }
/>
);
}
diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu-list-item.js b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu-list-item.js
new file mode 100644
index 00000000000000..b685c766107a32
--- /dev/null
+++ b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu-list-item.js
@@ -0,0 +1,28 @@
+/**
+ * WordPress dependencies
+ */
+import { useEntityProp } from '@wordpress/core-data';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import SidebarNavigationItem from '../sidebar-navigation-item';
+import { useLink } from '../routes/link';
+
+export default function TemplatePartNavigationMenuListItem( { id } ) {
+ const [ title ] = useEntityProp( 'postType', 'wp_navigation', 'title', id );
+
+ const linkInfo = useLink( {
+ postId: id,
+ postType: 'wp_navigation',
+ } );
+
+ if ( ! id ) return null;
+
+ return (
+
+ { title || __( '(no title)' ) }
+
+ );
+}
diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu-list.js b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu-list.js
new file mode 100644
index 00000000000000..4171b1e782575e
--- /dev/null
+++ b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu-list.js
@@ -0,0 +1,21 @@
+/**
+ * WordPress dependencies
+ */
+import { __experimentalItemGroup as ItemGroup } from '@wordpress/components';
+/**
+ * Internal dependencies
+ */
+import TemplatePartNavigationMenuListItem from './template-part-navigation-menu-list-item';
+
+export default function TemplatePartNavigationMenuList( { menus } ) {
+ return (
+
+ { menus.map( ( menuId ) => (
+
+ ) ) }
+
+ );
+}
diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js
new file mode 100644
index 00000000000000..f451c17e00adb7
--- /dev/null
+++ b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menu.js
@@ -0,0 +1,30 @@
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import { __experimentalHeading as Heading } from '@wordpress/components';
+import { useEntityProp } from '@wordpress/core-data';
+
+/**
+ * Internal dependencies
+ */
+import NavigationMenuEditor from '../sidebar-navigation-screen-navigation-menu/navigation-menu-editor';
+
+export default function TemplatePartNavigationMenu( { id } ) {
+ const [ title ] = useEntityProp( 'postType', 'wp_navigation', 'title', id );
+
+ if ( ! id ) return null;
+
+ return (
+ <>
+
+ { title?.rendered || __( 'Navigation' ) }
+
+
+ >
+ );
+}
diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menus.js b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menus.js
new file mode 100644
index 00000000000000..418b1d4423b202
--- /dev/null
+++ b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/template-part-navigation-menus.js
@@ -0,0 +1,33 @@
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import { __experimentalHeading as Heading } from '@wordpress/components';
+/**
+ * Internal dependencies
+ */
+import TemplatePartNavigationMenu from './template-part-navigation-menu';
+import TemplatePartNavigationMenuList from './template-part-navigation-menu-list';
+
+export default function TemplatePartNavigationMenus( { menus } ) {
+ if ( ! menus.length ) return null;
+
+ // if there is a single menu then render TemplatePartNavigationMenu
+ if ( menus.length === 1 ) {
+ return ;
+ }
+
+ // if there are multiple menus then render TemplatePartNavigationMenuList
+ return (
+ <>
+
+ { __( 'Navigation' ) }
+
+
+ >
+ );
+}
diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-navigation-menu-content.js b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-navigation-menu-content.js
new file mode 100644
index 00000000000000..84f09c19ff3b0d
--- /dev/null
+++ b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-navigation-menu-content.js
@@ -0,0 +1,71 @@
+/**
+ * Internal dependencies
+ */
+import TemplatePartNavigationMenus from './template-part-navigation-menus';
+import useEditedEntityRecord from '../use-edited-entity-record';
+
+/**
+ * Retrieves a list of specific blocks from a given tree of blocks.
+ *
+ * @param {string} targetBlockType The name of the block type to find.
+ * @param {Array} blocks A list of blocks from a template part entity.
+ *
+ * @return {Array} A list of any navigation blocks found in the blocks.
+ */
+function getBlocksOfTypeFromBlocks( targetBlockType, blocks ) {
+ if ( ! targetBlockType || ! blocks?.length ) {
+ return [];
+ }
+
+ const findInBlocks = ( _blocks ) => {
+ if ( ! _blocks ) {
+ return [];
+ }
+
+ const navigationBlocks = [];
+
+ for ( const block of _blocks ) {
+ if ( block.name === targetBlockType ) {
+ navigationBlocks.push( block );
+ }
+
+ if ( block?.innerBlocks ) {
+ const innerNavigationBlocks = findInBlocks( block.innerBlocks );
+
+ if ( innerNavigationBlocks.length ) {
+ navigationBlocks.push( ...innerNavigationBlocks );
+ }
+ }
+ }
+
+ return navigationBlocks;
+ };
+
+ return findInBlocks( blocks );
+}
+
+export default function useNavigationMenuContent( postType, postId ) {
+ const { record } = useEditedEntityRecord( postType, postId );
+
+ // Only managing navigation menus in template parts is supported
+ // to match previous behaviour. This could potentially be expanded
+ // to patterns as well.
+ if ( postType !== 'wp_template_part' ) {
+ return;
+ }
+
+ const navigationBlocks = getBlocksOfTypeFromBlocks(
+ 'core/navigation',
+ record?.blocks
+ );
+
+ const navigationMenuIds = navigationBlocks?.map(
+ ( block ) => block.attributes.ref
+ );
+
+ if ( ! navigationMenuIds?.length ) {
+ return;
+ }
+
+ return ;
+}
diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js
new file mode 100644
index 00000000000000..028b1c781f8f2c
--- /dev/null
+++ b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js
@@ -0,0 +1,86 @@
+/**
+ * WordPress dependencies
+ */
+import { __, sprintf, _x } from '@wordpress/i18n';
+import { store as coreStore } from '@wordpress/core-data';
+import { useSelect } from '@wordpress/data';
+import { Icon } from '@wordpress/components';
+
+/**
+ * Internal dependencies
+ */
+import { useAddedBy } from '../list/added-by';
+import useEditedEntityRecord from '../use-edited-entity-record';
+import SidebarNavigationScreenDetailsFooter from '../sidebar-navigation-screen-details-footer';
+
+export default function usePatternDetails( postType, postId ) {
+ const { getDescription, getTitle, record } = useEditedEntityRecord(
+ postType,
+ postId
+ );
+ const currentTheme = useSelect(
+ ( select ) => select( coreStore ).getCurrentTheme(),
+ []
+ );
+ const addedBy = useAddedBy( postType, postId );
+ const isAddedByActiveTheme =
+ addedBy.type === 'theme' && record.theme === currentTheme?.stylesheet;
+ const title = getTitle();
+ let descriptionText = getDescription();
+
+ if ( ! descriptionText && addedBy.text ) {
+ descriptionText = sprintf(
+ // translators: %s: pattern title e.g: "Header".
+ __( 'This is your %s pattern.' ),
+ getTitle()
+ );
+ }
+
+ if ( ! descriptionText && postType === 'wp_block' && record?.title ) {
+ descriptionText = sprintf(
+ // translators: %s: user created pattern title e.g. "Footer".
+ __( 'This is your %s pattern.' ),
+ record.title
+ );
+ }
+
+ const description = (
+ <>
+ { descriptionText }
+
+ { addedBy.text && ! isAddedByActiveTheme && (
+
+
+
+ { addedBy.imageUrl ? (
+
+ ) : (
+
+ ) }
+
+ { addedBy.text }
+
+
+ { addedBy.isCustomized && (
+
+ { _x( '(Customized)', 'pattern' ) }
+
+ ) }
+
+ ) }
+ >
+ );
+
+ const footer = !! record?.modified ? (
+
+ ) : null;
+
+ return { title, description, footer };
+}