Index: src/wp-admin/includes/class-wp-comments-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-comments-list-table.php	(revision 32613)
+++ src/wp-admin/includes/class-wp-comments-list-table.php	(working copy)
@@ -323,6 +323,18 @@
 		);
 	}
 
+	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3
+	 * @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' );
 
@@ -375,57 +387,32 @@
 		echo "</tr>\n";
 	}
 
-	public function column_cb( $comment ) {
-		if ( $this->user_can ) { ?>
-		<label class="screen-reader-text" for="cb-select-<?php echo $comment->comment_ID; ?>"><?php _e( 'Select comment' ); ?></label>
-		<input id="cb-select-<?php echo $comment->comment_ID; ?>" type="checkbox" name="delete_comments[]" value="<?php echo $comment->comment_ID; ?>" />
-		<?php
+	/**
+	 * Generate and display row actions links
+	 *
+	 * @since 4.3
+	 * @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;
 		}
-	}
 
-	public function column_comment( $comment ) {
-		global $comment_status;
 		$post = get_post();
 
-		$comment_url = esc_url( get_comment_link( $comment->comment_ID ) );
 		$the_comment_status = wp_get_comment_status( $comment->comment_ID );
 
-		echo '<div class="comment-author">';
-			$this->column_author( $comment );
-		echo '</div>';
+		$out = '';
 
-		echo '<div class="submitted-on">';
-		/* translators: 2: comment date, 3: comment time */
-		printf( __( 'Submitted on <a href="%1$s">%2$s at %3$s</a>' ), $comment_url,
-			/* translators: comment date format. See http://php.net/date */
-			get_comment_date( __( 'Y/m/d' ) ),
-			get_comment_date( get_option( 'time_format' ) )
-		);
-
-		if ( $comment->comment_parent ) {
-			$parent = get_comment( $comment->comment_parent );
-			$parent_link = esc_url( get_comment_link( $comment->comment_parent ) );
-			$name = get_comment_author( $parent->comment_ID );
-			printf( ' | '.__( 'In reply to <a href="%1$s">%2$s</a>.' ), $parent_link, $name );
-		}
-
-		echo '</div>';
-		comment_text();
-		if ( $this->user_can ) { ?>
-		<div id="inline-<?php echo $comment->comment_ID; ?>" class="hidden">
-		<textarea class="comment" rows="1" cols="1"><?php
-			/** This filter is documented in wp-admin/includes/comment.php */
-			echo esc_textarea( apply_filters( 'comment_edit_pre', $comment->comment_content ) );
-		?></textarea>
-		<div class="author-email"><?php echo esc_attr( $comment->comment_author_email ); ?></div>
-		<div class="author"><?php echo esc_attr( $comment->comment_author ); ?></div>
-		<div class="author-url"><?php echo esc_attr( $comment->comment_author_url ); ?></div>
-		<div class="comment_status"><?php echo $comment->comment_approved; ?></div>
-		</div>
-		<?php
-		}
-
-		if ( $this->user_can ) {
+		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" ) );
 
@@ -462,7 +449,8 @@
 			}
 
 			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>';
+				$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>';
 			}
@@ -478,11 +466,11 @@
 			}
 
 			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>';
+				$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['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' ) );
 			}
@@ -491,15 +479,15 @@
 			$actions = apply_filters( 'comment_row_actions', array_filter( $actions ), $comment );
 
 			$i = 0;
-			echo '<div class="row-actions">';
+			$out .= '<div class="row-actions">';
 			foreach ( $actions as $action => $link ) {
 				++$i;
-				( ( ( 'approve' == $action || 'unapprove' == $action ) && 2 === $i ) || 1 === $i ) ? $sep = '' : $sep = ' | ';
+				( (( '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') )
+				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' ) ) {
+				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
@@ -506,12 +494,65 @@
 						$action .= ' unapprove';
 				}
 
-				echo "<span class='$action'>$sep$link</span>";
+				$out .= "<span class='$action'>$sep$link</span>";
 			}
-			echo '</div>';
+			$out .= '</div>';
 		}
+
+		return $out;
 	}
 
