: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
const isEditedPostEmpty = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => state => {
// While the condition of truthy content string is sufficient to determine
// emptiness, testing saveable blocks length is a trivial operation. Since
// this function can be called frequently, optimize for the fast case as a
// condition of the mere existence of blocks. Note that the value of edited
// content takes precedent over block content, and must fall through to the
const postId = getCurrentPostId(state);
const postType = getCurrentPostType(state);
const record = select(external_wp_coreData_namespaceObject.store).getEditedEntityRecord('postType', postType, postId);
if (typeof record.content !== 'function') {
const blocks = getEditedPostAttribute(state, 'blocks');
if (blocks.length === 0) {
// Pierce the abstraction of the serializer in knowing that blocks are
// joined with newlines such that even if every individual block
// produces an empty save result, the serialized content is non-empty.
// There are two conditions under which the optimization cannot be
// assumed, and a fallthrough to getEditedPostContent must occur:
// 1. getBlocksForSerialization has special treatment in omitting a
// single unmodified default block.
// 2. Comment delimiters are omitted for a freeform or unregistered
// block in its serialization. The freeform block specifically may
// produce an empty string in its saved output.
// For all other content, the single block is assumed to make a post
// non-empty, if only by virtue of its own comment delimiters.
const blockName = blocks[0].name;
if (blockName !== (0,external_wp_blocks_namespaceObject.getDefaultBlockName)() && blockName !== (0,external_wp_blocks_namespaceObject.getFreeformContentHandlerName)()) {
return !getEditedPostContent(state);
* Returns true if the post can be autosaved, or false otherwise.
* @param {Object} state Global application state.
* @param {Object} autosave A raw autosave object from the REST API.
* @return {boolean} Whether the post can be autosaved.
const isEditedPostAutosaveable = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => state => {
// A post must contain a title, an excerpt, or non-empty content to be valid for autosaving.
if (!isEditedPostSaveable(state)) {
// A post is not autosavable when there is a post autosave lock.
if (isPostAutosavingLocked(state)) {
const postType = getCurrentPostType(state);
// Currently template autosaving is not supported.
if (postType === 'wp_template') {
const postId = getCurrentPostId(state);
const hasFetchedAutosave = select(external_wp_coreData_namespaceObject.store).hasFetchedAutosaves(postType, postId);
const currentUserId = select(external_wp_coreData_namespaceObject.store).getCurrentUser()?.id;
// Disable reason - this line causes the side-effect of fetching the autosave
// via a resolver, moving below the return would result in the autosave never
// eslint-disable-next-line @wordpress/no-unused-vars-before-return
const autosave = select(external_wp_coreData_namespaceObject.store).getAutosave(postType, postId, currentUserId);
// If any existing autosaves have not yet been fetched, this function is
// unable to determine if the post is autosaveable, so return false.
if (!hasFetchedAutosave) {
// If we don't already have an autosave, the post is autosaveable.
// To avoid an expensive content serialization, use the content dirtiness
// flag in place of content field comparison against the known autosave.
// This is not strictly accurate, and relies on a tolerance toward autosave
// request failures for unnecessary saves.
if (hasChangedContent(state)) {
// If title, excerpt, or meta have changed, the post is autosaveable.
return ['title', 'excerpt', 'meta'].some(field => getPostRawValue(autosave[field]) !== getEditedPostAttribute(state, field));
* Return true if the post being edited is being scheduled. Preferring the
* @param {Object} state Global application state.
* @return {boolean} Whether the post has been published.
function isEditedPostBeingScheduled(state) {
const date = getEditedPostAttribute(state, 'date');
// Offset the date by one minute (network latency).
const checkedDate = new Date(Number((0,external_wp_date_namespaceObject.getDate)(date)) - ONE_MINUTE_IN_MS);
return (0,external_wp_date_namespaceObject.isInTheFuture)(checkedDate);
* Returns whether the current post should be considered to have a "floating"
* date (i.e. that it would publish "Immediately" rather than at a set time).
* Unlike in the PHP backend, the REST API returns a full date string for posts
* where the 0000-00-00T00:00:00 placeholder is present in the database. To
* infer that a post is set to publish "Immediately" we check whether the date
* and modified date are the same.
* @param {Object} state Editor state.
* @return {boolean} Whether the edited post has a floating date value.
function isEditedPostDateFloating(state) {
const date = getEditedPostAttribute(state, 'date');
const modified = getEditedPostAttribute(state, 'modified');
// This should be the status of the persisted post
// It shouldn't use the "edited" status otherwise it breaks the
// inferred post data floating status
// See https://github.com/WordPress/gutenberg/issues/28083.
const status = getCurrentPost(state).status;
if (status === 'draft' || status === 'auto-draft' || status === 'pending') {
return date === modified || date === null;
* Returns true if the post is currently being deleted, or false otherwise.
* @param {Object} state Editor state.
* @return {boolean} Whether post is being deleted.
function isDeletingPost(state) {
return !!state.deleting.pending;
* Returns true if the post is currently being saved, or false otherwise.
* @param {Object} state Global application state.
* @return {boolean} Whether post is being saved.
function isSavingPost(state) {
return !!state.saving.pending;
* Returns true if non-post entities are currently being saved, or false otherwise.
* @param {Object} state Global application state.
* @return {boolean} Whether non-post entities are being saved.
const isSavingNonPostEntityChanges = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => state => {
const entitiesBeingSaved = select(external_wp_coreData_namespaceObject.store).__experimentalGetEntitiesBeingSaved();
} = getCurrentPost(state);
return entitiesBeingSaved.some(entityRecord => entityRecord.kind !== 'postType' || entityRecord.name !== type || entityRecord.key !== id);
* Returns true if a previous post save was attempted successfully, or false
* @param {Object} state Global application state.
* @return {boolean} Whether the post was saved successfully.
const didPostSaveRequestSucceed = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => state => {
const postType = getCurrentPostType(state);
const postId = getCurrentPostId(state);
return !select(external_wp_coreData_namespaceObject.store).getLastEntitySaveError('postType', postType, postId);
* Returns true if a previous post save was attempted but failed, or false
* @param {Object} state Global application state.
* @return {boolean} Whether the post save failed.
const didPostSaveRequestFail = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => state => {
const postType = getCurrentPostType(state);
const postId = getCurrentPostId(state);
return !!select(external_wp_coreData_namespaceObject.store).getLastEntitySaveError('postType', postType, postId);
* Returns true if the post is autosaving, or false otherwise.
* @param {Object} state Global application state.
* @return {boolean} Whether the post is autosaving.
function isAutosavingPost(state) {
return isSavingPost(state) && Boolean(state.saving.options?.isAutosave);
* Returns true if the post is being previewed, or false otherwise.
* @param {Object} state Global application state.
* @return {boolean} Whether the post is being previewed.
function isPreviewingPost(state) {
return isSavingPost(state) && Boolean(state.saving.options?.isPreview);
* Returns the post preview link
* @param {Object} state Global application state.
* @return {string | undefined} Preview Link.
function getEditedPostPreviewLink(state) {
if (state.saving.pending || isSavingPost(state)) {
let previewLink = getAutosaveAttribute(state, 'preview_link');
// Fix for issue: https://github.com/WordPress/gutenberg/issues/33616
// If the post is draft, ignore the preview link from the autosave record,
// because the preview could be a stale autosave if the post was switched from
// See: https://github.com/WordPress/gutenberg/pull/37952.
if (!previewLink || 'draft' === getCurrentPost(state).status) {
previewLink = getEditedPostAttribute(state, 'link');
previewLink = (0,external_wp_url_namespaceObject.addQueryArgs)(previewLink, {
const featuredImageId = getEditedPostAttribute(state, 'featured_media');
if (previewLink && featuredImageId) {
return (0,external_wp_url_namespaceObject.addQueryArgs)(previewLink, {
_thumbnail_id: featuredImageId
* Returns a suggested post format for the current post, inferred only if there
* is a single block within the post and it is of a type known to match a
* default post format. Returns null if the format cannot be determined.
* @return {?string} Suggested post format.
const getSuggestedPostFormat = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => () => {
const blocks = select(external_wp_blockEditor_namespaceObject.store).getBlocks();
// If there is only one block in the content of the post grab its name
// so we can derive a suitable post format from it.
if (blocks.length === 1) {
// Check for core/embed `video` and `audio` eligible suggestions.
if (name === 'core/embed') {
const provider = blocks[0].attributes?.providerNameSlug;
if (['youtube', 'vimeo'].includes(provider)) {
} else if (['spotify', 'soundcloud'].includes(provider)) {
// If there are two blocks in the content and the last one is a text blocks
// grab the name of the first one to also suggest a post format from it.
if (blocks.length === 2 && blocks[1].name === 'core/paragraph') {
// We only convert to default post formats in core.
* Returns the content of the post being edited.
* @param {Object} state Global application state.
* @return {string} Post content.
const getEditedPostContent = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => state => {
const postId = getCurrentPostId(state);
const postType = getCurrentPostType(state);
const record = select(external_wp_coreData_namespaceObject.store).getEditedEntityRecord('postType', postType, postId);
if (typeof record.content === 'function') {
return record.content(record);
} else if (record.blocks) {
return (0,external_wp_blocks_namespaceObject.__unstableSerializeAndClean)(record.blocks);
} else if (record.content) {
* Returns true if the post is being published, or false otherwise.
* @param {Object} state Global application state.
* @return {boolean} Whether post is being published.
function isPublishingPost(state) {
return isSavingPost(state) && !isCurrentPostPublished(state) && getEditedPostAttribute(state, 'status') === 'publish';
* Returns whether the permalink is editable or not.
* @param {Object} state Editor state.
* @return {boolean} Whether or not the permalink is editable.
function isPermalinkEditable(state) {
const permalinkTemplate = getEditedPostAttribute(state, 'permalink_template');
return PERMALINK_POSTNAME_REGEX.test(permalinkTemplate);
* Returns the permalink for the post.
* @param {Object} state Editor state.
* @return {?string} The permalink, or null if the post is not viewable.
function getPermalink(state) {
const permalinkParts = getPermalinkParts(state);
if (isPermalinkEditable(state)) {
return prefix + postName + suffix;
* Returns the slug for the post being edited, preferring a manually edited
* value if one exists, then a sanitized version of the current post title, and
* @param {Object} state Editor state.
* @return {string} The current slug to be displayed in the editor
function getEditedPostSlug(state) {
return getEditedPostAttribute(state, 'slug') || (0,external_wp_url_namespaceObject.cleanForSlug)(getEditedPostAttribute(state, 'title')) || getCurrentPostId(state);
* Returns the permalink for a post, split into its three parts: the prefix,
* the postName, and the suffix.
* @param {Object} state Editor state.
* @return {Object} An object containing the prefix, postName, and suffix for
* the permalink, or null if the post is not viewable.
function getPermalinkParts(state) {
const permalinkTemplate = getEditedPostAttribute(state, 'permalink_template');
if (!permalinkTemplate) {
const postName = getEditedPostAttribute(state, 'slug') || getEditedPostAttribute(state, 'generated_slug');
const [prefix, suffix] = permalinkTemplate.split(PERMALINK_POSTNAME_REGEX);
* Returns whether the post is locked.
* @param {Object} state Global application state.
* @return {boolean} Is locked.
function isPostLocked(state) {
return state.postLock.isLocked;
* Returns whether post saving is locked.
* @param {Object} state Global application state.
* @return {boolean} Is locked.
function isPostSavingLocked(state) {
return Object.keys(state.postSavingLock).length > 0;
* Returns whether post autosaving is locked.
* @param {Object} state Global application state.
* @return {boolean} Is locked.
function isPostAutosavingLocked(state) {
return Object.keys(state.postAutosavingLock).length > 0;
* Returns whether the edition of the post has been taken over.
* @param {Object} state Global application state.
* @return {boolean} Is post lock takeover.
function isPostLockTakeover(state) {
return state.postLock.isTakeover;
* Returns details about the post lock user.
* @param {Object} state Global application state.
* @return {Object} A user object.
function getPostLockUser(state) {
return state.postLock.user;
* Returns the active post lock.
* @param {Object} state Global application state.
* @return {Object} The lock object.
function getActivePostLock(state) {
return state.postLock.activePostLock;
* Returns whether or not the user has the unfiltered_html capability.
* @param {Object} state Editor state.
* @return {boolean} Whether the user can or can't post unfiltered HTML.
function canUserUseUnfilteredHTML(state) {
return Boolean(getCurrentPost(state)._links?.hasOwnProperty('wp:action-unfiltered-html'));