Skip to content

Commit

Permalink
Performance: Improve opening inserter in post editor (#57006)
Browse files Browse the repository at this point in the history
* Performance: Improve opening inserter in post editor

* make selector private
  • Loading branch information
ntsekouras authored Dec 13, 2023
1 parent 77a8b55 commit ef65c8b
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 74 deletions.
10 changes: 5 additions & 5 deletions packages/block-editor/src/components/inserter/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { useDebouncedInput } from '@wordpress/compose';
/**
* Internal dependencies
*/
import { unlock } from '../../lock-unlock';
import Tips from './tips';
import InserterPreviewPanel from './preview-panel';
import BlockTypesTab from './block-types-tab';
Expand Down Expand Up @@ -68,12 +69,11 @@ function InserterMenu(
} );
const { showPatterns, inserterItems } = useSelect(
( select ) => {
const { __experimentalGetAllowedPatterns, getInserterItems } =
select( blockEditorStore );
const { hasAllowedPatterns, getInserterItems } = unlock(
select( blockEditorStore )
);
return {
showPatterns: !! __experimentalGetAllowedPatterns(
destinationRootClientId
).length,
showPatterns: hasAllowedPatterns( destinationRootClientId ),
inserterItems: getInserterItems( destinationRootClientId ),
};
},
Expand Down
45 changes: 45 additions & 0 deletions packages/block-editor/src/store/private-selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import {
getBlockOrder,
getBlockParents,
getBlockEditingMode,
getSettings,
__experimentalGetParsedPattern,
canInsertBlockType,
__experimentalGetAllowedPatterns,
} from './selectors';
import { getUserPatterns, checkAllowListRecursive } from './utils';

/**
* Returns true if the block interface is hidden, or false otherwise.
Expand Down Expand Up @@ -236,3 +241,43 @@ export const getInserterMediaCategories = createSelector(
state.registeredInserterMediaCategories,
]
);

/**
* Returns whether there is at least one allowed pattern for inner blocks children.
* This is useful for deferring the parsing of all patterns until needed.
*
* @param {Object} state Editor state.
* @param {string} [rootClientId=null] Target root client ID.
*
* @return {boolean} If there is at least one allowed pattern.
*/
export const hasAllowedPatterns = createSelector(
( state, rootClientId = null ) => {
const patterns = state.settings.__experimentalBlockPatterns;
const userPatterns = getUserPatterns( state );
const { allowedBlockTypes } = getSettings( state );
return [ ...userPatterns, ...patterns ].some(
( { name, inserter = true } ) => {
if ( ! inserter ) {
return false;
}
const { blocks } = __experimentalGetParsedPattern(
state,
name
);
return (
checkAllowListRecursive( blocks, allowedBlockTypes ) &&
blocks.every( ( { name: blockName } ) =>
canInsertBlockType( state, blockName, rootClientId )
)
);
}
);
},
( state, rootClientId ) => [
...__experimentalGetAllowedPatterns.getDependants(
state,
rootClientId
),
]
);
74 changes: 5 additions & 69 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,12 @@ import { createRegistrySelector } from '@wordpress/data';
/**
* Internal dependencies
*/
import {
getUserPatterns,
checkAllowListRecursive,
checkAllowList,
} from './utils';
import { orderBy } from '../utils/sorting';
import { PATTERN_TYPES } from '../components/inserter/block-patterns-tab/utils';

/**
* A block selection object.
Expand Down Expand Up @@ -1481,22 +1485,6 @@ export function getTemplateLock( state, rootClientId ) {
return getBlockListSettings( state, rootClientId )?.templateLock ?? false;
}

const checkAllowList = ( list, item, defaultResult = null ) => {
if ( typeof list === 'boolean' ) {
return list;
}
if ( Array.isArray( list ) ) {
// TODO: when there is a canonical way to detect that we are editing a post
// the following check should be changed to something like:
// if ( list.includes( 'core/post-content' ) && getEditorMode() === 'post-content' && item === null )
if ( list.includes( 'core/post-content' ) && item === null ) {
return true;
}
return list.includes( item );
}
return defaultResult;
};

/**
* Determines if the given block type is allowed to be inserted into the block list.
* This function is not exported and not memoized because using a memoized selector
Expand Down Expand Up @@ -2249,58 +2237,6 @@ export const __experimentalGetDirectInsertBlock = createSelector(
]
);

const checkAllowListRecursive = ( blocks, allowedBlockTypes ) => {
if ( typeof allowedBlockTypes === 'boolean' ) {
return allowedBlockTypes;
}

const blocksQueue = [ ...blocks ];
while ( blocksQueue.length > 0 ) {
const block = blocksQueue.shift();

const isAllowed = checkAllowList(
allowedBlockTypes,
block.name || block.blockName,
true
);
if ( ! isAllowed ) {
return false;
}

block.innerBlocks?.forEach( ( innerBlock ) => {
blocksQueue.push( innerBlock );
} );
}

return true;
};

function getUserPatterns( state ) {
const userPatterns =
state?.settings?.__experimentalReusableBlocks ?? EMPTY_ARRAY;
const userPatternCategories =
state?.settings?.__experimentalUserPatternCategories ?? [];
const categories = new Map();
userPatternCategories.forEach( ( userCategory ) =>
categories.set( userCategory.id, userCategory )
);
return userPatterns.map( ( userPattern ) => {
return {
name: `core/block/${ userPattern.id }`,
id: userPattern.id,
type: PATTERN_TYPES.user,
title: userPattern.title.raw,
categories: userPattern.wp_pattern_category.map( ( catId ) =>
categories && categories.get( catId )
? categories.get( catId ).slug
: catId
),
content: userPattern.content.raw,
syncStatus: userPattern.wp_pattern_sync_status,
};
} );
}

export const __experimentalUserPatternCategories = createSelector(
( state ) => {
return state?.settings?.__experimentalUserPatternCategories;
Expand Down
74 changes: 74 additions & 0 deletions packages/block-editor/src/store/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Internal dependencies
*/
import { PATTERN_TYPES } from '../components/inserter/block-patterns-tab/utils';

const EMPTY_ARRAY = [];

export function getUserPatterns( state ) {
const userPatterns =
state?.settings?.__experimentalReusableBlocks ?? EMPTY_ARRAY;
const userPatternCategories =
state?.settings?.__experimentalUserPatternCategories ?? [];
const categories = new Map();
userPatternCategories.forEach( ( userCategory ) =>
categories.set( userCategory.id, userCategory )
);
return userPatterns.map( ( userPattern ) => {
return {
name: `core/block/${ userPattern.id }`,
id: userPattern.id,
type: PATTERN_TYPES.user,
title: userPattern.title.raw,
categories: userPattern.wp_pattern_category.map( ( catId ) =>
categories && categories.get( catId )
? categories.get( catId ).slug
: catId
),
content: userPattern.content.raw,
syncStatus: userPattern.wp_pattern_sync_status,
};
} );
}

export const checkAllowList = ( list, item, defaultResult = null ) => {
if ( typeof list === 'boolean' ) {
return list;
}
if ( Array.isArray( list ) ) {
// TODO: when there is a canonical way to detect that we are editing a post
// the following check should be changed to something like:
// if ( list.includes( 'core/post-content' ) && getEditorMode() === 'post-content' && item === null )
if ( list.includes( 'core/post-content' ) && item === null ) {
return true;
}
return list.includes( item );
}
return defaultResult;
};

export const checkAllowListRecursive = ( blocks, allowedBlockTypes ) => {
if ( typeof allowedBlockTypes === 'boolean' ) {
return allowedBlockTypes;
}

const blocksQueue = [ ...blocks ];
while ( blocksQueue.length > 0 ) {
const block = blocksQueue.shift();

const isAllowed = checkAllowList(
allowedBlockTypes,
block.name || block.blockName,
true
);
if ( ! isAllowed ) {
return false;
}

block.innerBlocks?.forEach( ( innerBlock ) => {
blocksQueue.push( innerBlock );
} );
}

return true;
};

1 comment on commit ef65c8b

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in ef65c8b.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/7193286921
📝 Reported issues:

Please sign in to comment.