+	public function column_cb( $comment ) {
+		if ( $this->user_can ) { ?>
+		<label class="screen-reader-text" for="cb-select-<?php echo $comment->comment_ID; ?>"><?php _e( 'Select comment' ); ?></label>
+		<input id="cb-select-<?php echo $comment->comment_ID; ?>" type="checkbox" name="delete_comments[]" value="<?php echo $comment->comment_ID; ?>" />
+		<?php
+		}
+	}
+
+	public function column_comment( $comment ) {
+		global $comment_status;
+		$post = get_post();
+
+		$comment_url = esc_url( get_comment_link( $comment->comment_ID ) );
+		$the_comment_status = wp_get_comment_status( $comment->comment_ID );
+
+		echo '<div class="comment-author">';
+			$this->column_author( $comment );
+		echo '</div>';
+
+		echo '<div class="submitted-on">';
+		/* translators: 2: comment date, 3: comment time */
+		printf( __( 'Submitted on <a href="%1$s">%2$s at %3$s</a>' ), $comment_url,
+			/* translators: comment date format. See http://php.net/date */
+			get_comment_date( __( 'Y/m/d' ) ),
+			get_comment_date( get_option( 'time_format' ) )
+		);
+
+		if ( $comment->comment_parent ) {
+			$parent = get_comment( $comment->comment_parent );
+			$parent_link = esc_url( get_comment_link( $comment->comment_parent ) );
+			$name = get_comment_author( $parent->comment_ID );
+			printf( ' | '.__( 'In reply to <a href="%1$s">%2$s</a>.' ), $parent_link, $name );
+		}
+
+		echo '</div>';
+		comment_text();
+		if ( $this->user_can ) { ?>
+		<div id="inline-<?php echo $comment->comment_ID; ?>" class="hidden">
+		<textarea class="comment" rows="1" cols="1"><?php
+			/** This filter is documented in wp-admin/includes/comment.php */
+			echo esc_textarea( apply_filters( 'comment_edit_pre', $comment->comment_content ) );
+		?></textarea>
+		<div class="author-email"><?php echo esc_attr( $comment->comment_author_email ); ?></div>
+		<div class="author"><?php echo esc_attr( $comment->comment_author ); ?></div>
+		<div class="author-url"><?php echo esc_attr( $comment->comment_author_url ); ?></div>
+		<div class="comment_status"><?php echo $comment->comment_approved; ?></div>
+		</div>
+		<?php
+		}
+	}
+
 	public function column_author( $comment ) {
 		global $comment_status;
 
Index: src/wp-admin/includes/class-wp-links-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-links-list-table.php	(revision 32613)
+++ src/wp-admin/includes/class-wp-links-list-table.php	(working copy)
@@ -108,6 +108,18 @@
 		);
 	}
 
+	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'name';
+	}
+
 	public function display_rows() {
 		global $cat_id;
 
@@ -126,16 +138,20 @@
 		<tr id="link-<?php echo $link->link_id; ?>">
 <?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;
+				$attributes = "class='$classes'$style";
 
 				switch ( $column_name ) {
 					case 'cb': ?>
@@ -148,16 +164,9 @@
 
 					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>";
+						echo "<td $attributes><a href='$link->link_url' title='". esc_attr( sprintf( __( 'Visit %s' ), $link->link_name ) )."'>$short_url</a>";
 						break;
 					case 'categories':
 						?><td <?php echo $attributes ?>><?php
@@ -172,16 +181,15 @@
 							$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
+						?><td <?php echo $attributes ?>><?php echo empty( $link->link_rel ) ? '<br />' : $link->link_rel;
 						break;
 					case 'visible':
-						?><td <?php echo $attributes ?>><?php echo $visible; ?></td><?php
+						?><td <?php echo $attributes ?>><?php echo $visible;
 						break;
 					case 'rating':
-	 					?><td <?php echo $attributes ?>><?php echo $rating; ?></td><?php
+	 					?><td <?php echo $attributes ?>><?php echo $rating;
 						break;
 					default:
 						?>
@@ -195,10 +203,11 @@
 							 * @param int    $link_id     Link ID.
 							 */
 							do_action( 'manage_link_custom_column', $column_name, $link->link_id );
-						?></td>
-						<?php
 						break;
 				}
+
+				echo $this->handle_row_actions( $link, $column_name, $primary );
+				echo '</td>';
 			}
 ?>
 		</tr>
