diff --git a/includes/class-custom-action.php b/includes/class-custom-action.php
index 7f37d6dcc4be1b4286c2bbf694fa3369455e4f68..1e06158b2a8f54316afb83a243fd8c1d17f418e1 100644
--- a/includes/class-custom-action.php
+++ b/includes/class-custom-action.php
@@ -36,17 +36,29 @@ class Custom_Action {
 		// Provide for capabilities checks.
 		wp_set_current_user( $vars->user_id );
 
-		// TODO: capture and repopulate $_REQUEST?
-		// Rebuild something akin to the URL this would normally be filtering.
+		// Rebuild something akin to the URL the custom action would normally be filtering.
 		$return_url = sprintf( '/wp-admin/%1$s.php', $vars->current_screen->base );
 		$return_url = add_query_arg( array(
 			'post_type'   => $vars->post_type,
 			'post_status' => $vars->post_status,
 		), $return_url );
 
+		// Because custom actions could be accessing $_REQUEST directly.
+		if ( ! is_null( $vars->raw_request ) ) {
+			global $real_request;
+			$real_request = $_REQUEST;
+
+			$_REQUEST = $vars->raw_request;
+		}
+
 		// Run the custom action as Core does. See note above.
 		$return_url = apply_filters( 'handle_bulk_actions-' . $vars->current_screen->id, $return_url, $vars->action, $vars->posts ); // Core violates its own standard by using a hyphen in the hook name. @codingStandardsIgnoreLine
 
+		// If $_REQUEST was overwritten, restore the original.
+		if ( isset( $real_request ) ) {
+			$_REQUEST = $real_request;
+		}
+
 		// Can't get much more than this in terms of success or failure.
 		$results = compact( 'return_url', 'vars' );
 		do_action( 'bulk_actions_cron_offload_custom_request_completed', $results, $vars );
diff --git a/includes/class-main.php b/includes/class-main.php
index e0c6a2fa011d2d9ce4639b95189b684906af42a5..1eb93b196d2dc14f19ed722103188d54a2a84553 100644
--- a/includes/class-main.php
+++ b/includes/class-main.php
@@ -99,7 +99,15 @@ class Main {
 	 * Capture relevant variables
 	 */
 	private static function capture_vars() {
-		$vars = array( 'action', 'custom_action', 'user_id', 'current_screen' ); // Extra data that normally would be available from the context.
+		// Extra data that normally would be available from the request.
+		$vars = array(
+			'action',         // Bulk action, or "custom" when not from Core.
+			'custom_action',  // Name of custom action.
+			'user_id',        // For permissions checks.
+			'current_screen', // Public properties from \WP_Screen.
+			'raw_request',    // When using a custom action, $_REQUEST.
+		);
+
 		$vars = array_merge( $vars, self::get_supported_vars() );
 		$vars = (object) array_fill_keys( $vars, null );
 
@@ -187,10 +195,11 @@ class Main {
 			$vars->keep_private = true;
 		}
 
-		// Standardize custom actions.
+		// Standardize custom actions and capture extra data.
 		if ( ! self::is_core_action( $vars->action ) ) {
 			$vars->custom_action = $vars->action;
 			$vars->action        = 'custom';
+			$vars->raw_request   = $_REQUEST;
 		}
 
 		return $vars;
@@ -228,11 +237,11 @@ class Main {
 	 */
 	public static function is_core_action( $action ) {
 		$core_actions = array(
-			'delete', // class Delete_Permanently.
+			'delete',     // class Delete_Permanently.
 			'delete_all', // class Delete_All.
-			'edit', // class Edit.
-			'trash', // class Move_To_Trash.
-			'untrash', // class Restore_From_Trash.
+			'edit',       // class Edit.
+			'trash',      // class Move_To_Trash.
+			'untrash',    // class Restore_From_Trash.
 		);
 
 		return in_array( $action, $core_actions, true );