Index: /trunk/src/wp-admin/includes/class-wp-comments-list-table.php
===================================================================
--- /trunk/src/wp-admin/includes/class-wp-comments-list-table.php	(revision 32643)
+++ /trunk/src/wp-admin/includes/class-wp-comments-list-table.php	(revision 32644)
@@ -358,4 +358,16 @@
 	}
 
+	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'comment';
+	}
+
 	public function display() {
 		wp_nonce_field( "fetch-list-" . get_class( $this ), '_ajax_fetch_list_nonce' );
@@ -414,4 +426,119 @@
 		$this->single_row_columns( $comment );
 		echo "</tr>\n";
+	}
+
+ 	/**
+ 	 * Generate and display row actions links
+ 	 *
+ 	 * @since 4.3.0
+ 	 * @access protected
+ 	 *
+ 	 * @param object $comment Comment being acted upon
+ 	 * @param string $column_name Current column name
+ 	 * @param string $primary Primary column name
+ 	 *
+ 	 * @return string
+ 	 */
+ 	protected function handle_row_actions( $comment, $column_name, $primary ) {
+ 		global $comment_status;
+ 
+ 		if ( ! $this->user_can ) {
+ 			return;
+
+		}
+
+		$post = get_post();
+
+		$the_comment_status = wp_get_comment_status( $comment->comment_ID );
+
+		$out = '';
+
+		if( $primary === $column_name ) {
+			$del_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "delete-comment_$comment->comment_ID" ) );
+			$approve_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "approve-comment_$comment->comment_ID" ) );
+
+			$url = "comment.php?c=$comment->comment_ID";
+
+			$approve_url = esc_url( $url . "&action=approvecomment&$approve_nonce" );
+			$unapprove_url = esc_url( $url . "&action=unapprovecomment&$approve_nonce" );
+			$spam_url = esc_url( $url . "&action=spamcomment&$del_nonce" );
+			$unspam_url = esc_url( $url . "&action=unspamcomment&$del_nonce" );
+			$trash_url = esc_url( $url . "&action=trashcomment&$del_nonce" );
+			$untrash_url = esc_url( $url . "&action=untrashcomment&$del_nonce" );
+			$delete_url = esc_url( $url . "&action=deletecomment&$del_nonce" );
+
+			// Preorder it: Approve | Reply | Quick Edit | Edit | Spam | Trash.
+			$actions = array(
+				'approve' => '', 'unapprove' => '',
+				'reply' => '',
+				'quickedit' => '',
+				'edit' => '',
+				'spam' => '', 'unspam' => '',
+				'trash' => '', 'untrash' => '', 'delete' => ''
+			);
+
+			// Not looking at all comments.
+			if ( $comment_status && 'all' != $comment_status ) {
+				if ( 'approved' == $the_comment_status ) {
+					$actions['unapprove'] = "<a href='$unapprove_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:e7e7d3:action=dim-comment&amp;new=unapproved' class='vim-u vim-destructive' title='" . esc_attr__( 'Unapprove this comment' ) . "'>" . __( 'Unapprove' ) . '</a>';
+				} elseif ( 'unapproved' == $the_comment_status ) {
+					$actions['approve'] = "<a href='$approve_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:e7e7d3:action=dim-comment&amp;new=approved' class='vim-a vim-destructive' title='" . esc_attr__( 'Approve this comment' ) . "'>" . __( 'Approve' ) . '</a>';
+				}
+			} else {
+				$actions['approve'] = "<a href='$approve_url' data-wp-lists='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=approved' class='vim-a' title='" . esc_attr__( 'Approve this comment' ) . "'>" . __( 'Approve' ) . '</a>';
+				$actions['unapprove'] = "<a href='$unapprove_url' data-wp-lists='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=unapproved' class='vim-u' title='" . esc_attr__( 'Unapprove this comment' ) . "'>" . __( 'Unapprove' ) . '</a>';
+			}
+
+			if ( 'spam' != $the_comment_status ) {
+				$actions['spam'] = "<a href='$spam_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::spam=1' class='vim-s vim-destructive' title='" . esc_attr__( 'Mark this comment as spam' ) . "'>" . /* translators: mark as spam link */ _x( 'Spam', 'verb' ) . '</a>';
+			} elseif ( 'spam' == $the_comment_status ) {
+				$actions['unspam'] = "<a href='$unspam_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:66cc66:unspam=1' class='vim-z vim-destructive'>" . _x( 'Not Spam', 'comment' ) . '</a>';
+			}
+
+			if ( 'trash' == $the_comment_status ) {
+				$actions['untrash'] = "<a href='$untrash_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:66cc66:untrash=1' class='vim-z vim-destructive'>" . __( 'Restore' ) . '</a>';
+			}
+
+			if ( 'spam' == $the_comment_status || 'trash' == $the_comment_status || !EMPTY_TRASH_DAYS ) {
+				$actions['delete'] = "<a href='$delete_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::delete=1' class='delete vim-d vim-destructive'>" . __( 'Delete Permanently' ) . '</a>';
+			} else {
+				$actions['trash'] = "<a href='$trash_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::trash=1' class='delete vim-d vim-destructive' title='" . esc_attr__( 'Move this comment to the trash' ) . "'>" . _x( 'Trash', 'verb' ) . '</a>';
+			}
+
+			if ( 'spam' != $the_comment_status && 'trash' != $the_comment_status ) {
+				$actions['edit'] = "<a href='comment.php?action=editcomment&amp;c={$comment->comment_ID}' title='" . esc_attr__( 'Edit comment' ) . "'>". __( 'Edit' ) . '</a>';
+
+				$format = '<a data-comment-id="%d" data-post-id="%d" data-action="%s" class="%s" title="%s" href="#">%s</a>';
+
+				$actions['quickedit'] = sprintf( $format, $comment->comment_ID, $post->ID, 'edit', 'vim-q comment-inline',esc_attr__( 'Edit this item inline' ), __( 'Quick&nbsp;Edit' ) );
+
+				$actions['reply'] = sprintf( $format, $comment->comment_ID, $post->ID, 'replyto', 'vim-r comment-inline', esc_attr__( 'Reply to this comment' ), __( 'Reply' ) );
+			}
+
+			/** This filter is documented in wp-admin/includes/dashboard.php */
+			$actions = apply_filters( 'comment_row_actions', array_filter( $actions ), $comment );
+
+			$i = 0;
+			$out .= '<div class="row-actions">';
+			foreach ( $actions as $action => $link ) {
+				++$i;
+				( ( ( 'approve' == $action || 'unapprove' == $action ) && 2 === $i ) || 1 === $i ) ? $sep = '' : $sep = ' | ';
+
+				// Reply and quickedit need a hide-if-no-js span when not added with ajax
+				if ( ( 'reply' == $action || 'quickedit' == $action ) && ! defined('DOING_AJAX') )
+					$action .= ' hide-if-no-js';
+				elseif ( ( $action == 'untrash' && $the_comment_status == 'trash' ) || ( $action == 'unspam' && $the_comment_status == 'spam' ) ) {
+					if ( '1' == get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true ) )
+						$action .= ' approve';
+					else
+						$action .= ' unapprove';
+				}
+
+				$out .= "<span class='$action'>$sep$link</span>";
+			}
+			$out .= '</div>';
+		}
+
+		return $out;
 	}
 
@@ -470,90 +597,4 @@
 		<?php
 		}
-
-		if ( $this->user_can ) {
-			$del_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "delete-comment_$comment->comment_ID" ) );
-			$approve_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "approve-comment_$comment->comment_ID" ) );
-
-			$url = "comment.php?c=$comment->comment_ID";
-
-			$approve_url = esc_url( $url . "&action=approvecomment&$approve_nonce" );
-			$unapprove_url = esc_url( $url . "&action=unapprovecomment&$approve_nonce" );
-			$spam_url = esc_url( $url . "&action=spamcomment&$del_nonce" );
-			$unspam_url = esc_url( $url . "&action=unspamcomment&$del_nonce" );
-			$trash_url = esc_url( $url . "&action=trashcomment&$del_nonce" );
-			$untrash_url = esc_url( $url . "&action=untrashcomment&$del_nonce" );
-			$delete_url = esc_url( $url . "&action=deletecomment&$del_nonce" );
-
-			// Preorder it: Approve | Reply | Quick Edit | Edit | Spam | Trash.
-			$actions = array(
-				'approve' => '', 'unapprove' => '',
-				'reply' => '',
-				'quickedit' => '',
-				'edit' => '',
-				'spam' => '', 'unspam' => '',
-				'trash' => '', 'untrash' => '', 'delete' => ''
-			);
-
-			// Not looking at all comments.
-			if ( $comment_status && 'all' != $comment_status ) {
-				if ( 'approved' == $the_comment_status ) {
-					$actions['unapprove'] = "<a href='$unapprove_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:e7e7d3:action=dim-comment&amp;new=unapproved' class='vim-u vim-destructive' title='" . esc_attr__( 'Unapprove this comment' ) . "'>" . __( 'Unapprove' ) . '</a>';
-				} elseif ( 'unapproved' == $the_comment_status ) {
-					$actions['approve'] = "<a href='$approve_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:e7e7d3:action=dim-comment&amp;new=approved' class='vim-a vim-destructive' title='" . esc_attr__( 'Approve this comment' ) . "'>" . __( 'Approve' ) . '</a>';
-				}
-			} else {
-				$actions['approve'] = "<a href='$approve_url' data-wp-lists='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=approved' class='vim-a' title='" . esc_attr__( 'Approve this comment' ) . "'>" . __( 'Approve' ) . '</a>';
-				$actions['unapprove'] = "<a href='$unapprove_url' data-wp-lists='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=unapproved' class='vim-u' title='" . esc_attr__( 'Unapprove this comment' ) . "'>" . __( 'Unapprove' ) . '</a>';
-			}
-
-			if ( 'spam' != $the_comment_status ) {
-				$actions['spam'] = "<a href='$spam_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::spam=1' class='vim-s vim-destructive' title='" . esc_attr__( 'Mark this comment as spam' ) . "'>" . /* translators: mark as spam link */ _x( 'Spam', 'verb' ) . '</a>';
-			} elseif ( 'spam' == $the_comment_status ) {
-				$actions['unspam'] = "<a href='$unspam_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:66cc66:unspam=1' class='vim-z vim-destructive'>" . _x( 'Not Spam', 'comment' ) . '</a>';
-			}
-
-			if ( 'trash' == $the_comment_status ) {
-				$actions['untrash'] = "<a href='$untrash_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:66cc66:untrash=1' class='vim-z vim-destructive'>" . __( 'Restore' ) . '</a>';
-			}
-
-			if ( 'spam' == $the_comment_status || 'trash' == $the_comment_status || !EMPTY_TRASH_DAYS ) {
-				$actions['delete'] = "<a href='$delete_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::delete=1' class='delete vim-d vim-destructive'>" . __( 'Delete Permanently' ) . '</a>';
-			} else {
-				$actions['trash'] = "<a href='$trash_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::trash=1' class='delete vim-d vim-destructive' title='" . esc_attr__( 'Move this comment to the trash' ) . "'>" . _x( 'Trash', 'verb' ) . '</a>';
-			}
-
-			if ( 'spam' != $the_comment_status && 'trash' != $the_comment_status ) {
-				$actions['edit'] = "<a href='comment.php?action=editcomment&amp;c={$comment->comment_ID}' title='" . esc_attr__( 'Edit comment' ) . "'>". __( 'Edit' ) . '</a>';
-
-				$format = '<a data-comment-id="%d" data-post-id="%d" data-action="%s" class="%s" title="%s" href="#">%s</a>';
-
-				$actions['quickedit'] = sprintf( $format, $comment->comment_ID, $post->ID, 'edit', 'vim-q comment-inline',esc_attr__( 'Edit this item inline' ), __( 'Quick&nbsp;Edit' ) );
-
-				$actions['reply'] = sprintf( $format, $comment->comment_ID, $post->ID, 'replyto', 'vim-r comment-inline', esc_attr__( 'Reply to this comment' ), __( 'Reply' ) );
-			}
-
-			/** This filter is documented in wp-admin/includes/dashboard.php */
-			$actions = apply_filters( 'comment_row_actions', array_filter( $actions ), $comment );
-
-			$i = 0;
-			echo '<div class="row-actions">';
-			foreach ( $actions as $action => $link ) {
-				++$i;
-				( ( ( 'approve' == $action || 'unapprove' == $action ) && 2 === $i ) || 1 === $i ) ? $sep = '' : $sep = ' | ';
-
-				// Reply and quickedit need a hide-if-no-js span when not added with ajax
-				if ( ( 'reply' == $action || 'quickedit' == $action ) && ! defined('DOING_AJAX') )
-					$action .= ' hide-if-no-js';
-				elseif ( ( $action == 'untrash' && $the_comment_status == 'trash' ) || ( $action == 'unspam' && $the_comment_status == 'spam' ) ) {
-					if ( '1' == get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true ) )
-						$action .= ' approve';
-					else
-						$action .= ' unapprove';
-				}
-
-				echo "<span class='$action'>$sep$link</span>";
-			}
-			echo '</div>';
-		}
 	}
 
