From 92c30a26fb97ef4c1bb214cadc6a68f0a3e6bb2e Mon Sep 17 00:00:00 2001 From: Andrew Ozz Date: Tue, 12 Mar 2013 03:22:30 +0000 Subject: [PATCH] Check post locks with heartbeat and display modal notifications when a post is locked or a user takes over editing, props dh-shredder, see #23697 git-svn-id: https://develop.svn.wordpress.org/trunk@23661 602fd350-edb4-49c9-b593-d223f7449a82 --- wp-admin/css/wp-admin.css | 40 ++++++++++++++++++ wp-admin/includes/ajax-actions.php | 9 +--- wp-admin/includes/misc.php | 41 +++++++++++++++++++ wp-admin/includes/post.php | 66 ++++++++++++++++++++++-------- wp-admin/js/post.js | 44 +++++++++++++++++++- wp-admin/post.php | 17 ++++++-- 6 files changed, 188 insertions(+), 29 deletions(-) diff --git a/wp-admin/css/wp-admin.css b/wp-admin/css/wp-admin.css index ccf1f8b12e..4959ad287c 100644 --- a/wp-admin/css/wp-admin.css +++ b/wp-admin/css/wp-admin.css @@ -3407,6 +3407,46 @@ td.plugin-title p { border-style: solid; } +#notification-dialog { + position: fixed; + top: 30%; + left: 50%; + width: 450px; + margin-left: -225px; + background: #fff; + z-index: 1000005; +} + +#notification-dialog-background { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: #000; + opacity: 0.5; + filter: alpha(opacity=50); + z-index: 1000000; +} + +#notification-dialog .post-locked-message, +#notification-dialog .post-taken-over { + margin: 25px; +} + +#notification-dialog .post-locked-message a.button-primary { + margin: 0 10px; +} + +#notification-dialog .post-locked-avatar { + float: left; + margin-right: 20px; +} + +#notification-dialog .currently-editing { + margin-bottom: 20px; +} + /*------------------------------------------------------------------------------ 11.1 - Custom Fields diff --git a/wp-admin/includes/ajax-actions.php b/wp-admin/includes/ajax-actions.php index 0c57781b71..78796fb152 100644 --- a/wp-admin/includes/ajax-actions.php +++ b/wp-admin/includes/ajax-actions.php @@ -1057,6 +1057,7 @@ function wp_ajax_autosave() { $_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 ); @@ -1064,7 +1065,6 @@ function wp_ajax_autosave() { $data = __( 'Autosave disabled.' ); $supplemental['disable_autosave'] = 'disable'; - $alert .= sprintf( __( '%s is currently editing this article. If you update it, you will overwrite the changes.' ), esc_html( $last_user_name ) ); } if ( 'page' == $post->post_type ) { @@ -1094,11 +1094,6 @@ function wp_ajax_autosave() { $id = $post->ID; } - if ( $do_lock && empty( $_POST['auto_draft'] ) && $id && is_numeric( $id ) ) { - $lock_result = wp_set_post_lock( $id ); - $supplemental['active-post-lock'] = implode( ':', $lock_result ); - } - if ( $nonce_age == 2 ) { $supplemental['replace-autosavenonce'] = wp_create_nonce('autosave'); $supplemental['replace-getpermalinknonce'] = wp_create_nonce('getpermalink'); @@ -1777,7 +1772,7 @@ function wp_ajax_wp_remove_post_lock() { if ( $active_lock[1] != get_current_user_id() ) wp_die( 0 ); - $new_lock = ( time() - apply_filters( 'wp_check_post_lock_window', AUTOSAVE_INTERVAL * 2 ) + 5 ) . ':' . $active_lock[1]; + $new_lock = ( time() - apply_filters( 'wp_check_post_lock_window', 120 ) + 5 ) . ':' . $active_lock[1]; update_post_meta( $post_id, '_edit_lock', $new_lock, implode( ':', $active_lock ) ); wp_die( 1 ); } diff --git a/wp-admin/includes/misc.php b/wp-admin/includes/misc.php index b1ee77a183..630a28128b 100644 --- a/wp-admin/includes/misc.php +++ b/wp-admin/includes/misc.php @@ -586,3 +586,44 @@ function wp_check_locked_posts( $response, $data ) { return $response; } add_filter( 'heartbeat_received', 'wp_check_locked_posts', 10, 2 ); + +/** + * Check lock status on the New/Edit Post screen and refresh the lock + * + * @since 3.6 + */ +function wp_refresh_post_lock( $response, $data, $screen_id ) { + if ( 'post' == $screen_id && array_key_exists( 'wp-refresh-post-lock', $data ) ) { + $received = $data['wp-refresh-post-lock']; + $send = array(); + + if ( !$post_id = absint( $received['post_id'] ) ) + return $response; + + if ( !current_user_can('edit_post', $post_id) ) + return $response; + + if ( $user_id = wp_check_post_lock( $post_id ) ) { + $user = get_userdata( $user_id ); + + $error = array( + 'text' => sprintf( __( '%s has taken over and is currently editing.' ), $user->display_name ) + ); + + if ( $avatar = get_avatar( $user->ID, 64 ) ) { + if ( preg_match( "|src='([^']+)'|", $avatar, $matches ) ) + $error['avatar_src'] = $matches[1]; + } + + $send['lock_error'] = $error; + } else { + if ( $new_lock = wp_set_post_lock( $post_id ) ) + $send['new_lock'] = implode( ':', $new_lock ); + } + + $response['wp-refresh-post-lock'] = $send; + } + + return $response; +} +add_filter( 'heartbeat_received', 'wp_refresh_post_lock', 10, 3 ); diff --git a/wp-admin/includes/post.php b/wp-admin/includes/post.php index ff06525b4f..dfd47b0d5f 100644 --- a/wp-admin/includes/post.php +++ b/wp-admin/includes/post.php @@ -1162,7 +1162,7 @@ function wp_check_post_lock( $post_id ) { $time = $lock[0]; $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true ); - $time_window = apply_filters( 'wp_check_post_lock_window', AUTOSAVE_INTERVAL * 2 ); + $time_window = apply_filters( 'wp_check_post_lock_window', 120 ); if ( $time && $time > time() - $time_window && $user != get_current_user_id() ) return $user; @@ -1192,31 +1192,61 @@ function wp_set_post_lock( $post_id ) { } /** - * Outputs the notice message to say that someone else is editing this post at the moment. + * 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() { - $post = get_post(); - $lock = explode( ':', get_post_meta( $post->ID, '_edit_lock', true ) ); - $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true ); - $last_user = get_userdata( $user ); - $last_user_name = $last_user ? $last_user->display_name : __('Somebody'); + global $post_ID; - switch ($post->post_type) { - case 'post': - $message = __( 'Warning: %s is currently editing this post' ); - break; - case 'page': - $message = __( 'Warning: %s is currently editing this page' ); - break; - default: - $message = __( 'Warning: %s is currently editing this.' ); + if ( !empty( $post_ID ) && ( $user = wp_check_post_lock( $post_ID ) ) ) { + $user = get_userdata( $user ); + $locked = apply_filters( 'show_post_locked_dialog', true, $post_ID, $user ); + } else { + $locked = false; } - $message = sprintf( $message, esc_html( $last_user_name ) ); - echo "

