: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* The number returned includes nested blocks.
* @param {Object} state Global application state.
* @param {?string} blockName Optional block name, if specified only blocks of that type will be counted.
* @return {number} Number of blocks in the post, or number of blocks with name equal to blockName.
const getGlobalBlockCount = (0,external_wp_data_namespaceObject.createSelector)((state, blockName) => {
const clientIds = getClientIdsWithDescendants(state);
for (const clientId of clientIds) {
const block = state.blocks.byClientId.get(clientId);
if (block.name === blockName) {
}, state => [state.blocks.order, state.blocks.byClientId]);
* Returns all blocks that match a blockName. Results include nested blocks.
* @param {Object} state Global application state.
* @param {?string} blockName Optional block name, if not specified, returns an empty array.
* @return {Array} Array of clientIds of blocks with name equal to blockName.
const getBlocksByName = (0,external_wp_data_namespaceObject.createSelector)((state, blockName) => {
return selectors_EMPTY_ARRAY;
const blockNames = Array.isArray(blockName) ? blockName : [blockName];
const clientIds = getClientIdsWithDescendants(state);
const foundBlocks = clientIds.filter(clientId => {
const block = state.blocks.byClientId.get(clientId);
return blockNames.includes(block.name);
return foundBlocks.length > 0 ? foundBlocks : selectors_EMPTY_ARRAY;
}, state => [state.blocks.order, state.blocks.byClientId]);
* Returns all global blocks that match a blockName. Results include nested blocks.
* @param {Object} state Global application state.
* @param {?string} blockName Optional block name, if not specified, returns an empty array.
* @return {Array} Array of clientIds of blocks with name equal to blockName.
function __experimentalGetGlobalBlocksByName(state, blockName) {
external_wp_deprecated_default()("wp.data.select( 'core/block-editor' ).__experimentalGetGlobalBlocksByName", {
alternative: `wp.data.select( 'core/block-editor' ).getBlocksByName`
return getBlocksByName(state, blockName);
* Given an array of block client IDs, returns the corresponding array of block
* @param {Object} state Editor state.
* @param {string[]} clientIds Client IDs for which blocks are to be returned.
* @return {WPBlock[]} Block objects.
const getBlocksByClientId = (0,external_wp_data_namespaceObject.createSelector)((state, clientIds) => (Array.isArray(clientIds) ? clientIds : [clientIds]).map(clientId => getBlock(state, clientId)), (state, clientIds) => (Array.isArray(clientIds) ? clientIds : [clientIds]).map(clientId => state.blocks.tree.get(clientId)));
* Given an array of block client IDs, returns the corresponding array of block
* @param {Object} state Editor state.
* @param {string[]} clientIds Client IDs for which block names are to be returned.
* @return {string[]} Block names.
const getBlockNamesByClientId = (0,external_wp_data_namespaceObject.createSelector)((state, clientIds) => getBlocksByClientId(state, clientIds).filter(Boolean).map(block => block.name), (state, clientIds) => getBlocksByClientId(state, clientIds));
* Returns the number of blocks currently present in the post.
* @param {Object} state Editor state.
* @param {?string} rootClientId Optional root client ID of block list.
* @return {number} Number of blocks in the post.
function getBlockCount(state, rootClientId) {
return getBlockOrder(state, rootClientId).length;
* Returns the current selection start block client ID, attribute key and text
* @param {Object} state Block editor state.
* @return {WPBlockSelection} Selection start information.
function getSelectionStart(state) {
return state.selection.selectionStart;
* Returns the current selection end block client ID, attribute key and text
* @param {Object} state Block editor state.
* @return {WPBlockSelection} Selection end information.
function getSelectionEnd(state) {
return state.selection.selectionEnd;
* Returns the current block selection start. This value may be null, and it
* may represent either a singular block selection or multi-selection start.
* A selection is singular if its start and end match.
* @param {Object} state Global application state.
* @return {?string} Client ID of block selection start.
function getBlockSelectionStart(state) {
return state.selection.selectionStart.clientId;
* Returns the current block selection end. This value may be null, and it
* may represent either a singular block selection or multi-selection end.
* A selection is singular if its start and end match.
* @param {Object} state Global application state.
* @return {?string} Client ID of block selection end.
function getBlockSelectionEnd(state) {
return state.selection.selectionEnd.clientId;
* Returns the number of blocks currently selected in the post.
* @param {Object} state Global application state.
* @return {number} Number of blocks selected in the post.
function getSelectedBlockCount(state) {
const multiSelectedBlockCount = getMultiSelectedBlockClientIds(state).length;
if (multiSelectedBlockCount) {
return multiSelectedBlockCount;
return state.selection.selectionStart.clientId ? 1 : 0;
* Returns true if there is a single selected block, or false otherwise.
* @param {Object} state Editor state.
* @return {boolean} Whether a single block is selected.
function hasSelectedBlock(state) {
return !!selectionStart.clientId && selectionStart.clientId === selectionEnd.clientId;
* Returns the currently selected block client ID, or null if there is no
* @param {Object} state Editor state.
* @return {?string} Selected block client ID.
function getSelectedBlockClientId(state) {
if (!clientId || clientId !== selectionEnd.clientId) {
* Returns the currently selected block, or null if there is no selected block.
* @param {Object} state Global application state.
* @return {?Object} Selected block.
function getSelectedBlock(state) {
const clientId = getSelectedBlockClientId(state);
return clientId ? getBlock(state, clientId) : null;
* Given a block client ID, returns the root block from which the block is
* nested, an empty string for top-level blocks, or null if the block does not
* @param {Object} state Editor state.
* @param {string} clientId Block from which to find root client ID.
* @return {?string} Root client ID, if exists
function getBlockRootClientId(state, clientId) {
var _state$blocks$parents;
return (_state$blocks$parents = state.blocks.parents.get(clientId)) !== null && _state$blocks$parents !== void 0 ? _state$blocks$parents : null;
* Given a block client ID, returns the list of all its parents from top to bottom.
* @param {Object} state Editor state.
* @param {string} clientId Block from which to find root client ID.
* @param {boolean} ascending Order results from bottom to top (true) or top to bottom (false).
* @return {Array} ClientIDs of the parent blocks.
const getBlockParents = (0,external_wp_data_namespaceObject.createSelector)((state, clientId, ascending = false) => {
while (current = state.blocks.parents.get(current)) {
return selectors_EMPTY_ARRAY;
return ascending ? parents : parents.reverse();
}, state => [state.blocks.parents]);
* Given a block client ID and a block name, returns the list of all its parents
* from top to bottom, filtered by the given name(s). For example, if passed
* 'core/group' as the blockName, it will only return parents which are group
* blocks. If passed `[ 'core/group', 'core/cover']`, as the blockName, it will
* return parents which are group blocks and parents which are cover blocks.
* @param {Object} state Editor state.
* @param {string} clientId Block from which to find root client ID.
* @param {string|string[]} blockName Block name(s) to filter.
* @param {boolean} ascending Order results from bottom to top (true) or top to bottom (false).
* @return {Array} ClientIDs of the parent blocks.
const getBlockParentsByBlockName = (0,external_wp_data_namespaceObject.createSelector)((state, clientId, blockName, ascending = false) => {
const parents = getBlockParents(state, clientId, ascending);
const hasName = Array.isArray(blockName) ? name => blockName.includes(name) : name => blockName === name;
return parents.filter(id => hasName(getBlockName(state, id)));
}, state => [state.blocks.parents]);
* Given a block client ID, returns the root of the hierarchy from which the block is nested, return the block itself for root level blocks.
* @param {Object} state Editor state.
* @param {string} clientId Block from which to find root client ID.
* @return {string} Root client ID
function getBlockHierarchyRootClientId(state, clientId) {
current = state.blocks.parents.get(current);
* Given a block client ID, returns the lowest common ancestor with selected client ID.
* @param {Object} state Editor state.
* @param {string} clientId Block from which to find common ancestor client ID.
* @return {string} Common ancestor client ID or undefined
function getLowestCommonAncestorWithSelectedBlock(state, clientId) {
const selectedId = getSelectedBlockClientId(state);
const clientParents = [...getBlockParents(state, clientId), clientId];
const selectedParents = [...getBlockParents(state, selectedId), selectedId];
let lowestCommonAncestor;
const maxDepth = Math.min(clientParents.length, selectedParents.length);
for (let index = 0; index < maxDepth; index++) {
if (clientParents[index] === selectedParents[index]) {
lowestCommonAncestor = clientParents[index];
return lowestCommonAncestor;
* Returns the client ID of the block adjacent one at the given reference
* startClientId and modifier directionality. Defaults start startClientId to
* the selected block, and direction as next block. Returns null if there is no
* @param {Object} state Editor state.
* @param {?string} startClientId Optional client ID of block from which to
* @param {?number} modifier Directionality multiplier (1 next, -1
* @return {?string} Return the client ID of the block, or null if none exists.
function getAdjacentBlockClientId(state, startClientId, modifier = 1) {
// Default to selected block.
if (startClientId === undefined) {
startClientId = getSelectedBlockClientId(state);
// Try multi-selection starting at extent based on modifier.
if (startClientId === undefined) {
startClientId = getFirstMultiSelectedBlockClientId(state);
startClientId = getLastMultiSelectedBlockClientId(state);
// Validate working start client ID.
// Retrieve start block root client ID, being careful to allow the falsey
// empty string top-level root by explicitly testing against null.
const rootClientId = getBlockRootClientId(state, startClientId);
if (rootClientId === null) {
const orderSet = order.get(rootClientId);
const index = orderSet.indexOf(startClientId);
const nextIndex = index + 1 * modifier;
// Block was first in set and we're attempting to get previous.
// Block was last in set and we're attempting to get next.
if (nextIndex === orderSet.length) {
// Assume incremented index is within the set.
return orderSet[nextIndex];
* Returns the previous block's client ID from the given reference start ID.
* Defaults start to the selected block. Returns null if there is no previous
* @param {Object} state Editor state.
* @param {?string} startClientId Optional client ID of block from which to
* @return {?string} Adjacent block's client ID, or null if none exists.
function getPreviousBlockClientId(state, startClientId) {
return getAdjacentBlockClientId(state, startClientId, -1);
* Returns the next block's client ID from the given reference start ID.
* Defaults start to the selected block. Returns null if there is no next
* @param {Object} state Editor state.
* @param {?string} startClientId Optional client ID of block from which to
* @return {?string} Adjacent block's client ID, or null if none exists.
function getNextBlockClientId(state, startClientId) {
return getAdjacentBlockClientId(state, startClientId, 1);
/* eslint-disable jsdoc/valid-types */
* Returns the initial caret position for the selected block.
* This position is to used to position the caret properly when the selected block changes.
* If the current block is not a RichText, having initial position set to 0 means "focus block"
* @param {Object} state Global application state.
* @return {0|-1|null} Initial position.
function getSelectedBlocksInitialCaretPosition(state) {
/* eslint-enable jsdoc/valid-types */
return state.initialPosition;
* Returns the current selection set of block client IDs (multiselection or single selection).
* @param {Object} state Editor state.
* @return {Array} Multi-selected block client IDs.
const getSelectedBlockClientIds = (0,external_wp_data_namespaceObject.createSelector)(state => {
if (!selectionStart.clientId || !selectionEnd.clientId) {
return selectors_EMPTY_ARRAY;
if (selectionStart.clientId === selectionEnd.clientId) {
return [selectionStart.clientId];
// Retrieve root client ID to aid in retrieving relevant nested block
// order, being careful to allow the falsey empty string top-level root
// by explicitly testing against null.
const rootClientId = getBlockRootClientId(state, selectionStart.clientId);
if (rootClientId === null) {
return selectors_EMPTY_ARRAY;
const blockOrder = getBlockOrder(state, rootClientId);
const startIndex = blockOrder.indexOf(selectionStart.clientId);
const endIndex = blockOrder.indexOf(selectionEnd.clientId);
if (startIndex > endIndex) {
return blockOrder.slice(endIndex, startIndex + 1);
return blockOrder.slice(startIndex, endIndex + 1);
}, state => [state.blocks.order, state.selection.selectionStart.clientId, state.selection.selectionEnd.clientId]);
* Returns the current multi-selection set of block client IDs, or an empty
* array if there is no multi-selection.
* @param {Object} state Editor state.
* @return {Array} Multi-selected block client IDs.
function getMultiSelectedBlockClientIds(state) {
if (selectionStart.clientId === selectionEnd.clientId) {
return selectors_EMPTY_ARRAY;
return getSelectedBlockClientIds(state);
* Returns the current multi-selection set of blocks, or an empty array if
* there is no multi-selection.
* @param {Object} state Editor state.
* @return {Array} Multi-selected block objects.
const getMultiSelectedBlocks = (0,external_wp_data_namespaceObject.createSelector)(state => {
const multiSelectedBlockClientIds = getMultiSelectedBlockClientIds(state);
if (!multiSelectedBlockClientIds.length) {
return selectors_EMPTY_ARRAY;
return multiSelectedBlockClientIds.map(clientId => getBlock(state, clientId));
}, state => [...getSelectedBlockClientIds.getDependants(state), state.blocks.byClientId, state.blocks.order, state.blocks.attributes]);
* Returns the client ID of the first block in the multi-selection set, or null
* if there is no multi-selection.
* @param {Object} state Editor state.
* @return {?string} First block client ID in the multi-selection set.
function getFirstMultiSelectedBlockClientId(state) {
return getMultiSelectedBlockClientIds(state)[0] || null;
* Returns the client ID of the last block in the multi-selection set, or null
* if there is no multi-selection.
* @param {Object} state Editor state.