From 01b0ada13662910a7b38e203b3202966c1d247da Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 29 Aug 2023 15:50:12 +0200 Subject: [PATCH 01/10] Auto-inserting blocks: Remove toggle if block is present elsewhere --- .../src/hooks/auto-inserting-blocks.js | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 308212893e7cda..0b6b98cb9908fc 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -19,6 +19,24 @@ import { useDispatch, useSelect } from '@wordpress/data'; import { BlockIcon, InspectorControls } from '../components'; import { store as blockEditorStore } from '../store'; +function someBlock( blocks, predicate, getBlocks ) { + return blocks.some( ( block ) => { + const result = predicate( block ); + if ( result ) { + return result; + } + + // A Template Part block's innerBlocks array always shows up as empty, + // so we have to manually load its inner blocks via getBlocks(). + const innerBlocks = + block.name === 'core/template-part' + ? getBlocks( block.clientId ) + : block.innerBlocks; + + return someBlock( innerBlocks, predicate ); + } ); +} + function AutoInsertingBlocksControl( props ) { const { autoInsertedBlocksForCurrentBlock, groupedAutoInsertedBlocks } = useSelect( @@ -60,8 +78,9 @@ function AutoInsertingBlocksControl( props ) { innerBlocksLength, } = useSelect( ( select ) => { - const { getBlock, getBlockIndex, getBlockRootClientId } = + const { getBlock, getBlockIndex, getBlockRootClientId, getBlocks } = select( blockEditorStore ); + const _rootClientId = getBlockRootClientId( props.clientId ); const _autoInsertedBlockClientIds = @@ -99,13 +118,19 @@ function AutoInsertingBlocksControl( props ) { if ( autoInsertedBlock ) { clientIds[ block.name ] = autoInsertedBlock.clientId; + } else { + // If no auto-inserted block was found in any of its designated locations, + // we check if it's present elsewhere in the block tree. + // If it is, we consider it manually inserted and remove the corresponding + // toggle from the block inspector panel. + const blockIsPresentElsewhereInTree = someBlock( + getBlocks(), + ( { name } ) => name === block.name, + getBlocks + ); + // TODO: Remove the toggle from the block inspector panel. } - // TOOD: If no auto-inserted block was found in any of its designated locations, - // we want to check if it's present elsewhere in the block tree. - // If it is, we'd consider it manually inserted and would want to remove the - // corresponding toggle from the block inspector panel. - return clientIds; }, {} From 73be7c9802656379fd49f39a3230d630e2eb9337 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 29 Aug 2023 16:04:47 +0200 Subject: [PATCH 02/10] Move filtering and grouping outside of useSelect --- .../src/hooks/auto-inserting-blocks.js | 50 +++++++------------ 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 0b6b98cb9908fc..77cab5e76e7f9c 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -38,38 +38,13 @@ function someBlock( blocks, predicate, getBlocks ) { } function AutoInsertingBlocksControl( props ) { - const { autoInsertedBlocksForCurrentBlock, groupedAutoInsertedBlocks } = - useSelect( - ( select ) => { - const { getBlockTypes } = select( blocksStore ); - const _autoInsertedBlocksForCurrentBlock = - getBlockTypes()?.filter( - ( { autoInsert } ) => - autoInsert && props.blockName in autoInsert - ); - - // Group by block namespace (i.e. prefix before the slash). - const _groupedAutoInsertedBlocks = - _autoInsertedBlocksForCurrentBlock?.reduce( - ( groups, block ) => { - const [ namespace ] = block.name.split( '/' ); - if ( ! groups[ namespace ] ) { - groups[ namespace ] = []; - } - groups[ namespace ].push( block ); - return groups; - }, - {} - ); + const blockTypes = useSelect( ( select ) => + select( blocksStore ).getBlockTypes() + ); - return { - autoInsertedBlocksForCurrentBlock: - _autoInsertedBlocksForCurrentBlock, - groupedAutoInsertedBlocks: _groupedAutoInsertedBlocks, - }; - }, - [ props.blockName ] - ); + const autoInsertedBlocksForCurrentBlock = blockTypes?.filter( + ( { autoInsert } ) => autoInsert && props.blockName in autoInsert + ); const { autoInsertedBlockClientIds, @@ -153,6 +128,19 @@ function AutoInsertingBlocksControl( props ) { return null; } + // Group by block namespace (i.e. prefix before the slash). + const groupedAutoInsertedBlocks = autoInsertedBlocksForCurrentBlock?.reduce( + ( groups, block ) => { + const [ namespace ] = block.name.split( '/' ); + if ( ! groups[ namespace ] ) { + groups[ namespace ] = []; + } + groups[ namespace ].push( block ); + return groups; + }, + {} + ); + const insertBlockIntoDesignatedLocation = ( block, relativePosition ) => { switch ( relativePosition ) { case 'before': From f03c2f2b11eec5f4b134021c51f54477b7159e51 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 29 Aug 2023 16:30:33 +0200 Subject: [PATCH 03/10] Remove toggle --- .../src/hooks/auto-inserting-blocks.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 77cab5e76e7f9c..aeb4ffc6e514ab 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -103,7 +103,9 @@ function AutoInsertingBlocksControl( props ) { ( { name } ) => name === block.name, getBlocks ); - // TODO: Remove the toggle from the block inspector panel. + if ( blockIsPresentElsewhereInTree ) { + clientIds[ block.name ] = false; + } } return clientIds; @@ -124,12 +126,18 @@ function AutoInsertingBlocksControl( props ) { const { insertBlock, removeBlock } = useDispatch( blockEditorStore ); - if ( ! autoInsertedBlocksForCurrentBlock.length ) { + // Remove toggle if block isn't present in the designated location but elsewhere in the block tree. + const autoInsertedBlocksForCurrentBlockIfNotPresentElsewhere = + autoInsertedBlocksForCurrentBlock?.filter( + ( block ) => autoInsertedBlockClientIds?.[ block.name ] !== false + ); + + if ( ! autoInsertedBlocksForCurrentBlockIfNotPresentElsewhere.length ) { return null; } // Group by block namespace (i.e. prefix before the slash). - const groupedAutoInsertedBlocks = autoInsertedBlocksForCurrentBlock?.reduce( + const groupedAutoInsertedBlocks = autoInsertedBlocksForCurrentBlock.reduce( ( groups, block ) => { const [ namespace ] = block.name.split( '/' ); if ( ! groups[ namespace ] ) { From 1a0996015ec57d330631a95c9741d1720d2603e5 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 29 Aug 2023 16:41:04 +0200 Subject: [PATCH 04/10] Forgot to pass argument down :facepalm: --- packages/block-editor/src/hooks/auto-inserting-blocks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index aeb4ffc6e514ab..d54b59d048ce9d 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -33,7 +33,7 @@ function someBlock( blocks, predicate, getBlocks ) { ? getBlocks( block.clientId ) : block.innerBlocks; - return someBlock( innerBlocks, predicate ); + return someBlock( innerBlocks, predicate, getBlocks ); } ); } From fa832eb800ecef1372f117beef6c3fc53f0a2290 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 30 Aug 2023 14:26:48 +0200 Subject: [PATCH 05/10] Simplify by using getGlobalBlockCount --- .../src/hooks/auto-inserting-blocks.js | 42 +++++-------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index d54b59d048ce9d..5b68d35df3f397 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -19,24 +19,6 @@ import { useDispatch, useSelect } from '@wordpress/data'; import { BlockIcon, InspectorControls } from '../components'; import { store as blockEditorStore } from '../store'; -function someBlock( blocks, predicate, getBlocks ) { - return blocks.some( ( block ) => { - const result = predicate( block ); - if ( result ) { - return result; - } - - // A Template Part block's innerBlocks array always shows up as empty, - // so we have to manually load its inner blocks via getBlocks(). - const innerBlocks = - block.name === 'core/template-part' - ? getBlocks( block.clientId ) - : block.innerBlocks; - - return someBlock( innerBlocks, predicate, getBlocks ); - } ); -} - function AutoInsertingBlocksControl( props ) { const blockTypes = useSelect( ( select ) => select( blocksStore ).getBlockTypes() @@ -53,8 +35,12 @@ function AutoInsertingBlocksControl( props ) { innerBlocksLength, } = useSelect( ( select ) => { - const { getBlock, getBlockIndex, getBlockRootClientId, getBlocks } = - select( blockEditorStore ); + const { + getBlock, + getBlockIndex, + getBlockRootClientId, + getGlobalBlockCount, + } = select( blockEditorStore ); const _rootClientId = getBlockRootClientId( props.clientId ); @@ -93,19 +79,11 @@ function AutoInsertingBlocksControl( props ) { if ( autoInsertedBlock ) { clientIds[ block.name ] = autoInsertedBlock.clientId; - } else { + } else if ( getGlobalBlockCount( block.name ) > 0 ) { // If no auto-inserted block was found in any of its designated locations, - // we check if it's present elsewhere in the block tree. - // If it is, we consider it manually inserted and remove the corresponding - // toggle from the block inspector panel. - const blockIsPresentElsewhereInTree = someBlock( - getBlocks(), - ( { name } ) => name === block.name, - getBlocks - ); - if ( blockIsPresentElsewhereInTree ) { - clientIds[ block.name ] = false; - } + // but it exists elsewhere in the block tree, we consider it manually inserted. + // In this case, we remove the corresponding toggle from the block inspector panel. + clientIds[ block.name ] = false; } return clientIds; From 468ef4ac264f5566633c5f9b687126bd8cd3c8ff Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 30 Aug 2023 14:45:44 +0200 Subject: [PATCH 06/10] Retain reference equality for empty object --- .../src/hooks/auto-inserting-blocks.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 5b68d35df3f397..1ad0a8b8111063 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -19,6 +19,8 @@ import { useDispatch, useSelect } from '@wordpress/data'; import { BlockIcon, InspectorControls } from '../components'; import { store as blockEditorStore } from '../store'; +const emptyObject = {}; + function AutoInsertingBlocksControl( props ) { const blockTypes = useSelect( ( select ) => select( blocksStore ).getBlockTypes() @@ -77,18 +79,24 @@ function AutoInsertingBlocksControl( props ) { ); if ( autoInsertedBlock ) { - clientIds[ block.name ] = - autoInsertedBlock.clientId; + clientIds = { + ...clientIds, + [ block.name ]: autoInsertedBlock.clientId, + }; } else if ( getGlobalBlockCount( block.name ) > 0 ) { // If no auto-inserted block was found in any of its designated locations, // but it exists elsewhere in the block tree, we consider it manually inserted. - // In this case, we remove the corresponding toggle from the block inspector panel. - clientIds[ block.name ] = false; + // In this case, we take note and will remove the corresponding toggle from the + // block inspector panel. + clientIds = { + ...clientIds, + [ block.name ]: false, + }; } return clientIds; }, - {} + emptyObject // Retain reference equality across renders if there are no auto-inserted blocks. ); return { From c0ee31bc8af9401bacc3f96bb35d803c748e08cd Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 30 Aug 2023 19:56:56 +0400 Subject: [PATCH 07/10] Avoid returning different values when grouping inside the mapSelect --- .../src/hooks/auto-inserting-blocks.js | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 1ad0a8b8111063..af17e4a46258b7 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -3,7 +3,7 @@ */ import { __ } from '@wordpress/i18n'; import { addFilter } from '@wordpress/hooks'; -import { Fragment } from '@wordpress/element'; +import { Fragment, useMemo } from '@wordpress/element'; import { __experimentalHStack as HStack, PanelBody, @@ -19,30 +19,27 @@ import { useDispatch, useSelect } from '@wordpress/data'; import { BlockIcon, InspectorControls } from '../components'; import { store as blockEditorStore } from '../store'; -const emptyObject = {}; +const EMPTY_OBJECT = {}; function AutoInsertingBlocksControl( props ) { - const blockTypes = useSelect( ( select ) => - select( blocksStore ).getBlockTypes() + const blockTypes = useSelect( + ( select ) => select( blocksStore ).getBlockTypes(), + [] ); - const autoInsertedBlocksForCurrentBlock = blockTypes?.filter( - ( { autoInsert } ) => autoInsert && props.blockName in autoInsert + const autoInsertedBlocksForCurrentBlock = useMemo( + () => + blockTypes?.filter( + ( { autoInsert } ) => + autoInsert && props.blockName in autoInsert + ), + [ blockTypes, props.blockName ] ); - const { - autoInsertedBlockClientIds, - blockIndex, - rootClientId, - innerBlocksLength, - } = useSelect( + const autoInsertedBlockClientIds = useSelect( ( select ) => { - const { - getBlock, - getBlockIndex, - getBlockRootClientId, - getGlobalBlockCount, - } = select( blockEditorStore ); + const { getBlock, getGlobalBlockCount, getBlockRootClientId } = + select( blockEditorStore ); const _rootClientId = getBlockRootClientId( props.clientId ); @@ -96,18 +93,33 @@ function AutoInsertingBlocksControl( props ) { return clientIds; }, - emptyObject // Retain reference equality across renders if there are no auto-inserted blocks. + {} ); + if ( Object.values( _autoInsertedBlockClientIds ).length > 0 ) { + return _autoInsertedBlockClientIds; + } + + return EMPTY_OBJECT; + }, + [ autoInsertedBlocksForCurrentBlock, props.blockName, props.clientId ] + ); + + const { blockIndex, rootClientId, innerBlocksLength } = useSelect( + ( select ) => { + const { getBlock, getBlockIndex, getBlockRootClientId } = + select( blockEditorStore ); + + const _rootClientId = getBlockRootClientId( props.clientId ); + return { blockIndex: getBlockIndex( props.clientId ), innerBlocksLength: getBlock( props.clientId )?.innerBlocks ?.length, rootClientId: _rootClientId, - autoInsertedBlockClientIds: _autoInsertedBlockClientIds, }; }, - [ autoInsertedBlocksForCurrentBlock, props.blockName, props.clientId ] + [ props.clientId ] ); const { insertBlock, removeBlock } = useDispatch( blockEditorStore ); From 246da3b658d1f7786ae743ad7a79454e06a60aec Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 4 Sep 2023 11:56:05 +0200 Subject: [PATCH 08/10] Re-arrange code a bit --- .../src/hooks/auto-inserting-blocks.js | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index af17e4a46258b7..f69c2f2c7d81a7 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -46,6 +46,13 @@ function AutoInsertingBlocksControl( props ) { const _autoInsertedBlockClientIds = autoInsertedBlocksForCurrentBlock.reduce( ( clientIds, block ) => { + // If the block doesn't exist anywhere in the block tree, + // we know that we have to display the toggle for it, and set + // it to disabled. + if ( getGlobalBlockCount( block.name ) === 0 ) { + return clientIds; + } + const relativePosition = block?.autoInsert?.[ props.blockName ]; let candidates; @@ -75,23 +82,23 @@ function AutoInsertingBlocksControl( props ) { ( { name } ) => name === block.name ); + // If the block exists in the designated location, we consider it auto-inserted + // and show the toggle as enabled. if ( autoInsertedBlock ) { - clientIds = { + return { ...clientIds, [ block.name ]: autoInsertedBlock.clientId, }; - } else if ( getGlobalBlockCount( block.name ) > 0 ) { - // If no auto-inserted block was found in any of its designated locations, - // but it exists elsewhere in the block tree, we consider it manually inserted. - // In this case, we take note and will remove the corresponding toggle from the - // block inspector panel. - clientIds = { - ...clientIds, - [ block.name ]: false, - }; } - return clientIds; + // If no auto-inserted block was found in any of its designated locations, + // but it exists elsewhere in the block tree, we consider it manually inserted. + // In this case, we take note and will remove the corresponding toggle from the + // block inspector panel. + return { + ...clientIds, + [ block.name ]: false, + }; }, {} ); From 1f4495ae03a10159b1941b5f7cef17a089fe5f6e Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 4 Sep 2023 12:01:00 +0200 Subject: [PATCH 09/10] Inline rootClientId --- packages/block-editor/src/hooks/auto-inserting-blocks.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index f69c2f2c7d81a7..7b72f994e9de90 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -117,13 +117,11 @@ function AutoInsertingBlocksControl( props ) { const { getBlock, getBlockIndex, getBlockRootClientId } = select( blockEditorStore ); - const _rootClientId = getBlockRootClientId( props.clientId ); - return { blockIndex: getBlockIndex( props.clientId ), innerBlocksLength: getBlock( props.clientId )?.innerBlocks ?.length, - rootClientId: _rootClientId, + rootClientId: getBlockRootClientId( props.clientId ), }; }, [ props.clientId ] From 5f72af4483fa4c429738716e882268322df74d85 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 4 Sep 2023 12:04:14 +0200 Subject: [PATCH 10/10] Re-arrange code a bit more --- .../src/hooks/auto-inserting-blocks.js | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 7b72f994e9de90..9d5b9add0770c6 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -36,12 +36,25 @@ function AutoInsertingBlocksControl( props ) { [ blockTypes, props.blockName ] ); - const autoInsertedBlockClientIds = useSelect( + const { blockIndex, rootClientId, innerBlocksLength } = useSelect( ( select ) => { - const { getBlock, getGlobalBlockCount, getBlockRootClientId } = + const { getBlock, getBlockIndex, getBlockRootClientId } = select( blockEditorStore ); - const _rootClientId = getBlockRootClientId( props.clientId ); + return { + blockIndex: getBlockIndex( props.clientId ), + innerBlocksLength: getBlock( props.clientId )?.innerBlocks + ?.length, + rootClientId: getBlockRootClientId( props.clientId ), + }; + }, + [ props.clientId ] + ); + + const autoInsertedBlockClientIds = useSelect( + ( select ) => { + const { getBlock, getGlobalBlockCount } = + select( blockEditorStore ); const _autoInsertedBlockClientIds = autoInsertedBlocksForCurrentBlock.reduce( @@ -64,7 +77,7 @@ function AutoInsertingBlocksControl( props ) { // as an auto-inserted block (inserted `before` or `after` the current one), // as the block might've been auto-inserted and then moved around a bit by the user. candidates = - getBlock( _rootClientId )?.innerBlocks; + getBlock( rootClientId )?.innerBlocks; break; case 'first_child': @@ -109,22 +122,12 @@ function AutoInsertingBlocksControl( props ) { return EMPTY_OBJECT; }, - [ autoInsertedBlocksForCurrentBlock, props.blockName, props.clientId ] - ); - - const { blockIndex, rootClientId, innerBlocksLength } = useSelect( - ( select ) => { - const { getBlock, getBlockIndex, getBlockRootClientId } = - select( blockEditorStore ); - - return { - blockIndex: getBlockIndex( props.clientId ), - innerBlocksLength: getBlock( props.clientId )?.innerBlocks - ?.length, - rootClientId: getBlockRootClientId( props.clientId ), - }; - }, - [ props.clientId ] + [ + autoInsertedBlocksForCurrentBlock, + props.blockName, + props.clientId, + rootClientId, + ] ); const { insertBlock, removeBlock } = useDispatch( blockEditorStore );