@@ -205,4 +214,27 @@
 <?php
 		}
 	}
+
+	/**
+	 * 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: src/wp-admin/includes/class-wp-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-list-table.php	(revision 32613)
+++ src/wp-admin/includes/class-wp-list-table.php	(working copy)
@@ -792,6 +792,46 @@
 	}
 
 	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return '';
+	}
+
+	/**
+	 * Get name of primary column.
+	 *
+	 * @since 4.3
+	 * @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
+		 *
+		 * @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
 	 *
 	 * @since 3.1.0
@@ -831,7 +871,8 @@
 			$sortable[$id] = $data;
 		}
 
-		$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;
 	}
@@ -1059,16 +1100,20 @@
 	 * @param object $item The current item
 	 */
 	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 ) {
 				echo '<th scope="row" class="check-column">';
@@ -1078,6 +1123,7 @@
 			elseif ( method_exists( $this, 'column_' . $column_name ) ) {
 				echo "<td $attributes>";
 				echo call_user_func( array( $this, 'column_' . $column_name ), $item );
+				echo $this->handle_row_actions( $item, $column_name, $primary );
 				echo "</td>";
 			}
 			else {
@@ -1089,6 +1135,22 @@
 	}
 
 	/**
+	 * Generate and display row actions links
+	 *
+	 * @since 4.3
+	 * @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 '';
+ 	}
+
+	/**
 	 * Handle an incoming ajax request (called from admin-ajax.php)
 	 *
 	 * @since 3.1.0
Index: src/wp-admin/includes/class-wp-media-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-media-list-table.php	(revision 32613)
+++ src/wp-admin/includes/class-wp-media-list-table.php	(working copy)
@@ -288,15 +288,20 @@
 	<tr id="post-<?php echo $post->ID; ?>" class="<?php echo trim( ' author-' . $post_owner . ' status-' . $post->post_status ); ?>">
 <?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 ) {
 
@@ -345,7 +350,9 @@
 			_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 ) );
+		if( $primary === $column_name ) {
+			echo $this->row_actions( $this->_get_row_actions( $post, $att_title ) );
+		}
 ?>
 		</td>
 <?php
@@ -358,6 +365,10 @@
 				esc_url( add_query_arg( array( 'author' => get_the_author_meta('ID') ), 'upload.php' ) ),
 				get_the_author()
 			);
+
+			if( $primary === $column_name ) {
+				echo $this->row_actions( $this->_get_row_actions( $post, $att_title ) );
+			}
 		?></td>
 <?php
 		break;
@@ -364,8 +375,12 @@
 
 	case 'desc':
 ?>
-		<td <?php echo $attributes ?>><?php echo has_excerpt() ? $post->post_excerpt : ''; ?></td>
+		<td <?php echo $attributes ?>><?php echo has_excerpt() ? $post->post_excerpt : ''; ?>
 <?php
+			if( $primary === $column_name ) {
+				echo $this->row_actions( $this->_get_row_actions( $post, $att_title ) );
+			}
+			echo '</td>';
 		break;
 
 	case 'date':
@@ -384,8 +399,12 @@
 			}
 		}
 ?>
-		<td <?php echo $attributes ?>><?php echo $h_time ?></td>
+		<td <?php echo $attributes ?>><?php echo $h_time ?>
 <?php
+		if( $primary === $column_name ) {
+			echo $this->row_actions( $this->_get_row_actions( $post, $att_title ) );
+		}
+		echo '</td>';
 		break;
 
 	case 'parent':
@@ -414,9 +433,7 @@
 						'_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
+				<?php endif;
 		} else {
 ?>
 			<td <?php echo $attributes ?>><?php _e( '(Unattached)' ); ?><br />
@@ -425,9 +442,13 @@
 					onclick="findPosts.open( 'media[]','<?php echo $post->ID ?>' ); return false;"
 					href="#the-list">
 					<?php _e( 'Attach' ); ?></a>
-			<?php } ?></td>
-<?php
+			<?php }
 		}
+
+		if( $primary === $column_name ) {
+			echo $this->row_actions( $this->_get_row_actions( $post, $att_title ) );
+		}
+		echo '</td>';
 		break;
 
 	case 'comments':
@@ -474,6 +495,9 @@
 			} else {
 				echo '&#8212;';
 			}
+			if( $primary === $column_name ) {
+				echo $this->row_actions( $this->_get_row_actions( $post, $att_title ) );
+			}
 			echo '</td>';
 			break;
 		}
@@ -490,6 +514,10 @@
 			 * @param int    $post_id     Attachment ID.
 			 */
 			do_action( 'manage_media_custom_column', $column_name, $post->ID );
+
+			if( $primary === $column_name ) {
+				echo $this->row_actions( $this->_get_row_actions( $post, $att_title ) );
+			}
 		?></td>
 <?php
 		break;
@@ -501,6 +529,18 @@
 	}
 
 	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'title';
