Index: src/wp-admin/edit-form-advanced.php
===================================================================
--- src/wp-admin/edit-form-advanced.php	(revision 33664)
+++ src/wp-admin/edit-form-advanced.php	(working copy)
@@ -84,21 +84,45 @@
 /** This filter is documented in wp-admin/includes/meta-boxes.php */
 $post_preview_url = apply_filters( 'preview_post_link', add_query_arg( 'preview', 'true', $permalink ), $post );
 
+$preview_link_html = $scheduled_link_html = $view_post_html = '';
+
+$viewable = is_post_type_viewable( $post_type_object );
+
+if ( $viewable ) {
+	// Preview link.
+	$preview_link_html = sprintf( ' <a target="_blank" href="%s">%s</a>',
+		esc_url( $post_preview_url ),
+		__( 'Preview post' )
+	);
+
+	// Scheduled preview link.
+	$scheduled_link_html = sprintf( ' <a target="_blank" href="%s">%s</a>',
+		esc_url( $permalink ),
+		__( 'Preview post' )
+	);
+
+	// View post link.
+	$view_post_html = sprintf( ' <a href="%s">">%</a>',
+		esc_url( $permalink ),
+		__( 'View post' )
+	);
+}
+
+/* translators: Publish box date format, see http://php.net/date */
+$scheduled_date = date_i18n( __( 'M j, Y @ H:i' ), strtotime( $post->post_date ) );
 $messages['post'] = array(
 	 0 => '', // Unused. Messages start at index 1.
-	 1 => sprintf( __('Post updated. <a href="%s">View post</a>'), esc_url( $permalink ) ),
+	 1 => __( 'Post updated.' ) . $view_post_html,
 	 2 => __('Custom field updated.'),
 	 3 => __('Custom field deleted.'),
 	 4 => __('Post updated.'),
 	/* translators: %s: date and time of the revision */
 	 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( $permalink ) ),
+	 6 => __( 'Post published.' ) . $view_post_html,
 	 7 => __('Post saved.'),
-	 8 => sprintf( __('Post submitted. <a target="_blank" href="%s">Preview post</a>'), esc_url( $post_preview_url ) ),
-	 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 @ H:i' ), strtotime( $post->post_date ) ), esc_url( $permalink ) ),
-	10 => sprintf( __('Post draft updated. <a target="_blank" href="%s">Preview post</a>'), esc_url( $post_preview_url ) ),
+	 8 => __( 'Post submitted.' ) . $preview_link_html,
+	 9 => sprintf( __( 'Post scheduled for: <strong>%1$s</strong>' ), $scheduled_date ) . $scheduled_link_html,
+	10 => __( 'Post draft updated.' ) . $preview_link_html,
 );
 
 /** This filter is documented in wp-admin/includes/meta-boxes.php */
@@ -508,6 +532,7 @@
 ?>
 <div class="inside">
 <?php
+if ( $viewable ) :
 $sample_permalink_html = $post_type_object->public ? get_sample_permalink_html($post->ID) : '';
 $shortlink = wp_get_shortlink($post->ID, 'post');
 
@@ -525,6 +550,7 @@
 	</div>
 <?php
 }
+endif;
 ?>
 </div>
 <?php
Index: src/wp-admin/includes/class-wp-posts-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-posts-list-table.php	(revision 33664)
+++ src/wp-admin/includes/class-wp-posts-list-table.php	(working copy)
@@ -1072,7 +1072,7 @@
 				$actions['delete'] = "<a class='submitdelete' title='" . esc_attr__( 'Delete this item permanently' ) . "' href='" . get_delete_post_link( $post->ID, '', true ) . "'>" . __( 'Delete Permanently' ) . "</a>";
 		}
 
-		if ( $post_type_object->public ) {
+		if ( is_post_type_viewable( $post_type_object ) ) {
 			$title = _draft_or_post_title();
 			if ( in_array( $post->post_status, array( 'pending', 'draft', 'future' ) ) ) {
 				if ( $can_edit_post ) {
Index: src/wp-admin/includes/meta-boxes.php
===================================================================
--- src/wp-admin/includes/meta-boxes.php	(revision 33664)
+++ src/wp-admin/includes/meta-boxes.php	(working copy)
@@ -31,12 +31,13 @@
 <div id="save-action">
 <?php if ( 'publish' != $post->post_status && 'future' != $post->post_status && 'pending' != $post->post_status ) { ?>
 <input <?php if ( 'private' == $post->post_status ) { ?>style="display:none"<?php } ?> type="submit" name="save" id="save-post" value="<?php esc_attr_e('Save Draft'); ?>" class="button" />
+<span class="spinner"></span>
 <?php } elseif ( 'pending' == $post->post_status && $can_publish ) { ?>
 <input type="submit" name="save" id="save-post" value="<?php esc_attr_e('Save as Pending'); ?>" class="button" />
+<span class="spinner"></span>
 <?php } ?>
-<span class="spinner"></span>
 </div>
-<?php if ( $post_type_object->public ) : ?>
+<?php if ( is_post_type_viewable( $post_type_object ) ) : ?>
 <div id="preview-action">
 <?php
 if ( 'publish' == $post->post_status ) {
Index: src/wp-includes/post.php
===================================================================
--- src/wp-includes/post.php	(revision 33664)
+++ src/wp-includes/post.php	(working copy)
@@ -1844,6 +1844,21 @@
 }
 
 /**
+ * Determines whether a post type is considered "viewable".
+ *
+ * For built-in post types such as posts and pages, the 'public' value will be evaluated.
+ * For all others, the 'publicly_queryable' value will be used.
+ *
+ * @since 4.4.0
+ *
+ * @param object $post_type_object Post type object.
+ * @return bool Whether the post type should be considered viewable.
+ */
+function is_post_type_viewable( $post_type_object ) {
+	return $post_type_object->publicly_queryable || ( $post_type_object->_builtin && $post_type_object->public );
+}
+
+/**
  * Retrieve list of latest posts or posts matching criteria.
  *
  * The defaults are as follows:
