: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
selectorName: 'getEntityRecord',
dispatch.__unstableReleaseStoreLock(lock);
dispatch.__unstableReleaseStoreLock(lock);
resolvers_getEntityRecords.shouldInvalidate = (action, kind, name) => {
return (action.type === 'RECEIVE_ITEMS' || action.type === 'REMOVE_ITEMS') && action.invalidateCache && kind === action.kind && name === action.name;
* Requests the current theme.
const resolvers_getCurrentTheme = () => async ({
const activeThemes = await resolveSelect.getEntityRecords('root', 'theme', {
dispatch.receiveCurrentTheme(activeThemes[0]);
* Requests theme supports data from the index.
const resolvers_getThemeSupports = forward_resolver('getCurrentTheme');
* Requests a preview from the Embed API.
* @param {string} url URL to get the preview for.
const resolvers_getEmbedPreview = url => async ({
const embedProxyResponse = await external_wp_apiFetch_default()({
path: (0,external_wp_url_namespaceObject.addQueryArgs)('/oembed/1.0/proxy', {
dispatch.receiveEmbedPreview(url, embedProxyResponse);
// Embed API 404s if the URL cannot be embedded, so we have to catch the error from the apiRequest here.
dispatch.receiveEmbedPreview(url, false);
* Checks whether the current user can perform the given action on the given
* @param {string} requestedAction Action to check. One of: 'create', 'read', 'update',
* @param {string} resource REST resource to check, e.g. 'media' or 'posts'.
* @param {?string} id ID of the rest resource to check.
const resolvers_canUser = (requestedAction, resource, id) => async ({
} = registry.select(STORE_NAME);
const resourcePath = id ? `${resource}/${id}` : resource;
const retrievedActions = ['create', 'read', 'update', 'delete'];
if (!retrievedActions.includes(requestedAction)) {
throw new Error(`'${requestedAction}' is not a valid action.`);
// Prevent resolving the same resource twice.
for (const relatedAction of retrievedActions) {
if (relatedAction === requestedAction) {
const isAlreadyResolving = hasStartedResolution('canUser', [relatedAction, resource, id]);
if (isAlreadyResolving) {
response = await external_wp_apiFetch_default()({
path: `/wp/v2/${resourcePath}`,
// Do nothing if our OPTIONS request comes back with an API error (4xx or
// 5xx). The previously determined isAllowed value will remain in the store.
// Optional chaining operator is used here because the API requests don't
// return the expected result in the native version. Instead, API requests
// only return the result, without including response properties like the headers.
const allowHeader = response.headers?.get('allow');
const allowedMethods = allowHeader?.allow || allowHeader || '';
for (const [actionName, methodName] of Object.entries(methods)) {
permissions[actionName] = allowedMethods.includes(methodName);
for (const action of retrievedActions) {
dispatch.receiveUserPermission(`${action}/${resourcePath}`, permissions[action]);
* Checks whether the current user can perform the given action on the given
* @param {string} kind Entity kind.
* @param {string} name Entity name.
* @param {string} recordId Record's id.
const resolvers_canUserEditEntityRecord = (kind, name, recordId) => async ({
const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
const entityConfig = configs.find(config => config.name === name && config.kind === kind);
const resource = entityConfig.__unstable_rest_base;
await dispatch(resolvers_canUser('update', resource, recordId));
* Request autosave data from the REST API.
* @param {string} postType The type of the parent post.
* @param {number} postId The id of the parent post.
const resolvers_getAutosaves = (postType, postId) => async ({
rest_namespace: restNamespace = 'wp/v2'
} = await resolveSelect.getPostType(postType);
const autosaves = await external_wp_apiFetch_default()({
path: `/${restNamespace}/${restBase}/${postId}/autosaves?context=edit`
if (autosaves && autosaves.length) {
dispatch.receiveAutosaves(postId, autosaves);
* Request autosave data from the REST API.
* This resolver exists to ensure the underlying autosaves are fetched via
* `getAutosaves` when a call to the `getAutosave` selector is made.
* @param {string} postType The type of the parent post.
* @param {number} postId The id of the parent post.
const resolvers_getAutosave = (postType, postId) => async ({
await resolveSelect.getAutosaves(postType, postId);
* Retrieve the frontend template used for a given link.
* @param {string} link Link.
const resolvers_experimentalGetTemplateForLink = link => async ({
// This is NOT calling a REST endpoint but rather ends up with a response from
// an Ajax function which has a different shape from a WP_REST_Response.
template = await external_wp_apiFetch_default()({
url: (0,external_wp_url_namespaceObject.addQueryArgs)(link, {
'_wp-find-template': true
// For non-FSE themes, it is possible that this request returns an error.
const record = await resolveSelect.getEntityRecord('postType', 'wp_template', template.id);
dispatch.receiveEntityRecords('postType', 'wp_template', [record], {
resolvers_experimentalGetTemplateForLink.shouldInvalidate = action => {
return (action.type === 'RECEIVE_ITEMS' || action.type === 'REMOVE_ITEMS') && action.invalidateCache && action.kind === 'postType' && action.name === 'wp_template';
const resolvers_experimentalGetCurrentGlobalStylesId = () => async ({
const activeThemes = await resolveSelect.getEntityRecords('root', 'theme', {
const globalStylesURL = activeThemes?.[0]?._links?.['wp:user-global-styles']?.[0]?.href;
// Regex matches the ID at the end of a URL or immediately before
const matches = globalStylesURL.match(/\/(\d+)(?:\?|$)/);
const id = matches ? Number(matches[1]) : null;
dispatch.__experimentalReceiveCurrentGlobalStylesId(id);
const resolvers_experimentalGetCurrentThemeBaseGlobalStyles = () => async ({
const currentTheme = await resolveSelect.getCurrentTheme();
const themeGlobalStyles = await external_wp_apiFetch_default()({
path: `/wp/v2/global-styles/themes/${currentTheme.stylesheet}`
dispatch.__experimentalReceiveThemeBaseGlobalStyles(currentTheme.stylesheet, themeGlobalStyles);
const resolvers_experimentalGetCurrentThemeGlobalStylesVariations = () => async ({
const currentTheme = await resolveSelect.getCurrentTheme();
const variations = await external_wp_apiFetch_default()({
path: `/wp/v2/global-styles/themes/${currentTheme.stylesheet}/variations`
dispatch.__experimentalReceiveThemeGlobalStyleVariations(currentTheme.stylesheet, variations);
* Fetches and returns the revisions of the current global styles theme.
const resolvers_getCurrentThemeGlobalStylesRevisions = () => async ({
const globalStylesId = await resolveSelect.__experimentalGetCurrentGlobalStylesId();
const record = globalStylesId ? await resolveSelect.getEntityRecord('root', 'globalStyles', globalStylesId) : undefined;
const revisionsURL = record?._links?.['version-history']?.[0]?.href;
const resetRevisions = await external_wp_apiFetch_default()({
const revisions = resetRevisions?.map(revision => Object.fromEntries(Object.entries(revision).map(([key, value]) => [camelCase(key), value])));
dispatch.receiveThemeGlobalStyleRevisions(globalStylesId, revisions);
resolvers_getCurrentThemeGlobalStylesRevisions.shouldInvalidate = action => {
return action.type === 'SAVE_ENTITY_RECORD_FINISH' && action.kind === 'root' && !action.error && action.name === 'globalStyles';
const resolvers_getBlockPatterns = () => async ({
const patterns = await fetchBlockPatterns();
type: 'RECEIVE_BLOCK_PATTERNS',
const resolvers_getBlockPatternCategories = () => async ({
const categories = await external_wp_apiFetch_default()({
path: '/wp/v2/block-patterns/categories'
type: 'RECEIVE_BLOCK_PATTERN_CATEGORIES',
const resolvers_getUserPatternCategories = () => async ({
const patternCategories = await resolveSelect.getEntityRecords('taxonomy', 'wp_pattern_category', {
_fields: 'id,name,description,slug',
const mappedPatternCategories = patternCategories?.map(userCategory => ({
label: (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(userCategory.name),
type: 'RECEIVE_USER_PATTERN_CATEGORIES',
patternCategories: mappedPatternCategories
const resolvers_getNavigationFallbackId = () => async ({
const fallback = await external_wp_apiFetch_default()({
path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp-block-editor/v1/navigation-fallback', {
const record = fallback?._embedded?.self;
dispatch.receiveNavigationFallbackId(fallback?.id);
// If the fallback is already in the store, don't invalidate navigation queries.
// Otherwise, invalidate the cache for the scenario where there were no Navigation
// posts in the state and the fallback created one.
const existingFallbackEntityRecord = select.getEntityRecord('postType', 'wp_navigation', fallback.id);
const invalidateNavigationQueries = !existingFallbackEntityRecord;
dispatch.receiveEntityRecords('postType', 'wp_navigation', record, undefined, invalidateNavigationQueries);
// Resolve to avoid further network requests.
dispatch.finishResolution('getEntityRecord', ['postType', 'wp_navigation', fallback.id]);
const resolvers_getDefaultTemplateId = query => async ({
const template = await external_wp_apiFetch_default()({
path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/templates/lookup', query)
// Endpoint may return an empty object if no template is found.
dispatch.receiveDefaultTemplateId(query, template.id);
* Requests an entity's revisions from the REST API.
* @param {string} kind Entity kind.
* @param {string} name Entity name.
* @param {number|string} recordKey The key of the entity record whose revisions you want to fetch.
* @param {Object|undefined} query Optional object of query parameters to
* include with request. If requesting specific
* fields, fields must always include the ID.
const resolvers_getRevisions = (kind, name, recordKey, query = {}) => async ({
const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
const entityConfig = configs.find(config => config.name === name && config.kind === kind);
if (!entityConfig || entityConfig?.__experimentalNoFetch) {
// If requesting specific fields, items and query association to said
// records are stored by ID reference. Thus, fields must always include
_fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.revisionKey || DEFAULT_ENTITY_KEY])].join()
const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.getRevisionsUrl(recordKey), query);
const isPaginated = entityConfig.supportsPagination && query.per_page !== -1;
response = await external_wp_apiFetch_default()({
// Do nothing if our request comes back with an API error.
records = Object.values(await response.json());
meta.totalItems = parseInt(response.headers.get('X-WP-Total'));
records = Object.values(response);
// If we request fields but the result doesn't contain the fields,
// explicitly set these fields as "undefined"
// that way we consider the query "fulfilled".
records = records.map(record => {
query._fields.split(',').forEach(field => {
if (!record.hasOwnProperty(field)) {
record[field] = undefined;
dispatch.receiveRevisions(kind, name, recordKey, records, query, false, meta);
// When requesting all fields, the list of results can be used to
// resolve the `getRevision` selector in addition to `getRevisions`.
if (!query?._fields && !query.context) {
const key = entityConfig.key || DEFAULT_ENTITY_KEY;
const resolutionsArgs = records.filter(record => record[key]).map(record => [kind, name, recordKey, record[key]]);
type: 'START_RESOLUTIONS',
selectorName: 'getRevision',
type: 'FINISH_RESOLUTIONS',
selectorName: 'getRevision',
// Invalidate cache when a new revision is created.
resolvers_getRevisions.shouldInvalidate = (action, kind, name, recordKey) => action.type === 'SAVE_ENTITY_RECORD_FINISH' && name === action.name && kind === action.kind && !action.error && recordKey === action.recordId;
* Requests a specific Entity revision from the REST API.
* @param {string} kind Entity kind.
* @param {string} name Entity name.
* @param {number|string} recordKey The key of the entity record whose revisions you want to fetch.
* @param {number|string} revisionKey The revision's key.
* @param {Object|undefined} query Optional object of query parameters to
* include with request. If requesting specific
* fields, fields must always include the ID.
const resolvers_getRevision = (kind, name, recordKey, revisionKey, query) => async ({
const configs = await dispatch(getOrLoadEntitiesConfig(kind, name));
const entityConfig = configs.find(config => config.name === name && config.kind === kind);
if (!entityConfig || entityConfig?.__experimentalNoFetch) {
if (query !== undefined && query._fields) {
// If requesting specific fields, items and query association to said
// records are stored by ID reference. Thus, fields must always include
_fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.revisionKey || DEFAULT_ENTITY_KEY])].join()
const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.getRevisionsUrl(recordKey, revisionKey), query);
record = await external_wp_apiFetch_default()({
// Do nothing if our request comes back with an API error.
dispatch.receiveRevisions(kind, name, recordKey, record, query);
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/locks/utils.js
function deepCopyLocksTreePath(tree, path) {
let currentNode = newTree;
for (const branchName of path) {
...currentNode.children[branchName]
currentNode = currentNode.children[branchName];
function getNode(tree, path) {
for (const branchName of path) {
const nextNode = currentNode.children[branchName];