Index: src
===================================================================
--- src	(revision 38611)
+++ src	(working copy)

Property changes on: src
___________________________________________________________________
Modified: svn:ignore
## -1,2 +1,3 ##
 .wp-tests-version
 .htaccess
+.idea
Index: src/wp-admin/edit-comments.php
===================================================================
--- src/wp-admin/edit-comments.php	(revision 38611)
+++ src/wp-admin/edit-comments.php	(working copy)
@@ -46,40 +46,84 @@
 
 	wp_defer_comment_counting( true );
 
-	foreach ( $comment_ids as $comment_id ) { // Check the permissions on each
-		if ( !current_user_can( 'edit_comment', $comment_id ) )
-			continue;
-
-		switch ( $doaction ) {
-			case 'approve' :
+	switch ( $doaction ) {
+		case 'approve' :
+			foreach ( $comment_ids as $comment_id ) { // Check the permissions on each
+				if ( ! current_user_can( 'edit_comment', $comment_id ) ) {
+					continue;
+				}
 				wp_set_comment_status( $comment_id, 'approve' );
-				$approved++;
-				break;
-			case 'unapprove' :
+				$approved ++;
+			}
+			break;
+		case 'unapprove' :
+			foreach ( $comment_ids as $comment_id ) { // Check the permissions on each
+				if ( ! current_user_can( 'edit_comment', $comment_id ) ) {
+					continue;
+				}
 				wp_set_comment_status( $comment_id, 'hold' );
-				$unapproved++;
-				break;
-			case 'spam' :
+				$unapproved ++;
+			}
+			break;
+		case 'spam' :
+			foreach ( $comment_ids as $comment_id ) { // Check the permissions on each
+				if ( ! current_user_can( 'edit_comment', $comment_id ) ) {
+					continue;
+				}
 				wp_spam_comment( $comment_id );
-				$spammed++;
-				break;
-			case 'unspam' :
+				$spammed ++;
+			}
+			break;
+		case 'unspam' :
+			foreach ( $comment_ids as $comment_id ) { // Check the permissions on each
+				if ( ! current_user_can( 'edit_comment', $comment_id ) ) {
+					continue;
+				}
 				wp_unspam_comment( $comment_id );
-				$unspammed++;
-				break;
-			case 'trash' :
+				$unspammed ++;
+			}
+			break;
+		case 'trash' :
+			foreach ( $comment_ids as $comment_id ) { // Check the permissions on each
+				if ( ! current_user_can( 'edit_comment', $comment_id ) ) {
+					continue;
+				}
 				wp_trash_comment( $comment_id );
-				$trashed++;
-				break;
-			case 'untrash' :
+				$trashed ++;
+			}
+			break;
+		case 'untrash' :
+			foreach ( $comment_ids as $comment_id ) { // Check the permissions on each
+				if ( ! current_user_can( 'edit_comment', $comment_id ) ) {
+					continue;
+				}
 				wp_untrash_comment( $comment_id );
-				$untrashed++;
-				break;
-			case 'delete' :
+				$untrashed ++;
+			}
+			break;
+		case 'delete' :
+			foreach ( $comment_ids as $comment_id ) { // Check the permissions on each
+				if ( ! current_user_can( 'edit_comment', $comment_id ) ) {
+					continue;
+				}
 				wp_delete_comment( $comment_id );
-				$deleted++;
-				break;
-		}
+				$deleted ++;
+			}
+			break;
+		default:
+			/**
+			 * Fires when a custom bulk action should be handled.
+			 *
+			 * The sendback link should be modified with success or failure feedback
+			 * from the action to be used to display feedback to the user.
+			 *
+			 * @since 4.7.0
+			 *
+			 * @param string $redirect_to The redirect URL.
+			 * @param string $doaction    The action being taken.
+			 * @param array  $comment_ids The comments to take the action on.
+			 */
+			$redirect_to = apply_filters( 'handle_bulk_actions-' . get_current_screen()->id, $redirect_to, $doaction, $comment_ids );
 	}
 
 	wp_defer_comment_counting( false );
@@ -100,7 +144,7 @@
 		$redirect_to = add_query_arg( 'deleted', $deleted, $redirect_to );
 	if ( $trashed || $spammed )
 		$redirect_to = add_query_arg( 'ids', join( ',', $comment_ids ), $redirect_to );
-
+		
 	wp_safe_redirect( $redirect_to );
 	exit;
 } elseif ( ! empty( $_GET['_wp_http_referer'] ) ) {
Index: src/wp-admin/edit-tags.php
===================================================================
--- src/wp-admin/edit-tags.php	(revision 38611)
+++ src/wp-admin/edit-tags.php	(working copy)
@@ -195,12 +195,27 @@
 	else
 		$location = add_query_arg( array( 'error' => true, 'message' => 5 ), $location );
 	break;
+default:
+	/**
+	 * Fires when a custom bulk action should be handled.
+	 *
+	 * The sendback link should be modified with success or failure feedback
+	 * from the action to be used to display feedback to the user.
+	 *
+	 * @since 4.7.0
+	 *
+	 * @param string $location The redirect URL.
+	 * @param string $action The action being taken.
+	 * @param array  $tag_ids The tags to take the action on.
+	 */
+	$location = apply_filters( 'handle_bulk_actions-' . get_current_screen()->id, $location, $wp_list_table->current_action(), $_REQUEST['delete_tags'] );
+	break;
 }
 
 if ( ! $location && ! empty( $_REQUEST['_wp_http_referer'] ) ) {
 	$location = remove_query_arg( array('_wp_http_referer', '_wpnonce'), wp_unslash($_SERVER['REQUEST_URI']) );
 }
