Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navigation: browse mode list all Navigation Menus. #50840

Merged
merged 11 commits into from
May 23, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import { __ } from '@wordpress/i18n';
import { layout, symbol, navigation, styles, page } from '@wordpress/icons';
import { useDispatch, useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';

import { useEffect } from '@wordpress/element';

/**
Expand All @@ -19,27 +19,9 @@ import SidebarNavigationItem from '../sidebar-navigation-item';
import { SidebarNavigationItemGlobalStyles } from '../sidebar-navigation-screen-global-styles';
import { unlock } from '../../private-apis';
import { store as editSiteStore } from '../../store';
import SidebarNavigationScreenNavigationMenuButton from '../sidebar-navigation-screen-navigation-menus/navigator-button';

export default function SidebarNavigationScreenMain() {
const hasNavigationMenus = useSelect( ( select ) => {
// The query needs to be the same as in the "SidebarNavigationScreenNavigationMenus" component,
// to avoid double network calls.
const navigationMenus = select( coreStore ).getEntityRecords(
'postType',
'wp_navigation',
{
per_page: 1,
status: 'publish',
order: 'desc',
orderby: 'date',
}
);
return !! navigationMenus?.length;
}, [] );
const showNavigationScreen = process.env.IS_GUTENBERG_PLUGIN
? hasNavigationMenus
: false;

const editorCanvasContainerView = useSelect( ( select ) => {
return unlock( select( editSiteStore ) ).getEditorCanvasContainerView();
}, [] );
Expand All @@ -64,16 +46,14 @@ export default function SidebarNavigationScreenMain() {
) }
content={
<ItemGroup>
{ showNavigationScreen && (
<NavigatorButton
as={ SidebarNavigationItem }
path="/navigation"
withChevron
icon={ navigation }
>
{ __( 'Navigation' ) }
</NavigatorButton>
) }
<SidebarNavigationScreenNavigationMenuButton
withChevron
icon={ navigation }
as={ SidebarNavigationItem }
>
{ __( 'Navigation' ) }
</SidebarNavigationScreenNavigationMenuButton>

<SidebarNavigationItemGlobalStyles
withChevron
icon={ styles }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/**
* WordPress dependencies
*/
import { useEntityRecord } from '@wordpress/core-data';
import { __experimentalUseNavigator as useNavigator } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useCallback, useMemo } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { privateApis as routerPrivateApis } from '@wordpress/router';
import { BlockEditorProvider } from '@wordpress/block-editor';
import { createBlock } from '@wordpress/blocks';
import { decodeEntities } from '@wordpress/html-entities';

/**
* Internal dependencies
*/
import { unlock } from '../../private-apis';
import { store as editSiteStore } from '../../store';
import {
isPreviewingTheme,
currentlyPreviewingTheme,
} from '../../utils/is-previewing-theme';
import { SidebarNavigationScreenWrapper } from '../sidebar-navigation-screen-navigation-menus';
import NavigationMenuContent from '../sidebar-navigation-screen-navigation-menus/navigation-menu-content';

const { useHistory } = unlock( routerPrivateApis );
const noop = () => {};

export default function SidebarNavigationScreenNavigationMenu() {
const postType = `wp_navigation`;
const {
params: { postId },
} = useNavigator();

const { record: navigationMenu, isResolving: isLoading } = useEntityRecord(
'postType',
postType,
postId
);

const menuTitle = navigationMenu?.title?.rendered || navigationMenu?.slug;

if ( isLoading ) {
return (
<SidebarNavigationScreenWrapper
description={ __( 'Loading Navigation Menu.' ) }
/>
);
}

if ( ! isLoading && ! navigationMenu ) {
return (
<SidebarNavigationScreenWrapper
description={ __( 'Navigation Menu missing.' ) }
/>
);
}

return (
<SidebarNavigationScreenWrapper
title={ decodeEntities( menuTitle ) }
description={ __(
'Navigation menus are a curated collection of blocks that allow visitors to get around your site.'
) }
>
<NavigationMenuEditor navigationMenu={ navigationMenu } />
</SidebarNavigationScreenWrapper>
);
}

