diff --git a/editor/components/provider/index.js b/editor/components/provider/index.js index 6067b90712cd8..788c29ea4df4f 100644 --- a/editor/components/provider/index.js +++ b/editor/components/provider/index.js @@ -26,7 +26,7 @@ class EditorProvider extends Component { // Assume that we don't need to initialize in the case of an error recovery. if ( ! props.recovery ) { this.props.updateEditorSettings( props.settings ); - this.props.setupEditor( props.post ); + this.props.setupEditor( props.post, props.settings.autosave ); } } diff --git a/editor/store/actions.js b/editor/store/actions.js index 24d86603d87b2..65619fb8b54ad 100644 --- a/editor/store/actions.js +++ b/editor/store/actions.js @@ -16,13 +16,15 @@ import { * Returns an action object used in signalling that editor has initialized with * the specified post object and editor settings. * - * @param {Object} post Post object. + * @param {Object} post Post object. + * @param {Object} autosaveStatus The Post's autosave status. * * @return {Object} Action object. */ -export function setupEditor( post ) { +export function setupEditor( post, autosaveStatus ) { return { type: 'SETUP_EDITOR', + autosave: autosaveStatus, post, }; } diff --git a/editor/store/effects.js b/editor/store/effects.js index dd4531055d87b..8adb80b0ab68f 100644 --- a/editor/store/effects.js +++ b/editor/store/effects.js @@ -35,6 +35,7 @@ import { replaceBlocks, createSuccessNotice, createErrorNotice, + createWarningNotice, removeNotice, saveSharedBlock, insertBlock, @@ -69,6 +70,7 @@ import { * Module Constants */ const SAVE_POST_NOTICE_ID = 'SAVE_POST_NOTICE_ID'; +const AUTOSAVE_POST_NOTICE_ID = 'AUTOSAVE_POST_NOTICE_ID'; const TRASH_POST_NOTICE_ID = 'TRASH_POST_NOTICE_ID'; const SHARED_BLOCK_NOTICE_ID = 'SHARED_BLOCK_NOTICE_ID'; @@ -133,6 +135,7 @@ export default { } ); dispatch( removeNotice( SAVE_POST_NOTICE_ID ) ); + dispatch( removeNotice( AUTOSAVE_POST_NOTICE_ID ) ); request = wp.apiRequest( { path: `/wp/v2/${ basePath }/${ post.id }`, @@ -209,7 +212,7 @@ export default { if ( noticeMessage ) { dispatch( createSuccessNotice(

- { noticeMessage } + { noticeMessage } { ' ' } { shouldShowLink && { __( 'View post' ) } }

, @@ -344,7 +347,7 @@ export default { ) ); }, SETUP_EDITOR( action, { getState } ) { - const { post } = action; + const { post, autosave } = action; const state = getState(); const template = getTemplate( state ); const templateLock = getTemplateLock( state ); @@ -376,9 +379,27 @@ export default { edits.status = 'draft'; } + // Check the auto-save status + let autosaveAction; + if ( autosave ) { + const noticeMessage = __( 'There is an autosave of this post that is more recent than the version below.' ); + autosaveAction = createWarningNotice( +

+ { noticeMessage } + { ' ' } + { __( 'View the autosave' ) } +

, + { + id: AUTOSAVE_POST_NOTICE_ID, + spokenMessage: noticeMessage, + } + ); + } + return [ setTemplateValidity( isValidTemplate ), setupEditorState( post, blocks, edits ), + ...( autosaveAction ? [ autosaveAction ] : [] ), ]; }, SYNCHRONIZE_TEMPLATE( action, { getState } ) { diff --git a/editor/store/test/actions.js b/editor/store/test/actions.js index 5972aa9476491..4729c88c28655 100644 --- a/editor/store/test/actions.js +++ b/editor/store/test/actions.js @@ -48,10 +48,12 @@ describe( 'actions', () => { describe( 'setupEditor', () => { it( 'should return the SETUP_EDITOR action', () => { const post = {}; - const result = setupEditor( post ); + const autosave = {}; + const result = setupEditor( post, autosave ); expect( result ).toEqual( { type: 'SETUP_EDITOR', post, + autosave, } ); } ); } ); diff --git a/editor/store/test/effects.js b/editor/store/test/effects.js index 4a25a91137079..86217dca00f10 100644 --- a/editor/store/test/effects.js +++ b/editor/store/test/effects.js @@ -302,7 +302,7 @@ describe( 'effects', () => { expect( dispatch ).toHaveBeenCalledTimes( 1 ); expect( dispatch ).toHaveBeenCalledWith( expect.objectContaining( { notice: { - content:

Post published! View post

, // eslint-disable-line jsx-a11y/anchor-is-valid + content:

Post published!{ ' ' }View post

, // eslint-disable-line jsx-a11y/anchor-is-valid id: 'SAVE_POST_NOTICE_ID', isDismissible: true, status: 'success', @@ -325,7 +325,7 @@ describe( 'effects', () => { expect( dispatch ).toHaveBeenCalledWith( expect.objectContaining( { notice: { content:

- Post reverted to draft. + Post reverted to draft. { ' ' } { false }

, @@ -350,7 +350,7 @@ describe( 'effects', () => { expect( dispatch ).toHaveBeenCalledTimes( 1 ); expect( dispatch ).toHaveBeenCalledWith( expect.objectContaining( { notice: { - content:

Post updated!{ ' ' }{ 'View post' }

, // eslint-disable-line jsx-a11y/anchor-is-valid + content:

Post updated!{ ' ' }{ 'View post' }

, // eslint-disable-line jsx-a11y/anchor-is-valid id: 'SAVE_POST_NOTICE_ID', isDismissible: true, status: 'success', diff --git a/lib/client-assets.php b/lib/client-assets.php index 56a74b6a13a6d..3227ecaeac3c2 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -932,6 +932,35 @@ function gutenberg_capture_code_editor_settings( $settings ) { return false; } +/** + * Retrieve a stored autosave that is newer than the post save. + * + * Deletes autosaves that are older than the post save. + * + * @param WP_Post $post Post object. + * @return WP_Post|boolean The post autosave. False if none found. + */ +function get_autosave_newer_than_post_save( $post ) { + // Add autosave data if it is newer and changed. + $autosave = wp_get_post_autosave( $post->ID ); + + if ( ! $autosave ) { + return false; + } + + // Check if the autosave is newer than the current post. + if ( + mysql2date( 'U', $autosave->post_modified_gmt, false ) > mysql2date( 'U', $post->post_modified_gmt, false ) + ) { + return $autosave; + } + + // If the autosave isn't newer, remove it. + wp_delete_post_revision( $autosave->ID ); + + return false; +} + /** * Scripts & Styles. * @@ -1104,6 +1133,13 @@ function gutenberg_editor_scripts_and_styles( $hook ) { 'autosaveInterval' => 10, ); + $post_autosave = get_autosave_newer_than_post_save( $post ); + if ( $post_autosave ) { + $editor_settings['autosave'] = array( + 'editLink' => add_query_arg( 'gutenberg', true, get_edit_post_link( $post_autosave->ID ) ), + ); + } + if ( ! empty( $color_palette ) ) { $editor_settings['colors'] = $color_palette; }