-
+	
 if ( $location ) {
 	if ( ! empty( $_REQUEST['paged'] ) ) {
 		$location = add_query_arg( 'paged', (int) $_REQUEST['paged'], $location );
Index: src/wp-admin/edit.php
===================================================================
--- src/wp-admin/edit.php	(revision 38611)
+++ src/wp-admin/edit.php	(working copy)
@@ -162,6 +162,21 @@
 				}
 			}
 			break;
+		default:
+			/**
+			 * Fires when a custom bulk action should be handled. 
+			 * 
+			 * The sendback link should be modified with success or failure feedback 
+			 * from the action to be used to display feedback to the user. 
+			 * 
+			 * @since 4.7.0 
+			 * 
+			 * @param string $sendback The redirect URL. 
+			 * @param string $doaction The action being taken. 
+			 * @param array  $post_ids The posts to take the action on. 
+			 */
+			$sendback = apply_filters( 'handle_bulk_actions-' . get_current_screen()->id, $sendback, $doaction, $post_ids );
+			break;
 	}
 
 	$sendback = remove_query_arg( array('action', 'action2', 'tags_input', 'post_author', 'comment_status', 'ping_status', '_status', 'post', 'bulk_edit', 'post_view'), $sendback );
Index: src/wp-admin/includes/class-wp-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-list-table.php	(revision 38611)
+++ src/wp-admin/includes/class-wp-list-table.php	(working copy)
@@ -436,7 +436,7 @@
 	 */
 	protected function bulk_actions( $which = '' ) {
 		if ( is_null( $this->_actions ) ) {
-			$no_new_actions = $this->_actions = $this->get_bulk_actions();
+			$this->_actions = $this->get_bulk_actions();
 			/**
 			 * Filters the list table Bulk Actions drop-down.
 			 *
@@ -450,7 +450,6 @@
 			 * @param array $actions An array of the available bulk actions.
 			 */
 			$this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions );
-			$this->_actions = array_intersect_assoc( $this->_actions, $no_new_actions );
 			$two = '';
 		} else {
 			$two = '2';
Index: src/wp-admin/link-manager.php
===================================================================
--- src/wp-admin/link-manager.php	(revision 38611)
+++ src/wp-admin/link-manager.php	(working copy)
@@ -18,18 +18,37 @@
 
 if ( $doaction && isset( $_REQUEST['linkcheck'] ) ) {
 	check_admin_referer( 'bulk-bookmarks' );
+	
+	$redirect_to = admin_url( 'link-manager.php' );
+	$bulklinks = (array) $_REQUEST['linkcheck'];
 
 	if ( 'delete' == $doaction ) {
-		$bulklinks = (array) $_REQUEST['linkcheck'];
+		
 		foreach ( $bulklinks as $link_id ) {
 			$link_id = (int) $link_id;
 
 			wp_delete_link( $link_id );
 		}
 
-		wp_redirect( add_query_arg('deleted', count( $bulklinks ), admin_url( 'link-manager.php' ) ) );
-		exit;
+		$redirect_to = add_query_arg('deleted', count( $bulklinks ), $redirect_to );
+	} else {
+		/**
+		 * Fires when a custom bulk action should be handled.
+		 *
+		 * The sendback link should be modified with success or failure feedback
+		 * from the action to be used to display feedback to the user.
+		 *
+		 * @since 4.7.0
+		 *
+		 * @param string $redirect_to The redirect URL.
+		 * @param string $doaction    The action being taken.
+		 * @param array  $bulklinks   The links to take the action on.
+		 */
+		$redirect_to = apply_filters( 'handle_bulk_actions-' . get_current_screen()->id, $redirect_to, $doaction, $bulklinks );
 	}
+	
+	wp_redirect( $redirect_to );
+	exit;
 } elseif ( ! empty( $_GET['_wp_http_referer'] ) ) {
 	 wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
 	 exit;
Index: src/wp-admin/network/site-themes.php
===================================================================
--- src/wp-admin/network/site-themes.php	(revision 38611)
+++ src/wp-admin/network/site-themes.php	(working copy)
@@ -122,6 +122,22 @@
 				$n = 'none';
 			}
 			break;
+		default:
+			/**
+			 * Fires when a custom bulk action should be handled.
+			 *
+			 * The sendback link should be modified with success or failure feedback
+			 * from the action to be used to display feedback to the user.
+			 *
+			 * @since 4.7.0
+			 *
+			 * @param string $referer The redirect URL.
+			 * @param string $action The action being taken.
+			 * @param array  $theme_ids The themes to take the action on.
+			 * @param int    $site_id The current site id
+			 */
+			$referer = apply_filters( 'handle_bulk_actions-' . get_current_screen()->id, $referer, $action, $_REQUEST['checked'], $id );
+			$n = count( $themes );
 	}
 
 	update_option( 'allowedthemes', $allowed_themes );
