: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @param {Object} state Global application state.
* @param {string} clientId The block to check.
* @return {boolean} True if the block has controlled inner blocks.
function areInnerBlocksControlled(state, clientId) {
return !!state.blocks.controlledInnerBlocks[clientId];
* Returns the clientId for the first 'active' block of a given array of block names.
* A block is 'active' if it (or a child) is the selected block.
* Returns the first match moving up the DOM from the selected block.
* @param {Object} state Global application state.
* @param {string[]} validBlocksNames The names of block types to check for.
* @return {string} The matching block's clientId.
const __experimentalGetActiveBlockIdByBlockNames = (0,external_wp_data_namespaceObject.createSelector)((state, validBlockNames) => {
if (!validBlockNames.length) {
// Check if selected block is a valid entity area.
const selectedBlockClientId = getSelectedBlockClientId(state);
if (validBlockNames.includes(getBlockName(state, selectedBlockClientId))) {
return selectedBlockClientId;
// Check if first selected block is a child of a valid entity area.
const multiSelectedBlockClientIds = getMultiSelectedBlockClientIds(state);
const entityAreaParents = getBlockParentsByBlockName(state, selectedBlockClientId || multiSelectedBlockClientIds[0], validBlockNames);
// Last parent closest/most interior.
return entityAreaParents[entityAreaParents.length - 1];
}, (state, validBlockNames) => [state.selection.selectionStart.clientId, state.selection.selectionEnd.clientId, validBlockNames]);
* Tells if the block with the passed clientId was just inserted.
* @param {Object} state Global application state.
* @param {Object} clientId Client Id of the block.
* @param {?string} source Optional insertion source of the block.
* @return {boolean} True if the block matches the last block inserted from the specified source.
function wasBlockJustInserted(state, clientId, source) {
return lastBlockInserted.clientIds?.includes(clientId) && lastBlockInserted.source === source;
* Tells if the block is visible on the canvas or not.
* @param {Object} state Global application state.
* @param {Object} clientId Client Id of the block.
* @return {boolean} True if the block is visible.
function isBlockVisible(state, clientId) {
var _state$blockVisibilit;
return (_state$blockVisibilit = state.blockVisibility?.[clientId]) !== null && _state$blockVisibilit !== void 0 ? _state$blockVisibilit : true;
* Returns the list of all hidden blocks.
* @param {Object} state Global application state.
* @return {[string]} List of hidden blocks.
const __unstableGetVisibleBlocks = (0,external_wp_data_namespaceObject.createSelector)(state => {
const visibleBlocks = new Set(Object.keys(state.blockVisibility).filter(key => state.blockVisibility[key]));
if (visibleBlocks.size === 0) {
}, state => [state.blockVisibility]);
function __unstableHasActiveBlockOverlayActive(state, clientId) {
// Prevent overlay on blocks with a non-default editing mode. If the mdoe is
// 'disabled' then the overlay is redundant since the block can't be
// selected. If the mode is 'contentOnly' then the overlay is redundant
// since there will be no controls to interact with once selected.
if (getBlockEditingMode(state, clientId) !== 'default') {
// If the block editing is locked, the block overlay is always active.
if (!canEditBlock(state, clientId)) {
const editorMode = __unstableGetEditorMode(state);
// In zoom-out mode, the block overlay is always active for section level blocks.
if (editorMode === 'zoom-out') {
} = unlock(getSettings(state));
if (sectionRootClientId) {
const sectionClientIds = getBlockOrder(state, sectionRootClientId);
if (sectionClientIds?.includes(clientId)) {
} else if (clientId && !getBlockRootClientId(state, clientId)) {
// In navigation mode, the block overlay is active when the block is not
// selected (and doesn't contain a selected child). The same behavior is
// also enabled in all modes for blocks that have controlled children
// (reusable block, template part, navigation), unless explicitly disabled
// with `supports.__experimentalDisableBlockOverlay`.
const blockSupportDisable = (0,external_wp_blocks_namespaceObject.hasBlockSupport)(getBlockName(state, clientId), '__experimentalDisableBlockOverlay', false);
const shouldEnableIfUnselected = editorMode === 'navigation' || (blockSupportDisable ? false : areInnerBlocksControlled(state, clientId));
return shouldEnableIfUnselected && !isBlockSelected(state, clientId) && !hasSelectedInnerBlock(state, clientId, true);
function __unstableIsWithinBlockOverlay(state, clientId) {
let parent = state.blocks.parents.get(clientId);
if (__unstableHasActiveBlockOverlayActive(state, parent)) {
parent = state.blocks.parents.get(parent);
* @typedef {import('../components/block-editing-mode').BlockEditingMode} BlockEditingMode
* Returns the block editing mode for a given block.
* The mode can be one of three options:
* - `'disabled'`: Prevents editing the block entirely, i.e. it cannot be
* - `'contentOnly'`: Hides all non-content UI, e.g. auxiliary controls in the
* toolbar, the block movers, block settings.
* - `'default'`: Allows editing the block as normal.
* Blocks can set a mode using the `useBlockEditingMode` hook.
* The mode is inherited by all of the block's inner blocks, unless they have
* A template lock can also set a mode. If the template lock is `'contentOnly'`,
* the block's mode is overridden to `'contentOnly'` if the block has a content
* role attribute, or `'disabled'` otherwise.
* @see useBlockEditingMode
* @param {Object} state Global application state.
* @param {string} clientId The block client ID, or `''` for the root container.
* @return {BlockEditingMode} The block editing mode. One of `'disabled'`,
* `'contentOnly'`, or `'default'`.
const getBlockEditingMode = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (state, clientId = '') => {
// Some selectors that call this provide `null` as the default
// rootClientId, but the default rootClientId is actually `''`.
// In zoom-out mode, override the behavior set by
// __unstableSetBlockEditingMode to only allow editing the top-level
const editorMode = __unstableGetEditorMode(state);
if (editorMode === 'zoom-out') {
} = unlock(getSettings(state));
if (clientId === '' /* ROOT_CONTAINER_CLIENT_ID */) {
return sectionRootClientId ? 'disabled' : 'contentOnly';
if (clientId === sectionRootClientId) {
const sectionsClientIds = getBlockOrder(state, sectionRootClientId);
if (!sectionsClientIds?.includes(clientId)) {
const blockEditingMode = state.blockEditingModes.get(clientId);
const rootClientId = getBlockRootClientId(state, clientId);
const templateLock = getTemplateLock(state, rootClientId);
if (templateLock === 'contentOnly') {
const name = getBlockName(state, clientId);
const isContent = select(external_wp_blocks_namespaceObject.store).__experimentalHasContentRoleAttribute(name);
return isContent ? 'contentOnly' : 'disabled';
const parentMode = getBlockEditingMode(state, rootClientId);
return parentMode === 'contentOnly' ? 'default' : parentMode;
* Indicates if a block is ungroupable.
* A block is ungroupable if it is a single grouping block with inner blocks.
* If a block has an `ungroup` transform, it is also ungroupable, without the
* requirement of being the default grouping block.
* Additionally a block can only be ungrouped if it has inner blocks and can
* @param {Object} state Global application state.
* @param {string} clientId Client Id of the block. If not passed the selected block's client id will be used.
* @return {boolean} True if the block is ungroupable.
const isUngroupable = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (state, clientId = '') => {
const _clientId = clientId || getSelectedBlockClientId(state);
} = select(external_wp_blocks_namespaceObject.store);
const block = getBlock(state, _clientId);
const groupingBlockName = getGroupingBlockName();
const _isUngroupable = block && (block.name === groupingBlockName || (0,external_wp_blocks_namespaceObject.getBlockType)(block.name)?.transforms?.ungroup) && !!block.innerBlocks.length;
return _isUngroupable && canRemoveBlock(state, _clientId);
* Indicates if the provided blocks(by client ids) are groupable.
* We need to have at least one block, have a grouping block name set and
* be able to remove these blocks.
* @param {Object} state Global application state.
* @param {string[]} clientIds Block client ids. If not passed the selected blocks client ids will be used.
* @return {boolean} True if the blocks are groupable.
const isGroupable = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (state, clientIds = selectors_EMPTY_ARRAY) => {
} = select(external_wp_blocks_namespaceObject.store);
const groupingBlockName = getGroupingBlockName();
const _clientIds = clientIds?.length ? clientIds : getSelectedBlockClientIds(state);
const rootClientId = _clientIds?.length ? getBlockRootClientId(state, _clientIds[0]) : undefined;
const groupingBlockAvailable = canInsertBlockType(state, groupingBlockName, rootClientId);
const _isGroupable = groupingBlockAvailable && _clientIds.length;
return _isGroupable && canRemoveBlocks(state, _clientIds);
* DO-NOT-USE in production.
* This selector is created for internal/experimental only usage and may be
* removed anytime without any warning, causing breakage on any plugin or theme invoking it.
* @param {Object} state Global application state.
* @param {Object} clientId Client Id of the block.
* @return {?string} Client ID of the ancestor block that is content locking the block.
const __unstableGetContentLockingParent = (state, clientId) => {
external_wp_deprecated_default()("wp.data.select( 'core/block-editor' ).__unstableGetContentLockingParent", {
return getContentLockingParent(state, clientId);
* DO-NOT-USE in production.
* This selector is created for internal/experimental only usage and may be
* removed anytime without any warning, causing breakage on any plugin or theme invoking it.
* @param {Object} state Global application state.
function __unstableGetTemporarilyEditingAsBlocks(state) {
external_wp_deprecated_default()("wp.data.select( 'core/block-editor' ).__unstableGetTemporarilyEditingAsBlocks", {
return getTemporarilyEditingAsBlocks(state);
* DO-NOT-USE in production.
* This selector is created for internal/experimental only usage and may be
* removed anytime without any warning, causing breakage on any plugin or theme invoking it.
* @param {Object} state Global application state.
function __unstableGetTemporarilyEditingFocusModeToRevert(state) {
external_wp_deprecated_default()("wp.data.select( 'core/block-editor' ).__unstableGetTemporarilyEditingFocusModeToRevert", {
return getTemporarilyEditingFocusModeToRevert(state);
;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/store/undo-ignore.js
// Keep track of the blocks that should not be pushing an additional
// undo stack when editing the entity.
// See the implementation of `syncDerivedUpdates` and `useBlockSync`.
const undoIgnoreBlocks = new WeakSet();
;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/store/private-actions.js
const castArray = maybeArray => Array.isArray(maybeArray) ? maybeArray : [maybeArray];
* A list of private/experimental block editor settings that
* should not become a part of the WordPress public API.
* BlockEditorProvider will remove these settings from the
* settings object it receives.
* @see https://github.com/WordPress/gutenberg/pull/46131
const privateSettings = ['inserterMediaCategories', 'blockInspectorAnimation'];
* Action that updates the block editor settings and
* conditionally preserves the experimental ones.
* @param {Object} settings Updated settings
* @param {Object} options Options object.
* @param {boolean} options.stripExperimentalSettings Whether to strip experimental settings.
* @param {boolean} options.reset Whether to reset the settings.
* @return {Object} Action object
function __experimentalUpdateSettings(settings, {
stripExperimentalSettings = false,
let cleanSettings = settings;
// There are no plugins in the mobile apps, so there is no
// need to strip the experimental settings:
if (stripExperimentalSettings && external_wp_element_namespaceObject.Platform.OS === 'web') {
for (const key in settings) {
if (!privateSettings.includes(key)) {
cleanSettings[key] = settings[key];
* Hides the block interface (eg. toolbar, outline, etc.)
* @return {Object} Action object.
function hideBlockInterface() {
type: 'HIDE_BLOCK_INTERFACE'
* Shows the block interface (eg. toolbar, outline, etc.)
* @return {Object} Action object.
function showBlockInterface() {
type: 'SHOW_BLOCK_INTERFACE'
* Yields action objects used in signalling that the blocks corresponding to
* the set of specified client IDs are to be removed.
* Compared to `removeBlocks`, this private interface exposes an additional
* parameter; see `forceRemove`.
* @param {string|string[]} clientIds Client IDs of blocks to remove.
* @param {boolean} selectPrevious True if the previous block
* or the immediate parent
* (if no previous block exists)
* when a block is removed.
* @param {boolean} forceRemove Whether to force the operation,
* bypassing any checks for certain
const privateRemoveBlocks = (clientIds, selectPrevious = true, forceRemove = false) => ({
if (!clientIds || !clientIds.length) {
clientIds = castArray(clientIds);
const canRemoveBlocks = select.canRemoveBlocks(clientIds);
// In certain editing contexts, we'd like to prevent accidental removal
// of important blocks. For example, in the site editor, the Query Loop
// block is deemed important. In such cases, we'll ask the user for
// confirmation that they intended to remove such block(s). However,
// the editor instance is responsible for presenting those confirmation
// prompts to the user. Any instance opting into removal prompts must
// register using `setBlockRemovalRules()`.
// @see https://github.com/WordPress/gutenberg/pull/51145
const rules = !forceRemove && select.getBlockRemovalRules();
function flattenBlocks(blocks) {
const stack = [...blocks];
stack.push(...innerBlocks);
const blockList = clientIds.map(select.getBlock);
const flattenedBlocks = flattenBlocks(blockList);
// Find the first message and use it.
for (const rule of rules) {
message = rule.callback(flattenedBlocks);
dispatch(displayBlockRemovalPrompt(clientIds, selectPrevious, message));
dispatch.selectPreviousBlock(clientIds[0], selectPrevious);
// We're batching these two actions because an extra `undo/redo` step can
// be created, based on whether we insert a default block or not.
// To avoid a focus loss when removing the last block, assure there is
// always a default block if the last of the blocks have been removed.
dispatch(ensureDefaultBlock());
* Action which will insert a default block insert action if there
* are no other blocks at the root of the editor. This action should be used
* in actions which may result in no blocks remaining in the editor (removal,
const ensureDefaultBlock = () => ({
// To avoid a focus loss when removing the last block, assure there is
// always a default block if the last of the blocks have been removed.
const count = select.getBlockCount();
// If there's an custom appender, don't insert default block.
// We have to remember to manually move the focus elsewhere to
// prevent it from being lost though.
__unstableHasCustomAppender
} = select.getSettings();
if (__unstableHasCustomAppender) {
dispatch.insertDefaultBlock();