Index: /trunk/src/wp-admin/includes/class-wp-links-list-table.php
===================================================================
--- /trunk/src/wp-admin/includes/class-wp-links-list-table.php	(revision 32643)
+++ /trunk/src/wp-admin/includes/class-wp-links-list-table.php	(revision 32644)
@@ -122,4 +122,16 @@
 
 	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'name';
+	}
+
+	/**
 	 *
 	 * @global int $cat_id
@@ -143,64 +155,59 @@
 <?php
 
-			list( $columns, $hidden ) = $this->get_column_info();
+			list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
 
 			foreach ( $columns as $column_name => $column_display_name ) {
-				$class = "class='column-$column_name'";
+				$classes = "$column_name column-$column_name";
+				if ( $primary === $column_name ) {
+					$classes .= ' has-row-actions column-primary';
+				}
 
 				$style = '';
-				if ( in_array( $column_name, $hidden ) )
+				if ( in_array( $column_name, $hidden ) ) {
 					$style = ' style="display:none;"';
-
-				$attributes = $class . $style;
-
-				switch ( $column_name ) {
-					case 'cb': ?>
-						<th scope="row" class="check-column">
-							<label class="screen-reader-text" for="cb-select-<?php echo $link->link_id; ?>"><?php echo sprintf( __( 'Select %s' ), $link->link_name ); ?></label>
-							<input type="checkbox" name="linkcheck[]" id="cb-select-<?php echo $link->link_id; ?>" value="<?php echo esc_attr( $link->link_id ); ?>" />
-						</th>
-						<?php
-						break;
-
-					case 'name':
-						echo "<td $attributes><strong><a class='row-title' href='$edit_link' title='" . esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $link->link_name ) ) . "'>$link->link_name</a></strong><br />";
-
-						$actions = array();
-						$actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
-						$actions['delete'] = "<a class='submitdelete' href='" . wp_nonce_url( "link.php?action=delete&amp;link_id=$link->link_id", 'delete-bookmark_' . $link->link_id ) . "' onclick=\"if ( confirm( '" . esc_js( sprintf( __( "You are about to delete this link '%s'\n  'Cancel' to stop, 'OK' to delete." ), $link->link_name ) ) . "' ) ) { return true;}return false;\">" . __( 'Delete' ) . "</a>";
-						echo $this->row_actions( $actions );
-
-						echo '</td>';
-						break;
-					case 'url':
-						echo "<td $attributes><a href='$link->link_url' title='". esc_attr( sprintf( __( 'Visit %s' ), $link->link_name ) )."'>$short_url</a></td>";
-						break;
-					case 'categories':
-						?><td <?php echo $attributes ?>><?php
-						$cat_names = array();
-						foreach ( $link->link_category as $category ) {
-							$cat = get_term( $category, 'link_category', OBJECT, 'display' );
-							if ( is_wp_error( $cat ) )
-								echo $cat->get_error_message();
-							$cat_name = $cat->name;
-							if ( $cat_id != $category )
-								$cat_name = "<a href='link-manager.php?cat_id=$category'>$cat_name</a>";
-							$cat_names[] = $cat_name;
-						}
-						echo implode( ', ', $cat_names );
-						?></td><?php
-						break;
-					case 'rel':
-						?><td <?php echo $attributes ?>><?php echo empty( $link->link_rel ) ? '<br />' : $link->link_rel; ?></td><?php
-						break;
-					case 'visible':
-						?><td <?php echo $attributes ?>><?php echo $visible; ?></td><?php
-						break;
-					case 'rating':
-	 					?><td <?php echo $attributes ?>><?php echo $rating; ?></td><?php
-						break;
-					default:
-						?>
-						<td <?php echo $attributes ?>><?php
+				}
+
+				$attributes = "class='$classes'$style";
+
+				if ( 'cb' === $column_name ) {
+					?>
+					<th scope="row" class="check-column">
+						<label class="screen-reader-text" for="cb-select-<?php echo $link->link_id; ?>"><?php echo sprintf( __( 'Select %s' ), $link->link_name ); ?></label>
+						<input type="checkbox" name="linkcheck[]" id="cb-select-<?php echo $link->link_id; ?>" value="<?php echo esc_attr( $link->link_id ); ?>" />
+					</th>
+					<?php
+				} else {
+					echo "<td $attributes>";
+
+					switch ( $column_name ) {
+						case 'name':
+							echo "<strong><a class='row-title' href='$edit_link' title='" . esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $link->link_name ) ) . "'>$link->link_name</a></strong><br />";
+							break;
+						case 'url':
+							echo "<a href='$link->link_url' title='". esc_attr( sprintf( __( 'Visit %s' ), $link->link_name ) )."'>$short_url</a>";
+							break;
+						case 'categories':
+							$cat_names = array();
+							foreach ( $link->link_category as $category ) {
+								$cat = get_term( $category, 'link_category', OBJECT, 'display' );
+								if ( is_wp_error( $cat ) )
+									echo $cat->get_error_message();
+								$cat_name = $cat->name;
+								if ( $cat_id != $category )
+									$cat_name = "<a href='link-manager.php?cat_id=$category'>$cat_name</a>";
+								$cat_names[] = $cat_name;
+							}
+							echo implode( ', ', $cat_names );
+							break;
+						case 'rel':
+							echo empty( $link->link_rel ) ? '<br />' : $link->link_rel;
+							break;
+						case 'visible':
+							echo $visible;
+							break;
+						case 'rating':
+							echo $rating;
+							break;
+						default:
 							/**
 							 * Fires for each registered custom link column.
@@ -212,7 +219,9 @@
 							 */
 							do_action( 'manage_link_custom_column', $column_name, $link->link_id );
-						?></td>
-						<?php
-						break;
+							break;
+					}
+
+					echo $this->handle_row_actions( $link, $column_name, $primary );
+					echo '</td>';
 				}
 			}
@@ -222,3 +231,26 @@
 		}
 	}
+
+	/**
+	 * Generate and display row actions links
+	 *
+	 * @since 4.3
+	 * @access protected
+	 *
+	 * @param object $link Link being acted upon
+	 * @param string $column_name Current column name
+	 * @param string $primary Primary column name
+	 *
+	 * @return string
+	 */
+	protected function handle_row_actions( $link, $column_name, $primary ) {
+		if( $primary === $column_name ) {
+			$edit_link = get_edit_bookmark_link( $link );
+
+			$actions = array();
+			$actions['edit'] = '<a href="' . $edit_link . '">' . __('Edit') . '</a>';
+			$actions['delete'] = "<a class='submitdelete' href='" . wp_nonce_url("link.php?action=delete&amp;link_id=$link->link_id", 'delete-bookmark_' . $link->link_id) . "' onclick=\"if ( confirm( '" . esc_js(sprintf(__("You are about to delete this link '%s'\n  'Cancel' to stop, 'OK' to delete."), $link->link_name)) . "' ) ) { return true;}return false;\">" . __('Delete') . "</a>";
+			return $this->row_actions($actions);
+		}
+	}
 }
Index: /trunk/src/wp-admin/includes/class-wp-list-table.php
===================================================================
--- /trunk/src/wp-admin/includes/class-wp-list-table.php	(revision 32643)
+++ /trunk/src/wp-admin/includes/class-wp-list-table.php	(revision 32644)
@@ -796,4 +796,44 @@
 
 	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return '';
