diff --git a/execution/ViewsBulkOperationsExecutionBase.class.php b/execution/ViewsBulkOperationsExecutionBase.class.php
index e69de29..4a01928 100644
--- a/execution/ViewsBulkOperationsExecutionBase.class.php
+++ b/execution/ViewsBulkOperationsExecutionBase.class.php
@@ -0,0 +1,146 @@
+<?php
+
+/**
+ * @file
+ *  Base class for the Views Bulk Operations Execution classes.
+ */
+
+require_once dirname(__FILE__) . '/ViewsBulkOperationsExecutionInterface.interface.php';
+
+
+abstract class ViewsBulkOperationsExecutionBase implements ViewsBulkOperationsExecutionInterface {
+  /**
+   * Executes the operation. Called from the process functions.
+   */
+  public static function doOperation($operation, $entity, $context, $account = NULL) {
+    global $user;
+
+    // If no account was provided, fallback to the current user.
+    if (!$account) {
+      $account = $user;
+    }
+
+    if (!$operation->access($account)) {
+      watchdog('actions permissions', 'An attempt by user %user to run operation %operation was blocked due to insufficient permissions.',
+        array('%operation' => $operation->label(), '%user' => format_username($account)), WATCHDOG_ALERT);
+      drupal_access_denied();
+      drupal_exit();
+    }
+
+    $operation->execute($entity, $context);
+  }
+
+  /**
+   * Helper function that runs after the execution process is complete.
+   */
+  public static function executionFinished($success, $results, $operations, $elapsed, $options = NULL) {
+    if ($success) {
+      if (count($results['log']) > 1) {
+        $message = theme('item_list', array('items' => $results['log']));
+      }
+      else {
+        $message = reset($results['log']);
+      }
+    }
+    else {
+      // An error occurred.
+      // $operations contains the operations that remained unprocessed.
+      $error_operation = reset($operations);
+      $message = t('An error occurred while processing @operation with arguments: @arguments',
+        array('@operation' => $error_operation[0], '@arguments' => print_r($error_operation[0], TRUE)));
+    }
+    if (empty($options)) {
+      // If the execution went through Batch API, the options are in $results.
+      $options = $results['options'];
+    }
+
+    if (!empty($options['display_result'])) {
+      _views_bulk_operations_log($message);
+    }
+  }
+
+  public static function adjustSelection(&$selection, $select_all, $vbo) {
+    if ($select_all) {
+      // Adjust selection to select all rows across pages.
+      $view = views_get_view($vbo->view->name);
+      $view->set_exposed_input($vbo->view->get_exposed_input());
+      $view->set_arguments($vbo->view->args);
+      $view->set_display($vbo->view->current_display);
+      $view->display_handler->set_option('pager', array(
+        'type' => 'none',
+        'options' => array()
+      ));
+      $view->build();
+      // Unset every field except the VBO one (which holds the entity id).
+      // That way the performance hit becomes much smaller, because there is no
+      // chance of views_handler_field_field::post_execute() firing entity_load().
+      foreach ($view->field as $field_name => $field) {
+        if ($field_name != $vbo->options['id']) {
+          unset($view->field[$field_name]);
+        }
+      }
+
+      $view->execute($vbo->view->current_display);
+      $results = array();
+      foreach ($view->result as $row_index => $result) {
+        $results[$row_index] = $vbo->get_value($result);
+      }
+      $selection = $results;
+    }
+  }
+
+  public static function execute($vbo, $selection, $operation, $select_all) {
+    // Options that affect execution.
+    $options = array(
+      'revision' => $vbo->revision,
+      'display_result' => $vbo->get_vbo_option('display_result'),
+      'entity_load_capacity' => $vbo->get_vbo_option('entity_load_capacity'),
+      'vbo_view' => array(
+        'name' => $vbo->view->name,
+        'current_display' => $vbo->view->current_display,
+        'exposed_input' => $vbo->view->get_exposed_input(),
+        'arguments' => $vbo->view->args,
+        'current_page' => $vbo->view->get_current_page(),
+      ),
+      'entity_type' => $vbo->get_entity_type(),
+      'vbo_field' => $vbo->options['id'],
+    );
+
+    // An operation that needs aggregated results can only be executed directly.
+    if ($operation->aggregate()) {
+      ViewsBulkOperationsExecutionDirect::_execute($options, $operation, $selection, $select_all, $vbo);
+    }
+    else {
+      static::_execute($options, $operation, $selection, $select_all, $vbo);
+    }
+  }
+
+  public static function prepareRows($operation, $selection, $select_all, $vbo) {
+    // Adjust the selection if needed, for example by fetching all entity ids
+    // when "Select all on all pages" was used by the user.
+    if (!$operation->aggregate() && $operation->getAdminOption('use_queue')) {
+      ViewsBulkOperationsExecutionQueue::adjustSelection($selection, $select_all, $vbo);
+    }
+    else {
+      ViewsBulkOperationsExecutionDirect::adjustSelection($selection, $select_all, $vbo);
+    }
+
+    // Create an array of rows with the data needed by the process functions.
+    $rows = array();
+    foreach ($selection as $row_index => $entity_id) {
+      $rows[$row_index] = array(
+        'entity_id' => $entity_id,
+        'views_row' => array(),
+      );
+      // Some operations require full selected rows.
+      // @todo Make this work when all rows on all pages are selected. #1367644
+      if ($operation->needsRows() && isset($vbo->view->result[$row_index])) {
+        $rows[$row_index]['views_row'] = $vbo->view->result[$row_index];
+      }
+    }
+
+    return $rows;
+  }
+}
+
+
diff --git a/execution/ViewsBulkOperationsExecutionBatch.class.php b/execution/ViewsBulkOperationsExecutionBatch.class.php
index e69de29..15f6fd7 100644
--- a/execution/ViewsBulkOperationsExecutionBatch.class.php
+++ b/execution/ViewsBulkOperationsExecutionBatch.class.php
@@ -0,0 +1,213 @@
+<?php
+/**
+ * @file
+ *  Batch execution type.
+ */
+
+require_once dirname(__FILE__) . '/ViewsBulkOperationsExecutionBase.class.php';
+
+/**
+ * Batch execution type for views bulk operations, where the operation will be
+ * executed in batch mode.
+ */
+class ViewsBulkOperationsExecutionBatch extends ViewsBulkOperationsExecutionBase implements ViewsBulkOperationsExecutionInterface {
+
+  public static function _execute($options, $operation, $selection, $select_all, $vbo) {
+    $batch = array(
+      'operations' => array(
+        array(
+          'ViewsBulkOperationsExecutionBatch::process',
+          array($operation, $selection, $select_all, $options)
+        ),
+      ),
+      'finished' => 'ViewsBulkOperationsExecutionBatch::executionFinished',
+      'progress_message' => '',
+      'title' => t('Performing %operation on the selected items...', array('%operation' => $operation->label())),
+    );
+    batch_set($batch);
+  }
+
+  /**
+   * Process function for the Batch API execution type.
+   */
+  public static function process($operation, $selection, $select_all, $options, &$context) {
+    // It is still possible to hit the time limit
+    set_time_limit(0);
+
+    if ($select_all) {
+      if (!isset($context['sandbox']['progress'])) {
+        $context['sandbox']['progress'] = 0;
+        $context['results']['time'] = microtime(TRUE);
+      }
+
+      // Rebuilding the view to get the items to be processed.
+      $view_settings = $options['vbo_view'];
+      $view = views_get_view($view_settings['name']);
+      $view->set_exposed_input($view_settings['exposed_input']);
+      $view->set_arguments($view_settings['arguments']);
+      $view->set_display($view_settings['current_display']);
+      $view->set_offset($context['sandbox']['progress']);
+
+      // Setting the offset.
+      $view->build();
+      // Unset every field except the VBO one (which holds the entity id).
+      // That way the performance hit becomes much smaller, because there is no
+      // chance of views_handler_field_field::post_execute() firing entity_load().
+      foreach ($view->field as $field_name => $field) {
+        if ($field_name != $options['field_name']) {
+          unset($view->field[$field_name]);
+        }
+      }
+      $view->execute($view->current_display);
+
+      // After view execution we are setting the maximum number of rows to be
+      // processed.
+      $context['sandbox']['max'] = $view->total_rows;
+      $entity_type = $operation->entityType;
+      foreach ($view->result as $row_id => $row) {
+        $entity = $row->entity;
+        if (!_views_bulk_operations_entity_access($operation, $entity_type, $entity)) {
+          $context['results']['log'][] = t('Skipped %operation on @type %title due to insufficient permissions.', array(
+            '%operation' => $operation->label(),
+            '@type' => $entity_type,
+            '%title' => _views_bulk_operations_entity_label($entity_type, $entity),
+          ));
+          $context['sandbox']['progress']++;
+          continue;
+        }
+
+        // Some operations rely on knowing their position in the execution set
+        // (because of specific things that need to be done at the beginning
+        // or the end of the set).
+        $operation_context = array(
+          'progress' => array(
+            'current' => $context['sandbox']['progress'] + 1,
+            'total' => $context['sandbox']['max'],
+          ),
+          'view' => $options['vbo_view'],
+        );
+        // Pass the selected row to the operation if needed.
+        if ($operation->needsRows()) {
+          $operation_context['rows'] = array($row_id => $view->result[$row_id]);
+        }
+        static::doOperation($operation, $entity, $operation_context);
+
+        $context['sandbox']['progress']++;
+      }
+
+      if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
+        // Provide an estimation of the completion level we've reached.
+        $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
+        $context['message'] = t('Processed @current out of @total', array('@current' => $context['sandbox']['progress'], '@total' => $context['sandbox']['max']));
+      }
+      else {
+        // All done. Save data for the finish callback.
+        $context['results']['rows'] = $context['sandbox']['progress'];
+        $context['results']['options'] = $options;
+
+        $context['results']['log'][] = t('Performed %operation on @items.', array(
+          '%operation' => $operation->label(),
+          '@items' => format_plural($context['results']['rows'], '1 item', '@count items'),
+        ));
+      }
+      $view->destroy();
+    }
+    else {
+      // Rebuilding the view to get the items to be processed.
+      $view_settings = $options['vbo_view'];
+      $view = views_get_view($view_settings['name']);
+      $view->set_exposed_input($view_settings['exposed_input']);
+      $view->set_arguments($view_settings['arguments']);
+      $view->set_display($view_settings['current_display']);
+      $view->set_current_page($view_settings['current_page']);
+
+      $view->init_pager();
+
+      // Setting the offset.
+      $view->build();
+      // Unset every field except the VBO one (which holds the entity id).
+      // That way the performance hit becomes much smaller, because there is no
+      // chance of views_handler_field_field::post_execute() firing entity_load().
+      foreach ($view->field as $field_name => $field) {
+        if ($field_name != $options['field_name']) {
+          unset($view->field[$field_name]);
+        }
+      }
+      $view->execute($view->current_display);
+
+      if (!isset($context['sandbox']['progress'])) {
+        $context['sandbox']['progress'] = 0;
+        $context['sandbox']['max'] = count($selection);
+        $context['results']['time'] = microtime(TRUE);
+        $context['sandbox']['page'] = $view->get_current_page();
+      }
+
+      // Process the rows in groups.
+      $remaining = $context['sandbox']['max'] - $context['sandbox']['progress'];
+      $count = min($options['entity_load_capacity'], $remaining);
+      $row_group = array_slice($selection, $context['sandbox']['progress'], $count, TRUE);
+      $entity_type = $operation->entityType;
+      $entity_ids = array();
+      foreach ($row_group as $row_id => $entity_id) {
+        $entity_ids[] = $entity_id;
+      }
+
+      $entities = _views_bulk_operations_entity_load($entity_type, $entity_ids, $options['revision']);
+      foreach ($row_group as $row_id => $entity_id) {
+        // A matching entity couldn't be loaded. Adjust the count and move on.
+        if (!isset($entities[$entity_id])) {
+          $context['sandbox']['progress']++;
+          unset($row_group[$row_id]);
+          continue;
+        }
+        $entity = $entities[$entity_id];
+
+        if (!_views_bulk_operations_entity_access($operation, $entity_type, $entity)) {
+          $context['results']['log'][] = t('Skipped %operation on @type %title due to insufficient permissions.', array(
+            '%operation' => $operation->label(),
+            '@type' => $entity_type,
+            '%title' => _views_bulk_operations_entity_label($entity_type, $entity),
+          ));
+          $context['sandbox']['progress']++;
+          continue;
+        }
+
+        // Some operations rely on knowing their position in the execution set
+        // (because of specific things that need to be done at the beginning
+        // or the end of the set).
+        $operation_context = array(
+          'progress' => array(
+            'current' => $context['sandbox']['progress'] + 1,
+            'total' => $context['sandbox']['max'],
+          ),
+          'view' => $options['vbo_view'],
+        );
+        // Pass the selected row to the operation if needed.
+        if ($operation->needsRows()) {
+          $operation_context['rows'] = array($row_id => $view->result[$row_id]);
+        }
+        static::doOperation($operation, $entity, $operation_context);
+
+        $context['sandbox']['progress']++;
+        unset($row_group[$row_id]);
+      }
+
+      if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
+        // Provide an estimation of the completion level we've reached.
+        $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
+        $context['message'] = t('Processed @current out of @total', array('@current' => $context['sandbox']['progress'], '@total' => $context['sandbox']['max']));
+      }
+      else {
+        // All done. Save data for the finish callback.
+        $context['results']['rows'] = $context['sandbox']['progress'];
+        $context['results']['options'] = $options;
+
+        $context['results']['log'][] = t('Performed %operation on @items.', array(
+          '%operation' => $operation->label(),
+          '@items' => format_plural($context['results']['rows'], '1 item', '@count items'),
+        ));
+      }
+      $view->destroy();
+    }
+  }
+}
diff --git a/execution/ViewsBulkOperationsExecutionDirect.class.php b/execution/ViewsBulkOperationsExecutionDirect.class.php
index e69de29..2f842d5 100644
--- a/execution/ViewsBulkOperationsExecutionDirect.class.php
+++ b/execution/ViewsBulkOperationsExecutionDirect.class.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * @file
+ *  Direct execution type.
+ */
+
+require_once dirname(__FILE__) . '/ViewsBulkOperationsExecutionBase.class.php';
+
+/**
+ * Class for the direct execution type for views bulk operations.
+ */
+class ViewsBulkOperationsExecutionDirect extends ViewsBulkOperationsExecutionBase implements ViewsBulkOperationsExecutionInterface {
+
+  public static function _execute($options, $operation, $selection, $select_all, $vbo) {
+    $rows = static::prepareRows($operation, $selection, $select_all, $vbo);
+    @set_time_limit(0);
+
+    // Prepare an array of status information. Imitates the Batch API naming
+    // for consistency. Passed to _views_bulk_operations_execute_finished().
+    $context = array();
+    $context['results']['rows'] = 0;
+    $context['results']['time'] = microtime(TRUE);
+    $context['results']['log'] = array();
+
+    $entity_type = $operation->entityType;
+    $entity_ids = array();
+    foreach ($rows as $row_index => $row) {
+      $entity_ids[] = $row['entity_id'];
+    }
+    $entities = _views_bulk_operations_entity_load($entity_type, $entity_ids, $options['revision']);
+
+    foreach ($entities as $id => $entity) {
+      if (!_views_bulk_operations_entity_access($operation, $entity_type, $entity)) {
+        unset($entities[$id]);
+        $context['results']['log'][] = t('Skipped %operation on @type %title due to insufficient permissions.', array(
+          '%operation' => $operation->label(),
+          '@type' => $entity_type,
+          '%title' => _views_bulk_operations_entity_label($entity_type, $entity),
+        ));
+      }
+    }
+    if (empty($entities)) {
+      return;
+    }
+
+    if ($operation->aggregate()) {
+      // Pass the selected rows to the operation if needed.
+      $operation_context = array();
+      if ($operation->needsRows()) {
+        $operation_context['rows'] = array();
+        foreach ($rows as $row_index => $row) {
+          $operation_context['rows'][$row_index] = $row['views_row'];
+        }
+      }
+      static::doOperation($operation, $entities, $operation_context);
+
+      $context['results']['log'][] = t('Performed aggregate %operation on @items.', array(
+        '%operation' => $operation->label(),
+        '@items' => format_plural(count($entities), '1 item', '@count items'),
+      ));
+      $context['results']['rows'] += count($entities);
+    }
+    else {
+      foreach ($rows as $row_index => $row) {
+        $entity_id = $row['entity_id'];
+        // A matching entity couldn't be loaded.
+        if (!isset($entities[$entity_id])) {
+          continue;
+        }
+
+        $entity = $entities[$entity_id];
+        // Some operations rely on knowing their position in the execution set
+        // (because of specific things that need to be done at the beginning
+        // or the end of the set).
+        $operation_context = array(
+          'progress' => array(
+            'current' => $context['results']['rows'] + 1,
+            'total' => count($rows),
+          ),
+          'view' => $options['vbo_view'],
+        );
+        // Pass the selected rows to the operation if needed.
+        if ($operation->needsRows()) {
+          $operation_context['rows'] = array($row_index => $row['views_row']);
+        }
+        static::doOperation($operation, $entity, $operation_context);
+
+        $context['results']['rows'] += 1;
+      }
+
+      $context['results']['log'][] = t('Performed %operation on @items.', array(
+        '%operation' => $operation->label(),
+        '@items' => format_plural(count($entities), '1 item', '@count items'),
+      ));
+    }
+
+    static::executionFinished(TRUE, $context['results'], array(), 0, $options + array('operation' => $operation));
+  }
+}
\ No newline at end of file
diff --git a/execution/ViewsBulkOperationsExecutionInterface.interface.php b/execution/ViewsBulkOperationsExecutionInterface.interface.php
index e69de29..1313990 100644
--- a/execution/ViewsBulkOperationsExecutionInterface.interface.php
+++ b/execution/ViewsBulkOperationsExecutionInterface.interface.php
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @file
+ *  Abstract class for the View Bulk Operations Execution types.
+ */
+
+interface ViewsBulkOperationsExecutionInterface {
+  static function adjustSelection(&$selection, $select_all, $vbo);
+  static function execute($vbo, $selection, $operation, $select_all);
+  static function _execute($options, $operation, $selection, $select_all, $vbo);
+  static function executionFinished($success, $results, $operations, $elapsed, $options = NULL);
+  static function prepareRows($operation, $selection, $select_all, $vbo);
+}
diff --git a/execution/ViewsBulkOperationsExecutionQueue.class.php b/execution/ViewsBulkOperationsExecutionQueue.class.php
index e69de29..8549435 100644
--- a/execution/ViewsBulkOperationsExecutionQueue.class.php
+++ b/execution/ViewsBulkOperationsExecutionQueue.class.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * @file
+ *  Queue execution type.
+ */
+
+require_once dirname(__FILE__) . '/ViewsBulkOperationsExecutionBase.class.php';
+
+/**
+ * Queue execution type for views bulk operations, where the operations will be
+ * queued and executed later.
+ */
+class ViewsBulkOperationsExecutionQueue extends ViewsBulkOperationsExecutionBase implements ViewsBulkOperationsExecutionInterface {
+
+  /**
+   * Process function for the Drupal Queue execution type.
+   */
+  function process($data) {
+    list($row_index, $row, $operation, $operation_context, $options) = $data['arguments'];
+
+    $entity_type = $operation->entityType;
+    $entities = _views_bulk_operations_entity_load($entity_type, array($row['entity_id']), $options['revision']);
+    $entity = reset($entities);
+    // No entity found. It might have been deleted in the meantime. Abort.
+    if (!$entity) {
+      return;
+    }
+
+    $account = user_load($data['uid']);
+    if (!_views_bulk_operations_entity_access($operation, $entity_type, $entity, $account)) {
+      watchdog('views bulk operations', 'Skipped %operation on @type %title due to insufficient permissions.', array(
+        '%operation' => $operation->label(),
+        '@type' => $entity_type,
+        '%title' => _views_bulk_operations_entity_label($entity_type, $entity),
+      ), WATCHDOG_ALERT);
+      return;
+    }
+
+    // Pass the selected row to the operation if needed.
+    if ($operation->needsRows()) {
+      $operation_context['rows'] = array($row_index => $row['views_row']);
+    }
+    static::doOperation($operation, $entity, $operation_context, $account);
+
+    // @todo Provide a way to spam less here.
+    if ($options['display_result']) {
+      watchdog('views bulk operations', 'Performed %operation on @type %title.', array(
+        '%operation' => $operation->label(),
+        '@type' => $entity_type,
+        '%title' => _views_bulk_operations_entity_label($entity_type, $entity),
+      ), WATCHDOG_INFO);
+    }
+  }
+
+  public static function _execute($options, $operation, $selection, $select_all, $vbo) {
+    $rows = static::prepareRows($operation, $selection, $select_all, $vbo);
+    global $user;
+    $entity_type = $options['entity_type'];
+    $queue = DrupalQueue::get('views_bulk_operations');
+    $current = 1;
+    foreach ($rows as $row_index => $row) {
+      // Some operations rely on knowing their position in the execution set
+      // (because of specific things that need to be done at the beginning
+      // or the end of the set).
+      $context = array(
+        'progress' => array(
+          'current' => $current,
+          'total' => count($rows),
+        ),
+      );
+
+      $job = array(
+        'title' => t('Perform %operation on @type !entity_id.', array(
+          '%operation' => $operation->label(),
+          '@type' => $entity_type,
+          '!entity_id' => $row['entity_id'],
+        )),
+        'uid' => $user->uid,
+        'arguments' => array(
+          $row_index,
+          $row,
+          $operation,
+          $context,
+          $options
+        ),
+      );
+      $queue->createItem($job);
+      $current++;
+    }
+    if ($options['display_result']) {
+      drupal_set_message(t('Enqueued the selected operation (%operation).', array(
+        '%operation' => $operation->label(),
+      )));
+    }
+  }
+}
diff --git a/views_bulk_operations.module b/views_bulk_operations.module
index 05e20e9..3a262a0 100644
--- a/views_bulk_operations.module
+++ b/views_bulk_operations.module
@@ -67,7 +67,7 @@ function views_bulk_operations_load_action_includes() {
 function views_bulk_operations_cron_queue_info() {
   return array(
     'views_bulk_operations' => array(
-      'worker callback' => '_views_bulk_operations_queue_process',
+      'worker callback' => 'ViewsBulkOperationsExecutionQueue::process',
       'time' => 30,
     ),
   );
@@ -154,12 +154,12 @@ function views_bulk_operations_get_operation_types() {
 }
 
 /**
-  * Gets the info array of an operation from the provider plugin.
-  *
-  * @param $operation_id
-  *   The id of the operation for which the info shall be returned, or NULL
-  *   to return an array with info about all operations.
-  */
+ * Gets the info array of an operation from the provider plugin.
+ *
+ * @param $operation_id
+ *   The id of the operation for which the info shall be returned, or NULL
+ *   to return an array with info about all operations.
+ */
 function views_bulk_operations_get_operation_info($operation_id = NULL) {
   $operations = &drupal_static(__FUNCTION__);
 
@@ -288,16 +288,10 @@ function views_bulk_operations_form_alter(&$form, &$form_state, $form_id) {
   // in the meantime. Matching views issue: http://drupal.org/node/1473276.
   $form_state['cache'] = TRUE;
 
+  // Allow VBO to work when embedded using views_embed_view(), or in a block.
   if (empty($vbo->view->override_url)) {
-    // If the VBO view is embedded using views_embed_view(), or in a block,
-    // $view->get_url() doesn't point to the current page, which means that
-    // the form doesn't get processed.
     if (!empty($vbo->view->preview) || $vbo->view->display_handler instanceof views_plugin_display_block) {
       $vbo->view->override_url = $_GET['q'];
-      // We are changing the override_url too late, the form action was already
-      // set by Views to the previous URL, so it needs to be overriden as well.
-      $query = drupal_get_query_parameters($_GET, array('q'));
-      $form['#action'] = url($_GET['q'], array('query' => $query));
     }
   }
 
@@ -611,36 +605,6 @@ function _views_bulk_operations_get_selection($vbo, $form_state) {
 }
 
 /**
- * Helper function to adjust the selected set of rows.
- */
-function _views_bulk_operations_adjust_selection(&$selection, $select_all, $vbo) {
-  if ($select_all) {
-    // Adjust selection to select all rows across pages.
-    $view = views_get_view($vbo->view->name);
-    $view->set_exposed_input($vbo->view->get_exposed_input());
-    $view->set_arguments($vbo->view->args);
-    $view->set_display($vbo->view->current_display);
-    $view->display_handler->set_option('pager', array('type' => 'none', 'options' => array()));
-    $view->build();
-    // Unset every field except the VBO one (which holds the entity id).
-    // That way the performance hit becomes much smaller, because there is no
-    // chance of views_handler_field_field::post_execute() firing entity_load().
-    foreach ($view->field as $field_name => $field) {
-      if ($field_name != $vbo->options['id']) {
-        unset($view->field[$field_name]);
-      }
-    }
-
-    $view->execute($vbo->view->current_display);
-    $results = array();
-    foreach ($view->result as $row_index => $result) {
-      $results[$row_index] = $vbo->get_value($result);
-    }
-    $selection = $results;
-  }
-}
-
-/**
  * Submit handler for all steps of the VBO multistep form.
  */
 function views_bulk_operations_form_submit($form, &$form_state) {
@@ -676,11 +640,8 @@ function views_bulk_operations_form_submit($form, &$form_state) {
       break;
   }
 
-  // Adjust the selection if needed, for example by fetching all entity ids
-  // when "Select all on all pages" was used by the user.
-  _views_bulk_operations_adjust_selection($form_state['selection'], $form_state['select_all_pages'], $vbo);
   // Execute the operation.
-  _views_bulk_operations_execute($vbo, $form_state['selection'], $form_state['operation']);
+  _views_bulk_operations_execute($vbo, $form_state['selection'], $form_state['operation'], $form_state['select_all_pages']);
 
   // Redirect.
   $query = drupal_get_query_parameters($_GET, array('q'));
@@ -721,337 +682,19 @@ function views_bulk_operations_form_submit($form, &$form_state) {
  * @param $force_direct
  *   Whether to force the direct method (when ran through drush, for example).
  */
-function _views_bulk_operations_execute($vbo, $selection, $operation, $force_direct = FALSE) {
-  global $user;
-
-  // Options that affect execution.
-  $options = array(
-    'revision' => $vbo->revision,
-    'display_result' => $vbo->get_vbo_option('display_result'),
-    'entity_load_capacity' => $vbo->get_vbo_option('entity_load_capacity'),
-  );
-  // An operation that needs aggregated results can only be executed directly.
-  if ($operation->aggregate()) {
-    $force_direct = TRUE;
-  }
-  // Create an array of rows with the data needed by the process functions.
-  $rows = array();
-  foreach ($selection as $row_index => $entity_id) {
-    $rows[$row_index] = array(
-      'entity_id' => $entity_id,
-      'views_row' => array(),
-    );
-    // Some operations require full selected rows.
-    // @todo Make this work when all rows on all pages are selected. #1367644
-    if ($operation->needsRows() && isset($vbo->view->result[$row_index])) {
-      $rows[$row_index]['views_row'] = $vbo->view->result[$row_index];
-    }
-  }
-
+function _views_bulk_operations_execute($vbo, $selection, $operation, $select_all = FALSE, $force_direct = FALSE) {
   if (!$force_direct && $operation->getAdminOption('use_queue')) {
-    $entity_type = $vbo->get_entity_type();
-    $queue = DrupalQueue::get('views_bulk_operations');
-    $current = 1;
-    foreach ($rows as $row_index => $row) {
-      // Some operations rely on knowing their position in the execution set
-      // (because of specific things that need to be done at the beginning
-      // or the end of the set).
-      $context = array(
-        'progress' => array(
-          'current' => $current,
-          'total' => count($rows),
-        ),
-      );
-
-      $job = array(
-        'title' => t('Perform %operation on @type !entity_id.', array(
-          '%operation' => $operation->label(),
-          '@type' => $entity_type,
-          '!entity_id' => $row['entity_id'],
-        )),
-        'uid' => $user->uid,
-        'arguments' => array($row_index, $row, $operation, $context, $options),
-      );
-      $queue->createItem($job);
-      $current++;
-    }
-    if ($options['display_result']) {
-      drupal_set_message(t('Enqueued the selected operation (%operation).', array(
-        '%operation' => $operation->label(),
-      )));
-    }
-  }
-  elseif (!$force_direct && $options['entity_load_capacity'] < count($rows)) {
-    $batch = array(
-      'operations' => array(
-        array('_views_bulk_operations_batch_process', array($rows, $operation, $options)),
-      ),
-      'finished' => '_views_bulk_operations_execute_finished',
-      'progress_message' => '',
-      'title' => t('Performing %operation on the selected items...', array('%operation' => $operation->label())),
-    );
-    batch_set($batch);
-  }
-  else {
-    _views_bulk_operations_direct_process($operation, $rows, $options);
-  }
-}
-
-/**
- * Process function for the Drupal Queue execution type.
- */
-function _views_bulk_operations_queue_process($data) {
-  list($row_index, $row, $operation, $operation_context, $options) = $data['arguments'];
-
-  $entity_type = $operation->entityType;
-  $entities = _views_bulk_operations_entity_load($entity_type, array($row['entity_id']), $options['revision']);
-  $entity = reset($entities);
-  // No entity found. It might have been deleted in the meantime. Abort.
-  if (!$entity) {
-    return;
-  }
-
-  $account = user_load($data['uid']);
-  if (!_views_bulk_operations_entity_access($operation, $entity_type, $entity, $account)) {
-    watchdog('views bulk operations', 'Skipped %operation on @type %title due to insufficient permissions.', array(
-      '%operation' => $operation->label(),
-      '@type' => $entity_type,
-      '%title' => _views_bulk_operations_entity_label($entity_type, $entity),
-    ), WATCHDOG_ALERT);
-    return;
-  }
-
-  // Pass the selected row to the operation if needed.
-  if ($operation->needsRows()) {
-    $operation_context['rows'] = array($row_index => $row['views_row']);
-  }
-  _views_bulk_operations_operation_do($operation, $entity, $operation_context, $account);
-
-  // @todo Provide a way to spam less here.
-  if ($options['display_result']) {
-    watchdog('views bulk operations', 'Performed %operation on @type %title.', array(
-      '%operation' => $operation->label(),
-      '@type' => $entity_type,
-      '%title' => _views_bulk_operations_entity_label($entity_type, $entity),
-    ), WATCHDOG_INFO);
-  }
-}
-
-/**
- * Process function for the Batch API execution type.
- */
-function _views_bulk_operations_batch_process($rows, $operation, $options, &$context) {
-  // It is still possible to hit the time limit.
-  set_time_limit(0);
-
-  if (!isset($context['sandbox']['progress'])) {
-    $context['sandbox']['progress'] = 0;
-    $context['sandbox']['max'] = count($rows);
-    $context['results']['time'] = microtime(TRUE);
-  }
-
-  // Process the rows in groups.
-  $remaining = $context['sandbox']['max'] - $context['sandbox']['progress'];
-  $count = min($options['entity_load_capacity'], $remaining);
-  $row_group = array_slice($rows, $context['sandbox']['progress'], $count, TRUE);
-  $entity_type = $operation->entityType;
-  $entity_ids = array();
-  foreach ($row_group as $row_id => $row) {
-    $entity_ids[] = $row['entity_id'];
-  }
-
-  $entities = _views_bulk_operations_entity_load($entity_type, $entity_ids, $options['revision']);
-  foreach ($row_group as $row_id => $row) {
-    $entity_id = $row['entity_id'];
-    // A matching entity couldn't be loaded. Adjust the count and move on.
-    if (!isset($entities[$entity_id])) {
-      $context['sandbox']['progress']++;
-      unset($row_group[$row_id]);
-      continue;
-    }
-    $entity = $entities[$entity_id];
-
-    if (!_views_bulk_operations_entity_access($operation, $entity_type, $entity)) {
-      $context['results']['log'][] = t('Skipped %operation on @type %title due to insufficient permissions.', array(
-        '%operation' => $operation->label(),
-        '@type' => $entity_type,
-        '%title' => _views_bulk_operations_entity_label($entity_type, $entity),
-      ));
-      $context['sandbox']['progress']++;
-      continue;
-    }
-
-    // Some operations rely on knowing their position in the execution set
-    // (because of specific things that need to be done at the beginning
-    // or the end of the set).
-    $operation_context = array(
-      'progress' => array(
-        'current' => $context['sandbox']['progress'] + 1,
-        'total' => $context['sandbox']['max'],
-      ),
-    );
-    // Pass the selected row to the operation if needed.
-    if ($operation->needsRows()) {
-      $operation_context['rows'] = array($row_index => $row['views_row']);
-    }
-    _views_bulk_operations_operation_do($operation, $entity, $operation_context);
-
-    $context['sandbox']['progress']++;
-    unset($row_group[$row_id]);
+    $execution_class = 'ViewsBulkOperationsExecutionQueue';
   }
-
-  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
-    // Provide an estimation of the completion level we've reached.
-    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
-    $context['message'] = t('Processed @current out of @total', array('@current' => $context['sandbox']['progress'], '@total' => $context['sandbox']['max']));
+  elseif (!$force_direct && $vbo->get_vbo_option('entity_load_capacity') < count($selection)) {
+    $execution_class = 'ViewsBulkOperationsExecutionBatch';
   }
   else {
-    // All done. Save data for the finish callback.
-    $context['results']['rows'] = $context['sandbox']['progress'];
-    $context['results']['options'] = $options;
-
-    $context['results']['log'][] = t('Performed %operation on @items.', array(
-      '%operation' => $operation->label(),
-      '@items' => format_plural($context['results']['rows'], '1 item', '@count items'),
-    ));
-  }
-}
-
-/**
- * Process function for the direct execution type.
- */
-function _views_bulk_operations_direct_process($operation, $rows, $options) {
-  @set_time_limit(0);
-
-  // Prepare an array of status information. Imitates the Batch API naming
-  // for consistency. Passed to _views_bulk_operations_execute_finished().
-  $context = array();
-  $context['results']['rows'] = 0;
-  $context['results']['time'] = microtime(TRUE);
-  $context['results']['log'] = array();
-
-  $entity_type = $operation->entityType;
-  $entity_ids = array();
-  foreach ($rows as $row_index => $row) {
-    $entity_ids[] = $row['entity_id'];
-  }
-  $entities = _views_bulk_operations_entity_load($entity_type, $entity_ids, $options['revision']);
-
-  foreach ($entities as $id => $entity) {
-    if (!_views_bulk_operations_entity_access($operation, $entity_type, $entity)) {
-      unset($entities[$id]);
-      $context['results']['log'][] = t('Skipped %operation on @type %title due to insufficient permissions.', array(
-        '%operation' => $operation->label(),
-        '@type' => $entity_type,
-        '%title' => _views_bulk_operations_entity_label($entity_type, $entity),
-      ));
-    }
-  }
-  if (empty($entities)) {
-    return;
+    $execution_class = 'ViewsBulkOperationsExecutionDirect';
   }
 
-  if ($operation->aggregate()) {
-    // Pass the selected rows to the operation if needed.
-    $operation_context = array();
-    if ($operation->needsRows()) {
-      $operation_context['rows'] = array();
-      foreach ($rows as $row_index => $row) {
-        $operation_context['rows'][$row_index] = $row['views_row'];
-      }
-    }
-    _views_bulk_operations_operation_do($operation, $entities, $operation_context);
-
-    $context['results']['log'][] = t('Performed aggregate %operation on @items.', array(
-      '%operation' => $operation->label(),
-      '@items' => format_plural(count($entities), '1 item', '@count items'),
-    ));
-    $context['results']['rows'] += count($entities);
-  }
-  else {
-    foreach ($rows as $row_index => $row) {
-      $entity_id = $row['entity_id'];
-      // A matching entity couldn't be loaded.
-      if (!isset($entities[$entity_id])) {
-        continue;
-      }
-
-      $entity = $entities[$entity_id];
-      // Some operations rely on knowing their position in the execution set
-      // (because of specific things that need to be done at the beginning
-      // or the end of the set).
-      $operation_context = array(
-        'progress' => array(
-          'current' => $context['results']['rows'] + 1,
-          'total' => count($rows),
-        ),
-      );
-      // Pass the selected rows to the operation if needed.
-      if ($operation->needsRows()) {
-        $operation_context['rows'] = array($row_index => $row['views_row']);
-      }
-      _views_bulk_operations_operation_do($operation, $entity, $operation_context);
-
-      $context['results']['rows'] += 1;
-    }
-
-    $context['results']['log'][] = t('Performed %operation on @items.', array(
-      '%operation' => $operation->label(),
-      '@items' => format_plural(count($entities), '1 item', '@count items'),
-    ));
-  }
-
-  _views_bulk_operations_execute_finished(TRUE, $context['results'], array(), 0, $options + array('operation' => $operation));
-}
-
-/**
- * Executes the operation. Called from the process functions.
- */
-function _views_bulk_operations_operation_do($operation, $entity, $context, $account = NULL) {
-  global $user;
-
-  // If no account was provided, fallback to the current user.
-  if (!$account) {
-    $account = $user;
-  }
-
-  if (!$operation->access($account)) {
-    watchdog('actions permissions', 'An attempt by user %user to run operation %operation was blocked due to insufficient permissions.',
-      array('%operation' => $operation->label(), '%user' => format_username($account)), WATCHDOG_ALERT);
-    drupal_access_denied();
-    drupal_exit();
-  }
-
-  $operation->execute($entity, $context);
-}
-
-/**
- * Helper function that runs after the execution process is complete.
- */
-function _views_bulk_operations_execute_finished($success, $results, $operations, $elapsed, $options = NULL) {
-  if ($success) {
-    if (count($results['log']) > 1) {
-      $message = theme('item_list', array('items' => $results['log']));
-    }
-    else {
-      $message = reset($results['log']);
-    }
-  }
-  else {
-    // An error occurred.
-    // $operations contains the operations that remained unprocessed.
-    $error_operation = reset($operations);
-    $message = t('An error occurred while processing @operation with arguments: @arguments',
-      array('@operation' => $error_operation[0], '@arguments' => print_r($error_operation[0], TRUE)));
-  }
-  if (empty($options)) {
-    // If the execution went through Batch API, the options are in $results.
-    $options = $results['options'];
-  }
-
-  if (!empty($options['display_result'])) {
-    _views_bulk_operations_log($message);
-  }
+  require_once dirname(__FILE__) . '/execution/' . $execution_class . '.class.php';
+  $execution_class::execute($vbo, $selection, $operation, $select_all);
 }
 
 /**
