diff --git a/packages/edit-navigation/src/components/header/manage-locations.js b/packages/edit-navigation/src/components/header/manage-locations.js
index 1f75db5c6df7a7..e69de29bb2d1d6 100644
--- a/packages/edit-navigation/src/components/header/manage-locations.js
+++ b/packages/edit-navigation/src/components/header/manage-locations.js
@@ -1,45 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { Spinner, SelectControl } from '@wordpress/components';
-import { __ } from '@wordpress/i18n';
-
-/**
- * Internal dependencies
- */
-import useMenuLocations from '../../hooks/use-menu-locations';
-
-export default function ManageLocations( { menus } ) {
- const [ menuLocations, assignMenuToLocation ] = useMenuLocations();
-
- if ( ! menus || ! menuLocations ) {
- return ;
- }
-
- if ( ! menus.length ) {
- return
{ __( 'There are no available menus.' ) }
;
- }
-
- if ( ! menuLocations.length ) {
- return { __( 'There are no available menu locations.' ) }
;
- }
-
- return menuLocations.map( ( menuLocation ) => (
- ( {
- value: menu.id,
- label: menu.name,
- } ) ),
- ] }
- onChange={ ( menuId ) => {
- assignMenuToLocation( menuLocation.name, Number( menuId ) );
- } }
- />
- ) );
-}
diff --git a/packages/edit-navigation/src/components/header/save-button.js b/packages/edit-navigation/src/components/header/save-button.js
index 4d526ebbe40ed3..604a7812cc92d1 100644
--- a/packages/edit-navigation/src/components/header/save-button.js
+++ b/packages/edit-navigation/src/components/header/save-button.js
@@ -9,8 +9,12 @@ import { __ } from '@wordpress/i18n';
* Internal dependencies
*/
import { store as editNavigationStore } from '../../store';
+import { useMenuEntity, MenuIdContext } from '../../hooks';
+import { useContext } from '@wordpress/element';
export default function SaveButton( { navigationPost } ) {
+ const menuId = useContext( MenuIdContext );
+ const { saveMenuName } = useMenuEntity( menuId );
const { saveNavigationPost } = useDispatch( editNavigationStore );
return (
@@ -19,6 +23,7 @@ export default function SaveButton( { navigationPost } ) {
isPrimary
onClick={ () => {
saveNavigationPost( navigationPost );
+ saveMenuName();
} }
disabled={ ! navigationPost }
>
diff --git a/packages/edit-navigation/src/components/inspector-additions/index.js b/packages/edit-navigation/src/components/inspector-additions/index.js
index 50fddb1987785c..11192b9b052d91 100644
--- a/packages/edit-navigation/src/components/inspector-additions/index.js
+++ b/packages/edit-navigation/src/components/inspector-additions/index.js
@@ -9,11 +9,19 @@ import { InspectorControls } from '@wordpress/block-editor';
*/
import AutoAddPagesPanel from './auto-add-pages-panel';
import DeleteMenuPanel from './delete-menu-panel';
+import ManageLocations from './manage-locations';
import { NameEditor } from '../name-editor';
import { PanelBody } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
-export default function InspectorAdditions( { menuId, onDeleteMenu } ) {
+export default function InspectorAdditions( {
+ menuId,
+ onDeleteMenu,
+ onSelectMenu,
+ isManageLocationsModalOpen,
+ closeManageLocationsModal,
+ openManageLocationsModal,
+} ) {
const selectedBlock = useSelect(
( select ) => select( 'core/block-editor' ).getSelectedBlock(),
[]
@@ -25,7 +33,15 @@ export default function InspectorAdditions( { menuId, onDeleteMenu } ) {
return (
-
+
+
+
+
diff --git a/packages/edit-navigation/src/components/inspector-additions/manage-locations.js b/packages/edit-navigation/src/components/inspector-additions/manage-locations.js
new file mode 100644
index 00000000000000..a0736e848d5a77
--- /dev/null
+++ b/packages/edit-navigation/src/components/inspector-additions/manage-locations.js
@@ -0,0 +1,158 @@
+/**
+ * WordPress dependencies
+ */
+import { useSelect } from '@wordpress/data';
+import { useContext } from '@wordpress/element';
+import {
+ Spinner,
+ SelectControl,
+ CheckboxControl,
+ Button,
+ Modal,
+} from '@wordpress/components';
+import { __, sprintf } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import { useMenuLocations, MenuIdContext } from '../../hooks';
+
+export default function ManageLocations( {
+ onSelectMenu,
+ isModalOpen,
+ openModal,
+ closeModal,
+} ) {
+ const menus = useSelect( ( select ) => select( 'core' ).getMenus(), [] );
+
+ const selectedMenuId = useContext( MenuIdContext );
+
+ const {
+ menuLocations,
+ assignMenuToLocation,
+ toggleMenuLocationAssignment,
+ } = useMenuLocations();
+
+ const themeLocationCountTextMain = sprintf(
+ // translators: Number of available theme locations.
+ __(
+ 'Your current theme provides %d different locations to place menu.'
+ ),
+ menuLocations.length
+ );
+
+ const themeLocationCountTextModal = sprintf(
+ // translators: Number of available theme locations.
+ __(
+ 'Your current theme supports %d different locations. Select which menu appears in each location.'
+ ),
+ menuLocations.length
+ );
+
+ const menusWithSelection = menuLocations.map( ( { name, menu } ) => {
+ const menuOnLocation = menus
+ .filter( ( { id } ) => ! [ 0, selectedMenuId ].includes( id ) )
+ .find( ( { id } ) => id === menu );
+
+ return (
+
+
+ toggleMenuLocationAssignment( name, selectedMenuId )
+ }
+ label={ name }
+ help={
+ menuOnLocation &&
+ sprintf(
+ // translators: menu name.
+ __( 'Currently using %s' ),
+ menuOnLocation.name
+ )
+ }
+ />
+
+ );
+ } );
+
+ if ( ! menus || ! menuLocations ) {
+ return ;
+ }
+
+ if ( ! menuLocations.length ) {
+ return { __( 'There are no available menu locations.' ) }
;
+ }
+
+ const menuLocationCard = menuLocations.map( ( menuLocation ) => (
+
+ ( {
+ key: id,
+ value: id,
+ label: name,
+ } ) ),
+ ] }
+ onChange={ ( menuId ) => {
+ assignMenuToLocation( menuLocation.name, Number( menuId ) );
+ } }
+ />
+
+
+ ) );
+
+ return (
+ <>
+
+ { themeLocationCountTextMain }
+
+
+ { menusWithSelection }
+
+
+ { isModalOpen && (
+
+
+ { themeLocationCountTextModal }
+
+ { menuLocationCard }
+
+ ) }
+ >
+ );
+}
diff --git a/packages/edit-navigation/src/components/inspector-additions/style.scss b/packages/edit-navigation/src/components/inspector-additions/style.scss
index 359310cfb6e0b9..f0074ddb591d52 100644
--- a/packages/edit-navigation/src/components/inspector-additions/style.scss
+++ b/packages/edit-navigation/src/components/inspector-additions/style.scss
@@ -1,3 +1,59 @@
.edit-navigation-inspector-additions__delete-menu-panel {
text-align: center;
}
+
+.block-editor-block-inspector__no-blocks,
+.block-editor-block-inspector {
+ width: $sidebar-width;
+ background: $white;
+ border-left: 1px solid $gray-300;
+ position: fixed;
+ top: $grid-unit-40;
+ right: 0;
+ bottom: 0;
+ z-index: 1;
+ overflow: auto;
+}
+
+.edit-navigation-manage-locations__modal {
+ max-width: 360px;
+}
+
+.edit-navigation-manage-locations__delete-menu-panel {
+ text-align: center;
+}
+
+.edit-navigation-manage-locations__menu-entry .components-base-control {
+ width: 100%;
+}
+
+.edit-navigation-manage-locations__edit-button {
+ flex: 1;
+}
+
+.edit-navigation-manage-locations__menu-entry {
+ display: flex;
+ margin-bottom: $grid-unit-15;
+ margin-top: $grid-unit-15;
+ .components-custom-select-control,
+ .components-custom-select-control__button {
+ width: 100%;
+ }
+ button {
+ height: 100%;
+ }
+}
+
+.edit-navigation-manage-locations__select-menu {
+ padding-right: $grid-unit-10;
+}
+
+.edit-navigation-manage-locations__open-menu-locations-modal-button {
+ width: 100%;
+ justify-content: center;
+}
+
+.edit-navigation-manage-locations__theme-location-text-main,
+.edit-navigation-manage-locations__theme-location-text-modal {
+ margin-bottom: $grid-unit-30;
+}
diff --git a/packages/edit-navigation/src/components/layout/index.js b/packages/edit-navigation/src/components/layout/index.js
index dd36aec418ef40..f815dac4c22b13 100644
--- a/packages/edit-navigation/src/components/layout/index.js
+++ b/packages/edit-navigation/src/components/layout/index.js
@@ -74,6 +74,9 @@ export default function Layout( { blockEditorSettings } ) {
navigationPost,
selectMenu,
deleteMenu,
+ openManageLocationsModal,
+ closeManageLocationsModal,
+ isManageLocationsModalOpen,
} = useNavigationEditor();
const [ blocks, onInput, onChange ] = useNavigationBlockEditor(
@@ -167,6 +170,18 @@ export default function Layout( { blockEditorSettings } ) {
blocks={ blocks }
/>
+ Object.values( menuLocationsByName )
+ .filter( ( { menu } ) => menu === id )
+ .map( ( { name } ) => name );
+
+const withLocations = ( menuLocationsByName ) => ( id ) => ( {
+ id,
+ locations: locationsForMenuId( menuLocationsByName, id ),
+} );
+
export default function useMenuLocations() {
const [ menuLocationsByName, setMenuLocationsByName ] = useState( null );
@@ -14,7 +29,7 @@ export default function useMenuLocations() {
const fetchMenuLocationsByName = async () => {
const newMenuLocationsByName = await apiFetch( {
method: 'GET',
- path: '/__experimental/menu-locations',
+ path: '/__experimental/menu-locations/',
} );
if ( isMounted ) {
@@ -23,7 +38,6 @@ export default function useMenuLocations() {
};
fetchMenuLocationsByName();
-
return () => ( isMounted = false );
}, [] );
@@ -33,50 +47,36 @@ export default function useMenuLocations() {
async ( locationName, newMenuId ) => {
const oldMenuId = menuLocationsByName[ locationName ].menu;
- const newMenuLocationsByName = {
- ...menuLocationsByName,
- [ locationName ]: {
- ...menuLocationsByName[ locationName ],
- menu: newMenuId,
- },
- };
+ const newMenuLocationsByName = merge( menuLocationsByName, {
+ [ locationName ]: { menu: newMenuId },
+ } );
setMenuLocationsByName( newMenuLocationsByName );
- const promises = [];
-
- if ( oldMenuId ) {
- promises.push(
- saveMenu( {
- id: oldMenuId,
- locations: Object.values( newMenuLocationsByName )
- .filter( ( { menu } ) => menu === oldMenuId )
- .map( ( { name } ) => name ),
- } )
- );
- }
-
- if ( newMenuId ) {
- promises.push(
- saveMenu( {
- id: newMenuId,
- locations: Object.values( newMenuLocationsByName )
- .filter( ( { menu } ) => menu === newMenuId )
- .map( ( { name } ) => name ),
- } )
- );
- }
-
- await Promise.all( promises );
+ [ oldMenuId, newMenuId ]
+ .filter( Boolean )
+ .map( withLocations( newMenuLocationsByName ) )
+ .forEach( saveMenu );
},
[ menuLocationsByName ]
);
+ const toggleMenuLocationAssignment = ( locationName, newMenuId ) => {
+ const idToSet =
+ menuLocationsByName[ locationName ].menu === newMenuId
+ ? 0
+ : newMenuId;
+ assignMenuToLocation( locationName, idToSet );
+ };
+
const menuLocations = useMemo(
- () =>
- menuLocationsByName ? Object.values( menuLocationsByName ) : null,
+ () => Object.values( menuLocationsByName || {} ),
[ menuLocationsByName ]
);
- return [ menuLocations, assignMenuToLocation ];
+ return {
+ menuLocations,
+ assignMenuToLocation,
+ toggleMenuLocationAssignment,
+ };
}
diff --git a/packages/edit-navigation/src/hooks/use-navigation-editor.js b/packages/edit-navigation/src/hooks/use-navigation-editor.js
index 3af9a2b1003860..ab6aeb0638c1eb 100644
--- a/packages/edit-navigation/src/hooks/use-navigation-editor.js
+++ b/packages/edit-navigation/src/hooks/use-navigation-editor.js
@@ -19,6 +19,14 @@ const getMenusData = ( select ) => {
};
};
export default function useNavigationEditor() {
+ const [
+ isManageLocationsModalOpen,
+ setIsManageLocationsModalOpen,
+ ] = useState( false );
+ const [ openManageLocationsModal, closeManageLocationsModal ] = [
+ true,
+ false,
+ ].map( ( bool ) => () => setIsManageLocationsModalOpen( bool ) );
const { deleteMenu: _deleteMenu } = useDispatch( 'core' );
const [ selectedMenuId, setSelectedMenuId ] = useState( null );
const [ hasFinishedInitialLoad, setHasFinishedInitialLoad ] = useState(
@@ -67,5 +75,8 @@ export default function useNavigationEditor() {
deleteMenu,
hasFinishedInitialLoad,
hasLoadedMenus,
+ openManageLocationsModal,
+ closeManageLocationsModal,
+ isManageLocationsModalOpen,
};
}
diff --git a/packages/edit-navigation/src/utils/constants.js b/packages/edit-navigation/src/utils/constants.js
new file mode 100644
index 00000000000000..9074d2f5e0a59e
--- /dev/null
+++ b/packages/edit-navigation/src/utils/constants.js
@@ -0,0 +1,27 @@
+/**
+ * "Kind" of the menu post.
+ *
+ * @type {string}
+ */
+export const MENU_KIND = 'root';
+
+/**
+ * "post type" of the menu post.
+ *
+ * @type {string}
+ */
+export const MENU_POST_TYPE = 'menu';
+
+/**
+ * "Kind" of the navigation post.
+ *
+ * @type {string}
+ */
+export const NAVIGATION_POST_KIND = 'root';
+
+/**
+ * "post type" of the navigation post.
+ *
+ * @type {string}
+ */
+export const NAVIGATION_POST_POST_TYPE = 'postType';