diff --git a/wp-admin/includes/ajax-actions.php b/wp-admin/includes/ajax-actions.php index 7d7d9ed6ec..cf6eea4ce8 100644 --- a/wp-admin/includes/ajax-actions.php +++ b/wp-admin/includes/ajax-actions.php @@ -1043,15 +1043,12 @@ function wp_ajax_autosave() { unset($_POST['post_category']); $do_autosave = (bool) $_POST['autosave']; - $do_lock = true; $data = ''; $supplemental = array(); $id = $revision_id = 0; - /* translators: draft saved date format, see http://php.net/date */ - $draft_saved_date_format = __('g:i:s a'); - /* translators: %s: date and time */ - $message = sprintf( __('Draft saved at %s.'), date_i18n( $draft_saved_date_format ) ); + if ( ! $user_id = get_current_user_id() ) + wp_die('-1'); $post_id = (int) $_POST['post_id']; $_POST['ID'] = $_POST['post_ID'] = $post_id; @@ -1059,17 +1056,6 @@ function wp_ajax_autosave() { if ( 'auto-draft' == $post->post_status ) $_POST['post_status'] = 'draft'; - if ( $last = wp_check_post_lock( $post->ID ) ) { - // This will change after we have per-user autosaves - $do_autosave = $do_lock = false; - - $last_user = get_userdata( $last ); - $last_user_name = $last_user ? $last_user->display_name : __( 'Someone' ); - $data = __( 'Autosave disabled.' ); - - $supplemental['disable_autosave'] = 'disable'; - } - if ( 'page' == $post->post_type ) { if ( !current_user_can('edit_page', $post->ID) ) wp_die( __( 'You are not allowed to edit this page.' ) ); @@ -1079,17 +1065,28 @@ function wp_ajax_autosave() { } if ( $do_autosave ) { - // Drafts and auto-drafts are just overwritten by autosave - if ( 'auto-draft' == $post->post_status || 'draft' == $post->post_status ) { + // Drafts and auto-drafts are just overwritten by autosave for the same user + if ( $user_id == $post->post_author && ( 'auto-draft' == $post->post_status || 'draft' == $post->post_status ) ) { $id = edit_post(); - } else { // Non drafts are not overwritten. The autosave is stored in a special post revision. + } else { // Non drafts are not overwritten. The autosave is stored in a special post revision for each user. $revision_id = wp_create_post_autosave( $post->ID ); if ( is_wp_error($revision_id) ) $id = $revision_id; else $id = $post->ID; } - $data = $message; + + if ( is_wp_error($id) ) { + // is_wp_error($id) overwrites $data in WP_Ajax_Response but no point in doing wp_create_nonce('update-post_' . $id) below + // todo: Needs review. The errors generated in WP_Ajax_Response and parsed with wpAjax.parseAjaxResponse() haven't been used for many years. + $data = $id; + $id = 0; + } else { + /* translators: draft saved date format, see http://php.net/date */ + $draft_saved_date_format = __('g:i:s a'); + /* translators: %s: date and time */ + $data = sprintf( __('Draft saved at %s.'), date_i18n( $draft_saved_date_format ) ); + } } else { if ( ! empty( $_POST['auto_draft'] ) ) $id = 0; // This tells us it didn't actually save @@ -1103,12 +1100,8 @@ function wp_ajax_autosave() { $supplemental['replace-samplepermalinknonce'] = wp_create_nonce('samplepermalink'); $supplemental['replace-closedpostboxesnonce'] = wp_create_nonce('closedpostboxes'); $supplemental['replace-_ajax_linking_nonce'] = wp_create_nonce( 'internal-linking' ); - if ( $id ) { - if ( $_POST['post_type'] == 'post' ) - $supplemental['replace-_wpnonce'] = wp_create_nonce('update-post_' . $id); - elseif ( $_POST['post_type'] == 'page' ) - $supplemental['replace-_wpnonce'] = wp_create_nonce('update-page_' . $id); - } + if ( $id ) + $supplemental['replace-_wpnonce'] = wp_create_nonce('update-post_' . $id); } $x = new WP_Ajax_Response( array( diff --git a/wp-admin/includes/post.php b/wp-admin/includes/post.php index 5f420e7846..33c3e0350e 100644 --- a/wp-admin/includes/post.php +++ b/wp-admin/includes/post.php @@ -1280,11 +1280,13 @@ function wp_create_post_autosave( $post_id ) { if ( is_wp_error( $translated ) ) return $translated; - // Only store one autosave. If there is already an autosave, overwrite it. - if ( $old_autosave = wp_get_post_autosave( $post_id ) ) { + $post_author = get_current_user_id(); + + // Store one autosave per author. If there is already an autosave, overwrite it. + if ( $old_autosave = wp_get_post_autosave( $post_id, $post_author ) ) { $new_autosave = _wp_post_revision_fields( $_POST, true ); $new_autosave['ID'] = $old_autosave->ID; - $new_autosave['post_author'] = get_current_user_id(); + $new_autosave['post_author'] = $post_author; return wp_update_post( $new_autosave ); } @@ -1339,7 +1341,8 @@ function post_preview() { wp_die(__('You are not allowed to edit this post.')); } - if ( 'draft' == $post->post_status ) { + $user_id = get_current_user_id(); + if ( 'draft' == $post->post_status && $user_id == $post->post_author ) { $id = edit_post(); } else { // Non drafts are not overwritten. The autosave is stored in a special post revision. $id = wp_create_post_autosave( $post->ID ); @@ -1350,7 +1353,7 @@ function post_preview() { if ( is_wp_error($id) ) wp_die( $id->get_error_message() ); - if ( $_POST['post_status'] == 'draft' ) { + if ( $_POST['post_status'] == 'draft' && $user_id == $post->post_author ) { $url = add_query_arg( 'preview', 'true', get_permalink($id) ); } else { $nonce = wp_create_nonce('post_preview_' . $id); diff --git a/wp-includes/js/autosave.js b/wp-includes/js/autosave.js index d1914d190b..aa988cb681 100644 --- a/wp-includes/js/autosave.js +++ b/wp-includes/js/autosave.js @@ -1,4 +1,4 @@ -var autosave, autosaveLast = '', autosavePeriodical, autosaveOldMessage = '', autosaveDelayPreview = false, notSaved = true, blockSave = false, fullscreen, autosaveLockRelease = true; +var autosave, autosaveLast = '', autosavePeriodical, autosaveDelayPreview = false, notSaved = true, blockSave = false, fullscreen, autosaveLockRelease = true; jQuery(document).ready( function($) { @@ -130,49 +130,29 @@ jQuery(document).ready( function($) { } }); -function autosave_parse_response(response) { - var res = wpAjax.parseAjaxResponse(response, 'autosave'), message = '', postID, sup; +function autosave_parse_response( response ) { + var res = wpAjax.parseAjaxResponse(response, 'autosave'), post_id, sup; if ( res && res.responses && res.responses.length ) { - message = res.responses[0].data; // The saved message or error. - // someone else is editing: disable autosave, set errors if ( res.responses[0].supplemental ) { sup = res.responses[0].supplemental; - if ( 'disable' == sup['disable_autosave'] ) { - autosave = function() {}; - autosaveLockRelease = false; - res = { errors: true }; - } - if ( sup['active-post-lock'] ) { - jQuery('#active_post_lock').val( sup['active-post-lock'] ); - } - - if ( sup['alert'] ) { - jQuery('#autosave-alert').remove(); - jQuery('#titlediv').after('

' + sup['alert'] + '

'); - } - - jQuery.each(sup, function(selector, value) { - if ( selector.match(/^replace-/) ) { - jQuery('#'+selector.replace('replace-', '')).val(value); - } + jQuery.each( sup, function( selector, value ) { + if ( selector.match(/^replace-/) ) + jQuery( '#' + selector.replace('replace-', '') ).val( value ); }); } - // if no errors: add slug UI + // if no errors: add slug UI and update autosave-message if ( !res.errors ) { - postID = parseInt( res.responses[0].id, 10 ); - if ( !isNaN(postID) && postID > 0 ) { - autosave_update_slug(postID); - } + if ( post_id = parseInt( res.responses[0].id, 10 ) ) + autosave_update_slug( post_id ); + + if ( res.responses[0].data ) // update autosave message + jQuery('.autosave-message').text( res.responses[0].data ); } } - if ( message ) { // update autosave message - jQuery('.autosave-message').html(message); - } else if ( autosaveOldMessage && res ) { - jQuery('.autosave-message').html( autosaveOldMessage ); - } + return res; } @@ -186,16 +166,19 @@ function autosave_saved(response) { // called when autosaving new post function autosave_saved_new(response) { blockSave = false; - var res = autosave_parse_response(response), postID; + var res = autosave_parse_response(response), post_id; if ( res && res.responses.length && !res.errors ) { // An ID is sent only for real auto-saves, not for autosave=0 "keepalive" saves - postID = parseInt( res.responses[0].id, 10 ); - if ( !isNaN(postID) && postID > 0 ) { + post_id = parseInt( res.responses[0].id, 10 ); + + if ( post_id ) { notSaved = false; jQuery('#auto_draft').val('0'); // No longer an auto-draft } + autosave_enable_buttons(); + if ( autosaveDelayPreview ) { autosaveDelayPreview = false; doPreview(); @@ -286,7 +269,6 @@ autosave = function() { successCallback = autosave_saved; // pre-existing post } - autosaveOldMessage = jQuery('#autosave').html(); jQuery.ajax({ data: post_data, beforeSend: doAutoSave ? autosave_loading : null, diff --git a/wp-includes/revision.php b/wp-includes/revision.php index ea7b17c8a9..7b0cbb5bf8 100644 --- a/wp-includes/revision.php +++ b/wp-includes/revision.php @@ -135,53 +135,34 @@ function wp_save_post_revision( $post_id, $new_data = null ) { * Retrieve the autosaved data of the specified post. * * Returns a post object containing the information that was autosaved for the - * specified post. + * specified post. If the optional $user_id is passed, returns the autosave for that user + * otherwise returns the latest autosave. * * @package WordPress * @subpackage Post_Revisions * @since 2.6.0 - * + * @uses wp_get_post_revisions() + * * @param int $post_id The post ID. + * @param int $user_id optional The post author ID. * @return object|bool The autosaved data or false on failure or when no autosave exists. */ -function wp_get_post_autosave( $post_id ) { +function wp_get_post_autosave( $post_id, $user_id = 0 ) { + $revisions = wp_get_post_revisions($post_id); - if ( !$post = get_post( $post_id ) ) - return false; + foreach ( $revisions as $revision ) { + if ( false !== strpos( $revision->post_name, "{$post_id}-autosave" ) ) { + if ( $user_id && $user_id != $revision->post_author ) + continue; - $q = array( - 'name' => "{$post->ID}-autosave", - 'post_parent' => $post->ID, - 'post_type' => 'revision', - 'post_status' => 'inherit' - ); - - // Use WP_Query so that the result gets cached - $autosave_query = new WP_Query; - - add_action( 'parse_query', '_wp_get_post_autosave_hack' ); - $autosave = $autosave_query->query( $q ); - remove_action( 'parse_query', '_wp_get_post_autosave_hack' ); - - if ( $autosave && is_array($autosave) && is_object($autosave[0]) ) - return $autosave[0]; + return $revision; + break; + } + } return false; } -/** - * Internally used to hack WP_Query into submission. - * - * @package WordPress - * @subpackage Post_Revisions - * @since 2.6.0 - * - * @param object $query WP_Query object - */ -function _wp_get_post_autosave_hack( $query ) { - $query->is_single = false; -} - /** * Determines if the specified post is a revision. * @@ -195,6 +176,7 @@ function _wp_get_post_autosave_hack( $query ) { function wp_is_post_revision( $post ) { if ( !$post = wp_get_post_revision( $post ) ) return false; + return (int) $post->post_parent; } @@ -211,9 +193,11 @@ function wp_is_post_revision( $post ) { function wp_is_post_autosave( $post ) { if ( !$post = wp_get_post_revision( $post ) ) return false; - if ( "{$post->post_parent}-autosave" !== $post->post_name ) - return false; - return (int) $post->post_parent; + + if ( false !== strpos( $post->post_name, "{$post->post_parent}-autosave" ) ) + return (int) $post->post_parent; + + return false; } /** @@ -234,6 +218,7 @@ function _wp_put_post_revision( $post = null, $autosave = false ) { $post = get_object_vars( $post ); elseif ( !is_array($post) ) $post = get_post($post, ARRAY_A); + if ( !$post || empty($post['ID']) ) return; @@ -249,6 +234,7 @@ function _wp_put_post_revision( $post = null, $autosave = false ) { if ( $revision_id ) do_action( '_wp_put_post_revision', $revision_id ); + return $revision_id; } @@ -312,8 +298,9 @@ function wp_restore_post_revision( $revision_id, $fields = null ) { $fields = array_keys( _wp_post_revision_fields() ); $update = array(); - foreach( array_intersect( array_keys( $revision ), $fields ) as $field ) + foreach( array_intersect( array_keys( $revision ), $fields ) as $field ) { $update[$field] = $revision[$field]; + } if ( !$update ) return false; @@ -374,8 +361,6 @@ function wp_delete_post_revision( $revision_id ) { * @return array empty if no revisions */ function wp_get_post_revisions( $post_id = 0, $args = null ) { - if ( ! WP_POST_REVISIONS ) - return array(); if ( ( !$post = get_post( $post_id ) ) || empty( $post->ID ) ) return array(); @@ -385,6 +370,7 @@ function wp_get_post_revisions( $post_id = 0, $args = null ) { if ( !$revisions = get_children( $args ) ) return array(); + return $revisions; }