+	}
+
+	/**
 	 * @param WP_Post $post
 	 * @param string  $att_title
 	 */
Index: src/wp-admin/includes/class-wp-ms-sites-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-ms-sites-list-table.php	(revision 32613)
+++ src/wp-admin/includes/class-wp-ms-sites-list-table.php	(working copy)
@@ -234,13 +234,21 @@
 
 			$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;"';
+				}
 
+				$attributes = "class='$classes'$style";
+
 				switch ( $column_name ) {
 					case 'cb': ?>
 						<th scope="row" class="check-column">
@@ -260,67 +268,16 @@
 					break;
 
 					case 'blogname':
-						echo "<td class='column-$column_name $column_name'$style>"; ?>
-							<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
-							if ( 'list' != $mode ) {
-								switch_to_blog( $blog['blog_id'] );
-								/* translators: 1: site name, 2: site tagline. */
-								echo '<p>' . sprintf( __( '%1$s &#8211; <em>%2$s</em>' ), get_option( 'blogname' ), get_option( 'blogdescription ' ) ) . '</p>';
-								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 ( get_blog_status( $blog['blog_id'], '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 ( get_blog_status( $blog['blog_id'], '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 ( get_blog_status( $blog['blog_id'], '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 );
-							echo $this->row_actions( $actions );
+						echo "<td $attributes>"; ?>
+						<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
+						if ( 'list' != $mode ) {
+							switch_to_blog( $blog['blog_id'] );
+							/* translators: 1: site name, 2: site tagline. */
+							echo '<p>' . sprintf( __( '%1$s &#8211; <em>%2$s</em>' ), get_option( 'blogname' ), get_option( 'blogdescription ' ) ) . '</p>';
+							restore_current_blog();
+						}
+						echo $this->handle_row_actions( $blog, $column_name, $primary );
 					?>
 						</td>
 					<?php
@@ -327,23 +284,26 @@
 					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'] ); ?>
+						echo "<td $attributes>";
+						echo ( $blog['last_updated'] == '0000-00-00 00:00:00' ) ? __( 'Never' ) : mysql2date( $date, $blog['last_updated'] );
+						echo $this->handle_row_actions( $blog, $column_name, $primary );
+						?>
 						</td>
 					<?php
 					break;
 				case 'registered':
-						echo "<td class='$column_name column-$column_name'$style>";
+						echo "<td $attributes>";
 						if ( $blog['registered'] == '0000-00-00 00:00:00' )
 							echo '&#x2014;';
 						else
 							echo mysql2date( $date, $blog['registered'] );
+						echo $this->handle_row_actions( $blog, $column_name, $primary );
 						?>
 						</td>
 					<?php
 					break;
 				case 'users':
-						echo "<td class='$column_name column-$column_name'$style>";
+						echo "<td $attributes>";
 							$blogusers = get_users( array( 'blog_id' => $blog['blog_id'], 'number' => 6) );
 							if ( is_array( $blogusers ) ) {
 								$blogusers_warning = '';
@@ -360,6 +320,8 @@
 								if ( $blogusers_warning != '' )
 									echo '<strong>' . $blogusers_warning . '</strong><br />';
 							}
+
+							echo $this->handle_row_actions( $blog, $column_name, $primary );
 							?>
 						</td>
 					<?php
@@ -367,7 +329,7 @@
 
 				case 'plugins': ?>
 					<?php if ( has_filter( 'wpmublogsaction' ) ) {
-					echo "<td class='$column_name column-$column_name'$style>";
+					echo "<td $attributes>";
 						/**
 						 * Fires inside the auxiliary 'Actions' column of the Sites list table.
 						 *
@@ -377,13 +339,16 @@
 						 *
 						 * @param int $blog_id The site ID.
 						 */
-						do_action( 'wpmublogsaction', $blog['blog_id'] ); ?>
+						do_action( 'wpmublogsaction', $blog['blog_id'] );
+
+						echo $this->handle_row_actions( $blog, $column_name, $primary );
+						?>
 					</td>
 					<?php }
 					break;
 
 				default:
-					echo "<td class='$column_name column-$column_name'$style>";
+					echo "<td $attributes>";
 					/**
 					 * Fires for each registered custom column in the Sites list table.
 					 *
@@ -393,6 +358,8 @@
 					 * @param int    $blog_id     The site ID.
 					 */
 					do_action( 'manage_sites_custom_column', $column_name, $blog['blog_id'] );
+
+					echo $this->handle_row_actions( $blog, $column_name, $primary );
 					echo "</td>";
 					break;
 				}
@@ -402,4 +369,88 @@
 			<?php
 		}
 	}
+
+	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'blogname';
+	}
+
+	/**
+	 * Generate and display row actions links
+	 *
+	 * @since 4.3
+	 * @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 ( get_blog_status( $blog['blog_id'], '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 ( get_blog_status( $blog['blog_id'], '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 ( get_blog_status( $blog['blog_id'], '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: src/wp-admin/includes/class-wp-ms-themes-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-ms-themes-list-table.php	(revision 32613)
+++ src/wp-admin/includes/class-wp-ms-themes-list-table.php	(working copy)
@@ -215,6 +215,18 @@
 		);
 	}
 
+	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'name';
+	}
+
 	protected function get_views() {
 		global $totals, $status;
 
@@ -375,7 +387,7 @@
 
 		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 ) {
 			$style = '';
@@ -388,7 +400,9 @@
 					break;
 				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;
 				case 'description':
@@ -426,7 +440,11 @@
 					$theme_meta = apply_filters( 'theme_row_meta', $theme_meta, $stylesheet, $theme, $status );
 					echo implode( ' | ', $theme_meta );
 
-					echo "</div></td>";
+					echo '</div>';
+					if ( $primary === $column_name ) {
+						echo $this->row_actions($actions, true);
+					}
+					echo '</td>';
 					break;
 
 				default:
@@ -442,6 +460,10 @@
 					 * @param WP_Theme $theme       Current WP_Theme object.
 					 */
 					do_action( 'manage_themes_custom_column', $column_name, $stylesheet, $theme );
+
+					if ( $primary === $column_name ) {
+						echo $this->row_actions($actions, true);
+					}
 					echo "</td>";
 			}
 		}