+	}
+
+	/**
+	 * Get name of primary column.
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @return string Filtered name of primary column
+	 */
+	protected function get_primary_column_name() {
+		$columns = $this->get_columns();
+		$default = $this->get_default_primary_column_name();
+		/**
+		 * Filter the name of the primary column for the current list table, with context as argument (eg: 'plugins').
+		 *
+		 * @since 4.3.0
+		 *
+		 * @param string $default Column name default for the specific list table (eg: 'name')
+		 * @param string $context Screen ID for specific list table (eg: 'plugins')
+		 */
+		$column  = apply_filters( 'list_table_primary_column', $default, $this->screen->id );
+
+		if ( empty( $column ) || ! isset( $columns[ $column ] ) ) {
+			$column = $default;
+		}
+
+		return $column;
+	}
+
+	/**
 	 * Get a list of all, hidden and sortable columns, with filter applied
 	 *
@@ -835,5 +875,6 @@
 		}
 
-		$this->_column_headers = array( $columns, $hidden, $sortable );
+		$primary = $this->get_primary_column_name();
+		$this->_column_headers = array( $columns, $hidden, $sortable, $primary );
 
 		return $this->_column_headers;
@@ -1063,14 +1104,18 @@
 	 */
 	protected function single_row_columns( $item ) {
-		list( $columns, $hidden ) = $this->get_column_info();
+		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
 
 		foreach ( $columns as $column_name => $column_display_name ) {
-			$class = "class='$column_name column-$column_name'";
+			$classes = "$column_name column-$column_name";
+			if ( $primary === $column_name ) {
+				$classes .= ' has-row-actions column-primary';
+			}
 
 			$style = '';
-			if ( in_array( $column_name, $hidden ) )
+			if ( in_array( $column_name, $hidden ) ) {
 				$style = ' style="display:none;"';
-
-			$attributes = "$class$style";
+			}
+
+			$attributes = "class='$classes'$style";
 
 			if ( 'cb' == $column_name ) {
@@ -1082,4 +1127,5 @@
 				echo "<td $attributes>";
 				echo call_user_func( array( $this, 'column_' . $column_name ), $item );
+				echo $this->handle_row_actions( $item, $column_name, $primary );
 				echo "</td>";
 			}
@@ -1087,8 +1133,25 @@
 				echo "<td $attributes>";
 				echo $this->column_default( $item, $column_name );
+				echo $this->handle_row_actions( $item, $column_name, $primary );
 				echo "</td>";
 			}
 		}
 	}
+
+	/**
+	 * Generate and display row actions links
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @param object $item Item being acted upon
+	 * @param string $column_name Current column name
+	 * @param string $primary Primary column name
+	 *
+	 * @return string
+	 */
+	protected function handle_row_actions( $item, $column_name, $primary ) {
+		return '';
+ 	}
 
 	/**
Index: /trunk/src/wp-admin/includes/class-wp-media-list-table.php
===================================================================
--- /trunk/src/wp-admin/includes/class-wp-media-list-table.php	(revision 32643)
+++ /trunk/src/wp-admin/includes/class-wp-media-list-table.php	(revision 32644)
@@ -309,17 +309,20 @@
 <?php
 
-list( $columns, $hidden ) = $this->get_column_info();
+list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
+
 foreach ( $columns as $column_name => $column_display_name ) {
-	$class = "class='$column_name column-$column_name'";
+	$classes = "$column_name column-$column_name";
+	if ( $primary === $column_name ) {
+		$classes .= ' has-row-actions column-primary';
+	}
 
 	$style = '';
-	if ( in_array( $column_name, $hidden ) )
+	if ( in_array( $column_name, $hidden ) ) {
 		$style = ' style="display:none;"';
-
-	$attributes = $class . $style;
-
-	switch ( $column_name ) {
-
-	case 'cb':
+	}
+
+	$attributes = "class='$classes'$style";
+
+	if ( 'cb' === $column_name ) {
 ?>
 		<th scope="row" class="check-column">
@@ -330,188 +333,169 @@
 		</th>
 <?php
-		break;
-
-	case 'icon':
-		list( $mime ) = explode( '/', $post->post_mime_type );
-		$attributes = 'class="column-icon media-icon ' . $mime . '-icon"' . $style;
-?>
-		<td <?php echo $attributes ?>><?php
-			if ( $thumb = wp_get_attachment_image( $post->ID, array( 80, 60 ), true ) ) {
-				if ( $this->is_trash || ! $user_can_edit ) {
-					echo $thumb;
+	} else {
+		echo "<td $attributes>";
+
+		switch ( $column_name ) {
+			case 'icon':
+				list( $mime ) = explode( '/', $post->post_mime_type );
+				$attributes = 'class="column-icon media-icon ' . $mime . '-icon"' . $style;
+
+				if ( $thumb = wp_get_attachment_image( $post->ID, array( 80, 60 ), true ) ) {
+					if ( $this->is_trash || ! $user_can_edit ) {
+						echo $thumb;
+					} else { ?>
+					<a href="<?php echo get_edit_post_link( $post->ID ); ?>" title="<?php echo esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $att_title ) ); ?>">
+						<?php echo $thumb; ?>
+					</a><?php
+					}
+				}
+				break;
+
+			case 'title':
+?>
+					<strong>
+					<?php if ( $this->is_trash || ! $user_can_edit ) {
+						echo $att_title;
+					} else { ?>
+					<a href="<?php echo get_edit_post_link( $post->ID ); ?>"
+						title="<?php echo esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $att_title ) ); ?>">
+						<?php echo $att_title; ?></a>
+					<?php }
+					_media_states( $post ); ?></strong>
+					<p class="filename"><?php echo wp_basename( $post->guid ); ?></p>
+<?php
+				break;
+
+			case 'author':
+				printf( '<a href="%s">%s</a>',
+					esc_url( add_query_arg( array( 'author' => get_the_author_meta('ID') ), 'upload.php' ) ),
+					get_the_author()
+				);
+
+				break;
+
+			case 'desc':
+				echo has_excerpt() ? $post->post_excerpt : '';
+				break;
+
+			case 'date':
+				if ( '0000-00-00 00:00:00' == $post->post_date ) {
+					$h_time = __( 'Unpublished' );
 				} else {
-?>
-				<a href="<?php echo get_edit_post_link( $post->ID ); ?>" title="<?php echo esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $att_title ) ); ?>">
-					<?php echo $thumb; ?>
-				</a>
-
-<?php			}
-			}
-?>
-		</td>
-<?php
-		break;
-
-	case 'title':
-?>
-		<td <?php echo $attributes ?>><strong>
-			<?php if ( $this->is_trash || ! $user_can_edit ) {
-				echo $att_title;
-			} else { ?>
-			<a href="<?php echo get_edit_post_link( $post->ID ); ?>"
-				title="<?php echo esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $att_title ) ); ?>">
-				<?php echo $att_title; ?></a>
-			<?php };
-			_media_states( $post ); ?></strong>
-			<p class="filename"><?php echo wp_basename( $post->guid ); ?></p>
-<?php
-		echo $this->row_actions( $this->_get_row_actions( $post, $att_title ) );
-?>
-		</td>
-<?php
-		break;
-
-	case 'author':
-?>
-		<td <?php echo $attributes ?>><?php
-			printf( '<a href="%s">%s</a>',
-				esc_url( add_query_arg( array( 'author' => get_the_author_meta('ID') ), 'upload.php' ) ),
-				get_the_author()
-			);
-		?></td>
-<?php
-		break;
-
-	case 'desc':
-?>
-		<td <?php echo $attributes ?>><?php echo has_excerpt() ? $post->post_excerpt : ''; ?></td>
-<?php
-		break;
-
-	case 'date':
-		if ( '0000-00-00 00:00:00' == $post->post_date ) {
-			$h_time = __( 'Unpublished' );
-		} else {
-			$m_time = $post->post_date;
-			$time = get_post_time( 'G', true, $post, false );
-			if ( ( abs( $t_diff = time() - $time ) ) < DAY_IN_SECONDS ) {
-				if ( $t_diff < 0 )
-					$h_time = sprintf( __( '%s from now' ), human_time_diff( $time ) );
+					$m_time = $post->post_date;
+					$time = get_post_time( 'G', true, $post, false );
+					if ( ( abs( $t_diff = time() - $time ) ) < DAY_IN_SECONDS ) {
+						if ( $t_diff < 0 )
+							$h_time = sprintf( __( '%s from now' ), human_time_diff( $time ) );
+						else
+							$h_time = sprintf( __( '%s ago' ), human_time_diff( $time ) );
+					} else {
+						$h_time = mysql2date( __( 'Y/m/d' ), $m_time );
+					}
+				}
+
+				echo $h_time;
+				break;
+
+			case 'parent':
+				if ( $post->post_parent > 0 )
+					$parent = get_post( $post->post_parent );
 				else
-					$h_time = sprintf( __( '%s ago' ), human_time_diff( $time ) );
-			} else {
-				$h_time = mysql2date( __( 'Y/m/d' ), $m_time );
-			}
-		}
-?>
-		<td <?php echo $attributes ?>><?php echo $h_time ?></td>
-<?php
-		break;
-
-	case 'parent':
-		if ( $post->post_parent > 0 )
-			$parent = get_post( $post->post_parent );
-		else
-			$parent = false;
-
-		if ( $parent ) {
-			$title = _draft_or_post_title( $post->post_parent );
-			$parent_type = get_post_type_object( $parent->post_type );
-?>
-			<td <?php echo $attributes ?>><strong>
-				<?php if ( $parent_type && $parent_type->show_ui && current_user_can( 'edit_post', $post->post_parent ) ) { ?>
-					<a href="<?php echo get_edit_post_link( $post->post_parent ); ?>">
-						<?php echo $title ?></a><?php
+					$parent = false;
+
+				if ( $parent ) {
+					$title = _draft_or_post_title( $post->post_parent );
+					$parent_type = get_post_type_object( $parent->post_type );
+		?>
+					<strong>
+					<?php if ( $parent_type && $parent_type->show_ui && current_user_can( 'edit_post', $post->post_parent ) ) { ?>
+						<a href="<?php echo get_edit_post_link( $post->post_parent ); ?>">
+							<?php echo $title ?></a><?php
+					} else {
+						echo $title;
+					} ?></strong>,
+					<?php echo get_the_time( __( 'Y/m/d' ) ); ?><br />
+					<?php
+					if ( $user_can_edit ):
+						$detach_url = add_query_arg( array(
+							'parent_post_id' => $post->post_parent,
+							'media[]' => $post->ID,
+							'_wpnonce' => wp_create_nonce( 'bulk-' . $this->_args['plural'] )
+						), 'upload.php' ); ?>
+					<a class="hide-if-no-js detach-from-parent" href="<?php echo $detach_url ?>"><?php _e( 'Detach' ); ?></a>
+					<?php endif;
 				} else {
-					echo $title;
-				} ?></strong>,
-				<?php echo get_the_time( __( 'Y/m/d' ) ); ?><br />
-				<?php
-				if ( $user_can_edit ):
-					$detach_url = add_query_arg( array(
-						'parent_post_id' => $post->post_parent,
-						'media[]' => $post->ID,
-						'_wpnonce' => wp_create_nonce( 'bulk-' . $this->_args['plural'] )
-					), 'upload.php' ); ?>
-				<a class="hide-if-no-js detach-from-parent" href="<?php echo $detach_url ?>"><?php _e( 'Detach' ); ?></a>
-				<?php endif; ?>
-			</td>
-<?php
-		} else {
-?>
-			<td <?php echo $attributes ?>><?php _e( '(Unattached)' ); ?><br />
-			<?php if ( $user_can_edit ) { ?>
-				<a class="hide-if-no-js"
-					onclick="findPosts.open( 'media[]','<?php echo $post->ID ?>' ); return false;"
-					href="#the-list">
-					<?php _e( 'Attach' ); ?></a>
-			<?php } ?></td>
-<?php
-		}
-		break;
-
-	case 'comments':
-		$attributes = 'class="comments column-comments num"' . $style;
-?>
-		<td <?php echo $attributes ?>>
-			<div class="post-com-count-wrapper">
-<?php
-		$pending_comments = get_pending_comments_num( $post->ID );
-
-		$this->comments_bubble( $post->ID, $pending_comments );
-?>
-			</div>
-		</td>
-<?php
-		break;
-
-	default:
-		if ( 'categories' == $column_name )
-			$taxonomy = 'category';
-		elseif ( 'tags' == $column_name )
-			$taxonomy = 'post_tag';
-		elseif ( 0 === strpos( $column_name, 'taxonomy-' ) )
-			$taxonomy = substr( $column_name, 9 );
-		else
-			$taxonomy = false;
-
-		if ( $taxonomy ) {
-			echo '<td ' . $attributes . '>';
-			if ( $terms = get_the_terms( $post->ID, $taxonomy ) ) {
-				$out = array();
-				foreach ( $terms as $t ) {
-					$posts_in_term_qv = array();
-					$posts_in_term_qv['taxonomy'] = $taxonomy;
-					$posts_in_term_qv['term'] = $t->slug;
-
-					$out[] = sprintf( '<a href="%s">%s</a>',
-						esc_url( add_query_arg( $posts_in_term_qv, 'upload.php' ) ),
-						esc_html( sanitize_term_field( 'name', $t->name, $t->term_id, $taxonomy, 'display' ) )
-					);
-				}
-				/* translators: used between list items, there is a space after the comma */
-				echo join( __( ', ' ), $out );
-			} else {
-				echo '&#8212;';
-			}
-			echo '</td>';
-			break;
-		}
-?>
-		<td <?php echo $attributes ?>><?php
-			/**
-			 * Fires for each custom column in the Media list table.
-			 *
-			 * Custom columns are registered using the 'manage_media_columns' filter.
-			 *
-			 * @since 2.5.0
-			 *
-			 * @param string $column_name Name of the custom column.
-			 * @param int    $post_id     Attachment ID.
-			 */
-			do_action( 'manage_media_custom_column', $column_name, $post->ID );
-		?></td>
-<?php
-		break;
+					_e( '(Unattached)' ); ?><br />
+					<?php if ( $user_can_edit ) { ?>
+						<a class="hide-if-no-js"
+							onclick="findPosts.open( 'media[]','<?php echo $post->ID ?>' ); return false;"
+							href="#the-list">
+							<?php _e( 'Attach' ); ?></a>
+					<?php }
+				}
+
+				break;
+
+			case 'comments':
+				echo '<div class="post-com-count-wrapper">';
+
+				$pending_comments = get_pending_comments_num( $post->ID );
+				$this->comments_bubble( $post->ID, $pending_comments );
+
+				echo '</div>';
+
+				break;
+
+			default:
+				if ( 'categories' == $column_name )
+					$taxonomy = 'category';
+				elseif ( 'tags' == $column_name )
+					$taxonomy = 'post_tag';
+				elseif ( 0 === strpos( $column_name, 'taxonomy-' ) )
+					$taxonomy = substr( $column_name, 9 );
+				else
+					$taxonomy = false;
+
+				if ( $taxonomy ) {
+					if ( $terms = get_the_terms( $post->ID, $taxonomy ) ) {
+						$out = array();
+						foreach ( $terms as $t ) {
+							$posts_in_term_qv = array();
+							$posts_in_term_qv['taxonomy'] = $taxonomy;
+							$posts_in_term_qv['term'] = $t->slug;
+
+							$out[] = sprintf( '<a href="%s">%s</a>',
+								esc_url( add_query_arg( $posts_in_term_qv, 'upload.php' ) ),
+								esc_html( sanitize_term_field( 'name', $t->name, $t->term_id, $taxonomy, 'display' ) )
+							);
+						}
+						/* translators: used between list items, there is a space after the comma */
+						echo join( __( ', ' ), $out );
+					} else {
+						echo '&#8212;';
+					}
+
+					break;
+				}
+
+				/**
+				 * Fires for each custom column in the Media list table.
+				 *
+				 * Custom columns are registered using the 'manage_media_columns' filter.
+				 *
+				 * @since 2.5.0
+				 *
+				 * @param string $column_name Name of the custom column.
+				 * @param int    $post_id     Attachment ID.
+				 */
+				do_action( 'manage_media_custom_column', $column_name, $post->ID );
+				break;
+		}
+
+		if( $primary === $column_name ) {
+			echo $this->row_actions( $this->_get_row_actions( $post, $att_title ) );
+		}
+		
+		echo '</td>';
 	}
 }