function NavigationMenuEditor( { navigationMenu } ) {
const history = useHistory();

const onSelect = useCallback(
( selectedBlock ) => {
const { attributes, name } = selectedBlock;
if (
attributes.kind === 'post-type' &&
attributes.id &&
attributes.type &&
history
) {
history.push( {
postType: attributes.type,
postId: attributes.id,
Copy link
Contributor

Choose a reason for hiding this comment

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

What do you think about using slug instead of ID? Is that possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Possibly. In this PR though?

Copy link
Contributor

Choose a reason for hiding this comment

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

Happy for it to be a followup, but remember once people start using these permalinks we have to support them so it would be good to look into it before the next Gutenberg release.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm going to look at the routing again and see what we have available.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thinking about this more, since pages already use IDs, I think it's fine for navigations to do the same

...( isPreviewingTheme() && {
theme_preview: currentlyPreviewingTheme(),
} ),
} );
}
if ( name === 'core/page-list-item' && attributes.id && history ) {
history.push( {
postType: 'page',
postId: attributes.id,
...( isPreviewingTheme() && {
theme_preview: currentlyPreviewingTheme(),
} ),
} );
}
},
[ history ]
);

const { storedSettings } = useSelect( ( select ) => {
const { getSettings } = unlock( select( editSiteStore ) );

return {
storedSettings: getSettings( false ),
};
}, [] );

const blocks = useMemo( () => {
if ( ! NavigationMenuEditor ) {
return [];
}

return [
createBlock( 'core/navigation', { ref: navigationMenu?.id } ),
];
}, [ navigationMenu ] );

if ( ! navigationMenu || ! blocks?.length ) {
return null;
}

return (
<BlockEditorProvider
settings={ storedSettings }
value={ blocks }
onChange={ noop }
onInput={ noop }
>
<div className="edit-site-sidebar-navigation-screen-navigation-menus__content">
<NavigationMenuContent
rootClientId={ blocks[ 0 ].clientId }
onSelect={ onSelect }
/>
</div>
</BlockEditorProvider>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,133 +2,89 @@
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { useCallback, useMemo } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { BlockEditorProvider } from '@wordpress/block-editor';
import { createBlock } from '@wordpress/blocks';
import { privateApis as routerPrivateApis } from '@wordpress/router';
import { useEntityRecords } from '@wordpress/core-data';

import { decodeEntities } from '@wordpress/html-entities';
import { __experimentalItemGroup as ItemGroup } from '@wordpress/components';
import { navigation } from '@wordpress/icons';

/**
* Internal dependencies
*/
import SidebarNavigationScreen from '../sidebar-navigation-screen';
import NavigationMenuContent from './navigation-menu-content';
import { unlock } from '../../private-apis';
import { store as editSiteStore } from '../../store';
import {
isPreviewingTheme,
currentlyPreviewingTheme,
} from '../../utils/is-previewing-theme';
import SidebarNavigationItem from '../sidebar-navigation-item';

const { useHistory } = unlock( routerPrivateApis );
import { useLink } from '../routes/link';

const noop = () => {};
const NAVIGATION_MENUS_QUERY = {
per_page: 1,
per_page: -1,
status: 'publish',
order: 'desc',
orderby: 'date',
};

function SidebarNavigationScreenWrapper( { children, actions } ) {
return (
<SidebarNavigationScreen
title={ __( 'Navigation' ) }
actions={ actions }
description={ __(
'Browse your site, edit pages, and manage your primary navigation menu.'
) }
content={ children }
/>
);
}

export default function SidebarNavigationScreenNavigationMenus() {
const history = useHistory();
const { navigationMenus, hasResolvedNavigationMenus, storedSettings } =
useSelect( ( select ) => {
const { getSettings } = unlock( select( editSiteStore ) );
const { getEntityRecords, hasFinishedResolution } =
select( coreStore );

const navigationMenusQuery = [
'postType',
'wp_navigation',
NAVIGATION_MENUS_QUERY,
];
return {
storedSettings: getSettings( false ),
navigationMenus: getEntityRecords( ...navigationMenusQuery ),
hasResolvedNavigationMenus: hasFinishedResolution(
'getEntityRecords',
navigationMenusQuery
),
};
}, [] );

const firstNavigationMenu = navigationMenus?.[ 0 ]?.id;
const blocks = useMemo( () => {
return [
createBlock( 'core/navigation', { ref: firstNavigationMenu } ),
];
}, [ firstNavigationMenu ] );
const { records: navigationMenus, isResolving: isLoading } =
useEntityRecords( 'postType', `wp_navigation`, NAVIGATION_MENUS_QUERY );

const hasNavigationMenus = !! navigationMenus?.length;

const onSelect = useCallback(
( selectedBlock ) => {
const { attributes, name } = selectedBlock;
if (
attributes.kind === 'post-type' &&
attributes.id &&
attributes.type &&
history
) {
history.push( {
postType: attributes.type,
postId: attributes.id,
...( isPreviewingTheme() && {
theme_preview: currentlyPreviewingTheme(),
} ),
} );
}
if ( name === 'core/page-list-item' && attributes.id && history ) {
history.push( {
postType: 'page',
postId: attributes.id,
...( isPreviewingTheme() && {
theme_preview: currentlyPreviewingTheme(),
} ),
} );
}
},
[ history ]
);
if ( isLoading ) {
return (
<SidebarNavigationScreenWrapper
description={ __( 'Loading Navigation Menus.' ) }
/>
);
}

if ( hasResolvedNavigationMenus && ! hasNavigationMenus ) {
if ( ! isLoading && ! hasNavigationMenus ) {
return (
<SidebarNavigationScreenWrapper>
{ __( 'There are no Navigation Menus.' ) }
</SidebarNavigationScreenWrapper>
<SidebarNavigationScreenWrapper
description={ __( 'No Navigation Menus found.' ) }
/>
);
}

return (
<BlockEditorProvider
settings={ storedSettings }
value={ blocks }
onChange={ noop }
onInput={ noop }
>
<SidebarNavigationScreenWrapper>
<div className="edit-site-sidebar-navigation-screen-navigation-menus__content">
<NavigationMenuContent
rootClientId={ blocks[ 0 ].clientId }
onSelect={ onSelect }
/>
</div>
</SidebarNavigationScreenWrapper>
</BlockEditorProvider>
<SidebarNavigationScreenWrapper>
<ItemGroup>
{ navigationMenus?.map( ( navMenu ) => (
<NavMenuItem
postId={ navMenu.id }
key={ navMenu.id }
withChevron
icon={ navigation }
>
{ decodeEntities(
navMenu.title?.rendered || navMenu.slug
) }
</NavMenuItem>
) ) }
</ItemGroup>
</SidebarNavigationScreenWrapper>
);
}

export function SidebarNavigationScreenWrapper( {
children,
actions,
title,
description,
} ) {
return (
<SidebarNavigationScreen
title={ title || __( 'Navigation' ) }
actions={ actions }
description={ description || __( 'Manage your Navigation menus.' ) }
content={ children }
/>
);
}

const NavMenuItem = ( { postId, ...props } ) => {
const linkInfo = useLink( {
postId,
postType: 'wp_navigation',
} );
return <SidebarNavigationItem { ...linkInfo } { ...props } />;
};
Loading