Index: src/wp-admin/includes/class-wp-ms-users-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-ms-users-list-table.php	(revision 32613)
+++ src/wp-admin/includes/class-wp-ms-users-list-table.php	(working copy)
@@ -164,16 +164,24 @@
 			<tr class="<?php echo trim( $class ); ?>">
 			<?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 && 'blogs' === $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";
+				$attributes = "class='$classes'$style";
 
 				switch ( $column_name ) {
 					case 'cb': ?>
@@ -193,38 +201,15 @@
 							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>";
+						echo "<td $attributes>$user->first_name $user->last_name";
 					break;
 
 					case 'email':
-						echo "<td $attributes><a href='mailto:$user->user_email'>$user->user_email</a></td>";
+						echo "<td $attributes><a href='mailto:$user->user_email'>$user->user_email</a>";
 					break;
 
 					case 'registered':
@@ -233,7 +218,7 @@
 						else
 							$date = __( 'Y/m/d g:i:s a' );
 
-						echo "<td $attributes>" . mysql2date( $date, $user->user_registered ) . "</td>";
+						echo "<td $attributes>" . mysql2date( $date, $user->user_registered );
 					break;
 
 					case 'blogs':
@@ -286,7 +271,6 @@
 								}
 							}
 							?>
-						</td>
 					<?php
 					break;
 
@@ -294,9 +278,11 @@
 						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;
 				}
+
+				echo $this->handle_row_actions( $user, $column_name, $primary );
+				echo '</td>';
 			endforeach
 			?>
 			</tr>
@@ -303,4 +289,55 @@
 			<?php
 		}
 	}
