Skip to content

Commit

Permalink
Apply changes manually from trunk
Browse files Browse the repository at this point in the history
  • Loading branch information
getdave committed May 5, 2023
1 parent b93fd88 commit c8154bf
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 37 deletions.
2 changes: 1 addition & 1 deletion docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ A collection of blocks that allow visitors to get around your site. ([Source](ht
- **Name:** core/navigation
- **Category:** theme
- **Supports:** align (full, wide), anchor, inserter, spacing (blockGap, units), typography (fontSize, lineHeight), ~~html~~
- **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
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 @@ -11,6 +11,9 @@
"ref": {
"type": "number"
},
"slug": {
"type": "string"
},
"textColor": {
"type": "string"
},
Expand Down
33 changes: 20 additions & 13 deletions packages/block-library/src/navigation/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,18 @@ 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 [ idRef, setIdRef ] = useState( attributes.ref );

const setRef = useCallback(
( postId ) => {
setAttributes( { ref: postId } );
( { id, slug } ) => {
setAttributes( { slug } );
setIdRef( id );
},
[ setAttributes ]
[ setAttributes, setIdRef ]
);

const recursionId = `navigationMenu/${ ref }`;
Expand Down Expand Up @@ -202,14 +207,16 @@ function Navigation( {

// Only auto-fallback to the latest published menu.
// The REST API already returns items sorted by publishing date.
const fallbackNavigationMenuId = navigationMenus?.find(
const fallbackNavigationMenu = navigationMenus?.find(
( menu ) => menu.status === 'publish'
)?.id;
);

const fallbackNavigationMenuId = fallbackNavigationMenu?.id;

const handleUpdateMenu = useCallback(
( menuId, options = { focusNavigationBlock: false } ) => {
( menu, options = { focusNavigationBlock: false } ) => {
const { focusNavigationBlock } = options;
setRef( menuId );
setRef( menu );
if ( focusNavigationBlock ) {
selectBlock( clientId );
}
Expand All @@ -229,7 +236,7 @@ function Navigation( {
hasUncontrolledInnerBlocks ||
isCreatingNavigationMenu ||
ref ||
! fallbackNavigationMenuId
! fallbackNavigationMenu
) {
return;
}
Expand All @@ -242,12 +249,12 @@ function Navigation( {
* nor to be undoable, hence why it is marked as non persistent
*/
__unstableMarkNextChangeAsNotPersistent();
setRef( fallbackNavigationMenuId );
setRef( fallbackNavigationMenu );
}, [
ref,
setRef,
isCreatingNavigationMenu,
fallbackNavigationMenuId,
fallbackNavigationMenu,
hasUncontrolledInnerBlocks,
__unstableMarkNextChangeAsNotPersistent,
] );
Expand Down Expand Up @@ -409,7 +416,7 @@ function Navigation( {
'draft'
);
if ( navMenu ) {
handleUpdateMenu( navMenu.id, {
handleUpdateMenu( navMenu, {
focusNavigationBlock: true,
} );
}
Expand All @@ -427,7 +434,7 @@ function Navigation( {
}

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

Expand Down
1 change: 1 addition & 0 deletions packages/block-library/src/navigation/edit/inner-blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const ALLOWED_BLOCKS = [
'core/site-title',
'core/site-logo',
'core/navigation-submenu',
'core/loginout',
];

const DEFAULT_BLOCK = {
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;

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: 35 additions & 3 deletions packages/block-library/src/navigation/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ function render_block_core_navigation( $attributes, $content, $block ) {
if (
defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN &&
array_key_exists( '__unstableLocation', $attributes ) &&
! array_key_exists( 'slug', $attributes ) &&
! array_key_exists( 'ref', $attributes ) &&
! empty( block_core_navigation_get_menu_items_at_location( $attributes['__unstableLocation'] ) )
) {
Expand All @@ -604,12 +605,43 @@ function render_block_core_navigation( $attributes, $content, $block ) {
}

// Load inner blocks from the navigation post.
if ( array_key_exists( 'ref', $attributes ) ) {
$navigation_post = get_post( $attributes['ref'] );
if ( ! isset( $navigation_post ) ) {
if ( array_key_exists( 'slug', $attributes ) || array_key_exists( 'ref', $attributes ) ) {

$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];

// Only published posts are valid. If this is changed then a corresponding change
// must also be implemented in `use-navigation-menu.js`.
if ( 'publish' === $navigation_post->post_status ) {
Expand Down
90 changes: 71 additions & 19 deletions packages/block-library/src/navigation/use-navigation-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ import {
} from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';

export default function useNavigationMenu( ref ) {
const permissions = useResourcePermissions( 'navigation', ref );
/**
* Internal dependencies
*/
import { isNumeric } from './edit/utils';

export default function useNavigationMenu( recordKey, navPostId ) {
const permissions = useResourcePermissions( 'navigation', navPostId );

return useSelect(
( select ) => {
Expand All @@ -30,7 +35,7 @@ export default function useNavigationMenu( ref ) {
navigationMenu,
isNavigationMenuResolved,
isNavigationMenuMissing,
} = selectExistingMenu( select, ref );
} = selectExistingMenu( select, recordKey );

return {
navigationMenus,
Expand All @@ -41,7 +46,7 @@ export default function useNavigationMenu( ref ) {
isNavigationMenuResolved,
isNavigationMenuMissing,

canSwitchNavigationMenu: ref
canSwitchNavigationMenu: recordKey
? navigationMenus?.length > 1
: navigationMenus?.length > 0,

Expand All @@ -50,17 +55,17 @@ export default function useNavigationMenu( ref ) {
hasResolvedCanUserCreateNavigationMenu: hasResolved,

canUserUpdateNavigationMenu: canUpdate,
hasResolvedCanUserUpdateNavigationMenu: ref
hasResolvedCanUserUpdateNavigationMenu: recordKey
? hasResolved
: undefined,

canUserDeleteNavigationMenu: canDelete,
hasResolvedCanUserDeleteNavigationMenu: ref
hasResolvedCanUserDeleteNavigationMenu: recordKey
? hasResolved
: undefined,
};
},
[ ref, permissions ]
[ recordKey, permissions ]
);
}

Expand All @@ -83,38 +88,85 @@ function selectNavigationMenus( select ) {
};
}

function selectExistingMenu( select, ref ) {
if ( ! ref ) {
function selectExistingMenu( select, recordKey ) {
if ( ! recordKey ) {
return {
isNavigationMenuResolved: false,
isNavigationMenuMissing: true,
};
}

const { getEntityRecord, getEditedEntityRecord, hasFinishedResolution } =
const { getEntityRecords, getEditedEntityRecord, hasFinishedResolution } =
select( coreStore );

const args = [ 'postType', 'wp_navigation', ref ];
const navigationMenu = getEntityRecord( ...args );
const editedNavigationMenu = getEditedEntityRecord( ...args );
const hasResolvedNavigationMenu = hasFinishedResolution(
'getEditedEntityRecord',
args
const recordKeyQuery = isNumeric( recordKey )
? {
include: recordKey, // fetch by post id.
}
: {
slug: recordKey, // fetch by slug (post_name).
};

// Find a **single** Navigation Menu using the appropriate
// recordKey as the identifier (i.e. recordKey). This may be
// either a slug or (for legacy blocks) as post ID.
// This call to `getEntityRecords` **must** be distinct from the
// call within the `selectNavigationMenus` (above) otherwise the
// query will return only `published` menus.
const navigationMenus = getEntityRecords( 'postType', 'wp_navigation', {
...recordKeyQuery,
per_page: 1, // only a single record is required.
status: [ 'publish', 'draft' ],
} );

const hasResolvedNavigationMenuSlugQuery = hasFinishedResolution(
'getEntityRecords',
[
'postType',
'wp_navigation',
{
...recordKeyQuery,
per_page: 1, // only a single record is required.
status: [ 'publish', 'draft' ],
},
]
);

const hasNavigationMenu =
hasResolvedNavigationMenuSlugQuery && navigationMenus?.length;

// `wp_navigation` entities are keyed by Post ID in state.
// Perform subsequent lookups based on the ID of the record
// returned by the slug-based query (if available).
const idQueryArgs = hasNavigationMenu
? [ 'postType', 'wp_navigation', navigationMenus[ 0 ]?.id ]
: [];

const editedNavigationMenu = hasNavigationMenu
? getEditedEntityRecord( ...idQueryArgs )
: null;

// "Resolved" in this case means either
// - the resolution state of request for the edited entity record
// (in the case there is an 0th Nav Post).
// - the resolution state of the query to look up with 0th post.
const hasResolvedNavigationMenu = hasNavigationMenu
? hasFinishedResolution( 'getEditedEntityRecord', idQueryArgs )
: hasResolvedNavigationMenuSlugQuery;

// 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';

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

0 comments on commit c8154bf

Please sign in to comment.