: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
case 'REPLACE_BLOCKS_AUGMENTED_WITH_CHILDREN':
const newState = new Map(state);
action.replacedClientIds.forEach(clientId => {
newState.delete(clientId);
mapBlockParents(action.blocks, state.get(action.clientIds[0])).forEach(([key, value]) => {
newState.set(key, value);
case 'REMOVE_BLOCKS_AUGMENTED_WITH_CHILDREN':
const newState = new Map(state);
action.removedClientIds.forEach(clientId => {
newState.delete(clientId);
controlledInnerBlocks(state = {}, {
if (type === 'SET_HAS_CONTROLLED_INNER_BLOCKS') {
[clientId]: hasControlledInnerBlocks
* Reducer returning visibility status of block interface.
* @param {boolean} state Current state.
* @param {Object} action Dispatched action.
* @return {boolean} Updated state.
function isBlockInterfaceHidden(state = false, action) {
case 'HIDE_BLOCK_INTERFACE':
case 'SHOW_BLOCK_INTERFACE':
* Reducer returning typing state.
* @param {boolean} state Current state.
* @param {Object} action Dispatched action.
* @return {boolean} Updated state.
function isTyping(state = false, action) {
* Reducer returning dragging state. It is possible for a user to be dragging
* data from outside of the editor, so this state is separate from `draggedBlocks`.
* @param {boolean} state Current state.
* @param {Object} action Dispatched action.
* @return {boolean} Updated state.
function isDragging(state = false, action) {
* Reducer returning dragged block client id.
* @param {string[]} state Current state.
* @param {Object} action Dispatched action.
* @return {string[]} Updated state.
function draggedBlocks(state = [], action) {
case 'START_DRAGGING_BLOCKS':
case 'STOP_DRAGGING_BLOCKS':
* Reducer tracking the visible blocks.
* @param {Record<string,boolean>} state Current state.
* @param {Object} action Dispatched action.
* @return {Record<string,boolean>} Block visibility.
function blockVisibility(state = {}, action) {
if (action.type === 'SET_BLOCK_VISIBILITY') {
* Internal helper reducer for selectionStart and selectionEnd. Can hold a block
* selection, represented by an object with property clientId.
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
* @return {Object} Updated state.
function selectionHelper(state = {}, action) {
case 'CLEAR_SELECTED_BLOCK':
if (action.clientId === state.clientId) {
clientId: action.clientId
case 'REPLACE_INNER_BLOCKS':
if (!action.updateSelection || !action.blocks.length) {
clientId: action.blocks[0].clientId
if (!action.clientIds || !action.clientIds.length || action.clientIds.indexOf(state.clientId) === -1) {
if (action.clientIds.indexOf(state.clientId) === -1) {
const blockToSelect = action.blocks[action.indexToSelect] || action.blocks[action.blocks.length - 1];
if (blockToSelect.clientId === state.clientId) {
clientId: blockToSelect.clientId
* Reducer returning the selection state.
* @param {boolean} state Current state.
* @param {Object} action Dispatched action.
* @return {boolean} Updated state.
function selection(state = {}, action) {
clientId: action.clientId,
attributeKey: action.attributeKey,
offset: action.startOffset
clientId: action.clientId,
attributeKey: action.attributeKey,
selectionStart: action.start || state.selectionStart,
selectionEnd: action.end || state.selectionEnd
if (start === state.selectionStart?.clientId && end === state.selectionEnd?.clientId) {
const startClientId = state?.selectionStart?.clientId;
const endClientId = state?.selectionEnd?.clientId;
// Do nothing if there's no selected block.
if (!startClientId && !endClientId) {
// If the start of the selection won't exist after reset, remove selection.
if (!action.blocks.some(block => block.clientId === startClientId)) {
// If the end of the selection won't exist after reset, collapse selection.
if (!action.blocks.some(block => block.clientId === endClientId)) {
selectionEnd: state.selectionStart
const selectionStart = selectionHelper(state.selectionStart, action);
const selectionEnd = selectionHelper(state.selectionEnd, action);
if (selectionStart === state.selectionStart && selectionEnd === state.selectionEnd) {
* Reducer returning whether the user is multi-selecting.
* @param {boolean} state Current state.
* @param {Object} action Dispatched action.
* @return {boolean} Updated state.
function isMultiSelecting(state = false, action) {
case 'START_MULTI_SELECT':
case 'STOP_MULTI_SELECT':
* Reducer returning whether selection is enabled.
* @param {boolean} state Current state.
* @param {Object} action Dispatched action.
* @return {boolean} Updated state.
function isSelectionEnabled(state = true, action) {
return action.isSelectionEnabled;
* Reducer returning the data needed to display a prompt when certain blocks
* are removed, or `false` if no such prompt is requested.
* @param {boolean} state Current state.
* @param {Object} action Dispatched action.
* @return {Object|false} Data for removal prompt display, if any.
function removalPromptData(state = false, action) {
case 'DISPLAY_BLOCK_REMOVAL_PROMPT':
case 'CLEAR_BLOCK_REMOVAL_PROMPT':
* Reducer returning any rules that a block editor may provide in order to
* prevent a user from accidentally removing certain blocks. These rules are
* then used to display a confirmation prompt to the user. For instance, in the
* Site Editor, the Query Loop block is important enough to warrant such
* The data is a record whose keys are block types (e.g. 'core/query') and
* whose values are the explanation to be shown to users (e.g. 'Query Loop
* displays a list of posts or pages.').
* @param {boolean} state Current state.
* @param {Object} action Dispatched action.
* @return {Record<string,string>} Updated state.
function blockRemovalRules(state = false, action) {
case 'SET_BLOCK_REMOVAL_RULES':
* Reducer returning the initial block selection.
* Currently this in only used to restore the selection after block deletion and
* pasting new content.This reducer should eventually be removed in favour of setting
* @param {boolean} state Current state.
* @param {Object} action Dispatched action.
* @return {number|null} Initial position: 0, -1 or null.
function initialPosition(state = null, action) {
if (action.type === 'REPLACE_BLOCKS' && action.initialPosition !== undefined) {
return action.initialPosition;
} else if (['MULTI_SELECT', 'SELECT_BLOCK', 'RESET_SELECTION', 'INSERT_BLOCKS', 'REPLACE_INNER_BLOCKS'].includes(action.type)) {
return action.initialPosition;
function blocksMode(state = {}, action) {
if (action.type === 'TOGGLE_BLOCK_MODE') {
[clientId]: state[clientId] && state[clientId] === 'html' ? 'visual' : 'html'
* Reducer returning the block insertion point visibility, either null if there
* is not an explicit insertion point assigned, or an object of its `index` and
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
* @return {Object} Updated state.
function insertionPoint(state = null, action) {
case 'SHOW_INSERTION_POINT':
// Bail out updates if the states are the same.
return es6_default()(state, nextState) ? state : nextState;
case 'HIDE_INSERTION_POINT':
* Reducer returning whether the post blocks match the defined template or not.
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
* @return {boolean} Updated state.
function template(state = {
case 'SET_TEMPLATE_VALIDITY':
* Reducer returning the editor setting.
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
* @return {Object} Updated state.
function settings(state = SETTINGS_DEFAULTS, action) {
* Reducer returning the user preferences.
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
* @return {string} Updated state.
function preferences(state = PREFERENCES_DEFAULTS, action) {
const nextInsertUsage = action.blocks.reduce((prevUsage, block) => {