From 2177aed35b2adfe18ce557f41d4d121752fa5314 Mon Sep 17 00:00:00 2001 From: Shah Shalin <56588503+SH4LIN@users.noreply.github.com> Date: Thu, 17 Oct 2024 00:56:12 +0530 Subject: [PATCH] Fix error when using circlular parent blocks (#66121) Co-authored-by: SH4LIN Co-authored-by: youknowriad Co-authored-by: t-hamano Co-authored-by: yuliyan --- packages/block-editor/src/store/selectors.js | 22 ++++++++++++++++++-- packages/blocks/src/api/registration.js | 9 ++++++++ packages/blocks/src/api/test/registration.js | 11 ++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 2bfc52118d7ac..57e48442b1070 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -1552,12 +1552,18 @@ export function getTemplateLock( state, rootClientId ) { * @param {string|Object} blockNameOrType The block type object, e.g., the response * from the block directory; or a string name of * an installed block type, e.g.' core/paragraph'. + * @param {Set} checkedBlocks Set of block names that have already been checked. * * @return {boolean} Whether the given block type is allowed to be inserted. */ -const isBlockVisibleInTheInserter = ( state, blockNameOrType ) => { +const isBlockVisibleInTheInserter = ( + state, + blockNameOrType, + checkedBlocks = new Set() +) => { let blockType; let blockName; + if ( blockNameOrType && 'object' === typeof blockNameOrType ) { blockType = blockNameOrType; blockName = blockNameOrType.name; @@ -1565,6 +1571,7 @@ const isBlockVisibleInTheInserter = ( state, blockNameOrType ) => { blockType = getBlockType( blockNameOrType ); blockName = blockNameOrType; } + if ( ! blockType ) { return false; } @@ -1580,11 +1587,22 @@ const isBlockVisibleInTheInserter = ( state, blockNameOrType ) => { return false; } + if ( checkedBlocks.has( blockName ) ) { + return false; + } + + checkedBlocks.add( blockName ); + // If parent blocks are not visible, child blocks should be hidden too. if ( !! blockType.parent?.length ) { return blockType.parent.some( ( name ) => - isBlockVisibleInTheInserter( state, name ) || + ( blockName !== name && + isBlockVisibleInTheInserter( + state, + name, + checkedBlocks + ) ) || // Exception for blocks with post-content parent, // the root level is often consider as "core/post-content". // This exception should only apply to the post editor ideally though. diff --git a/packages/blocks/src/api/registration.js b/packages/blocks/src/api/registration.js index 2f4bab2b5f258..ef1b6bd20a4cd 100644 --- a/packages/blocks/src/api/registration.js +++ b/packages/blocks/src/api/registration.js @@ -232,6 +232,15 @@ export function registerBlockType( blockNameOrMetadata, settings ) { return; } + if ( 1 === settings?.parent?.length && name === settings.parent[ 0 ] ) { + warning( + 'Block "' + + name + + '" cannot be a parent of itself. Please remove the block name from the parent list.' + ); + return; + } + if ( ! /^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test( name ) ) { warning( 'Block names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-block' diff --git a/packages/blocks/src/api/test/registration.js b/packages/blocks/src/api/test/registration.js index 73f310bbf04dc..656e9471a541b 100644 --- a/packages/blocks/src/api/test/registration.js +++ b/packages/blocks/src/api/test/registration.js @@ -104,6 +104,17 @@ describe( 'blocks', () => { expect( block ).toBeUndefined(); } ); + it( 'Should reject blocks with the block name itself as the only parent attribute value', () => { + const block = registerBlockType( 'core/test-block', { + ...defaultBlockSettings, + parent: [ 'core/test-block' ], + } ); + expect( console ).toHaveWarnedWith( + 'Block "core/test-block" cannot be a parent of itself. Please remove the block name from the parent list.' + ); + expect( block ).toBeUndefined(); + } ); + it( 'should reject blocks with uppercase characters', () => { const block = registerBlockType( 'Core/Paragraph' ); expect( console ).toHaveWarnedWith(