Index: src/wp-admin/network/site-users.php
===================================================================
--- src/wp-admin/network/site-users.php	(revision 38611)
+++ src/wp-admin/network/site-users.php	(working copy)
@@ -164,6 +164,23 @@
 				$update = 'err_promote';
 			}
 			break;
+		default:
+			/**
+			 * Fires when a custom bulk action should be handled.
+			 *
+			 * The sendback link should be modified with success or failure feedback
+			 * from the action to be used to display feedback to the user.
+			 *
+			 * @since 4.7.0
+			 *
+			 * @param string $referer The redirect URL.
+			 * @param string $action The action being taken.
+			 * @param array  $user_ids The users to take the action on.
+			 * @param int    $site_id The id of the current site
+			 */
+			$referer = apply_filters( 'handle_bulk_actions-' . get_current_screen()->id, $referer, $action, $_REQUEST['users'], $id );
+			$update = $action;
+			break;
 	}
 
 	wp_safe_redirect( add_query_arg( 'update', $update, $referer ) );
Index: src/wp-admin/network/sites.php
===================================================================
--- src/wp-admin/network/sites.php	(revision 38611)
+++ src/wp-admin/network/sites.php	(working copy)
@@ -138,28 +138,60 @@
 		case 'allblogs':
 			if ( ( isset( $_POST['action'] ) || isset( $_POST['action2'] ) ) && isset( $_POST['allblogs'] ) ) {
 				$doaction = $_POST['action'] != -1 ? $_POST['action'] : $_POST['action2'];
-
-				foreach ( (array) $_POST['allblogs'] as $key => $val ) {
-					if ( $val != '0' && $val != $current_site->blog_id ) {
-						switch ( $doaction ) {
-							case 'delete':
-								if ( ! current_user_can( 'delete_site', $val ) )
+				switch ( $doaction ) {
+					case 'delete':
+						foreach ( (array) $_POST['allblogs'] as $key => $val ) {
+							if ( $val != '0' && $val != $current_site->blog_id ) {
+								if ( ! current_user_can( 'delete_site', $val ) ) {
 									wp_die( __( 'Sorry, you are not allowed to delete the site.' ) );
+								}
 
 								$updated_action = 'all_delete';
 								wpmu_delete_blog( $val, true );
-							break;
+							} else {
+								wp_die( __( 'Sorry, you are not allowed to change the current site.' ) );
+							}
+						}
+						break;
 
-							case 'spam':
-							case 'notspam':
+					case 'spam':
+					case 'notspam':
+						foreach ( (array) $_POST['allblogs'] as $key => $val ) {
+							if ( $val != '0' && $val != $current_site->blog_id ) {
 								$updated_action = ( 'spam' === $doaction ) ? 'all_spam' : 'all_notspam';
 								update_blog_status( $val, 'spam', ( 'spam' === $doaction ) ? '1' : '0' );
-							break;
+							} else {
+								wp_die( __( 'Sorry, you are not allowed to change the current site.' ) );
+							}
 						}
-					} else {
-						wp_die( __( 'Sorry, you are not allowed to change the current site.' ) );
-					}
+						break;
+					
+					default:
+						if ( isset($_REQUEST['allblogs']) ) {
+							$sendback = wp_get_referer();
+
+							/**
+							 * Fires when a custom bulk action should be handled.
+							 *
+							 * The sendback link should be modified with success or failure feedback
+							 * from the action to be used to display feedback to the user.
+							 *
+							 * @since 4.7.0
+							 *
+							 * @param string $sendback The redirect URL.
+							 * @param string $action The action being taken.
+							 * @param array  $blog_ids The blogs to take the action on.
+							 * @param int    $site_id The current site id.
+							 */
+							$sendback = apply_filters( 'handle_bulk_actions-' . get_current_screen()->id, $sendback, $doaction, $_REQUEST['allblogs'], $id );
+
+							if ( $sendback ) {
+								wp_safe_redirect( $sendback );
+								exit();
+							}
+						}
 				}
+				
 			} else {
 				$location = network_admin_url( 'sites.php' );
 				if ( ! empty( $_REQUEST['paged'] ) ) {
@@ -219,6 +251,7 @@
 		wp_safe_redirect( add_query_arg( array( 'updated' => $updated_action ), wp_get_referer() ) );
 		exit();
 	}
+
 }
 
 $msg = '';
Index: src/wp-admin/network/themes.php
===================================================================
--- src/wp-admin/network/themes.php	(revision 38611)
+++ src/wp-admin/network/themes.php	(working copy)
@@ -195,7 +195,32 @@
 				's' => $s
 			), network_admin_url( 'themes.php' ) ) );
 			exit;
