diff --git a/packages/edit-post/src/hooks/validate-multiple-use/index.js b/packages/edit-post/src/hooks/validate-multiple-use/index.js index 31444a86467c7..bf771f4522036 100644 --- a/packages/edit-post/src/hooks/validate-multiple-use/index.js +++ b/packages/edit-post/src/hooks/validate-multiple-use/index.js @@ -15,6 +15,33 @@ import { addFilter } from '@wordpress/hooks'; import { __ } from '@wordpress/i18n'; import { compose, createHigherOrderComponent } from '@wordpress/compose'; +/** + * Recursively find very first block of an specific block type. + * + * @param {Object[]} blocks List of blocks. + * @param {string} name Block name to search. + * + * @return {Object|undefined} Return block object or undefined. + */ +function findFirstOfSameType( blocks, name ) { + if ( ! Array.isArray( blocks ) || ! blocks.length ) { + return; + } + + for ( const block of blocks ) { + if ( block.name === name ) { + return block; + } + + // Search inside innerBlocks. + const firstBlock = findFirstOfSameType( block.innerBlocks, name ); + + if ( firstBlock ) { + return firstBlock; + } + } +} + const enhance = compose( /** * For blocks whose block type doesn't support `multiple`, provides the @@ -39,9 +66,7 @@ const enhance = compose( // Otherwise, only pass `originalBlockClientId` if it refers to a different // block from the current one. const blocks = select( blockEditorStore ).getBlocks(); - const firstOfSameType = blocks.find( - ( { name } ) => block.name === name - ); + const firstOfSameType = findFirstOfSameType( blocks, block.name ); const isInvalid = firstOfSameType && firstOfSameType.clientId !== block.clientId; return { diff --git a/test/e2e/specs/editor/various/validate-multiple-use.spec.js b/test/e2e/specs/editor/various/validate-multiple-use.spec.js new file mode 100644 index 0000000000000..4ab455d22cf29 --- /dev/null +++ b/test/e2e/specs/editor/various/validate-multiple-use.spec.js @@ -0,0 +1,36 @@ +/** + * WordPress dependencies + */ + +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); + +test.describe( 'Validate multiple use', () => { + test.beforeEach( async ( { admin } ) => { + await admin.createNewPost(); + } ); + + test( 'should display correct number of warning messages', async ( { + editor, + pageUtils, + } ) => { + // Insert a block with the `multiple` feature enabled, such as `core/more` + await editor.insertBlock( { + name: 'core/more', + } ); + + // Group the block + await pageUtils.pressKeys( 'primary+a' ); + await editor.clickBlockOptionsMenuItem( 'Group' ); + + // Duplicate the block + await pageUtils.pressKeys( 'primary+a' ); + await editor.clickBlockOptionsMenuItem( 'Duplicate' ); + + // Check if warning is visible + await expect( + editor.canvas.getByRole( 'button', { + name: 'Find original', + } ) + ).toBeVisible(); + } ); +} );