: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Returns the insertion point, the index at which the new inserted block would
* be placed. Defaults to the last index.
* @param {Object} state Editor state.
* @return {Object} Insertion point object with `rootClientId`, `index`.
const getBlockInsertionPoint = (0,external_wp_data_namespaceObject.createSelector)(state => {
if (insertionPoint !== null) {
rootClientId = getBlockRootClientId(state, clientId) || undefined;
index = getBlockIndex(state, selectionEnd.clientId) + 1;
index = getBlockOrder(state).length;
}, state => [state.insertionPoint, state.selection.selectionEnd.clientId, state.blocks.parents, state.blocks.order]);
* Returns true if we should show the block insertion point.
* @param {Object} state Global application state.
* @return {?boolean} Whether the insertion point is visible or not.
function isBlockInsertionPointVisible(state) {
return state.insertionPoint !== null;
* Returns whether the blocks matches the template or not.
* @return {?boolean} Whether the template is valid or not.
function isValidTemplate(state) {
return state.template.isValid;
* Returns the defined block template
* @return {?Array} Block Template.
function getTemplate(state) {
return state.settings.template;
* Returns the defined block template lock. Optionally accepts a root block
* client ID as context, otherwise defaulting to the global context.
* @param {Object} state Editor state.
* @param {?string} rootClientId Optional block root client ID.
* @return {string|false} Block Template Lock
function getTemplateLock(state, rootClientId) {
var _getBlockListSettings;
var _state$settings$templ;
return (_state$settings$templ = state.settings.templateLock) !== null && _state$settings$templ !== void 0 ? _state$settings$templ : false;
return (_getBlockListSettings = getBlockListSettings(state, rootClientId)?.templateLock) !== null && _getBlockListSettings !== void 0 ? _getBlockListSettings : false;
* 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
* inside another memoized selector is just a waste of time.
* @param {Object} state Editor state.
* @param {string|Object} blockName 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 {?string} rootClientId Optional root client ID of block list.
* @return {boolean} Whether the given block type is allowed to be inserted.
const canInsertBlockTypeUnmemoized = (state, blockName, rootClientId = null) => {
if (blockName && 'object' === typeof blockName) {
blockName = blockType.name;
blockType = (0,external_wp_blocks_namespaceObject.getBlockType)(blockName);
const isBlockAllowedInEditor = checkAllowList(allowedBlockTypes, blockName, true);
if (!isBlockAllowedInEditor) {
const isLocked = !!getTemplateLock(state, rootClientId);
if (getBlockEditingMode(state, rootClientId !== null && rootClientId !== void 0 ? rootClientId : '') === 'disabled') {
const parentBlockListSettings = getBlockListSettings(state, rootClientId);
// The parent block doesn't have settings indicating it doesn't support
// inner blocks, return false.
if (rootClientId && parentBlockListSettings === undefined) {
const parentName = getBlockName(state, rootClientId);
const parentBlockType = (0,external_wp_blocks_namespaceObject.getBlockType)(parentName);
// Look at the `blockType.allowedBlocks` field to determine whether this is an allowed child block.
const parentAllowedChildBlocks = parentBlockType?.allowedBlocks;
let hasParentAllowedBlock = checkAllowList(parentAllowedChildBlocks, blockName);
// The `allowedBlocks` block list setting can further limit which blocks are allowed children.
if (hasParentAllowedBlock !== false) {
const parentAllowedBlocks = parentBlockListSettings?.allowedBlocks;
const hasParentListAllowedBlock = checkAllowList(parentAllowedBlocks, blockName);
// Never downgrade the result from `true` to `null`
if (hasParentListAllowedBlock !== null) {
hasParentAllowedBlock = hasParentListAllowedBlock;
const blockAllowedParentBlocks = blockType.parent;
const hasBlockAllowedParent = checkAllowList(blockAllowedParentBlocks, parentName);
let hasBlockAllowedAncestor = true;
const blockAllowedAncestorBlocks = blockType.ancestor;
if (blockAllowedAncestorBlocks) {
const ancestors = [rootClientId, ...getBlockParents(state, rootClientId)];
hasBlockAllowedAncestor = ancestors.some(ancestorClientId => checkAllowList(blockAllowedAncestorBlocks, getBlockName(state, ancestorClientId)));
const canInsert = hasBlockAllowedAncestor && (hasParentAllowedBlock === null && hasBlockAllowedParent === null || hasParentAllowedBlock === true || hasBlockAllowedParent === true);
* This filter is an ad-hoc solution to prevent adding template parts inside post content.
* Conceptually, having a filter inside a selector is bad pattern so this code will be
* replaced by a declarative API that doesn't the following drawbacks:
* Filters are not reactive: Upon switching between "template mode" and non "template mode",
* the filter and selector won't necessarily be executed again. For now, it doesn't matter much
* because you can't switch between the two modes while the inserter stays open.
* Filters are global: Once they're defined, they will affect all editor instances and all registries.
* An ideal API would only affect specific editor instances.
return (0,external_wp_hooks_namespaceObject.applyFilters)('blockEditor.__unstableCanInsertBlockType', canInsert, blockType, rootClientId, {
// Pass bound selectors of the current registry. If we're in a nested
// context, the data will differ from the one selected from the root
getBlock: getBlock.bind(null, state),
getBlockParentsByBlockName: getBlockParentsByBlockName.bind(null, state)
* Determines if the given block type is allowed to be inserted into the block list.
* @param {Object} state Editor state.
* @param {string} blockName The name of the block type, e.g.' core/paragraph'.
* @param {?string} rootClientId Optional root client ID of block list.
* @return {boolean} Whether the given block type is allowed to be inserted.
const canInsertBlockType = (0,external_wp_data_namespaceObject.createSelector)(canInsertBlockTypeUnmemoized, (state, blockName, rootClientId) => getInsertBlockTypeDependants(state, rootClientId));
* Determines if the given blocks are allowed to be inserted into the block
* @param {Object} state Editor state.
* @param {string} clientIds The block client IDs to be inserted.
* @param {?string} rootClientId Optional root client ID of block list.
* @return {boolean} Whether the given blocks are allowed to be inserted.
function canInsertBlocks(state, clientIds, rootClientId = null) {
return clientIds.every(id => canInsertBlockType(state, getBlockName(state, id), rootClientId));
* Determines if the given block is allowed to be deleted.
* @param {Object} state Editor state.
* @param {string} clientId The block client Id.
* @return {boolean} Whether the given block is allowed to be removed.
function canRemoveBlock(state, clientId) {
const attributes = getBlockAttributes(state, clientId);
if (attributes === null) {
if (attributes.lock?.remove !== undefined) {
return !attributes.lock.remove;
const rootClientId = getBlockRootClientId(state, clientId);
if (getTemplateLock(state, rootClientId)) {
return getBlockEditingMode(state, rootClientId) !== 'disabled';
* Determines if the given blocks are allowed to be removed.
* @param {Object} state Editor state.
* @param {string} clientIds The block client IDs to be removed.
* @return {boolean} Whether the given blocks are allowed to be removed.
function canRemoveBlocks(state, clientIds) {
return clientIds.every(clientId => canRemoveBlock(state, clientId));
* Determines if the given block is allowed to be moved.
* @param {Object} state Editor state.
* @param {string} clientId The block client Id.
* @return {boolean | undefined} Whether the given block is allowed to be moved.
function canMoveBlock(state, clientId) {
const attributes = getBlockAttributes(state, clientId);
if (attributes === null) {
if (attributes.lock?.move !== undefined) {
return !attributes.lock.move;
const rootClientId = getBlockRootClientId(state, clientId);
if (getTemplateLock(state, rootClientId) === 'all') {
return getBlockEditingMode(state, rootClientId) !== 'disabled';
* Determines if the given blocks are allowed to be moved.
* @param {Object} state Editor state.
* @param {string} clientIds The block client IDs to be moved.
* @return {boolean} Whether the given blocks are allowed to be moved.
function canMoveBlocks(state, clientIds) {
return clientIds.every(clientId => canMoveBlock(state, clientId));
* Determines if the given block is allowed to be edited.
* @param {Object} state Editor state.
* @param {string} clientId The block client Id.
* @return {boolean} Whether the given block is allowed to be edited.
function canEditBlock(state, clientId) {
const attributes = getBlockAttributes(state, clientId);
if (attributes === null) {
// When the edit is true, we cannot edit the block.
* Determines if the given block type can be locked/unlocked by a user.
* @param {Object} state Editor state.
* @param {(string|Object)} nameOrType Block name or type object.
* @return {boolean} Whether a given block type can be locked/unlocked.
function canLockBlockType(state, nameOrType) {
if (!(0,external_wp_blocks_namespaceObject.hasBlockSupport)(nameOrType, 'lock', true)) {
// Use block editor settings as the default value.
return !!state.settings?.canLockBlocks;
* Returns information about how recently and frequently a block has been inserted.
* @param {Object} state Global application state.
* @param {string} id A string which identifies the insert, e.g. 'core/block/12'
* @return {?{ time: number, count: number }} An object containing `time` which is when the last
* insert occurred as a UNIX epoch, and `count` which is
* the number of inserts that have occurred.
function getInsertUsage(state, id) {
var _state$preferences$in;
return (_state$preferences$in = state.preferences.insertUsage?.[id]) !== null && _state$preferences$in !== void 0 ? _state$preferences$in : null;
* Returns whether we can show a block type in the inserter
* @param {Object} state Global State
* @param {Object} blockType BlockType
* @param {?string} rootClientId Optional root client ID of block list.
* @return {boolean} Whether the given block type is allowed to be shown in the inserter.
const canIncludeBlockTypeInInserter = (state, blockType, rootClientId) => {
if (!(0,external_wp_blocks_namespaceObject.hasBlockSupport)(blockType, 'inserter', true)) {
return canInsertBlockTypeUnmemoized(state, blockType.name, rootClientId);
* Return a function to be used to tranform a block variation to an inserter item
* @param {Object} state Global State
* @param {Object} item Denormalized inserter item
* @return {Function} Function to transform a block variation to inserter item
const getItemFromVariation = (state, item) => variation => {
const variationId = `${item.id}/${variation.name}`;
} = getInsertUsage(state, variationId) || {};
icon: variation.icon || item.icon,
title: variation.title || item.title,
description: variation.description || item.description,
category: variation.category || item.category,
// If `example` is explicitly undefined for the variation, the preview will not be shown.
example: variation.hasOwnProperty('example') ? variation.example : item.example,
...item.initialAttributes,
innerBlocks: variation.innerBlocks,
keywords: variation.keywords || item.keywords,
frecency: calculateFrecency(time, count)
* Returns the calculated frecency.
* 'frecency' is a heuristic (https://en.wikipedia.org/wiki/Frecency)
* that combines block usage frequenty and recency.
* @param {number} time When the last insert occurred as a UNIX epoch
* @param {number} count The number of inserts that have occurred.
* @return {number} The calculated frecency.
const calculateFrecency = (time, count) => {
// The selector is cached, which means Date.now() is the last time that the
// relevant state changed. This suits our needs.
const duration = Date.now() - time;
case duration < MILLISECONDS_PER_HOUR:
case duration < MILLISECONDS_PER_DAY:
case duration < MILLISECONDS_PER_WEEK:
* Returns a function that accepts a block type and builds an item to be shown
* in a specific context. It's used for building items for Inserter and available
* @param {Object} state Editor state.
* @param {Object} options Options object for handling the building of a block type.
* @param {string} options.buildScope The scope for which the item is going to be used.
* @return {Function} Function returns an item to be shown in a specific context (Inserter|Transforms list).
const buildBlockTypeItem = (state, {
const id = blockType.name;
if (!(0,external_wp_blocks_namespaceObject.hasBlockSupport)(blockType.name, 'multiple', true)) {
isDisabled = getBlocksByClientId(state, getClientIdsWithDescendants(state)).some(({
}) => name === blockType.name);
} = getInsertUsage(state, id) || {};
frecency: calculateFrecency(time, count)
if (buildScope === 'transform') {
const inserterVariations = (0,external_wp_blocks_namespaceObject.getBlockVariations)(blockType.name, 'inserter');
description: blockType.description,
category: blockType.category,
keywords: blockType.keywords,
variations: inserterVariations,
example: blockType.example,
utility: 1 // Deprecated.
* Determines the items that appear in the inserter. Includes both static
* items (e.g. a regular block type) and dynamic items (e.g. a reusable block).
* Each item object contains what's necessary to display a button in the
* inserter and handle its selection.
* The 'frecency' property is a heuristic (https://en.wikipedia.org/wiki/Frecency)
* that combines block usage frequenty and recency.
* Items are returned ordered descendingly by their 'utility' and 'frecency'.
* @param {Object} state Editor state.
* @param {?string} rootClientId Optional root client ID of block list.
* @return {WPEditorInserterItem[]} Items that appear in inserter.
* @typedef {Object} WPEditorInserterItem
* @property {string} id Unique identifier for the item.
* @property {string} name The type of block to create.
* @property {Object} initialAttributes Attributes to pass to the newly created block.
* @property {string} title Title of the item, as it appears in the inserter.
* @property {string} icon Dashicon for the item, as it appears in the inserter.
* @property {string} category Block category that the item is associated with.
* @property {string[]} keywords Keywords that can be searched to find this item.
* @property {boolean} isDisabled Whether or not the user should be prevented from inserting
* @property {number} frecency Heuristic that combines frequency and recency.
const getInserterItems = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (0,external_wp_data_namespaceObject.createSelector)((state, rootClientId = null, options = EMPTY_OBJECT) => {
const buildReusableBlockInserterItem = reusableBlock => {
const icon = !reusableBlock.wp_pattern_sync_status ? {
foreground: 'var(--wp-block-synced-color)'
const id = `core/block/${reusableBlock.id}`;
} = getInsertUsage(state, id) || {};
const frecency = calculateFrecency(time, count);