@@ -519,4 +503,16 @@
 	</tr>
 <?php endwhile;
+	}
+
+	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'title';
 	}
 
Index: /trunk/src/wp-admin/includes/class-wp-ms-sites-list-table.php
===================================================================
--- /trunk/src/wp-admin/includes/class-wp-ms-sites-list-table.php	(revision 32643)
+++ /trunk/src/wp-admin/includes/class-wp-ms-sites-list-table.php	(revision 32644)
@@ -247,31 +247,40 @@
 			$blogname = ( is_subdomain_install() ) ? str_replace( '.' . get_current_site()->domain, '', $blog['domain'] ) : $blog['path'];
 
-			list( $columns, $hidden ) = $this->get_column_info();
+			list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
 
 			foreach ( $columns as $column_name => $column_display_name ) {
+				$classes = "$column_name column-$column_name";
+				if ( $primary === $column_name ) {
+					$classes .= ' has-row-actions column-primary';
+				}
+
 				$style = '';
-				if ( in_array( $column_name, $hidden ) )
+				if ( in_array( $column_name, $hidden ) ) {
 					$style = ' style="display:none;"';
-
-				switch ( $column_name ) {
-					case 'cb': ?>
-						<th scope="row" class="check-column">
-							<?php if ( ! is_main_site( $blog['blog_id'] ) ) : ?>
-							<label class="screen-reader-text" for="blog_<?php echo $blog['blog_id']; ?>"><?php printf( __( 'Select %s' ), $blogname ); ?></label>
-							<input type="checkbox" id="blog_<?php echo $blog['blog_id'] ?>" name="allblogs[]" value="<?php echo esc_attr( $blog['blog_id'] ) ?>" />
-							<?php endif; ?>
-						</th>
-					<?php
-					break;
-
-					case 'id':?>
-						<th scope="row">
-							<?php echo $blog['blog_id'] ?>
-						</th>
-					<?php
-					break;
-
-					case 'blogname':
-						echo "<td class='column-$column_name $column_name'$style>"; ?>
+				}
+
+				$attributes = "class='$classes'$style";
+
+				if ( 'cb' === $column_name ) {
+?>
+				<th scope="row" class="check-column">
+					<?php if ( ! is_main_site( $blog['blog_id'] ) ) : ?>
+					<label class="screen-reader-text" for="blog_<?php echo $blog['blog_id']; ?>"><?php printf( __( 'Select %s' ), $blogname ); ?></label>
+					<input type="checkbox" id="blog_<?php echo $blog['blog_id'] ?>" name="allblogs[]" value="<?php echo esc_attr( $blog['blog_id'] ) ?>" />
+					<?php endif; ?>
+				</th>
+<?php
+				} elseif ( 'id' === $column_name ) {
+?>
+				<th scope="row">
+					<?php echo $blog['blog_id'] ?>
+				</th>
+<?php
+				} else {
+					echo "<td $attributes>";
+
+					switch ( $column_name ) {
+						case 'blogname':
+							?>
 							<a href="<?php echo esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ); ?>" class="edit"><?php echo $blogname . $blog_state; ?></a>
 							<?php
@@ -282,83 +291,19 @@
 								restore_current_blog();
 							}
-
-							// Preordered.
-							$actions = array(
-								'edit' => '', 'backend' => '',
-								'activate' => '', 'deactivate' => '',
-								'archive' => '', 'unarchive' => '',
-								'spam' => '', 'unspam' => '',
-								'delete' => '',
-								'visit' => '',
-							);
-
-							$actions['edit']	= '<span class="edit"><a href="' . esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ) . '">' . __( 'Edit' ) . '</a></span>';
-							$actions['backend']	= "<span class='backend'><a href='" . esc_url( get_admin_url( $blog['blog_id'] ) ) . "' class='edit'>" . __( 'Dashboard' ) . '</a></span>';
-							if ( get_current_site()->blog_id != $blog['blog_id'] ) {
-								if ( $blog['deleted'] == '1' ) {
-									$actions['activate']   = '<span class="activate"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=activateblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to activate the site %s' ), $blogname ) ) ), 'confirm' ) ) . '">' . __( 'Activate' ) . '</a></span>';
-								} else {
-									$actions['deactivate'] = '<span class="activate"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=deactivateblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to deactivate the site %s' ), $blogname ) ) ), 'confirm' ) ) . '">' . __( 'Deactivate' ) . '</a></span>';
-								}
-
-								if ( $blog['archived'] == '1' ) {
-									$actions['unarchive'] = '<span class="archive"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=unarchiveblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to unarchive the site %s.' ), $blogname ) ) ), 'confirm' ) ) . '">' . __( 'Unarchive' ) . '</a></span>';
-								} else {
-									$actions['archive']   = '<span class="archive"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=archiveblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to archive the site %s.' ), $blogname ) ) ), 'confirm' ) ) . '">' . _x( 'Archive', 'verb; site' ) . '</a></span>';
-								}
-
-								if ( $blog['spam'] == '1' ) {
-									$actions['unspam'] = '<span class="spam"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=unspamblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to unspam the site %s.' ), $blogname ) ) ), 'confirm' ) ) . '">' . _x( 'Not Spam', 'site' ) . '</a></span>';
-								} else {
-									$actions['spam']   = '<span class="spam"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=spamblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to mark the site %s as spam.' ), $blogname ) ) ), 'confirm' ) ) . '">' . _x( 'Spam', 'site' ) . '</a></span>';
-								}
-
-								if ( current_user_can( 'delete_site', $blog['blog_id'] ) ) {
-									$actions['delete'] = '<span class="delete"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=deleteblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to delete the site %s.' ), $blogname ) ) ), 'confirm' ) ) . '">' . __( 'Delete' ) . '</a></span>';
-								}
+						break;
+
+						case 'lastupdated':
+							echo ( $blog['last_updated'] == '0000-00-00 00:00:00' ) ? __( 'Never' ) : mysql2date( $date, $blog['last_updated'] );
+						break;
+
+						case 'registered':
+							if ( $blog['registered'] == '0000-00-00 00:00:00' ) {
+								echo '&#x2014;';
+							} else {
+								echo mysql2date( $date, $blog['registered'] );
 							}
