+/**
+ * Outputs the HTML for the notice to say that someone else is editing or has taken over editing of this post.
+ *
+ * @since 2.8.5
+ * @return none
+ */
+function _admin_notice_post_locked() {
+ if ( ! $post = get_post() )
+ return;
+
+ $user = null;
+ if ( $user_id = wp_check_post_lock( $post->ID ) )
+ $user = get_userdata( $user_id );
+
+ if ( $user ) {
+
+ /**
+ * Filter whether to show the post locked dialog.
+ *
+ * Returning a falsey value to the filter will short-circuit displaying the dialog.
+ *
+ * @since 3.6.0
+ *
+ * @param bool $display Whether to display the dialog. Default true.
+ * @param WP_User|bool $user WP_User object on success, false otherwise.
+ */
+ if ( ! apply_filters( 'show_post_locked_dialog', true, $post, $user ) )
+ return;
+
+ $locked = true;
+ } else {
+ $locked = false;
+ }
+
+ if ( $locked && ( $sendback = wp_get_referer() ) &&
+ false === strpos( $sendback, 'post.php' ) && false === strpos( $sendback, 'post-new.php' ) ) {
+
+ $sendback_text = __('Go back');
+ } else {
+ $sendback = admin_url( 'edit.php' );
+
+ if ( 'post' != $post->post_type )
+ $sendback = add_query_arg( 'post_type', $post->post_type, $sendback );
+
+ $sendback_text = get_post_type_object( $post->post_type )->labels->all_items;
+ }
+
+ $hidden = $locked ? '' : ' hidden';
+
+ ?>
+ <div id="post-lock-dialog" class="notification-dialog-wrap<?php echo $hidden; ?>">
+ <div class="notification-dialog-background"></div>
+ <div class="notification-dialog">
+ <?php
+
+ if ( $locked ) {
+ if ( get_post_type_object( $post->post_type )->public ) {
+ $preview_link = set_url_scheme( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) );
+
+ if ( 'publish' == $post->post_status || $user->ID != $post->post_author ) {
+ // Latest content is in autosave
+ $nonce = wp_create_nonce( 'post_preview_' . $post->ID );
+ $preview_link = add_query_arg( array( 'preview_id' => $post->ID, 'preview_nonce' => $nonce ), $preview_link );
+ }
+ } else {
+ $preview_link = '';
+ }
+
+ /** This filter is documented in wp-admin/includes/meta-boxes.php */
+ $preview_link = apply_filters( 'preview_post_link', $preview_link, $post );
+
+ /**
+ * Filter whether to allow the post lock to be overridden.
+ *
+ * Returning a falsey value to the filter will disable the ability
+ * to override the post lock.
+ *
+ * @since 3.6.0
+ *
+ * @param bool $override Whether to allow overriding post locks. Default true.
+ * @param WP_Post $post Post object.
+ * @param WP_User $user User object.
+ */
+ $override = apply_filters( 'override_post_lock', true, $post, $user );
+ $tab_last = $override ? '' : ' wp-tab-last';
+
+ ?>
+ <div class="post-locked-message">
+ <div class="post-locked-avatar"><?php echo get_avatar( $user->ID, 64 ); ?></div>
+ <p class="currently-editing wp-tab-first" tabindex="0">
+ <?php
+ _e( 'This content is currently locked.' );
+ if ( $override )
+ printf( ' ' . __( 'If you take over, %s will be blocked from continuing to edit.' ), esc_html( $user->display_name ) );
+ ?>
+ </p>
+ <?php
+ /**
+ * Fires inside the post locked dialog before the buttons are displayed.
+ *
+ * @since 3.6.0
+ *
+ * @param WP_Post $post Post object.
+ */
+ do_action( 'post_locked_dialog', $post );
+ ?>
+ <p>
+ <a class="button" href="<?php echo esc_url( $sendback ); ?>"><?php echo $sendback_text; ?></a>
+ <?php if ( $preview_link ) { ?>
+ <a class="button<?php echo $tab_last; ?>" href="<?php echo esc_url( $preview_link ); ?>"><?php _e('Preview'); ?></a>
+ <?php
+ }
+
+ // Allow plugins to prevent some users overriding the post lock
+ if ( $override ) {
+ ?>
+ <a class="button button-primary wp-tab-last" href="<?php echo esc_url( add_query_arg( 'get-post-lock', '1', get_edit_post_link( $post->ID, 'url' ) ) ); ?>"><?php _e('Take over'); ?></a>
+ <?php
+ }
+
+ ?>
+ </p>
+ </div>
+ <?php
+ } else {
+ ?>
+ <div class="post-taken-over">
+ <div class="post-locked-avatar"></div>
+ <p class="wp-tab-first" tabindex="0">
+ <span class="currently-editing"></span><br />
+ <span class="locked-saving hidden"><img src="images/wpspin_light-2x.gif" width="16" height="16" /> <?php _e('Saving revision...'); ?></span>
+ <span class="locked-saved hidden"><?php _e('Your latest changes were saved as a revision.'); ?></span>
+ </p>
+ <?php
+ /**
+ * Fires inside the dialog displayed when a user has lost the post lock.
+ *
+ * @since 3.6.0
+ *
+ * @param WP_Post $post Post object.
+ */
+ do_action( 'post_lock_lost_dialog', $post );
+ ?>
+ <p><a class="button button-primary wp-tab-last" href="<?php echo esc_url( $sendback ); ?>"><?php echo $sendback_text; ?></a></p>
+ </div>
+ <?php
+ }
+
+ ?>
+ </div>
+ </div>
+ <?php
+}
+
+/**
+ * Creates autosave data for the specified post from $_POST data.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @uses _wp_translate_postdata()
+ * @uses _wp_post_revision_fields()
+ *
+ * @param mixed $post_data Associative array containing the post data or int post ID.
+ * @return mixed The autosave revision ID. WP_Error or 0 on error.
+ */
+function wp_create_post_autosave( $post_data ) {
+ if ( is_numeric( $post_data ) ) {
+ $post_id = $post_data;
+ $post_data = &$_POST;
+ } else {
+ $post_id = (int) $post_data['post_ID'];
+ }
+
+ $post_data = _wp_translate_postdata( true, $post_data );
+ if ( is_wp_error( $post_data ) )
+ return $post_data;
+
+ $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_data, true );
+ $new_autosave['ID'] = $old_autosave->ID;
+ $new_autosave['post_author'] = $post_author;
+
+ // If the new autosave has the same content as the post, delete the autosave.
+ $post = get_post( $post_id );
+ $autosave_is_different = false;
+ foreach ( array_intersect( array_keys( $new_autosave ), array_keys( _wp_post_revision_fields() ) ) as $field ) {
+ if ( normalize_whitespace( $new_autosave[ $field ] ) != normalize_whitespace( $post->$field ) ) {
+ $autosave_is_different = true;
+ break;
+ }
+ }
+
+ if ( ! $autosave_is_different ) {
+ wp_delete_post_revision( $old_autosave->ID );
+ return 0;
+ }
+
+ return wp_update_post( $new_autosave );
+ }
+
+ // _wp_put_post_revision() expects unescaped.
+ $post_data = wp_unslash( $post_data );
+
+ // Otherwise create the new autosave as a special post revision
+ return _wp_put_post_revision( $post_data, true );
+}
+
+/**
+ * Save draft or manually autosave for showing preview.
+ *
+ * @package WordPress
+ * @since 2.7.0
+ *
+ * @uses get_post_status()
+ * @uses edit_post()
+ * @uses get_post()
+ * @uses current_user_can()
+ * @uses wp_die()
+ * @uses wp_create_post_autosave()
+ * @uses add_query_arg()
+ * @uses wp_create_nonce()
+ *
+ * @return str URL to redirect to show the preview
+ */
+function post_preview() {
+
+ $post_ID = (int) $_POST['post_ID'];
+ $_POST['ID'] = $post_ID;
+
+ if ( ! $post = get_post( $post_ID ) ) {
+ wp_die( __( 'You are not allowed to edit this post.' ) );
+ }
+
+ if ( ! current_user_can( 'edit_post', $post->ID ) ) {
+ wp_die( __( 'You are not allowed to edit this post.' ) );
+ }
+
+ $is_autosave = false;
+
+ if ( ! wp_check_post_lock( $post->ID ) && get_current_user_id() == $post->post_author && ( 'draft' == $post->post_status || 'auto-draft' == $post->post_status ) ) {
+ $saved_post_id = edit_post();
+ } else {
+ $is_autosave = true;
+
+ if ( 'auto-draft' == $_POST['post_status'] )
+ $_POST['post_status'] = 'draft';
+
+ $saved_post_id = wp_create_post_autosave( $post->ID );
+ }
+
+ if ( is_wp_error( $saved_post_id ) )
+ wp_die( $saved_post_id->get_error_message() );
+
+ $query_args = array( 'preview' => 'true' );
+
+ if ( $is_autosave && $saved_post_id ) {
+ $query_args['preview_id'] = $post->ID;
+ $query_args['preview_nonce'] = wp_create_nonce( 'post_preview_' . $post->ID );
+
+ if ( isset( $_POST['post_format'] ) )
+ $query_args['post_format'] = empty( $_POST['post_format'] ) ? 'standard' : sanitize_key( $_POST['post_format'] );
+ }
+
+ $url = add_query_arg( $query_args, get_permalink( $post->ID ) );
+
+ /** This filter is documented in wp-admin/includes/meta-boxes.php */
+ return apply_filters( 'preview_post_link', $url, $post );
+}
+
+/**
+ * Save a post submitted with XHR
+ *
+ * Intended for use with heartbeat and autosave.js
+ *
+ * @since 3.9.0
+ *
+ * @param $post_data Associative array of the submitted post data.
+ * @return mixed The value 0 or WP_Error on failure. The saved post ID on success.
+ * Te ID can be the draft post_id or the autosave revision post_id.
+ */
+function wp_autosave( $post_data ) {
+ // Back-compat
+ if ( ! defined( 'DOING_AUTOSAVE' ) )
+ define( 'DOING_AUTOSAVE', true );
+
+ $post_id = (int) $post_data['post_id'];
+ $post_data['ID'] = $post_data['post_ID'] = $post_id;
+
+ if ( false === wp_verify_nonce( $post_data['_wpnonce'], 'update-post_' . $post_id ) ) {
+ return new WP_Error( 'invalid_nonce', __( 'Error while saving.' ) );
+ }
+
+ $post = get_post( $post_id );
+
+ if ( ! current_user_can( 'edit_post', $post->ID ) ) {
+ return new WP_Error( 'edit_posts', __( 'You are not allowed to edit this item.' ) );
+ }
+
+ if ( 'auto-draft' == $post->post_status )
+ $post_data['post_status'] = 'draft';
+
+ if ( $post_data['post_type'] != 'page' && ! empty( $post_data['catslist'] ) )
+ $post_data['post_category'] = explode( ',', $post_data['catslist'] );
+
+ if ( ! wp_check_post_lock( $post->ID ) && get_current_user_id() == $post->post_author && ( 'auto-draft' == $post->post_status || 'draft' == $post->post_status ) ) {
+ // Drafts and auto-drafts are just overwritten by autosave for the same user if the post is not locked
+ return edit_post( wp_slash( $post_data ) );
+ } else {
+ // Non drafts or other users drafts are not overwritten. The autosave is stored in a special post revision for each user.
+ return wp_create_post_autosave( wp_slash( $post_data ) );
+ }
+}