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

Nav block - find menu by slug using existing core data API #45443

Draft
wants to merge 8 commits into
base: trunk
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ A collection of blocks that allow visitors to get around your site. ([Source](ht
- **Category:** theme
- **Allowed Blocks:** core/navigation-link, core/search, core/social-links, core/page-list, core/spacer, core/home-link, core/site-title, core/site-logo, core/navigation-submenu, core/loginout, core/buttons
- **Supports:** align (full, wide), ariaLabel, inserter, interactivity, layout (allowSizingOnChildren, default, ~~allowInheriting~~, ~~allowSwitching~~, ~~allowVerticalAlignment~~), spacing (blockGap, units), typography (fontSize, lineHeight), ~~html~~, ~~renaming~~
- **Attributes:** __unstableLocation, backgroundColor, customBackgroundColor, customOverlayBackgroundColor, customOverlayTextColor, customTextColor, hasIcon, icon, maxNestingLevel, openSubmenusOnClick, overlayBackgroundColor, overlayMenu, overlayTextColor, ref, rgbBackgroundColor, rgbTextColor, showSubmenuIcon, templateLock, textColor
- **Attributes:** __unstableLocation, backgroundColor, customBackgroundColor, customOverlayBackgroundColor, customOverlayTextColor, customTextColor, hasIcon, icon, maxNestingLevel, openSubmenusOnClick, overlayBackgroundColor, overlayMenu, overlayTextColor, ref, rgbBackgroundColor, rgbTextColor, showSubmenuIcon, slug, templateLock, textColor

## Custom Link

Expand Down
17 changes: 17 additions & 0 deletions docs/reference-guides/data/data-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,23 @@ _Returns_

- `any`: The entity record's save error.

### getNavigationMenu

Undocumented declaration.

### getNavigationMenuBySlug

Returns a Navigation Menu object by slug.

_Parameters_

- _state_ `State`:
- _slug_ `string`: the slug of the Navigation Menu.

_Returns_

- `Object | null`: The Navigation Menu object.

### getRawEntityRecord

Returns the entity's record object by key, with its attributes mapped to their raw values.
Expand Down
3 changes: 3 additions & 0 deletions packages/block-library/src/navigation/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
"ref": {
"type": "number"
},
"slug": {
"type": "string"
},
"textColor": {
"type": "string"
},
Expand Down
39 changes: 28 additions & 11 deletions packages/block-library/src/navigation/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,13 @@ function Navigation( {
icon = 'handle',
} = attributes;

const ref = attributes.ref;
// Older versions of the block used an ID based ref attribute.
// Allow for this to continue to be used.
const ref = attributes.slug || attributes.ref;

const setRef = useCallback(
( postId ) => {
setAttributes( { ref: postId } );
( { slug } ) => {
setAttributes( { slug } );
},
[ setAttributes ]
);
Expand Down Expand Up @@ -190,6 +192,7 @@ function Navigation( {
canUserCreateNavigationMenu,
isResolvingCanUserCreateNavigationMenu,
hasResolvedCanUserCreateNavigationMenu,
navigationMenu,
} = useNavigationMenu( ref );

const navMenuResolvedButMissing =
Expand All @@ -205,9 +208,10 @@ function Navigation( {
classicMenuConversionStatus === CLASSIC_MENU_CONVERSION_PENDING;

const handleUpdateMenu = useCallback(
( menuId, options = { focusNavigationBlock: false } ) => {
( menu, options = { focusNavigationBlock: false } ) => {
debugger;
const { focusNavigationBlock } = options;
setRef( menuId );
setRef( menu );
if ( focusNavigationBlock ) {
selectBlock( clientId );
}
Expand Down Expand Up @@ -342,7 +346,16 @@ function Navigation( {
const [ detectedOverlayColor, setDetectedOverlayColor ] = useState();

const onSelectClassicMenu = async ( classicMenu ) => {
return convertClassicMenu( classicMenu.id, classicMenu.name, 'draft' );
const navMenu = await convertClassicMenu(
classicMenu.id,
classicMenu.name,
'draft'
);
if ( navMenu ) {
handleUpdateMenu( navMenu, {
focusNavigationBlock: true,
} );
}
};

const onSelectNavigationMenu = ( menuId ) => {
Expand All @@ -357,7 +370,7 @@ function Navigation( {
}

if ( createNavigationMenuIsSuccess ) {
handleUpdateMenu( createNavigationMenuPost?.id, {
handleUpdateMenu( createNavigationMenuPost, {
focusNavigationBlock: true,
} );

Expand All @@ -374,7 +387,7 @@ function Navigation( {
}, [
createNavigationMenuStatus,
createNavigationMenuError,
createNavigationMenuPost?.id,
createNavigationMenuPost,
createNavigationMenuIsError,
createNavigationMenuIsSuccess,
isCreatingNavigationMenu,
Expand All @@ -393,7 +406,7 @@ function Navigation( {
showClassicMenuConversionNotice(
__( 'Classic menu imported successfully.' )
);
handleUpdateMenu( createNavigationMenuPost?.id, {
handleUpdateMenu( createNavigationMenuPost, {
focusNavigationBlock: true,
} );
}
Expand All @@ -408,7 +421,7 @@ function Navigation( {
classicMenuConversionError,
hideClassicMenuConversionNotice,
showClassicMenuConversionNotice,
createNavigationMenuPost?.id,
createNavigationMenuPost,
handleUpdateMenu,
] );

Expand Down Expand Up @@ -814,7 +827,11 @@ function Navigation( {
}

return (
<EntityProvider kind="postType" type="wp_navigation" id={ ref }>
<EntityProvider
kind="postType"
type="wp_navigation"
id={ navigationMenu?.id }
>
<RecursionProvider uniqueId={ recursionId }>
<MenuInspectorControls
clientId={ clientId }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ function NavigationMenuSelector( {
createNavigationMenuIsSuccess,
createNavigationMenuIsError,
} ) {
console.log( { currentMenuId } );

/* translators: %s: The name of a menu. */
const createActionLabel = __( "Create from '%s'" );

Expand All @@ -71,15 +73,15 @@ function NavigationMenuSelector( {

const menuChoices = useMemo( () => {
return (
navigationMenus?.map( ( { id, title, status }, index ) => {
navigationMenus?.map( ( { id, title, status, slug }, index ) => {
const label = buildMenuLabel(
title?.rendered,
index + 1,
status
);

return {
value: id,
value: slug,
label,
ariaLabel: sprintf( actionLabel, label ),
disabled:
Expand Down
23 changes: 23 additions & 0 deletions packages/block-library/src/navigation/edit/test/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Internal dependencies
*/
import { isNumeric } from '../utils';

describe( 'isNumeric', () => {
it.each( [
[ 42, true ],
[ '42', true ],
[ ' 42 ', true ],
[ '', false ],
[ 'some-slug', false ],
[ 'some-42-slug-with-trailing-number-42', false ],
[ '42-some-42-slug-with-leading-number', false ],
[ NaN, false ],
[ Infinity, false ],
] )(
'correctly determines variable type for "%s"',
( candidate, expected ) => {
expect( isNumeric( candidate ) ).toBe( expected );
}
);
} );
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default function useCreateNavigationMenu( clientId ) {
// This callback uses data from the two placeholder steps and only creates
// a new navigation menu when the user completes the final step.
const create = useCallback(
async ( title = null, blocks = [], postStatus ) => {
async ( title = null, blocks = [], postStatus, slug = '' ) => {
// Guard against creating Navigations without a title.
// Note you can pass no title, but if one is passed it must be
// a string otherwise the title may end up being empty.
Expand Down Expand Up @@ -57,8 +57,12 @@ export default function useCreateNavigationMenu( clientId ) {
);
} );
}

const maybeSlug = slug || title;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let's explain why this is here. In the future we may want to pass a slug to represent the template part hierarchy.


const record = {
title,
slug: maybeSlug,
content: serialize( blocks ),
status: postStatus,
};
Expand Down
7 changes: 7 additions & 0 deletions packages/block-library/src/navigation/edit/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,10 @@ export function getNavigationChildBlockProps( innerBlocksColors ) {
},
};
}

export function isNumeric( v ) {
if ( v === null || v === undefined || v === '' ) {
return false;
}
return ! isNaN( v ) && isFinite( v );
}
38 changes: 36 additions & 2 deletions packages/block-library/src/navigation/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,41 @@ private static function get_inner_blocks_html( $attributes, $inner_blocks ) {
* @return WP_Block_List Returns the inner blocks for the navigation block.
*/
private static function get_inner_blocks_from_navigation_post( $attributes ) {
$navigation_post = get_post( $attributes['ref'] );
$base_args = array(
'post_type' => 'wp_navigation',
'nopaging' => true,
'posts_per_page' => '1',
'update_post_term_cache' => false,
'no_found_rows' => true,
);

// Prefer query by slug if available, falling
// back to Post ID.
if ( ! empty( $attributes['slug'] ) ) {
$args = array_merge(
$base_args,
array(
'name' => $attributes['slug'], // query by slug
)
);
} else {
$args = array_merge(
$base_args,
array(
'p' => $attributes['ref'], // query by post ID
)
);
}

// Query for the Navigation Post.
$navigation_query = new WP_Query( $args );

if ( ! isset( $navigation_query->posts[0] ) ) {
return '';
}

$navigation_post = $navigation_query->posts[0];

if ( ! isset( $navigation_post ) ) {
return new WP_Block_List( array(), $attributes );
}
Expand Down Expand Up @@ -280,7 +314,7 @@ private static function get_inner_blocks( $attributes, $block ) {
}

// Load inner blocks from the navigation post.
if ( array_key_exists( 'ref', $attributes ) ) {
if ( array_key_exists( 'slug', $attributes ) || array_key_exists( 'ref', $attributes ) ) {
$inner_blocks = static::get_inner_blocks_from_navigation_post( $attributes );
}

Expand Down
49 changes: 40 additions & 9 deletions packages/block-library/src/navigation/use-navigation-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import {
} from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import { isNumeric } from './edit/utils';

/**
* Internal dependencies
*/
Expand Down Expand Up @@ -70,30 +75,56 @@ function selectExistingMenu( select, ref ) {
};
}

const { getEntityRecord, getEditedEntityRecord, hasFinishedResolution } =
select( coreStore );
const {
getNavigationMenuBySlug,
getNavigationMenu,
// getEntityRecord,
getEditedEntityRecord,
hasFinishedResolution,
} = select( coreStore );

// const args = [ 'postType', 'wp_navigation', ref ];
// const navigationMenu = getEntityRecord( ...args );

const navigationMenu = isNumeric( ref )
? getNavigationMenu( ref )
: getNavigationMenuBySlug( ref );

const hasNavigationMenu = !! navigationMenu;

const editedNavigationMenu = hasNavigationMenu
? getEditedEntityRecord(
'postType',
'wp_navigation',
navigationMenu.id
)
: null;

const args = [ 'postType', 'wp_navigation', ref ];
const navigationMenu = getEntityRecord( ...args );
const editedNavigationMenu = getEditedEntityRecord( ...args );
const hasResolvedNavigationMenu = hasFinishedResolution(
'getEditedEntityRecord',
args
[ 'postType', 'wp_navigation', navigationMenu?.id ]
);

// Only published Navigation posts are considered valid.
// Draft Navigation posts are valid only on the editor,
// requiring a post update to publish to show in frontend.
// To achieve that, index.php must reflect this validation only for published.
const isNavigationMenuPublishedOrDraft =
editedNavigationMenu.status === 'publish' ||
editedNavigationMenu.status === 'draft';
editedNavigationMenu?.status === 'publish' ||
editedNavigationMenu?.status === 'draft';

console.log( {
navigationMenu,
editedNavigationMenu,
hasResolvedNavigationMenu,
isNavigationMenuPublishedOrDraft,
} );

return {
isNavigationMenuResolved: hasResolvedNavigationMenu,
isNavigationMenuMissing:
hasResolvedNavigationMenu &&
( ! navigationMenu || ! isNavigationMenuPublishedOrDraft ),
( ! hasNavigationMenu || ! isNavigationMenuPublishedOrDraft ),

// getEditedEntityRecord will return the post regardless of status.
// Therefore if the found post is not published then we should ignore it.
Expand Down
17 changes: 17 additions & 0 deletions packages/core-data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,23 @@ _Returns_

- `any`: The entity record's save error.

### getNavigationMenu

Undocumented declaration.

### getNavigationMenuBySlug

Returns a Navigation Menu object by slug.

_Parameters_

- _state_ `State`:
- _slug_ `string`: the slug of the Navigation Menu.

_Returns_

- `Object | null`: The Navigation Menu object.

### getRawEntityRecord

Returns the entity's record object by key, with its attributes mapped to their raw values.
Expand Down
Loading
Loading