-
-							$actions['visit']	= "<span class='view'><a href='" . esc_url( get_home_url( $blog['blog_id'], '/' ) ) . "' rel='permalink'>" . __( 'Visit' ) . '</a></span>';
-
-							/**
-							 * Filter the action links displayed for each site in the Sites list table.
-							 *
-							 * The 'Edit', 'Dashboard', 'Delete', and 'Visit' links are displayed by
-							 * default for each site. The site's status determines whether to show the
-							 * 'Activate' or 'Deactivate' link, 'Unarchive' or 'Archive' links, and
-							 * 'Not Spam' or 'Spam' link for each site.
-							 *
-							 * @since 3.1.0
-							 *
-							 * @param array  $actions  An array of action links to be displayed.
-							 * @param int    $blog_id  The site ID.
-							 * @param string $blogname Site path, formatted depending on whether it is a sub-domain
-							 *                         or subdirectory multisite install.
-							 */
-							$actions = apply_filters( 'manage_sites_action_links', array_filter( $actions ), $blog['blog_id'], $blogname );
-							echo $this->row_actions( $actions );
-					?>
-						</td>
-					<?php
-					break;
-
-					case 'lastupdated':
-						echo "<td class='$column_name column-$column_name'$style>";
-							echo ( $blog['last_updated'] == '0000-00-00 00:00:00' ) ? __( 'Never' ) : mysql2date( $date, $blog['last_updated'] ); ?>
-						</td>
-					<?php
-					break;
-				case 'registered':
-						echo "<td class='$column_name column-$column_name'$style>";
-						if ( $blog['registered'] == '0000-00-00 00:00:00' )
-							echo '&#x2014;';
-						else
-							echo mysql2date( $date, $blog['registered'] );
-						?>
-						</td>
-					<?php
-					break;
-				case 'users':
-						echo "<td class='$column_name column-$column_name'$style>";
+						break;
+
+						case 'users':
 							$blogusers = get_users( array( 'blog_id' => $blog['blog_id'], 'number' => 6) );
 							if ( is_array( $blogusers ) ) {
@@ -377,39 +322,36 @@
 									echo '<strong>' . $blogusers_warning . '</strong><br />';
 							}
-							?>
-						</td>
-					<?php
-					break;
-
-				case 'plugins': ?>
-					<?php if ( has_filter( 'wpmublogsaction' ) ) {
-					echo "<td class='$column_name column-$column_name'$style>";
-						/**
-						 * Fires inside the auxiliary 'Actions' column of the Sites list table.
-						 *
-						 * By default this column is hidden unless something is hooked to the action.
-						 *
-						 * @since MU
-						 *
-						 * @param int $blog_id The site ID.
-						 */
-						do_action( 'wpmublogsaction', $blog['blog_id'] ); ?>
-					</td>
-					<?php }
-					break;
-
-				default:
-					echo "<td class='$column_name column-$column_name'$style>";
-					/**
-					 * Fires for each registered custom column in the Sites list table.
-					 *
-					 * @since 3.1.0
-					 *
-					 * @param string $column_name The name of the column to display.
-					 * @param int    $blog_id     The site ID.
-					 */
-					do_action( 'manage_sites_custom_column', $column_name, $blog['blog_id'] );
-					echo "</td>";
-					break;
+						break;
+
+						case 'plugins':
+							if ( has_filter( 'wpmublogsaction' ) ) {
+								/**
+								 * Fires inside the auxiliary 'Actions' column of the Sites list table.
+								 *
+								 * By default this column is hidden unless something is hooked to the action.
+								 *
+								 * @since MU
+								 *
+								 * @param int $blog_id The site ID.
+								 */
+								do_action( 'wpmublogsaction', $blog['blog_id'] );
+							}
+						break;
+
+						default:
+							/**
+							 * Fires for each registered custom column in the Sites list table.
+							 *
+							 * @since 3.1.0
+							 *
+							 * @param string $column_name The name of the column to display.
+							 * @param int    $blog_id     The site ID.
+							 */
+							do_action( 'manage_sites_custom_column', $column_name, $blog['blog_id'] );
+						break;
+					}
+
+					echo $this->handle_row_actions( $blog, $column_name, $primary );
+					echo '</td>';
 				}
 			}
@@ -419,3 +361,91 @@
 		}
 	}
+
+	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'blogname';
+	}
+
+	/**
+	 * Generate and display row actions links
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @param object $blog Blog being acted upon
+	 * @param string $column_name Current column name
+	 * @param string $primary Primary column name
+	 *
+	 * @return string
+	 */
+	protected function handle_row_actions( $blog, $column_name, $primary ) {
+		global $current_site;
+
+		if ( $primary === $column_name ) {
+			$blogname = ( is_subdomain_install() ) ? str_replace( '.'.$current_site->domain, '', $blog['domain'] ) : $blog['path'];
+
+			// Preordered.
+			$actions = array(
+				'edit' => '', 'backend' => '',
+				'activate' => '', 'deactivate' => '',
+				'archive' => '', 'unarchive' => '',
+				'spam' => '', 'unspam' => '',
+				'delete' => '',
+				'visit' => '',
+			);
+
+			$actions['edit']	= '<span class="edit"><a href="' . esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ) . '">' . __( 'Edit' ) . '</a></span>';
+			$actions['backend']	= "<span class='backend'><a href='" . esc_url( get_admin_url( $blog['blog_id'] ) ) . "' class='edit'>" . __( 'Dashboard' ) . '</a></span>';
+			if ( get_current_site()->blog_id != $blog['blog_id'] ) {
+				if ( $blog['deleted'] == '1' ) {
+					$actions['activate']   = '<span class="activate"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=activateblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to activate the site %s' ), $blogname ) ) ), 'confirm' ) ) . '">' . __( 'Activate' ) . '</a></span>';
+				} else {
+					$actions['deactivate'] = '<span class="activate"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=deactivateblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to deactivate the site %s' ), $blogname ) ) ), 'confirm' ) ) . '">' . __( 'Deactivate' ) . '</a></span>';
+				}
+
+				if ( $blog['archived'] == '1' ) {
+					$actions['unarchive'] = '<span class="archive"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=unarchiveblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to unarchive the site %s.' ), $blogname ) ) ), 'confirm' ) ) . '">' . __( 'Unarchive' ) . '</a></span>';
+				} else {
+					$actions['archive']   = '<span class="archive"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=archiveblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to archive the site %s.' ), $blogname ) ) ), 'confirm' ) ) . '">' . _x( 'Archive', 'verb; site' ) . '</a></span>';
+				}
+
+				if ( $blog['spam'] == '1' ) {
+					$actions['unspam'] = '<span class="spam"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=unspamblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to unspam the site %s.' ), $blogname ) ) ), 'confirm' ) ) . '">' . _x( 'Not Spam', 'site' ) . '</a></span>';
+				} else {
+					$actions['spam']   = '<span class="spam"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=spamblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to mark the site %s as spam.' ), $blogname ) ) ), 'confirm' ) ) . '">' . _x( 'Spam', 'site' ) . '</a></span>';
+				}
+
+				if ( current_user_can( 'delete_site', $blog['blog_id'] ) ) {
+					$actions['delete'] = '<span class="delete"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=deleteblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to delete the site %s.' ), $blogname ) ) ), 'confirm' ) ) . '">' . __( 'Delete' ) . '</a></span>';
+				}
+			}
+
+			$actions['visit']	= "<span class='view'><a href='" . esc_url( get_home_url( $blog['blog_id'], '/' ) ) . "' rel='permalink'>" . __( 'Visit' ) . '</a></span>';
+
+			/**
+			 * Filter the action links displayed for each site in the Sites list table.
+			 *
+			 * The 'Edit', 'Dashboard', 'Delete', and 'Visit' links are displayed by
+			 * default for each site. The site's status determines whether to show the
+			 * 'Activate' or 'Deactivate' link, 'Unarchive' or 'Archive' links, and
+			 * 'Not Spam' or 'Spam' link for each site.
+			 *
+			 * @since 3.1.0
+			 *
+			 * @param array  $actions  An array of action links to be displayed.
+			 * @param int    $blog_id  The site ID.
+			 * @param string $blogname Site path, formatted depending on whether it is a sub-domain
+			 *                         or subdirectory multisite install.
+			 */
+			$actions = apply_filters( 'manage_sites_action_links', array_filter( $actions ), $blog['blog_id'], $blogname );
+			return $this->row_actions( $actions );
+		}
+	}
 }
Index: /trunk/src/wp-admin/includes/class-wp-ms-themes-list-table.php
===================================================================
--- /trunk/src/wp-admin/includes/class-wp-ms-themes-list-table.php	(revision 32643)
+++ /trunk/src/wp-admin/includes/class-wp-ms-themes-list-table.php	(revision 32644)
@@ -231,4 +231,16 @@
 
 	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'name';
