Index: wp-admin/edit-form-advanced.php
--- wp-admin/edit-form-advanced.php
+++ wp-admin/edit-form-advanced.php
@@ -40,11 +40,11 @@
 	 5 => isset($_GET['revision']) ? sprintf( __('Post restored to revision from %s'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
 	 6 => sprintf( __('Post published. <a href="%s">View post</a>'), esc_url( get_permalink($post_ID) ) ),
 	 7 => __('Post saved.'),
-	 8 => sprintf( __('Post submitted. <a target="_blank" href="%s">Preview post</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
+	 8 => sprintf( __('Post submitted. <a target="_blank" href="%s">Preview post</a>'), esc_url( wp_get_preview_post_url( $post_ID ) ) ),
 	 9 => sprintf( __('Post scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview post</a>'),
 		// translators: Publish box date format, see http://php.net/date
 		date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
-	10 => sprintf( __('Post draft updated. <a target="_blank" href="%s">Preview post</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
+	10 => sprintf( __('Post draft updated. <a target="_blank" href="%s">Preview post</a>'), esc_url( wp_get_preview_post_url( $post_ID ) ) ),
 );
 $messages['page'] = array(
 	 0 => '', // Unused. Messages start at index 1.
Index: wp-admin/includes/class-wp-posts-list-table.php
--- wp-admin/includes/class-wp-posts-list-table.php
+++ wp-admin/includes/class-wp-posts-list-table.php
@@ -587,7 +587,7 @@
 				if ( $post_type_object->public ) {
 					if ( in_array( $post->post_status, array( 'pending', 'draft', 'future' ) ) ) {
 						if ( $can_edit_post )
-							$actions['view'] = '<a href="' . esc_url( apply_filters( 'preview_post_link', add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ) . '" title="' . esc_attr( sprintf( __( 'Preview &#8220;%s&#8221;' ), $title ) ) . '" rel="permalink">' . __( 'Preview' ) . '</a>';
+							$actions['view'] = '<a href="' . esc_url( wp_get_preview_post_url( $post->ID ) ) . '" title="' . esc_attr( sprintf( __( 'Preview &#8220;%s&#8221;' ), $title ) ) . '" rel="permalink">' . __( 'Preview' ) . '</a>';
 					} elseif ( 'trash' != $post->post_status ) {
 						$actions['view'] = '<a href="' . get_permalink( $post->ID ) . '" title="' . esc_attr( sprintf( __( 'View &#8220;%s&#8221;' ), $title ) ) . '" rel="permalink">' . __( 'View' ) . '</a>';
 					}
Index: wp-admin/includes/meta-boxes.php
--- wp-admin/includes/meta-boxes.php
+++ wp-admin/includes/meta-boxes.php
@@ -41,8 +41,7 @@
 	$preview_link = esc_url( get_permalink( $post->ID ) );
 	$preview_button = __( 'Preview Changes' );
 } else {
-	$preview_link = set_url_scheme( get_permalink( $post->ID ) );
-	$preview_link = esc_url( apply_filters( 'preview_post_link', add_query_arg( 'preview', 'true', $preview_link ) ) );
\ No newline at end of file
+	$preview_link = esc_url( wp_get_preview_post_url( $post->ID ) );
\ No newline at end of file
 	$preview_button = __( 'Preview' );
 }
 ?>
Index: wp-admin/includes/post.php
--- wp-admin/includes/post.php
+++ wp-admin/includes/post.php
@@ -1213,15 +1213,7 @@
 	<?php
 
 	if ( $locked ) {
-		$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 );
-		}
-
-		$preview_link = apply_filters( 'preview_post_link', $preview_link );
+		$preview_link = wp_get_preview_post_url( $post->ID );
 		$override = apply_filters( 'override_post_lock', true, $post, $user );
 		$tab_last = $override ? '' : ' wp-tab-last';
 
@@ -1372,12 +1364,5 @@
 	if ( is_wp_error($id) )
 		wp_die( $id->get_error_message() );
 
-	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);
-		$url = add_query_arg( array( 'preview' => 'true', 'preview_id' => $id, 'preview_nonce' => $nonce ), get_permalink($id) );
-	}
-
-	return apply_filters( 'preview_post_link', $url );
+	return wp_get_preview_post_url( $id );
 }
Index: wp-includes/default-filters.php
--- wp-includes/default-filters.php
+++ wp-includes/default-filters.php
@@ -276,7 +276,7 @@
 add_action( 'post_updated',      'wp_check_for_changed_slugs', 12, 3 );
 
 // Nonce check for Post Previews
-add_action( 'init', '_show_post_preview' );
+add_action( 'set_current_user', '_show_post_preview', 20 );
 
 // Timezone
 add_filter( 'pre_option_gmt_offset','wp_timezone_override_offset' );
Index: wp-includes/post.php
--- wp-includes/post.php
+++ wp-includes/post.php
@@ -4962,3 +4962,57 @@
 		update_post_caches( $fresh_posts, 'any', $update_term_cache, $update_meta_cache );
 	}
 }
+
+/**
+ * Return the URL used to preview a post.
+ *
+ * Checks that the post type is public, and makes sure the current user has the
+ * capability to view the post preview.
+ *
+ * @todo Always add the nonce and pass the preview_id?
+ *
+ * @since 3.6
+ * @param int $post_id The post ID to preview
+ * @return mixed Boolean false if no URL; String if URL
+ */
+function wp_get_preview_post_url( $post_id = 0 ) {
+
+	// Default return value
+	$preview_link = false;
+
+	// Get the post
+	$_post = get_post( $post_id );
+	if ( ! empty( $_post ) ) {
+
+		// Get the post type object, to check scope and get correct capability
+		$post_type_object = get_post_type_object( $_post->post_type );
+
+		// Only if post type is public
+		if ( $post_type_object->public ) {
+
+			// Use post permalink as preview base, and add the preview query arg
+			$preview_link   = set_url_scheme( add_query_arg( 'preview', 'true', get_permalink( $_post->ID ) ) );
+
+			// Get correct capability, and check if user has it
+			$edit_cap       = ( 'page' == $_post->post_type ) ? $post_type_object->cap->edit_page : $post_type_object->cap->edit_post;
+			$user_has_caps  = ( current_user_can( $edit_cap, $_post->ID ) );
+
+			// Is the current user the author of the post (since 3.6)
+			$user_is_author = ( get_current_user_id() == $_post->post_author );
+
+			// Hardcode the post statuses for now
+			// @todo check get_post_status_object() instead?
+			// @link http://core.trac.wordpress.org/attachment/ticket/23665/23665-post-preview.patch
+			$draft_check   = in_array( $_post->post_status, array( 'pending', 'draft'  ) );
+			$future_check  = in_array( $_post->post_status, array( 'publish', 'future' ) );
+
+			// Nonce preview URL in certain user-to-post-status comparison conditions
+			if ( ( $user_has_caps && $draft_check ) || ( $user_is_author && $future_check ) ) {
+				$nonce        = wp_create_nonce( 'post_preview_' . $_post->ID );
+				$preview_link = add_query_arg( array( 'preview_id' => $_post->ID, 'preview_nonce' => $nonce ), $preview_link );
+			}
+		}
+	}
+
+	return apply_filters( 'preview_post_link', $preview_link, $_post, $post_id );
+}
Index: wp-includes/revision.php
--- wp-includes/revision.php
+++ wp-includes/revision.php
@@ -501,7 +501,7 @@
 	if ( ! is_object($post) )
 		return $post;
 
-	$preview = wp_get_post_autosave($post->ID);
+	$preview = wp_get_post_autosave( $post->ID, get_current_user_id() );
 
 	if ( ! is_object($preview) )
 		return $post;
