: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @param kind Entity kind.
* @param name Entity name.
function getEntityConfig(state, kind, name) {
return state.entities.config?.find(config => config.kind === kind && config.name === name);
* GetEntityRecord is declared as a *callable interface* with
* two signatures to work around the fact that TypeScript doesn't
* allow currying generic functions:
* type CurriedState = F extends ( state: any, ...args: infer P ) => infer R
* type Selector = <K extends string | number>(
* key: K extends string ? 'string value' : false
* type BadlyInferredSignature = CurriedState< Selector >
* // BadlyInferredSignature evaluates to:
* // (kind: string number, key: false | "string value") => string number
* The signature without the state parameter shipped as CurriedSignature
* is used in the return value of `select( coreStore )`.
* See https://github.com/WordPress/gutenberg/pull/41578 for more details.
* Returns the Entity's record object by key. Returns `null` if the value is not
* yet received, undefined if the value entity is known to not exist, or the
* entity object if it exists and is received.
* @param state State tree
* @param kind Entity kind.
* @param name Entity name.
* @param key Record's key
* @param query Optional query. If requesting specific
* fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available "Retrieve a [Entity kind]".
const getEntityRecord = (0,external_wp_data_namespaceObject.createSelector)((state, kind, name, key, query) => {
const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
const context = (_query$context = query?.context) !== null && _query$context !== void 0 ? _query$context : 'default';
if (query === undefined) {
// If expecting a complete item, validate that completeness.
if (!queriedState.itemIsComplete[context]?.[key]) {
return queriedState.items[context][key];
const item = queriedState.items[context]?.[key];
if (item && query._fields) {
var _getNormalizedCommaSe;
const fields = (_getNormalizedCommaSe = get_normalized_comma_separable(query._fields)) !== null && _getNormalizedCommaSe !== void 0 ? _getNormalizedCommaSe : [];
for (let f = 0; f < fields.length; f++) {
const field = fields[f].split('.');
field.forEach(fieldName => {
value = value?.[fieldName];
setNestedValue(filteredItem, field, value);
}, (state, kind, name, recordId, query) => {
const context = (_query$context2 = query?.context) !== null && _query$context2 !== void 0 ? _query$context2 : 'default';
return [state.entities.records?.[kind]?.[name]?.queriedData?.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData?.itemIsComplete[context]?.[recordId]];
* Normalizes `recordKey`s that look like numeric IDs to numbers.
* @param args EntityRecordArgs the selector arguments.
* @return EntityRecordArgs the normalized arguments.
getEntityRecord.__unstableNormalizeArgs = args => {
const newArgs = [...args];
const recordKey = newArgs?.[2];
// If recordKey looks to be a numeric ID then coerce to number.
newArgs[2] = isNumericID(recordKey) ? Number(recordKey) : recordKey;
* Returns the Entity's record object by key. Doesn't trigger a resolver nor requests the entity records from the API if the entity record isn't available in the local state.
* @param state State tree
* @param kind Entity kind.
* @param name Entity name.
* @param key Record's key
function __experimentalGetEntityRecordNoResolver(state, kind, name, key) {
return getEntityRecord(state, kind, name, key);
* Returns the entity's record object by key,
* with its attributes mapped to their raw values.
* @param state State tree.
* @param kind Entity kind.
* @param name Entity name.
* @param key Record's key.
* @return Object with the entity's raw attributes.
const getRawEntityRecord = (0,external_wp_data_namespaceObject.createSelector)((state, kind, name, key) => {
const record = getEntityRecord(state, kind, name, key);
return record && Object.keys(record).reduce((accumulator, _key) => {
if (isRawAttribute(getEntityConfig(state, kind, name), _key)) {
// Because edits are the "raw" attribute values,
// we return those from record selectors to make rendering,
// comparisons, and joins with edits easier.
accumulator[_key] = (_record$_key$raw = record[_key]?.raw) !== null && _record$_key$raw !== void 0 ? _record$_key$raw : record[_key];
accumulator[_key] = record[_key];
}, (state, kind, name, recordId, query) => {
const context = (_query$context3 = query?.context) !== null && _query$context3 !== void 0 ? _query$context3 : 'default';
return [state.entities.config, state.entities.records?.[kind]?.[name]?.queriedData?.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData?.itemIsComplete[context]?.[recordId]];
* Returns true if records have been received for the given set of parameters,
* @param state State tree
* @param kind Entity kind.
* @param name Entity name.
* @param query Optional terms query. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for "List [Entity kind]s".
* @return Whether entity records have been received.
function hasEntityRecords(state, kind, name, query) {
return Array.isArray(getEntityRecords(state, kind, name, query));
* GetEntityRecord is declared as a *callable interface* with
* two signatures to work around the fact that TypeScript doesn't
* allow currying generic functions.
* @see https://github.com/WordPress/gutenberg/pull/41578
* Returns the Entity's records.
* @param state State tree
* @param kind Entity kind.
* @param name Entity name.
* @param query Optional terms query. If requesting specific
* fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for "List [Entity kind]s".
const getEntityRecords = (state, kind, name, query) => {
// Queried data state is prepopulated for all known entities. If this is not
// assigned for the given parameters, then it is known to not exist.
const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
return getQueriedItems(queriedState, query);
* Returns the Entity's total available records for a given query (ignoring pagination).
* @param state State tree
* @param kind Entity kind.
* @param name Entity name.
* @param query Optional terms query. If requesting specific
* fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for "List [Entity kind]s".
const getEntityRecordsTotalItems = (state, kind, name, query) => {
// Queried data state is prepopulated for all known entities. If this is not
// assigned for the given parameters, then it is known to not exist.
const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
return getQueriedTotalItems(queriedState, query);
* Returns the number of available pages for the given query.
* @param state State tree
* @param kind Entity kind.
* @param name Entity name.
* @param query Optional terms query. If requesting specific
* fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for "List [Entity kind]s".
const getEntityRecordsTotalPages = (state, kind, name, query) => {
// Queried data state is prepopulated for all known entities. If this is not
// assigned for the given parameters, then it is known to not exist.
const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
if (query.per_page === -1) {
const totalItems = getQueriedTotalItems(queriedState, query);
// If `per_page` is not set and the query relies on the defaults of the
// REST endpoint, get the info from query's meta.
return getQueriedTotalPages(queriedState, query);
return Math.ceil(totalItems / query.per_page);
* Returns the list of dirty entity records.
* @param state State tree.
* @return The list of updated records
const __experimentalGetDirtyEntityRecords = (0,external_wp_data_namespaceObject.createSelector)(state => {
Object.keys(records).forEach(kind => {
Object.keys(records[kind]).forEach(name => {
const primaryKeys = Object.keys(records[kind][name].edits).filter(primaryKey =>
// The entity record must exist (not be deleted),
// and it must have edits.
getEntityRecord(state, kind, name, primaryKey) && hasEditsForEntityRecord(state, kind, name, primaryKey));
if (primaryKeys.length) {
const entityConfig = getEntityConfig(state, kind, name);
primaryKeys.forEach(primaryKey => {
const entityRecord = getEditedEntityRecord(state, kind, name, primaryKey);
// We avoid using primaryKey because it's transformed into a string
// when it's used as an object key.
key: entityRecord ? entityRecord[entityConfig.key || DEFAULT_ENTITY_KEY] : undefined,
title: entityConfig?.getTitle?.(entityRecord) || '',
}, state => [state.entities.records]);
* Returns the list of entities currently being saved.
* @param state State tree.
* @return The list of records being saved.
const __experimentalGetEntitiesBeingSaved = (0,external_wp_data_namespaceObject.createSelector)(state => {
const recordsBeingSaved = [];
Object.keys(records).forEach(kind => {
Object.keys(records[kind]).forEach(name => {
const primaryKeys = Object.keys(records[kind][name].saving).filter(primaryKey => isSavingEntityRecord(state, kind, name, primaryKey));
if (primaryKeys.length) {
const entityConfig = getEntityConfig(state, kind, name);
primaryKeys.forEach(primaryKey => {
const entityRecord = getEditedEntityRecord(state, kind, name, primaryKey);
// We avoid using primaryKey because it's transformed into a string
// when it's used as an object key.
key: entityRecord ? entityRecord[entityConfig.key || DEFAULT_ENTITY_KEY] : undefined,
title: entityConfig?.getTitle?.(entityRecord) || '',
return recordsBeingSaved;
}, state => [state.entities.records]);
* Returns the specified entity record's edits.
* @param state State tree.
* @param kind Entity kind.
* @param name Entity name.
* @param recordId Record ID.
* @return The entity record's edits.
function getEntityRecordEdits(state, kind, name, recordId) {
return state.entities.records?.[kind]?.[name]?.edits?.[recordId];
* Returns the specified entity record's non transient edits.
* Transient edits don't create an undo level, and
* are not considered for change detection.
* They are defined in the entity's config.
* @param state State tree.
* @param kind Entity kind.
* @param name Entity name.
* @param recordId Record ID.
* @return The entity record's non transient edits.
const getEntityRecordNonTransientEdits = (0,external_wp_data_namespaceObject.createSelector)((state, kind, name, recordId) => {
} = getEntityConfig(state, kind, name) || {};
const edits = getEntityRecordEdits(state, kind, name, recordId) || {};
return Object.keys(edits).reduce((acc, key) => {
if (!transientEdits[key]) {
}, (state, kind, name, recordId) => [state.entities.config, state.entities.records?.[kind]?.[name]?.edits?.[recordId]]);
* Returns true if the specified entity record has edits,
* @param state State tree.
* @param kind Entity kind.
* @param name Entity name.
* @param recordId Record ID.
* @return Whether the entity record has edits or not.
function hasEditsForEntityRecord(state, kind, name, recordId) {
return isSavingEntityRecord(state, kind, name, recordId) || Object.keys(getEntityRecordNonTransientEdits(state, kind, name, recordId)).length > 0;
* Returns the specified entity record, merged with its edits.
* @param state State tree.
* @param kind Entity kind.
* @param name Entity name.
* @param recordId Record ID.
* @return The entity record, merged with its edits.
const getEditedEntityRecord = (0,external_wp_data_namespaceObject.createSelector)((state, kind, name, recordId) => {
const raw = getRawEntityRecord(state, kind, name, recordId);
const edited = getEntityRecordEdits(state, kind, name, recordId);
// Never return a non-falsy empty object. Unfortunately we can't return
// undefined or null because we were previously returning an empty
// object, so trying to read properties from the result would throw.
// Using false here is a workaround to avoid breaking changes.
}, (state, kind, name, recordId, query) => {
const context = (_query$context4 = query?.context) !== null && _query$context4 !== void 0 ? _query$context4 : 'default';
return [state.entities.config, state.entities.records?.[kind]?.[name]?.queriedData.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData.itemIsComplete[context]?.[recordId], state.entities.records?.[kind]?.[name]?.edits?.[recordId]];
* Returns true if the specified entity record is autosaving, and false otherwise.
* @param state State tree.
* @param kind Entity kind.
* @param name Entity name.
* @param recordId Record ID.
* @return Whether the entity record is autosaving or not.
function isAutosavingEntityRecord(state, kind, name, recordId) {
var _state$entities$recor;
} = (_state$entities$recor = state.entities.records?.[kind]?.[name]?.saving?.[recordId]) !== null && _state$entities$recor !== void 0 ? _state$entities$recor : {};
return Boolean(pending && isAutosave);
* Returns true if the specified entity record is saving, and false otherwise.
* @param state State tree.
* @param kind Entity kind.
* @param name Entity name.
* @param recordId Record ID.
* @return Whether the entity record is saving or not.
function isSavingEntityRecord(state, kind, name, recordId) {
var _state$entities$recor2;
return (_state$entities$recor2 = state.entities.records?.[kind]?.[name]?.saving?.[recordId]?.pending) !== null && _state$entities$recor2 !== void 0 ? _state$entities$recor2 : false;
* Returns true if the specified entity record is deleting, and false otherwise.
* @param state State tree.
* @param kind Entity kind.
* @param name Entity name.
* @param recordId Record ID.
* @return Whether the entity record is deleting or not.
function isDeletingEntityRecord(state, kind, name, recordId) {
var _state$entities$recor3;
return (_state$entities$recor3 = state.entities.records?.[kind]?.[name]?.deleting?.[recordId]?.pending) !== null && _state$entities$recor3 !== void 0 ? _state$entities$recor3 : false;
* Returns the specified entity record's last save error.
* @param state State tree.
* @param kind Entity kind.
* @param name Entity name.
* @param recordId Record ID.
* @return The entity record's save error.
function getLastEntitySaveError(state, kind, name, recordId) {
return state.entities.records?.[kind]?.[name]?.saving?.[recordId]?.error;
* Returns the specified entity record's last delete error.
* @param state State tree.
* @param kind Entity kind.
* @param name Entity name.
* @param recordId Record ID.
* @return The entity record's save error.
function getLastEntityDeleteError(state, kind, name, recordId) {
return state.entities.records?.[kind]?.[name]?.deleting?.[recordId]?.error;
* Returns the previous edit from the current undo offset
* for the entity records edits history, if any.
* @param state State tree.
function getUndoEdit(state) {
external_wp_deprecated_default()("select( 'core' ).getUndoEdit()", {