+	}
+
+	/**
 	 *
 	 * @global array $totals
@@ -401,5 +413,5 @@
 		echo "<tr id='$id' class='$class'>";
 
-		list( $columns, $hidden ) = $this->get_column_info();
+		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
 
 		foreach ( $columns as $column_name => $column_display_name ) {
@@ -414,5 +426,7 @@
 				case 'name':
 					echo "<td class='theme-title'$style><strong>" . $theme->display('Name') . "</strong>";
-					echo $this->row_actions( $actions, true );
+					if ( $primary === $column_name ) {
+						echo $this->row_actions($actions, true);
+					}
 					echo "</td>";
 					break;
@@ -452,5 +466,9 @@
 					echo implode( ' | ', $theme_meta );
 
-					echo "</div></td>";
+					echo '</div>';
+					if ( $primary === $column_name ) {
+						echo $this->row_actions($actions, true);
+					}
+					echo '</td>';
 					break;
 
@@ -468,4 +486,8 @@
 					 */
 					do_action( 'manage_themes_custom_column', $column_name, $stylesheet, $theme );
+
+					if ( $primary === $column_name ) {
+						echo $this->row_actions($actions, true);
+					}
 					echo "</td>";
 			}
Index: /trunk/src/wp-admin/includes/class-wp-ms-users-list-table.php
===================================================================
--- /trunk/src/wp-admin/includes/class-wp-ms-users-list-table.php	(revision 32643)
+++ /trunk/src/wp-admin/includes/class-wp-ms-users-list-table.php	(revision 32644)
@@ -181,79 +181,64 @@
 			<?php
 
-			list( $columns, $hidden ) = $this->get_column_info();
+			list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
 
 			foreach ( $columns as $column_name => $column_display_name ) :
-				$class = "class='$column_name column-$column_name'";
+				$classes = "$column_name column-$column_name";
+				if ( $primary === $column_name || 'blogs' === $column_name ) {
+					$classes .= ' has-row-actions';
+				}
+
+				if ( $primary === $column_name ) {
+					$classes .= ' column-primary';
+				}
 
 				$style = '';