+			break;
+		default:
+			if ( isset($_POST['checked']) ) {
+				$sendback = wp_get_referer();
+
+				/**
+				 * Fires when a custom bulk action should be handled.
+				 *
+				 * The sendback link should be modified with success or failure feedback
+				 * from the action to be used to display feedback to the user.
+				 *
+				 * @since 4.7.0
+				 *
+				 * @param string $sendback The redirect URL.
+				 * @param string $action The action being taken.
+				 * @param array  $theme_ids The themes to take the action on.
+				 */
+				$sendback = apply_filters( 'handle_bulk_actions-' . get_current_screen()->id, $sendback, $action, $_REQUEST['checked'] );
+
+				if ( $sendback ) {
+					wp_safe_redirect( $sendback );
+					exit;
+				}
+			}
 	}
+	
 }
 
 $wp_list_table->prepare_items();
Index: src/wp-admin/network/users.php
===================================================================
--- src/wp-admin/network/users.php	(revision 38611)
+++ src/wp-admin/network/users.php	(working copy)
@@ -52,13 +52,14 @@
 				$doaction = $_POST['action'] != -1 ? $_POST['action'] : $_POST['action2'];
 				$userfunction = '';
 
-				foreach ( (array) $_POST['allusers'] as $user_id ) {
-					if ( !empty( $user_id ) ) {
-						switch ( $doaction ) {
-							case 'delete':
-								if ( ! current_user_can( 'delete_users' ) )
+				switch ( $doaction ) {
+					case 'delete':
+						foreach ( (array) $_POST['allusers'] as $user_id ) {
+							if ( !empty( $user_id ) ) {
+								if ( ! current_user_can( 'delete_users' ) ) {
 									wp_die( __( 'Sorry, you are not allowed to access this page.' ), 403 );
-								$title = __( 'Users' );
+								}
+								$title       = __( 'Users' );
 								$parent_file = 'users.php';
 								require_once( ABSPATH . 'wp-admin/admin-header.php' );
 								echo '<div class="wrap">';
@@ -66,31 +67,71 @@
 								echo '</div>';
 								require_once( ABSPATH . 'wp-admin/admin-footer.php' );
 								exit();
-
-							case 'spam':
+							}
+						}
+						break;
+					
+					case 'spam':
+						foreach ( (array) $_POST['allusers'] as $user_id ) {
+							if ( !empty( $user_id ) ) {
 								$user = get_userdata( $user_id );
-								if ( is_super_admin( $user->ID ) )
+								if ( is_super_admin( $user->ID ) ) {
 									wp_die( sprintf( __( 'Warning! User cannot be modified. The user %s is a network administrator.' ), esc_html( $user->user_login ) ) );
+								}
 
 								$userfunction = 'all_spam';
-								$blogs = get_blogs_of_user( $user_id, true );
+								$blogs        = get_blogs_of_user( $user_id, true );
 								foreach ( (array) $blogs as $details ) {
 									if ( $details->userblog_id != $current_site->blog_id ) // main blog not a spam !
+									{
 										update_blog_status( $details->userblog_id, 'spam', '1' );
+									}
 								}
 								update_user_status( $user_id, 'spam', '1' );
-							break;
+							}
+						}
+						break;
 
-							case 'notspam':
+					case 'notspam':
+						foreach ( (array) $_POST['allusers'] as $user_id ) {
+							if ( ! empty( $user_id ) ) {
 								$userfunction = 'all_notspam';
-								$blogs = get_blogs_of_user( $user_id, true );
-								foreach ( (array) $blogs as $details )
+								$blogs        = get_blogs_of_user( $user_id, true );
+								foreach ( (array) $blogs as $details ) {
 									update_blog_status( $details->userblog_id, 'spam', '0' );
+								}
 
 								update_user_status( $user_id, 'spam', '0' );
-							break;
+							}
 						}
-					}
+						break;
+					
+					default:
+						if ( isset( $_POST['allusers'] ) ) {
+
+							$sendback = wp_get_referer();
+
+							/**
+							 * Fires when a custom bulk action should be handled.
+							 *
+							 * The sendback link should be modified with success or failure feedback
+							 * from the action to be used to display feedback to the user.
+							 *
+							 * @since 4.7.0
+							 *
+							 * @param string $sendback The redirect URL.
+							 * @param string $action The action being taken.
+							 * @param array  $user_ids The users to take the action on.
+							 * @param int    $site_id The id of the current site
+							 */
+							$sendback = apply_filters( 'handle_bulk_actions-' . get_current_screen()->id, $sendback, $doaction, $_POST['allusers'], $id );
+
+							if ( $sendback ) {
+								wp_safe_redirect( $sendback );
+								exit();
+							}
+						}
+						break;
 				}
 
 				wp_safe_redirect( add_query_arg( array( 'updated' => 'true', 'action' => $userfunction ), wp_get_referer() ) );
Index: src/wp-admin/plugins.php
===================================================================
--- src/wp-admin/plugins.php	(revision 38611)
+++ src/wp-admin/plugins.php	(working copy)
@@ -356,7 +356,33 @@
 				update_site_option( 'recently_activated', array() );
 			}
 			break;
+		
+		default:
+			if ( isset( $_POST['checked'] ) ) {
+				$sendback = wp_get_referer();
+
+				/**
+				 * Fires when a custom bulk action should be handled.
+				 *
+				 * The sendback link should be modified with success or failure feedback
+				 * from the action to be used to display feedback to the user.
+				 *
+				 * @since 4.7.0
+				 *
+				 * @param string $sendback The redirect URL.
+				 * @param string $action The action being taken.
+				 * @param array  $plugin_ids The plugins to take the action on.
+				 */
+				$sendback = apply_filters( 'handle_bulk_actions-' . get_current_screen()->id, $sendback, $action, $_POST['checked'] );
+
+				if ( $sendback ) {
+					wp_safe_redirect( $sendback );
+					exit;
+				}
+			}
+			break;
 	}
