diff --git a/docs/designers-developers/developers/data/data-core-editor.md b/docs/designers-developers/developers/data/data-core-editor.md
index 905e9cc077847d..6b08fa9b2187df 100644
--- a/docs/designers-developers/developers/data/data-core-editor.md
+++ b/docs/designers-developers/developers/data/data-core-editor.md
@@ -892,6 +892,18 @@ _Returns_
- `boolean`: Whether or not the permalink is editable.
+# **isPostAutosavingLocked**
+
+Returns whether post autosaving is locked.
+
+_Parameters_
+
+- _state_ `Object`: Global application state.
+
+_Returns_
+
+- `boolean`: Is locked.
+
# **isPostLocked**
Returns whether the post is locked.
diff --git a/packages/editor/src/store/reducer.js b/packages/editor/src/store/reducer.js
index a88e05f30ac775..69ab09f7bf0c8c 100644
--- a/packages/editor/src/store/reducer.js
+++ b/packages/editor/src/store/reducer.js
@@ -238,6 +238,27 @@ export function postSavingLock( state = {}, action ) {
return state;
}
+/**
+ * Post autosaving lock.
+ *
+ * When post autosaving is locked, the post will not autosave.
+ *
+ * @param {PostAutosavingLockState} state Current state.
+ * @param {Object} action Dispatched action.
+ *
+ * @return {PostLockState} Updated state.
+ */
+export function postAutosavingLock( state = {}, action ) {
+ switch ( action.type ) {
+ case 'LOCK_POST_AUTOSAVING':
+ return { ...state, [ action.lockName ]: true };
+
+ case 'UNLOCK_POST_AUTOSAVING':
+ return omit( state, action.lockName );
+ }
+ return state;
+}
+
export const reusableBlocks = combineReducers( {
data( state = {}, action ) {
switch ( action.type ) {
@@ -393,4 +414,5 @@ export default optimist( combineReducers( {
postSavingLock,
isReady,
editorSettings,
+ postAutosavingLock,
} ) );
diff --git a/packages/editor/src/store/selectors.js b/packages/editor/src/store/selectors.js
index daf7adbd9ee2ae..eda959abba370c 100644
--- a/packages/editor/src/store/selectors.js
+++ b/packages/editor/src/store/selectors.js
@@ -535,6 +535,11 @@ export const isEditedPostAutosaveable = createRegistrySelector( ( select ) => fu
return false;
}
+ // A post is not autosavable when there is a post autosave lock.
+ if ( isPostAutosavingLocked( state ) ) {
+ return false;
+ }
+
const postType = getCurrentPostType( state );
const postId = getCurrentPostId( state );
const hasFetchedAutosave = select( 'core' ).hasFetchedAutosaves( postType, postId );
@@ -1100,6 +1105,17 @@ export 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.
+ */
+export function isPostAutosavingLocked( state ) {
+ return Object.keys( state.postAutosavingLock ).length > 0;
+}
+
/**
* Returns whether the edition of the post has been taken over.
*
diff --git a/packages/editor/src/store/test/reducer.js b/packages/editor/src/store/test/reducer.js
index 3fc6461b34e538..156ce5b9b3602a 100644
--- a/packages/editor/src/store/test/reducer.js
+++ b/packages/editor/src/store/test/reducer.js
@@ -15,6 +15,7 @@ import {
saving,
reusableBlocks,
postSavingLock,
+ postAutosavingLock,
} from '../reducer';
describe( 'state', () => {
@@ -489,4 +490,49 @@ describe( 'state', () => {
expect( state ).toEqual( {} );
} );
} );
+
+ describe( 'postAutosavingLock', () => {
+ it( 'returns empty object by default', () => {
+ const state = postAutosavingLock( undefined, {} );
+
+ expect( state ).toEqual( {} );
+ } );
+
+ it( 'returns correct post locks when locks added and removed', () => {
+ let state = postAutosavingLock( undefined, {
+ type: 'LOCK_POST_AUTOSAVING',
+ lockName: 'test-lock',
+ } );
+
+ expect( state ).toEqual( {
+ 'test-lock': true,
+ } );
+
+ state = postAutosavingLock( deepFreeze( state ), {
+ type: 'LOCK_POST_AUTOSAVING',
+ lockName: 'test-lock-2',
+ } );
+
+ expect( state ).toEqual( {
+ 'test-lock': true,
+ 'test-lock-2': true,
+ } );
+
+ state = postAutosavingLock( deepFreeze( state ), {
+ type: 'UNLOCK_POST_AUTOSAVING',
+ lockName: 'test-lock',
+ } );
+
+ expect( state ).toEqual( {
+ 'test-lock-2': true,
+ } );
+
+ state = postAutosavingLock( deepFreeze( state ), {
+ type: 'UNLOCK_POST_AUTOSAVING',
+ lockName: 'test-lock-2',
+ } );
+
+ expect( state ).toEqual( {} );
+ } );
+ } );
} );
diff --git a/packages/editor/src/store/test/selectors.js b/packages/editor/src/store/test/selectors.js
index 73e0938ffccce4..99d0efac340932 100644
--- a/packages/editor/src/store/test/selectors.js
+++ b/packages/editor/src/store/test/selectors.js
@@ -159,6 +159,7 @@ const {
getPermalink,
getPermalinkParts,
isPostSavingLocked,
+ isPostAutosavingLocked,
canUserUseUnfilteredHTML,
} = selectors;
@@ -1157,6 +1158,28 @@ describe( 'selectors', () => {
} );
} );
+ describe( 'isPostAutosavingLocked', () => {
+ it( 'should return true if the post has postAutosavingLocks', () => {
+ const state = {
+ postAutosavingLock: { example: true },
+ currentPost: {},
+ saving: {},
+ };
+
+ expect( isPostAutosavingLocked( state ) ).toBe( true );
+ } );
+
+ it( 'should return false if the post has no postAutosavingLocks', () => {
+ const state = {
+ postAutosavingLock: {},
+ currentPost: {},
+ saving: {},
+ };
+
+ expect( isPostAutosavingLocked( state ) ).toBe( false );
+ } );
+ } );
+
describe( 'isEditedPostSaveable', () => {
it( 'should return false if the post has no title, excerpt, content', () => {
const state = {
@@ -1408,6 +1431,7 @@ describe( 'selectors', () => {
return true;
},
getAutosave() {},
+ postAutosavingLock: {},
};
expect( isEditedPostAutosaveable( state ) ).toBe( true );
@@ -1440,6 +1464,7 @@ describe( 'selectors', () => {
excerpt: 'foo',
};
},
+ postAutosavingLock: {},
};
expect( isEditedPostAutosaveable( state ) ).toBe( false );
@@ -1471,6 +1496,7 @@ describe( 'selectors', () => {
excerpt: 'foo',
};
},
+ postAutosavingLock: {},
};
expect( isEditedPostAutosaveable( state ) ).toBe( true );
@@ -1505,12 +1531,23 @@ describe( 'selectors', () => {
[ variantField ]: 'bar',
};
},
+ postAutosavingLock: {},
};
expect( isEditedPostAutosaveable( state ) ).toBe( true );
}
}
} );
+
+ it( 'should return false if autosaving is locked', () => {
+ const state = {
+ currentPost: {},
+ saving: {},
+ postAutosavingLock: { example: true },
+ };
+
+ expect( isEditedPostAutosaveable( state ) ).toBe( false );
+ } );
} );
describe( 'isEditedPostEmpty', () => {