-				if ( in_array( $column_name, $hidden ) )
+				if ( in_array( $column_name, $hidden ) ) {
 					$style = ' style="display:none;"';
-
-				$attributes = "$class$style";
-
-				switch ( $column_name ) {
-					case 'cb': ?>
-						<th scope="row" class="check-column">
-							<label class="screen-reader-text" for="blog_<?php echo $user->ID; ?>"><?php echo sprintf( __( 'Select %s' ), $user->user_login ); ?></label>
-							<input type="checkbox" id="blog_<?php echo $user->ID ?>" name="allusers[]" value="<?php echo esc_attr( $user->ID ) ?>" />
-						</th>
+				}
+
+				$attributes = "class='$classes'$style";
+
+				if ( 'cb' === $column_name ){
+					?>
+					<th scope="row" class="check-column">
+						<label class="screen-reader-text" for="blog_<?php echo $user->ID; ?>"><?php echo sprintf( __( 'Select %s' ), $user->user_login ); ?></label>
+						<input type="checkbox" id="blog_<?php echo $user->ID ?>" name="allusers[]" value="<?php echo esc_attr( $user->ID ) ?>" />
+					</th>
 					<?php
-					break;
-
-					case 'username':
-						$avatar	= get_avatar( $user->user_email, 32 );
-						$edit_link = esc_url( add_query_arg( 'wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), get_edit_user_link( $user->ID ) ) );
-
-						echo "<td $attributes>"; ?>
-							<?php echo $avatar; ?><strong><a href="<?php echo $edit_link; ?>" class="edit"><?php echo $user->user_login; ?></a><?php
+				} else {
+					echo "<td $attributes>";
+					
+					switch ( $column_name ) {
+						case 'username':
+							$avatar	= get_avatar( $user->user_email, 32 );
+							$edit_link = esc_url( add_query_arg( 'wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), get_edit_user_link( $user->ID ) ) );
+
+							echo $avatar; ?><strong><a href="<?php echo $edit_link; ?>" class="edit"><?php echo $user->user_login; ?></a><?php
 							if ( in_array( $user->user_login, $super_admins ) )
 								echo ' - ' . __( 'Super Admin' );
 							?></strong>
-							<br/>
-							<?php
-								$actions = array();
-								$actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
-
-								if ( current_user_can( 'delete_user', $user->ID ) && ! in_array( $user->user_login, $super_admins ) ) {
-									$actions['delete'] = '<a href="' . $delete = esc_url( network_admin_url( add_query_arg( '_wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), wp_nonce_url( 'users.php', 'deleteuser' ) . '&amp;action=deleteuser&amp;id=' . $user->ID ) ) ) . '" class="delete">' . __( 'Delete' ) . '</a>';
-								}
-
-								/**
-								 * Filter the action links displayed under each user
-								 * in the Network Admin Users list table.
-								 *
-								 * @since 3.2.0
-								 *
-								 * @param array   $actions An array of action links to be displayed.
-								 *                         Default 'Edit', 'Delete'.
-								 * @param WP_User $user    WP_User object.
-								 */
-								$actions = apply_filters( 'ms_user_row_actions', $actions, $user );
-								echo $this->row_actions( $actions );
-							?>
-						</td>
-					<?php
-					break;
-
-					case 'name':
-						echo "<td $attributes>$user->first_name $user->last_name</td>";
-					break;
-
-					case 'email':
-						echo "<td $attributes><a href='mailto:$user->user_email'>$user->user_email</a></td>";
-					break;
-
-					case 'registered':
-						if ( 'list' == $mode )
-							$date = __( 'Y/m/d' );
-						else
-							$date = __( 'Y/m/d g:i:s a' );
-
-						echo "<td $attributes>" . mysql2date( $date, $user->user_registered ) . "</td>";
-					break;
-
-					case 'blogs':
-						$blogs = get_blogs_of_user( $user->ID, true );
-						echo "<td $attributes>";
+						<?php
+						break;
+
+						case 'name':
+							echo "$user->first_name $user->last_name";
+						break;
+
+						case 'email':
+							echo "<a href='mailto:$user->user_email'>$user->user_email</a>";
+						break;
+
+						case 'registered':
+							if ( 'list' == $mode )
+								$date = __( 'Y/m/d' );
+							else
+								$date = __( 'Y/m/d g:i:s a' );
+
+							echo mysql2date( $date, $user->user_registered );
+						break;
+
+						case 'blogs':
+							$blogs = get_blogs_of_user( $user->ID, true );
 							if ( is_array( $blogs ) ) {
 								foreach ( (array) $blogs as $key => $val ) {
@@ -306,15 +291,14 @@
 								}
 							}
-							?>
-						</td>
-					<?php
-					break;
-
-					default:
-						echo "<td $attributes>";
-						/** This filter is documented in wp-admin/includes/class-wp-users-list-table.php */
-						echo apply_filters( 'manage_users_custom_column', '', $column_name, $user->ID );
-						echo "</td>";
-					break;
+						break;
+
+						default:
+							/** This filter is documented in wp-admin/includes/class-wp-users-list-table.php */
+							echo apply_filters( 'manage_users_custom_column', '', $column_name, $user->ID );
+						break;
+					}
+
+					echo $this->handle_row_actions( $user, $column_name, $primary );
+					echo '</td>';
 				}
 			endforeach
@@ -324,3 +308,54 @@
 		}
 	}
+
+	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'username';
+	}
+
+	/**
+	 * Generate and display row actions links
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @param object $user User being acted upon
+	 * @param string $column_name Current column name
+	 * @param string $primary Primary column name
+	 *
+	 * @return string
+	 */
+	protected function handle_row_actions( $user, $column_name, $primary ) {
+		$super_admins = get_super_admins();
+		$edit_link = esc_url( add_query_arg( 'wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), get_edit_user_link( $user->ID ) ) );
+
+		if ( $primary === $column_name ) {
+			$actions = array();
+			$actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
+
+			if ( current_user_can( 'delete_user', $user->ID ) && ! in_array( $user->user_login, $super_admins ) ) {
+				$actions['delete'] = '<a href="' . $delete = esc_url( network_admin_url( add_query_arg( '_wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), wp_nonce_url( 'users.php', 'deleteuser' ) . '&amp;action=deleteuser&amp;id=' . $user->ID ) ) ) . '" class="delete">' . __( 'Delete' ) . '</a>';
+			}
+
+			/**
+			 * Filter the action links displayed under each user
+			 * in the Network Admin Users list table.
+			 *
+			 * @since 3.2.0
+			 *
+			 * @param array   $actions An array of action links to be displayed.
+			 *                         Default 'Edit', 'Delete'.
+			 * @param WP_User $user    WP_User object.
+			 */
+			$actions = apply_filters( 'ms_user_row_actions', $actions, $user );
+			return $this->row_actions( $actions );
+		}
+	}
 }
Index: /trunk/src/wp-admin/includes/class-wp-plugins-list-table.php
===================================================================
--- /trunk/src/wp-admin/includes/class-wp-plugins-list-table.php	(revision 32643)
+++ /trunk/src/wp-admin/includes/class-wp-plugins-list-table.php	(revision 32644)
@@ -569,10 +569,13 @@
 		);
 
-		list( $columns, $hidden ) = $this->get_column_info();
+		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
+
+		$extra_class = ' has-row-actions column-primary';
 
 		foreach ( $columns as $column_name => $column_display_name ) {
 			$style = '';
-			if ( in_array( $column_name, $hidden ) )
+			if ( in_array( $column_name, $hidden ) ) {
 				$style = ' style="display:none;"';
+			}
 
 			switch ( $column_name ) {
@@ -581,10 +584,19 @@
 					break;
 				case 'name':
-					echo "<td class='plugin-title'$style><strong>$plugin_name</strong>";
-					echo $this->row_actions( $actions, true );
+					if ( $primary === $column_name || ! isset( $columns[ $primary ] ) ) {
+						echo "<td class='plugin-title $extra_class'$style><strong>$plugin_name</strong>";
+						echo $this->row_actions( $actions, true );
+					} else {
+						echo "<td class='plugin-title'$style><strong>$plugin_name</strong>";
+					}
 					echo "</td>";
 					break;
 				case 'description':
-					echo "<td class='column-description desc'$style>
+					$classes = 'column-description desc';
+					if ( $primary === $column_name ) {
+						$classes .= " $extra_class";
+					}
+
+					echo "<td class='$classes'$style>
 						<div class='plugin-description'>$description</div>
 						<div class='$class second plugin-version-author-uri'>";
@@ -633,8 +645,16 @@
 					echo implode( ' | ', $plugin_meta );
 
+					if ( $primary === $column_name ) {
+						echo $this->row_actions( $actions, true );
+					}
 					echo "</div></td>";
 					break;
 				default:
-					echo "<td class='$column_name column-$column_name'$style>";
+					$classes = "$column_name column-$column_name$class";
+					if ( $primary === $column_name ) {
+						$classes .= " $extra_class";
+					}
+
+					echo "<td class='$classes'$style>";
 
 					/**
@@ -648,4 +668,8 @@
 					 */
 					do_action( 'manage_plugins_custom_column', $column_name, $plugin_file, $plugin_data );
+
+					if ( $primary === $column_name ) {
+						echo $this->row_actions( $actions, true );
+					}
 					echo "</td>";
 			}
@@ -683,3 +707,15 @@
 		do_action( "after_plugin_row_$plugin_file", $plugin_file, $plugin_data, $status );
 	}
+
+	/**
+	 * Get name of default primary column for this specific list table.
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'plugin';
+	}
 }
Index: /trunk/src/wp-admin/includes/class-wp-posts-list-table.php
===================================================================
--- /trunk/src/wp-admin/includes/class-wp-posts-list-table.php	(revision 32643)
+++ /trunk/src/wp-admin/includes/class-wp-posts-list-table.php	(revision 32644)
@@ -685,14 +685,18 @@
 	<?php
 
-		list( $columns, $hidden ) = $this->get_column_info();
+		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
 
 		foreach ( $columns as $column_name => $column_display_name ) {
-			$class = "class=\"$column_name column-$column_name\"";
+			$classes = "$column_name column-$column_name";
+			if ( $primary === $column_name ) {
+				$classes .= ' has-row-actions column-primary';
+			}
 
 			$style = '';
-			if ( in_array( $column_name, $hidden ) )
+			if ( in_array( $column_name, $hidden ) ) {
 				$style = ' style="display:none;"';
-
-			$attributes = "$class$style";
+			}
+
+			$attributes = "class='$classes'$style";
 
 			switch ( $column_name ) {
@@ -716,5 +720,6 @@
 
 			case 'title':
-				$attributes = 'class="post-title page-title column-title"' . $style;
+				$classes .= ' page-title'; // Special addition for title column
+				$attributes = "class='$classes'$style";
 				if ( $this->hierarchical_display ) {
 					if ( 0 == $level && (int) $post->post_parent > 0 ) {
@@ -773,63 +778,5 @@
 						the_excerpt();
 
-				$actions = array();
-				if ( $can_edit_post && 'trash' != $post->post_status ) {
-					$actions['edit'] = '<a href="' . get_edit_post_link( $post->ID ) . '" title="' . esc_attr__( 'Edit this item' ) . '">' . __( 'Edit' ) . '</a>';
-					$actions['inline hide-if-no-js'] = '<a href="#" class="editinline" title="' . esc_attr__( 'Edit this item inline' ) . '">' . __( 'Quick&nbsp;Edit' ) . '</a>';
-				}
-				if ( current_user_can( 'delete_post', $post->ID ) ) {
-					if ( 'trash' == $post->post_status )
-						$actions['untrash'] = "<a title='" . esc_attr__( 'Restore this item from the Trash' ) . "' href='" . wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&amp;action=untrash', $post->ID ) ), 'untrash-post_' . $post->ID ) . "'>" . __( 'Restore' ) . "</a>";
-					elseif ( EMPTY_TRASH_DAYS )
-						$actions['trash'] = "<a class='submitdelete' title='" . esc_attr__( 'Move this item to the Trash' ) . "' href='" . get_delete_post_link( $post->ID ) . "'>" . __( 'Trash' ) . "</a>";
-					if ( 'trash' == $post->post_status || !EMPTY_TRASH_DAYS )
-						$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 ( in_array( $post->post_status, array( 'pending', 'draft', 'future' ) ) ) {
-						if ( $can_edit_post ) {
-							$preview_link = set_url_scheme( get_permalink( $post->ID ) );
-							/** This filter is documented in wp-admin/includes/meta-boxes.php */
-							$preview_link = apply_filters( 'preview_post_link', add_query_arg( 'preview', 'true', $preview_link ), $post );
-							$actions['view'] = '<a href="' . esc_url( $preview_link ) . '" 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>';
-					}
-				}
-
-				if ( is_post_type_hierarchical( $post->post_type ) ) {
-
-					/**
-					 * Filter the array of row action links on the Pages list table.
-					 *
-					 * The filter is evaluated only for hierarchical post types.
-					 *
-					 * @since 2.8.0
-					 *
-					 * @param array   $actions An array of row action links. Defaults are
-					 *                         'Edit', 'Quick Edit', 'Restore, 'Trash',
-					 *                         'Delete Permanently', 'Preview', and 'View'.
-					 * @param WP_Post $post    The post object.
-					 */
-					$actions = apply_filters( 'page_row_actions', $actions, $post );
-				} else {
-
-					/**
-					 * Filter the array of row action links on the Posts list table.
-					 *
-					 * The filter is evaluated only for non-hierarchical post types.
-					 *
-					 * @since 2.8.0
-					 *
-					 * @param array   $actions An array of row action links. Defaults are
-					 *                         'Edit', 'Quick Edit', 'Restore, 'Trash',
-					 *                         'Delete Permanently', 'Preview', and 'View'.
-					 * @param WP_Post $post    The post object.
-					 */
-					$actions = apply_filters( 'post_row_actions', $actions, $post );
-				}
-
-				echo $this->row_actions( $actions );
+				echo $this->handle_row_actions( $post, $column_name, $primary );
 
 				get_inline_data( $post );
@@ -888,4 +835,5 @@
 					_e( 'Last Modified' );
 				}
+				echo $this->handle_row_actions( $post, $column_name, $primary );
 				echo '</td>';
 			break;
@@ -899,5 +847,5 @@
 				$this->comments_bubble( $post->ID, $pending_comments );
 			?>
-			</div></td>
+			</div><?php echo $this->handle_row_actions( $post, $column_name, $primary ); ?></td>
 			<?php
 			break;
@@ -910,4 +858,5 @@
 					get_the_author()
 				);
+				echo $this->handle_row_actions( $post, $column_name, $primary );
 			?></td>
 			<?php
@@ -950,4 +899,5 @@
 						echo '&#8212;';
 					}
+					echo $this->handle_row_actions( $post, $column_name, $primary );
 					echo '</td>';
 					break;
@@ -996,4 +946,5 @@
 				 */
 				do_action( "manage_{$post->post_type}_posts_custom_column", $column_name, $post->ID );
+				echo $this->handle_row_actions( $post, $column_name, $primary );
 			?></td>
 			<?php
@@ -1005,4 +956,99 @@
 	<?php
 		$GLOBALS['post'] = $global_post;
+	}
+
+	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return( 'title' );
+	}
+
+	/**
+	 * Generate and display row actions links
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @param object $post Post being acted upon
+	 * @param string $column_name Current column name
+	 * @param string $primary Primary column name
+	 *
+	 * @return string
+	 */
+	protected function handle_row_actions( $post, $column_name, $primary ) {
+		$title = _draft_or_post_title();
+
+		if ( $primary === $column_name ) {
+			$post_type_object = get_post_type_object( $post->post_type );
+			$can_edit_post = current_user_can( 'edit_post', $post->ID );
+			$actions = array();
+
+			if ( $can_edit_post && 'trash' != $post->post_status ) {
+				$actions['edit'] = '<a href="' . get_edit_post_link( $post->ID ) . '" title="' . esc_attr__( 'Edit this item' ) . '">' . __( 'Edit' ) . '</a>';
+				$actions['inline hide-if-no-js'] = '<a href="#" class="editinline" title="' . esc_attr__( 'Edit this item inline' ) . '">' . __( 'Quick&nbsp;Edit' ) . '</a>';
+			}
+
+			if ( current_user_can( 'delete_post', $post->ID ) ) {
+				if ( 'trash' == $post->post_status )
+					$actions['untrash'] = "<a title='" . esc_attr__( 'Restore this item from the Trash' ) . "' href='" . wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&amp;action=untrash', $post->ID ) ), 'untrash-post_' . $post->ID ) . "'>" . __( 'Restore' ) . "</a>";
+				elseif ( EMPTY_TRASH_DAYS )
+					$actions['trash'] = "<a class='submitdelete' title='" . esc_attr__( 'Move this item to the Trash' ) . "' href='" . get_delete_post_link( $post->ID ) . "'>" . __( 'Trash' ) . "</a>";
+				if ( 'trash' == $post->post_status || !EMPTY_TRASH_DAYS )
+					$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 ( in_array( $post->post_status, array( 'pending', 'draft', 'future' ) ) ) {
+					if ( $can_edit_post ) {
+						$preview_link = set_url_scheme( get_permalink( $post->ID ) );
+						/** This filter is documented in wp-admin/includes/meta-boxes.php */
+						$preview_link = apply_filters( 'preview_post_link', add_query_arg( 'preview', 'true', $preview_link ), $post );
+						$actions['view'] = '<a href="' . esc_url( $preview_link ) . '" 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>';
+				}
+			}
+
+			if ( is_post_type_hierarchical( $post->post_type ) ) {
+
+				/**
+				 * Filter the array of row action links on the Pages list table.
+				 *
+				 * The filter is evaluated only for hierarchical post types.
+				 *
+				 * @since 2.8.0
+				 *
+				 * @param array $actions An array of row action links. Defaults are
+				 *                         'Edit', 'Quick Edit', 'Restore, 'Trash',
+				 *                         'Delete Permanently', 'Preview', and 'View'.
+				 * @param WP_Post $post The post object.
+				 */
+				$actions = apply_filters( 'page_row_actions', $actions, $post );
+			} else {
+
+				/**
+				 * Filter the array of row action links on the Posts list table.
+				 *
+				 * The filter is evaluated only for non-hierarchical post types.
+				 *
+				 * @since 2.8.0
+				 *
+				 * @param array $actions An array of row action links. Defaults are
+				 *                         'Edit', 'Quick Edit', 'Restore, 'Trash',
+				 *                         'Delete Permanently', 'Preview', and 'View'.
+				 * @param WP_Post $post The post object.
+				 */
+				$actions = apply_filters( 'post_row_actions', $actions, $post );
+			}
+
+			return $this->row_actions( $actions );
+		}
 	}
 
Index: /trunk/src/wp-admin/includes/class-wp-terms-list-table.php
===================================================================
--- /trunk/src/wp-admin/includes/class-wp-terms-list-table.php	(revision 32643)
+++ /trunk/src/wp-admin/includes/class-wp-terms-list-table.php	(revision 32644)
@@ -308,7 +308,4 @@
 	public function column_name( $tag ) {
 		$taxonomy = $this->screen->taxonomy;
-		$tax = get_taxonomy( $taxonomy );
-
-		$default_term = get_option( 'default_' . $taxonomy );
 
 		$pad = str_repeat( '&#8212; ', max( 0, $this->level ) );
@@ -334,40 +331,4 @@
 		$out = '<strong><a class="row-title" href="' . $edit_link . '" title="' . esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $name ) ) . '">' . $name . '</a></strong><br />';
 
-		$actions = array();
-		if ( current_user_can( $tax->cap->edit_terms ) ) {
-			$actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
-			$actions['inline hide-if-no-js'] = '<a href="#" class="editinline">' . __( 'Quick&nbsp;Edit' ) . '</a>';
-		}
-		if ( current_user_can( $tax->cap->delete_terms ) && $tag->term_id != $default_term )
-			$actions['delete'] = "<a class='delete-tag' href='" . wp_nonce_url( "edit-tags.php?action=delete&amp;taxonomy=$taxonomy&amp;tag_ID=$tag->term_id", 'delete-tag_' . $tag->term_id ) . "'>" . __( 'Delete' ) . "</a>";
-		if ( $tax->public )
-			$actions['view'] = '<a href="' . get_term_link( $tag ) . '">' . __( 'View' ) . '</a>';
-
-		/**
-		 * Filter the action links displayed for each term in the Tags list table.
-		 *
-		 * @since 2.8.0
-		 * @deprecated 3.0.0 Use {$taxonomy}_row_actions instead.
-		 *
-		 * @param array  $actions An array of action links to be displayed. Default
-		 *                        'Edit', 'Quick Edit', 'Delete', and 'View'.
-		 * @param object $tag     Term object.
-		 */
-		$actions = apply_filters( 'tag_row_actions', $actions, $tag );
-
-		/**
-		 * Filter the action links displayed for each term in the terms list table.
-		 *
-		 * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
-		 *
-		 * @since 3.0.0
-		 *
-		 * @param array  $actions An array of action links to be displayed. Default
-		 *                        'Edit', 'Quick Edit', 'Delete', and 'View'.
-		 * @param object $tag     Term object.
-		 */
-		$actions = apply_filters( "{$taxonomy}_row_actions", $actions, $tag );
-
-		$out .= $this->row_actions( $actions );
 		$out .= '<div class="hidden" id="inline_' . $qe_data->term_id . '">';
 		$out .= '<div class="name">' . $qe_data->name . '</div>';
@@ -378,4 +339,75 @@
 
 		return $out;
+	}
+
+	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'name';
+	}
+
+	/**
+	 * Generate and display row actions links
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @param object $tag Tag being acted upon
+	 * @param string $column_name Current column name
+	 * @param string $primary Primary column name
+	 *
+	 * @return string
+	 */
+	protected function handle_row_actions( $tag, $column_name, $primary ) {
+		$taxonomy = $this->screen->taxonomy;
+		$tax = get_taxonomy( $taxonomy );
+		$default_term = get_option( 'default_' . $taxonomy );
+
+		$edit_link = esc_url( get_edit_term_link( $tag->term_id, $taxonomy, $this->screen->post_type ) );
+
+		if ( $primary === $column_name ) {
+			$actions = array();
+			if ( current_user_can( $tax->cap->edit_terms ) ) {
+				$actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
+				$actions['inline hide-if-no-js'] = '<a href="#" class="editinline">' . __( 'Quick&nbsp;Edit' ) . '</a>';
+			}
+			if ( current_user_can( $tax->cap->delete_terms ) && $tag->term_id != $default_term )
+				$actions['delete'] = "<a class='delete-tag' href='" . wp_nonce_url( "edit-tags.php?action=delete&amp;taxonomy=$taxonomy&amp;tag_ID=$tag->term_id", 'delete-tag_' . $tag->term_id ) . "'>" . __( 'Delete' ) . "</a>";
+			if ( $tax->public )
+				$actions['view'] = '<a href="' . get_term_link( $tag ) . '">' . __( 'View' ) . '</a>';
+
+			/**
+			 * Filter the action links displayed for each term in the Tags list table.
+			 *
+			 * @since 2.8.0
+			 * @deprecated 3.0.0 Use {$taxonomy}_row_actions instead.
+			 *
+			 * @param array  $actions An array of action links to be displayed. Default
+			 *                        'Edit', 'Quick Edit', 'Delete', and 'View'.
+			 * @param object $tag     Term object.
+			 */
+			$actions = apply_filters( 'tag_row_actions', $actions, $tag );
+
+			/**
+			 * Filter the action links displayed for each term in the terms list table.
+			 *
+			 * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
+			 *
+			 * @since 3.0.0
+			 *
+			 * @param array  $actions An array of action links to be displayed. Default
+			 *                        'Edit', 'Quick Edit', 'Delete', and 'View'.
+			 * @param object $tag     Term object.
+			 */
+			$actions = apply_filters( "{$taxonomy}_row_actions", $actions, $tag );
+
+			return $this->row_actions( $actions );
+		}
 	}
 