+
 }
 
 $wp_list_table->prepare_items();
Index: src/wp-admin/upload.php
===================================================================
--- src/wp-admin/upload.php	(revision 38611)
+++ src/wp-admin/upload.php	(working copy)
@@ -163,6 +163,20 @@
 			}
 			$location = add_query_arg( 'deleted', count( $post_ids ), $location );
 			break;
+		default:
+			/**
+			 * Fires when a custom bulk action should be handled.
+			 *
+			 * The sendback link should be modified with success or failure feedback
+			 * from the action to be used to display feedback to the user.
+			 *
+			 * @since 4.7.0
+			 *
+			 * @param string $location The redirect URL.
+			 * @param string $doaction The action being taken.
+			 * @param array  $post_ids The posts to take the action on.
+			 */
+			$location = apply_filters( 'handle_bulk_actions-' . get_current_screen()->id, $location, $doaction, $post_ids );
 	}
 
 	wp_redirect( $location );
Index: src/wp-admin/users.php
===================================================================
--- src/wp-admin/users.php	(revision 38611)
+++ src/wp-admin/users.php	(working copy)
@@ -410,6 +410,29 @@
 		exit;
 	}
 
+	if ( !empty($_REQUEST['users']) ) {
+		$sendback = wp_get_referer();
+
+		/**
+		 * Fires when a custom bulk action should be handled.
+		 *
+		 * The sendback link should be modified with success or failure feedback
+		 * from the action to be used to display feedback to the user.
+		 *
+		 * @since 4.7.0
+		 *
+		 * @param string $sendback The redirect URL.
+		 * @param string $action The action being taken.
+		 * @param array  $user_ids The users to take the action on.
+		 */
+		$sendback = apply_filters( 'handle_bulk_actions-' . get_current_screen()->id, $sendback, $wp_list_table->current_action(), $_REQUEST['users'] );
+		
+		if ( $sendback ) {
+			wp_safe_redirect( $sendback );
+			exit;
+		}
+	}
+
 	$wp_list_table->prepare_items();
 	$total_pages = $wp_list_table->get_pagination_arg( 'total_pages' );
 	if ( $pagenum > $total_pages && $total_pages > 0 ) {