$message

"; + ?> + + ').attr( 'src', received.lock_error.avatar_src.replace(/&/g, '&') ); + wrap.find('div.post-locked-avatar').empty().append( avatar ); + } + + wrap.show(); + } + } + + if ( received['new_lock'] ) + $('#active_post_lock').val( received['new_lock'].replace(/[^0-9:]+/, '') ); + } +}); + +}(jQuery)); jQuery(document).ready( function($) { var stamp, visibility, sticky = '', last = 0, co = $('#content'); diff --git a/wp-admin/post.php b/wp-admin/post.php index 95f1cc6f26..7be9bfb046 100644 --- a/wp-admin/post.php +++ b/wp-admin/post.php @@ -147,6 +147,12 @@ case 'edit': if ( 'trash' == $post->post_status ) wp_die( __('You can’t edit this item because it is in the Trash. Please restore it and try again.') ); + if ( !empty( $_GET['get-post-lock'] ) ) { + wp_set_post_lock( $post_id ); + wp_redirect( get_edit_post_link( $post_id, 'url' ) ); + exit(); + } + $post_type = $post->post_type; if ( 'post' == $post_type ) { $parent_file = "edit.php"; @@ -165,15 +171,15 @@ case 'edit': $post_new_file = "post-new.php?post_type=$post_type"; } - if ( $last = wp_check_post_lock( $post->ID ) ) { - add_action('admin_notices', '_admin_notice_post_locked' ); - } else { + if ( ! wp_check_post_lock( $post->ID ) ) { $active_post_lock = wp_set_post_lock( $post->ID ); if ( 'attachment' !== $post_type ) wp_enqueue_script('autosave'); } + add_action( 'admin_footer', '_admin_notice_post_locked' ); + $title = $post_type_object->labels->edit_item; $post = get_post($post_id, OBJECT, 'edit'); @@ -217,6 +223,11 @@ case 'trash': if ( !current_user_can($post_type_object->cap->delete_post, $post_id) ) wp_die( __('You are not allowed to move this item to the Trash.') ); + if ( $user_id = wp_check_post_lock( $post_id ) ) { + $user = get_userdata( $user_id ); + wp_die( sprintf( __( 'You cannot move this item to the Trash. %s is currently editing.' ), $user->display_name ) ); + } + if ( ! wp_trash_post($post_id) ) wp_die( __('Error in moving to Trash.') );