Index: /trunk/src/wp-admin/includes/class-wp-users-list-table.php
===================================================================
--- /trunk/src/wp-admin/includes/class-wp-users-list-table.php	(revision 32643)
+++ /trunk/src/wp-admin/includes/class-wp-users-list-table.php	(revision 32644)
@@ -390,5 +390,4 @@
 			 */
 			$actions = apply_filters( 'user_row_actions', $actions, $user_object );
-			$edit .= $this->row_actions( $actions );
 
 			// Set up the checkbox ( because the user is editable, otherwise it's empty )
@@ -404,57 +403,64 @@
 		$r = "<tr id='user-$user_object->ID'>";
 
-		list( $columns, $hidden ) = $this->get_column_info();
+		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
 
 		foreach ( $columns as $column_name => $column_display_name ) {
-			$class = "class=\"$column_name column-$column_name\"";
+			$classes = "$column_name column-$column_name";
+			if ( $primary === $column_name ) {
+				$classes .= ' has-row-actions column-primary';
+			}
 
 			$style = '';
-			if ( in_array( $column_name, $hidden ) )
+			if ( in_array( $column_name, $hidden ) ) {
 				$style = ' style="display:none;"';
-
-			$attributes = "$class$style";
-
-			switch ( $column_name ) {
-				case 'cb':
-					$r .= "<th scope='row' class='check-column'>$checkbox</th>";
-					break;
-				case 'username':
-					$r .= "<td $attributes>$avatar $edit</td>";
-					break;
-				case 'name':
-					$r .= "<td $attributes>$user_object->first_name $user_object->last_name</td>";
-					break;
-				case 'email':
-					$r .= "<td $attributes><a href='mailto:$email' title='" . esc_attr( sprintf( __( 'E-mail: %s' ), $email ) ) . "'>$email</a></td>";
-					break;
-				case 'role':
-					$r .= "<td $attributes>$role_name</td>";
-					break;
-				case 'posts':
-					$attributes = 'class="posts column-posts num"' . $style;
-					$r .= "<td $attributes>";
-					if ( $numposts > 0 ) {
-						$r .= "<a href='edit.php?author=$user_object->ID' title='" . esc_attr__( 'View posts by this author' ) . "' class='edit'>";
-						$r .= $numposts;
-						$r .= '</a>';
-					} else {
-						$r .= 0;
-					}
-					$r .= "</td>";
-					break;
-				default:
-					$r .= "<td $attributes>";
-
-					/**
-					 * Filter the display output of custom columns in the Users list table.
-					 *
-					 * @since 2.8.0
-					 *
-					 * @param string $output      Custom column output. Default empty.
-					 * @param string $column_name Column name.
-					 * @param int    $user_id     ID of the currently-listed user.
-					 */
-					$r .= apply_filters( 'manage_users_custom_column', '', $column_name, $user_object->ID );
-					$r .= "</td>";
+			}
+
+			$attributes = "class='$classes'$style";
+
+			if ( 'cb' === $column_name ) {
+				$r .= "<th scope='row' class='check-column'>$checkbox</th>";
+			} else {
+				$r .= "<td $attributes>";
+				switch ( $column_name ) {
+					case 'username':
+						$r .= "$avatar $edit";
+						break;
+					case 'name':
+						$r .= "$user_object->first_name $user_object->last_name";
+						break;
+					case 'email':
+						$r .= "<a href='mailto:$email' title='" . esc_attr( sprintf( __( 'E-mail: %s' ), $email ) ) . "'>$email</a>";
+						break;
+					case 'role':
+						$r .= $role_name;
+						break;
+					case 'posts':
+						$attributes = 'class="posts column-posts num"' . $style;
+						$r .= "";
+						if ( $numposts > 0 ) {
+							$r .= "<a href='edit.php?author=$user_object->ID' title='" . esc_attr__( 'View posts by this author' ) . "' class='edit'>";
+							$r .= $numposts;
+							$r .= '</a>';
+						} else {
+							$r .= 0;
+						}
+						break;
+					default:
+						/**
+						 * Filter the display output of custom columns in the Users list table.
+						 *
+						 * @since 2.8.0
+						 *
+						 * @param string $output      Custom column output. Default empty.
+						 * @param string $column_name Column name.
+						 * @param int    $user_id     ID of the currently-listed user.
+						 */
+						$r .= apply_filters( 'manage_users_custom_column', '', $column_name, $user_object->ID );
+				}
+
+				if ( $primary === $column_name ) {
+					$r .= $this->row_actions( $actions );
+				}
+				$r .= "</td>";
 			}
 		}
@@ -463,3 +469,15 @@
 		return $r;
 	}
+
+	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3.0
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'username';
+	}
 }
