diff --git a/packages/block-library/src/navigation/menu-items-to-blocks.js b/packages/block-library/src/navigation/menu-items-to-blocks.js index 00bd4dbbe2a98a..d3bb052132e453 100644 --- a/packages/block-library/src/navigation/menu-items-to-blocks.js +++ b/packages/block-library/src/navigation/menu-items-to-blocks.js @@ -4,6 +4,11 @@ import { createBlock, parse } from '@wordpress/blocks'; import { applyFilters } from '@wordpress/hooks'; +/** + * Internal dependencies + */ +import { buildNavigationLinkEntityBinding } from '../navigation-link/shared/use-entity-binding'; + /** * Convert a flat menu item structure to a nested blocks structure. * @@ -145,12 +150,14 @@ function menuItemToBlockAttributes( object = 'tag'; } + const inferredKind = menuItemTypeField?.replace( '_', '-' ) || 'custom'; + return { label: menuItemTitleField?.rendered || '', ...( object?.length && { type: object, } ), - kind: menuItemTypeField?.replace( '_', '-' ) || 'custom', + kind: inferredKind, url: url || '', ...( xfn?.length && xfn.join( ' ' ).trim() && { @@ -165,8 +172,11 @@ function menuItemToBlockAttributes( title: attr_title, } ), ...( object_id && - 'custom' !== object && { + ( inferredKind === 'post-type' || inferredKind === 'taxonomy' ) && { id: object_id, + metadata: { + bindings: buildNavigationLinkEntityBinding( inferredKind ), + }, } ), /* eslint-enable camelcase */ ...( description?.length && { diff --git a/packages/block-library/src/navigation/test/menu-items-to-blocks.js b/packages/block-library/src/navigation/test/menu-items-to-blocks.js index 088880868022ae..12eb19af858caa 100644 --- a/packages/block-library/src/navigation/test/menu-items-to-blocks.js +++ b/packages/block-library/src/navigation/test/menu-items-to-blocks.js @@ -371,4 +371,148 @@ describe( 'converting menu items to blocks', () => { const { innerBlocks: actual } = menuItemsToBlocks( [] ); expect( actual ).toEqual( [] ); } ); + + it( 'adds entity bindings for non-custom menu items', () => { + const { innerBlocks: actual } = menuItemsToBlocks( [ + { + id: 1, + title: { + raw: 'Page Item', + rendered: 'Page Item', + }, + url: 'http://localhost:8889/page-item/', + attr_title: '', + description: '', + type: 'post_type', + type_label: 'Page', + object: 'page', + object_id: 123, + parent: 0, + menu_order: 1, + target: '', + classes: [ '' ], + xfn: [ '' ], + }, + { + id: 2, + title: { + raw: 'Category Item', + rendered: 'Category Item', + }, + url: 'http://localhost:8889/category/category-item/', + attr_title: '', + description: '', + type: 'taxonomy', + type_label: 'Category', + object: 'category', + object_id: 456, + parent: 0, + menu_order: 2, + target: '', + classes: [ '' ], + xfn: [ '' ], + }, + { + id: 3, + title: { + raw: 'Custom Item', + rendered: 'Custom Item', + }, + url: 'http://localhost:8889/custom-link/', + attr_title: '', + description: '', + type: 'custom', + type_label: 'Custom Link', + object: 'custom', + parent: 0, + menu_order: 3, + target: '', + classes: [ '' ], + xfn: [ '' ], + }, + ] ); + + expect( actual ).toEqual( [ + expect.objectContaining( { + name: 'core/navigation-link', + attributes: expect.objectContaining( { + label: 'Page Item', + id: 123, + metadata: { + bindings: { + url: { + source: 'core/post-data', + args: { + field: 'link', + }, + }, + }, + }, + } ), + innerBlocks: [], + } ), + expect.objectContaining( { + name: 'core/navigation-link', + attributes: expect.objectContaining( { + label: 'Category Item', + id: 456, + metadata: { + bindings: { + url: { + source: 'core/term-data', + args: { + field: 'link', + }, + }, + }, + }, + } ), + innerBlocks: [], + } ), + expect.objectContaining( { + name: 'core/navigation-link', + attributes: expect.objectContaining( { + label: 'Custom Item', + // Custom items should NOT have id, metadata, or bindings + } ), + innerBlocks: [], + } ), + ] ); + + // Verify custom item does NOT have bindings + expect( actual[ 2 ].attributes ).not.toHaveProperty( 'id' ); + expect( actual[ 2 ].attributes ).not.toHaveProperty( 'metadata' ); + } ); + + it( 'does not add bindings for invalid kinds even when object_id is present', () => { + const { innerBlocks: actual } = menuItemsToBlocks( [ + { + id: 10, + title: { + raw: 'Invalid Kind Item', + rendered: 'Invalid Kind Item', + }, + url: 'http://localhost:8889/invalid-kind-item/', + attr_title: '', + description: '', + type: 'invalid', // becomes inferred kind 'invalid' + type_label: 'Invalid', + object: 'page', + object_id: 999, + parent: 0, + menu_order: 1, + target: '', + classes: [ '' ], + xfn: [ '' ], + }, + ] ); + + expect( actual ).toHaveLength( 1 ); + expect( actual[ 0 ].name ).toBe( 'core/navigation-link' ); + // Should not set id or metadata when kind is not supported + expect( actual[ 0 ].attributes ).not.toHaveProperty( 'id' ); + expect( actual[ 0 ].attributes ).not.toHaveProperty( 'metadata' ); + // Label should still be set correctly + expect( actual[ 0 ].attributes.label ).toBe( 'Invalid Kind Item' ); + } ); } );