+
+	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'username';
+	}
+
+	/**
+	 * Generate and display row actions links
+	 *
+	 * @since 4.3
+	 * @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: src/wp-admin/includes/class-wp-plugins-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-plugins-list-table.php	(revision 32613)
+++ src/wp-admin/includes/class-wp-plugins-list-table.php	(working copy)
@@ -301,7 +301,7 @@
 					add_query_arg('plugin_status', $type, 'plugins.php'),
 					( $type == $status ) ? ' class="current"' : '',
 					sprintf( $text, number_format_i18n( $count ) )
-					);
+				);
 			}
 		}
 
@@ -451,7 +451,7 @@
 						$actions['delete'] = '<a href="' . wp_nonce_url('plugins.php?action=delete-selected&amp;checked[]=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins') . '" title="' . esc_attr__('Delete this plugin') . '" class="delete">' . __('Delete') . '</a>';
 				} // end if $is_active
 
-			 } // end if $screen->in_admin( 'network' )
+			} // end if $screen->in_admin( 'network' )
 
 			if ( ( ! is_multisite() || $screen->in_admin( 'network' ) ) && current_user_can('edit_plugins') && is_writable(WP_PLUGIN_DIR . '/' . $plugin_file) )
 				$actions['edit'] = '<a href="plugin-editor.php?file=' . $plugin_file . '" title="' . esc_attr__('Open this file in the Plugin Editor') . '" class="edit">' . __('Edit') . '</a>';
@@ -531,12 +531,15 @@
 			$plugin_slug
 		);
 
-		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 ) {
 				case 'cb':
@@ -543,12 +546,21 @@
 					echo "<th scope='row' class='check-column'>$checkbox</th>";
 					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'>";
 
@@ -595,11 +607,19 @@
 					$plugin_meta = apply_filters( 'plugin_row_meta', $plugin_meta, $plugin_file, $plugin_data, $status );
 					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>";
+
 					/**
 					 * Fires inside each custom column of the Plugins list table.
 					 *
@@ -610,6 +630,10 @@
 					 * @param array  $plugin_data An array of plugin data.
 					 */
 					do_action( 'manage_plugins_custom_column', $column_name, $plugin_file, $plugin_data );
+
+					if ( $primary === $column_name ) {
+						echo $this->row_actions( $actions, true );
+					}
 					echo "</td>";
 			}
 		}
@@ -645,4 +669,16 @@
 		 */
 		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
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'plugin';
+	}
+}
\ No newline at end of file
Index: src/wp-admin/includes/class-wp-posts-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-posts-list-table.php	(revision 32613)
+++ src/wp-admin/includes/class-wp-posts-list-table.php	(working copy)
@@ -665,16 +665,20 @@
 		<tr id="post-<?php echo $post->ID; ?>" class="<?php echo implode( ' ', get_post_class( $classes, $post->ID ) ); ?>">
 	<?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 ) {
 
@@ -696,7 +700,8 @@
 			break;
 
 			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 ) {
 						// Sent level 0 by accident, by default, or because we don't know the actual level.
@@ -753,66 +758,8 @@
 				if ( ! $this->hierarchical_display && 'excerpt' == $mode && current_user_can( 'read_post', $post->ID ) )
 						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>';
-					}
-				}
+				echo $this->handle_row_actions( $post, $column_name, $primary );
 
-				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 );
-
 				get_inline_data( $post );
 				echo '</td>';
 			break;
@@ -868,6 +815,7 @@
 				} else {
 					_e( 'Last Modified' );
 				}
+				echo $this->handle_row_actions( $post, $column_name, $primary );
 				echo '</td>';
 			break;
 
@@ -879,7 +827,7 @@
 
 				$this->comments_bubble( $post->ID, $pending_comments );
 			?>
-			</div></td>
+			</div><?php echo $this->handle_row_actions( $post, $column_name, $primary ); ?></td>
 			<?php
 			break;
 
@@ -890,6 +838,7 @@
 					esc_url( add_query_arg( array( 'post_type' => $post->post_type, 'author' => get_the_author_meta( 'ID' ) ), 'edit.php' )),
 					get_the_author()
 				);
+				echo $this->handle_row_actions( $post, $column_name, $primary );
 			?></td>
 			<?php
 			break;
@@ -930,6 +879,7 @@
 					} else {
 						echo '&#8212;';
 					}
+					echo $this->handle_row_actions( $post, $column_name, $primary );
 					echo '</td>';
 					break;
 				}
@@ -976,6 +926,7 @@
 				 * @param int    $post_id     The current post ID.
 				 */
 				do_action( "manage_{$post->post_type}_posts_custom_column", $column_name, $post->ID );
+				echo $this->handle_row_actions( $post, $column_name, $primary );
 			?></td>
 			<?php
 			break;
@@ -988,6 +939,101 @@
 	}
 
 	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return( 'title' );
+	}
+
+	/**
+	 * Generate and display row actions links
+	 *
+	 * @since 4.3
+	 * @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 );
+		}
+	}
+
+	/**
 	 * Outputs the hidden row displayed when inline editing
 	 *
 	 * @since 3.1.0
Index: src/wp-admin/includes/class-wp-terms-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-terms-list-table.php	(revision 32613)
+++ src/wp-admin/includes/class-wp-terms-list-table.php	(working copy)
@@ -302,10 +302,7 @@
 	 */
 	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 ) );
 
 		/**
@@ -328,42 +325,6 @@
 
 		$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>';
 
@@ -375,6 +336,77 @@
 	}
 
 	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'name';
+	}
+
+	/**
+	 * Generate and display row actions links
+	 *
+	 * @since 4.3
+	 * @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 );
+		}
+	}
+
+	/**
 	 * @param object $tag
 	 * @return string
 	 */
Index: src/wp-admin/includes/class-wp-users-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-users-list-table.php	(revision 32613)
+++ src/wp-admin/includes/class-wp-users-list-table.php	(working copy)
@@ -384,7 +384,6 @@
 			 * @param WP_User $user_object WP_User object for the currently-listed user.
 			 */
 			$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 )
 			$checkbox = '<label class="screen-reader-text" for="user_' . $user_object->ID . '">' . sprintf( __( 'Select %s' ), $user_object->user_login ) . '</label>'
@@ -398,16 +397,20 @@
 
 		$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";
+			$attributes = "class='$classes'$style";
 
 			switch ( $column_name ) {
 				case 'cb':
@@ -414,16 +417,16 @@
 					$r .= "<th scope='row' class='check-column'>$checkbox</th>";
 					break;
 				case 'username':
-					$r .= "<td $attributes>$avatar $edit</td>";
+					$r .= "<td $attributes>$avatar $edit";
 					break;
 				case 'name':
-					$r .= "<td $attributes>$user_object->first_name $user_object->last_name</td>";
+					$r .= "<td $attributes>$user_object->first_name $user_object->last_name";
 					break;
 				case 'email':
-					$r .= "<td $attributes><a href='mailto:$email' title='" . esc_attr( sprintf( __( 'E-mail: %s' ), $email ) ) . "'>$email</a></td>";
+					$r .= "<td $attributes><a href='mailto:$email' title='" . esc_attr( sprintf( __( 'E-mail: %s' ), $email ) ) . "'>$email</a>";
 					break;
 				case 'role':
-					$r .= "<td $attributes>$role_name</td>";
+					$r .= "<td $attributes>$role_name";
 					break;
 				case 'posts':
 					$attributes = 'class="posts column-posts num"' . $style;
@@ -435,7 +438,6 @@
 					} else {
 						$r .= 0;
 					}
-					$r .= "</td>";
 					break;
 				default:
 					$r .= "<td $attributes>";
@@ -450,11 +452,27 @@
 					 * @param int    $user_id     ID of the currently-listed user.
 					 */
 					$r .= apply_filters( 'manage_users_custom_column', '', $column_name, $user_object->ID );
-					$r .= "</td>";
 			}
+
+			if ( $primary === $column_name ) {
+				$r .= $this->row_actions( $actions );
+			}
+			$r .= "</td>";
 		}
 		$r .= '</tr>';
 
 		return $r;
 	}
+
+	/**
+	 * Get name of default primary column
+	 *
+	 * @since 4.3
+	 * @access protected
+	 *
+	 * @return string
+	 */
+	protected function get_default_primary_column_name() {
+		return 'username';
+	}
 }
