|  | @@ -45,10 +45,12 @@ function views_bulk_operations_load_action_includes() {
 | 
	
		
			
				|  |  |    $files = array(
 | 
	
		
			
				|  |  |      'archive.action.inc',
 | 
	
		
			
				|  |  |      'argument_selector.action.inc',
 | 
	
		
			
				|  |  | +    'book.action.inc',
 | 
	
		
			
				|  |  |      'delete.action.inc',
 | 
	
		
			
				|  |  |      'modify.action.inc',
 | 
	
		
			
				|  |  |      'script.action.inc',
 | 
	
		
			
				|  |  |      'user_roles.action.inc',
 | 
	
		
			
				|  |  | +    'user_cancel.action.inc',
 | 
	
		
			
				|  |  |    );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (!$loaded) {
 | 
	
	
		
			
				|  | @@ -110,7 +112,7 @@ function views_bulk_operations_theme() {
 | 
	
		
			
				|  |  |        'variables' => array('view' => NULL, 'enable_select_all_pages' => TRUE),
 | 
	
		
			
				|  |  |      ),
 | 
	
		
			
				|  |  |      'views_bulk_operations_confirmation' => array(
 | 
	
		
			
				|  |  | -      'variables' => array('rows' => NULL, 'vbo' => NULL),
 | 
	
		
			
				|  |  | +      'variables' => array('rows' => NULL, 'vbo' => NULL, 'operation' => NULL, 'select_all_pages' => FALSE),
 | 
	
		
			
				|  |  |      ),
 | 
	
		
			
				|  |  |    );
 | 
	
		
			
				|  |  |    $files = views_bulk_operations_load_action_includes();
 | 
	
	
		
			
				|  | @@ -300,6 +302,29 @@ function views_bulk_operations_form_alter(&$form, &$form_state, $form_id) {
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  // Add basic VBO functionality.
 | 
	
		
			
				|  |  | +  if ($form_state['step'] == 'views_form_views_form') {
 | 
	
		
			
				|  |  | +    // The submit button added by Views Form API might be used by a non-VBO Views
 | 
	
		
			
				|  |  | +    // Form handler. If there's no such handler on the view, hide the button.
 | 
	
		
			
				|  |  | +    $has_other_views_form_handlers = FALSE;
 | 
	
		
			
				|  |  | +    foreach ($vbo->view->field as $field) {
 | 
	
		
			
				|  |  | +      if (property_exists($field, 'views_form_callback') || method_exists($field, 'views_form')) {
 | 
	
		
			
				|  |  | +        if (!($field instanceof views_bulk_operations_handler_field_operations)) {
 | 
	
		
			
				|  |  | +          $has_other_views_form_handlers = TRUE;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (!$has_other_views_form_handlers) {
 | 
	
		
			
				|  |  | +      $form['actions']['#access'] = FALSE;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // The VBO field is excluded from display, stop here.
 | 
	
		
			
				|  |  | +    if (!empty($vbo->options['exclude'])) {
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    $form = views_bulk_operations_form($form, $form_state, $vbo);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    // Cache the built form to prevent it from being rebuilt prior to validation
 | 
	
		
			
				|  |  |    // and submission, which could lead to data being processed incorrectly,
 | 
	
		
			
				|  |  |    // because the views rows (and thus, the form elements as well) have changed
 | 
	
	
		
			
				|  | @@ -319,15 +344,25 @@ function views_bulk_operations_form_alter(&$form, &$form_state, $form_id) {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  // Add basic VBO functionality.
 | 
	
		
			
				|  |  | -  if ($form_state['step'] == 'views_form_views_form') {
 | 
	
		
			
				|  |  | -    $form = views_bulk_operations_form($form, $form_state, $vbo);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    // Give other modules a chance to alter the form.
 | 
	
		
			
				|  |  |    drupal_alter('views_bulk_operations_form', $form, $form_state, $vbo);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Implements hook_views_post_build().
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Hides the VBO field if no operations are available.
 | 
	
		
			
				|  |  | + * This causes the entire VBO form to be hidden.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @see views_bulk_operations_form_alter().
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +function views_bulk_operations_views_post_build(&$view) {
 | 
	
		
			
				|  |  | +  $vbo = _views_bulk_operations_get_field($view);
 | 
	
		
			
				|  |  | +  if ($vbo && $vbo->get_selected_operations() < 1) {
 | 
	
		
			
				|  |  | +    $vbo->options['exclude'] = TRUE;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  |   * Returns the 'select all' div that gets inserted below the table header row
 | 
	
		
			
				|  |  |   * (for table style plugins with grouping disabled), or above the view results
 | 
	
	
		
			
				|  | @@ -409,7 +444,12 @@ function theme_views_bulk_operations_select_all($variables) {
 | 
	
		
			
				|  |  |  function views_bulk_operations_form($form, &$form_state, $vbo) {
 | 
	
		
			
				|  |  |    $form['#attached']['js'][] = drupal_get_path('module', 'views_bulk_operations') . '/js/views_bulk_operations.js';
 | 
	
		
			
				|  |  |    $form['#attached']['css'][] = drupal_get_path('module', 'views_bulk_operations') . '/css/views_bulk_operations.css';
 | 
	
		
			
				|  |  | -  $form['#prefix'] = '<div class="vbo-views-form">';
 | 
	
		
			
				|  |  | +  // Wrap the form in a div with specific classes for JS targeting and theming.
 | 
	
		
			
				|  |  | +  $class = 'vbo-views-form';
 | 
	
		
			
				|  |  | +  if (empty($vbo->view->result)) {
 | 
	
		
			
				|  |  | +    $class .= ' vbo-views-form-empty';
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  $form['#prefix'] = '<div class="' . $class . '">';
 | 
	
		
			
				|  |  |    $form['#suffix'] = '</div>';
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Force browser to reload the page if Back is hit.
 | 
	
	
		
			
				|  | @@ -426,25 +466,10 @@ function views_bulk_operations_form($form, &$form_state, $vbo) {
 | 
	
		
			
				|  |  |      '#attributes' => array('class' => 'select-all-rows'),
 | 
	
		
			
				|  |  |      '#default_value' => FALSE,
 | 
	
		
			
				|  |  |    );
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // The submit button added by Views Form API might be used by a non-VBO Views
 | 
	
		
			
				|  |  | -  // Form handler. If there's no such handler on the view, hide the button.
 | 
	
		
			
				|  |  | -  $has_other_views_form_handlers = FALSE;
 | 
	
		
			
				|  |  | -  foreach ($vbo->view->field as $field) {
 | 
	
		
			
				|  |  | -    if (property_exists($field, 'views_form_callback') || method_exists($field, 'views_form')) {
 | 
	
		
			
				|  |  | -      if (!($field instanceof views_bulk_operations_handler_field_operations)) {
 | 
	
		
			
				|  |  | -        $has_other_views_form_handlers = TRUE;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (!$has_other_views_form_handlers) {
 | 
	
		
			
				|  |  | -    $form['actions']['submit']['#access'] = FALSE;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    $form['select'] = array(
 | 
	
		
			
				|  |  |      '#type' => 'fieldset',
 | 
	
		
			
				|  |  |      '#title' => t('Operations'),
 | 
	
		
			
				|  |  | -    '#collapsible' => TRUE,
 | 
	
		
			
				|  |  | +    '#collapsible' => FALSE,
 | 
	
		
			
				|  |  |      '#attributes' => array('class' => array('container-inline')),
 | 
	
		
			
				|  |  |    );
 | 
	
		
			
				|  |  |    if ($vbo->get_vbo_option('display_type') == 0) {
 | 
	
	
		
			
				|  | @@ -573,7 +598,7 @@ function views_bulk_operations_confirm_form($form, &$form_state, $view, $output)
 | 
	
		
			
				|  |  |    $form = confirm_form($form,
 | 
	
		
			
				|  |  |      t('Are you sure you want to perform %operation on the selected items?', array('%operation' => $operation->label())),
 | 
	
		
			
				|  |  |      array('path' => $view->get_url(), 'query' => $query),
 | 
	
		
			
				|  |  | -    theme('views_bulk_operations_confirmation', array('rows' => $rows, 'vbo' => $vbo, 'select_all_pages' => $form_state['select_all_pages']))
 | 
	
		
			
				|  |  | +    theme('views_bulk_operations_confirmation', array('rows' => $rows, 'vbo' => $vbo, 'operation' => $operation, 'select_all_pages' => $form_state['select_all_pages']))
 | 
	
		
			
				|  |  |    );
 | 
	
		
			
				|  |  |    // Add VBO's submit handler to the Confirm button added by config_form().
 | 
	
		
			
				|  |  |    $form['actions']['submit']['#submit'] = array('views_bulk_operations_form_submit');
 | 
	
	
		
			
				|  | @@ -676,8 +701,8 @@ function views_bulk_operations_form_submit($form, &$form_state) {
 | 
	
		
			
				|  |  |   * Entry point for executing the chosen operation upon selected rows.
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  |   * If the selected operation is an aggregate operation (requiring all selected
 | 
	
		
			
				|  |  | - * items to be passed at the same time), or the execution is being triggered
 | 
	
		
			
				|  |  | - * through Drush, the operation is executed directly.
 | 
	
		
			
				|  |  | + * items to be passed at the same time), restricted to a single value, or has
 | 
	
		
			
				|  |  | + * the skip_batching option set, the operation is executed directly.
 | 
	
		
			
				|  |  |   * This means that there is no batching & queueing, the PHP execution
 | 
	
		
			
				|  |  |   * time limit is ignored (if allowed), all selected entities are loaded and
 | 
	
		
			
				|  |  |   * processed.
 | 
	
	
		
			
				|  | @@ -703,9 +728,13 @@ function views_bulk_operations_form_submit($form, &$form_state) {
 | 
	
		
			
				|  |  |  function views_bulk_operations_execute($vbo, $operation, $selection, $select_all_pages = FALSE) {
 | 
	
		
			
				|  |  |    global $user;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  // This is an aggregate operation, and it requires all rows to be selected.
 | 
	
		
			
				|  |  | -  // Try to load them without a batch.
 | 
	
		
			
				|  |  | -  if ($operation->aggregate() && $select_all_pages) {
 | 
	
		
			
				|  |  | +  // Determine if the operation needs to be executed directly.
 | 
	
		
			
				|  |  | +  $aggregate = $operation->aggregate();
 | 
	
		
			
				|  |  | +  $skip_batching = $vbo->get_vbo_option('skip_batching');
 | 
	
		
			
				|  |  | +  $force_single = $vbo->get_vbo_option('force_single');
 | 
	
		
			
				|  |  | +  $execute_directly = ($aggregate || $skip_batching || $force_single);
 | 
	
		
			
				|  |  | +  // Try to load all rows without a batch if needed.
 | 
	
		
			
				|  |  | +  if ($execute_directly && $select_all_pages) {
 | 
	
		
			
				|  |  |      views_bulk_operations_direct_adjust($selection, $vbo);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -713,6 +742,15 @@ function views_bulk_operations_execute($vbo, $operation, $selection, $select_all
 | 
	
		
			
				|  |  |    $options = array(
 | 
	
		
			
				|  |  |      'revision' => $vbo->revision,
 | 
	
		
			
				|  |  |      'entity_load_capacity' => $vbo->get_vbo_option('entity_load_capacity', 10),
 | 
	
		
			
				|  |  | +    // The information needed to recreate the view, to avoid serializing the
 | 
	
		
			
				|  |  | +    // whole object. Passed to the executed operation. Also used by
 | 
	
		
			
				|  |  | +    // views_bulk_operations_adjust_selection().
 | 
	
		
			
				|  |  | +    'view_info' => array(
 | 
	
		
			
				|  |  | +      'name' => $vbo->view->name,
 | 
	
		
			
				|  |  | +      'display' => $vbo->view->current_display,
 | 
	
		
			
				|  |  | +      'arguments' => $vbo->view->args,
 | 
	
		
			
				|  |  | +      'exposed_input' => $vbo->view->get_exposed_input(),
 | 
	
		
			
				|  |  | +    ),
 | 
	
		
			
				|  |  |    );
 | 
	
		
			
				|  |  |    // Create an array of rows in the needed format.
 | 
	
		
			
				|  |  |    $rows = array();
 | 
	
	
		
			
				|  | @@ -735,8 +773,8 @@ function views_bulk_operations_execute($vbo, $operation, $selection, $select_all
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  // Aggregate operations can only be executed directly.
 | 
	
		
			
				|  |  | -  if ($operation->aggregate()) {
 | 
	
		
			
				|  |  | +  if ($execute_directly) {
 | 
	
		
			
				|  |  | +    // Execute the operation directly and stop here.
 | 
	
		
			
				|  |  |      views_bulk_operations_direct_process($operation, $rows, $options);
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -763,18 +801,8 @@ function views_bulk_operations_execute($vbo, $operation, $selection, $select_all
 | 
	
		
			
				|  |  |    if ($select_all_pages && $vbo->view->query->pager->has_more_records()) {
 | 
	
		
			
				|  |  |      $total_rows = $vbo->view->total_rows;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    // Pass information needed to recreate the view inside a batch,
 | 
	
		
			
				|  |  | -    // to avoid having to serialize the current object (which is expensive).
 | 
	
		
			
				|  |  | -    $view_info = array(
 | 
	
		
			
				|  |  | -      'name' => $vbo->view->name,
 | 
	
		
			
				|  |  | -      'display' => $vbo->view->current_display,
 | 
	
		
			
				|  |  | -      'arguments' => $vbo->view->args,
 | 
	
		
			
				|  |  | -      'exposed_input' => $vbo->view->get_exposed_input(),
 | 
	
		
			
				|  |  | -      'entity_load_capacity' => $vbo->get_vbo_option('entity_load_capacity', 10),
 | 
	
		
			
				|  |  | -    );
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      $batch['operations'][] = array(
 | 
	
		
			
				|  |  | -      'views_bulk_operations_adjust_selection', array($view_info, $queue_name, $operation, $options),
 | 
	
		
			
				|  |  | +      'views_bulk_operations_adjust_selection', array($queue_name, $operation, $options),
 | 
	
		
			
				|  |  |      );
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    else {
 | 
	
	
		
			
				|  | @@ -808,22 +836,21 @@ function views_bulk_operations_execute($vbo, $operation, $selection, $select_all
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  |   * Batch API callback: loads the view page by page and enqueues all items.
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  | - * @param $view_info
 | 
	
		
			
				|  |  | - *   An array of information about the view, used to recreate and re-execute it.
 | 
	
		
			
				|  |  |   * @param $queue_name
 | 
	
		
			
				|  |  |   *   The name of the queue to which the items should be added.
 | 
	
		
			
				|  |  |   * @param $operation
 | 
	
		
			
				|  |  |   *   The operation object.
 | 
	
		
			
				|  |  |   * @param $options
 | 
	
		
			
				|  |  | - *   An array of options that affect execution (revision, entity_load_capacity).
 | 
	
		
			
				|  |  | - *   Passed along with each new queue item.
 | 
	
		
			
				|  |  | + *   An array of options that affect execution (revision, entity_load_capacity,
 | 
	
		
			
				|  |  | + *   view_info). Passed along with each new queue item.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -function views_bulk_operations_adjust_selection($view_info, $queue_name, $operation, $options, &$context) {
 | 
	
		
			
				|  |  | +function views_bulk_operations_adjust_selection($queue_name, $operation, $options, &$context) {
 | 
	
		
			
				|  |  |    if (!isset($context['sandbox']['progress'])) {
 | 
	
		
			
				|  |  |      $context['sandbox']['progress'] = 0;
 | 
	
		
			
				|  |  |      $context['sandbox']['max'] = 0;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  $view_info = $options['view_info'];
 | 
	
		
			
				|  |  |    $view = views_get_view($view_info['name']);
 | 
	
		
			
				|  |  |    $view->set_exposed_input($view_info['exposed_input']);
 | 
	
		
			
				|  |  |    $view->set_arguments($view_info['arguments']);
 | 
	
	
		
			
				|  | @@ -927,7 +954,7 @@ function views_bulk_operations_active_queue_process($queue_name, $operation, $to
 | 
	
		
			
				|  |  |    static $queue;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // It is still possible to hit the time limit.
 | 
	
		
			
				|  |  | -  @set_time_limit(0);
 | 
	
		
			
				|  |  | +  drupal_set_time_limit(0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Prepare the sandbox.
 | 
	
		
			
				|  |  |    if (!isset($context['sandbox']['progress'])) {
 | 
	
	
		
			
				|  | @@ -980,19 +1007,35 @@ function views_bulk_operations_queue_item_process($queue_item_data, &$log = NULL
 | 
	
		
			
				|  |  |    $account = user_load($queue_item_data['uid']);
 | 
	
		
			
				|  |  |    $entity_type = $operation->entityType;
 | 
	
		
			
				|  |  |    $entity_ids = array();
 | 
	
		
			
				|  |  | -  foreach ($row_group as $row_id => $row) {
 | 
	
		
			
				|  |  | +  foreach ($row_group as $row_index => $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) {
 | 
	
		
			
				|  |  | +  foreach ($row_group as $row_index => $row) {
 | 
	
		
			
				|  |  |      $entity_id = $row['entity_id'];
 | 
	
		
			
				|  |  |      // A matching entity couldn't be loaded. Skip this item.
 | 
	
		
			
				|  |  |      if (!isset($entities[$entity_id])) {
 | 
	
		
			
				|  |  |        continue;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    $entity = $entities[$entity_id];
 | 
	
		
			
				|  |  | +    if ($options['revision']) {
 | 
	
		
			
				|  |  | +      // Don't reload revisions for now, they are not statically cached and
 | 
	
		
			
				|  |  | +      // usually don't run into the edge case described below.
 | 
	
		
			
				|  |  | +      $entity = $entities[$entity_id];
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    else {
 | 
	
		
			
				|  |  | +      // A previous action might have resulted in the entity being resaved
 | 
	
		
			
				|  |  | +      // (e.g. node synchronization from a prior node in this batch), so try
 | 
	
		
			
				|  |  | +      // to reload it. If no change occurred, the entity will be retrieved
 | 
	
		
			
				|  |  | +      // from the static cache, resulting in no performance penalty.
 | 
	
		
			
				|  |  | +      $entity = entity_load_single($entity_type, $entity_id);
 | 
	
		
			
				|  |  | +      if (empty($entity)) {
 | 
	
		
			
				|  |  | +        // The entity is no longer valid.
 | 
	
		
			
				|  |  | +        continue;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      // If the current entity can't be accessed, skip it and log a notice.
 | 
	
		
			
				|  |  |      if (!_views_bulk_operations_entity_access($operation, $entity_type, $entity, $account)) {
 | 
	
		
			
				|  |  |        $message = 'Skipped %operation on @type %title due to insufficient permissions.';
 | 
	
	
		
			
				|  | @@ -1014,11 +1057,14 @@ function views_bulk_operations_queue_item_process($queue_item_data, &$log = NULL
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      $operation_context = array(
 | 
	
		
			
				|  |  |        'progress' => $row['position'],
 | 
	
		
			
				|  |  | -      'rows' => $row['views_row'],
 | 
	
		
			
				|  |  | +      'view_info' => $options['view_info'],
 | 
	
		
			
				|  |  |      );
 | 
	
		
			
				|  |  | +    if ($operation->needsRows()) {
 | 
	
		
			
				|  |  | +      $operation_context['rows'] = array($row_index => $row['views_row']);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      $operation->execute($entity, $operation_context);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    unset($row_group[$row_id]);
 | 
	
		
			
				|  |  | +    unset($row_group[$row_index]);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1055,11 +1101,11 @@ function views_bulk_operations_direct_adjust(&$selection, $vbo) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  |   * Processes the passed rows directly (without batching and queueing).
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * This is a legacy function that is now only used for aggregate operations.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  function views_bulk_operations_direct_process($operation, $rows, $options) {
 | 
	
		
			
				|  |  | -  @set_time_limit(0);
 | 
	
		
			
				|  |  | +  global $user;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  drupal_set_time_limit(0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Prepare an array of status information. Imitates the Batch API naming
 | 
	
		
			
				|  |  |    // for consistency. Passed to views_bulk_operations_execute_finished().
 | 
	
	
		
			
				|  | @@ -1067,42 +1113,56 @@ function views_bulk_operations_direct_process($operation, $rows, $options) {
 | 
	
		
			
				|  |  |    $context['results']['progress'] = 0;
 | 
	
		
			
				|  |  |    $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)) {
 | 
	
		
			
				|  |  | -      $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),
 | 
	
		
			
				|  |  | -      ));
 | 
	
		
			
				|  |  | -      unset($entities[$id]);
 | 
	
		
			
				|  |  | +  if ($operation->aggregate()) {
 | 
	
		
			
				|  |  | +    // Load all entities.
 | 
	
		
			
				|  |  | +    $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']);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Filter out entities that can't be accessed.
 | 
	
		
			
				|  |  | +    foreach ($entities as $id => $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),
 | 
	
		
			
				|  |  | +        ));
 | 
	
		
			
				|  |  | +        unset($entities[$id]);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (empty($entities)) {
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  // 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'];
 | 
	
		
			
				|  |  | +    // If there are any entities left, execute the operation on them.
 | 
	
		
			
				|  |  | +    if ($entities) {
 | 
	
		
			
				|  |  | +      $operation_context = array(
 | 
	
		
			
				|  |  | +        'view_info' => $options['view_info'],
 | 
	
		
			
				|  |  | +      );
 | 
	
		
			
				|  |  | +      // Pass the selected rows to the operation if needed.
 | 
	
		
			
				|  |  | +      if ($operation->needsRows()) {
 | 
	
		
			
				|  |  | +        $operation_context['rows'] = array();
 | 
	
		
			
				|  |  | +        foreach ($rows as $row_index => $row) {
 | 
	
		
			
				|  |  | +          $operation_context['rows'][$row_index] = $row['views_row'];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      $operation->execute($entities, $operation_context);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  $operation->execute($entities, $operation_context);
 | 
	
		
			
				|  |  | +  else {
 | 
	
		
			
				|  |  | +    // Imitate a queue and process the entities one by one.
 | 
	
		
			
				|  |  | +    $queue_item_data = array(
 | 
	
		
			
				|  |  | +      'uid' => $user->uid,
 | 
	
		
			
				|  |  | +      'arguments' => array($rows, $operation, $options),
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +    views_bulk_operations_queue_item_process($queue_item_data, $context['results']['log']);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  $context['results']['log'][] = t('Performed aggregate %operation on @items.', array(
 | 
	
		
			
				|  |  | +  $context['results']['progress'] += count($rows);
 | 
	
		
			
				|  |  | +  $context['results']['log'][] = t('Performed %operation on @items.', array(
 | 
	
		
			
				|  |  |      '%operation' => $operation->label(),
 | 
	
		
			
				|  |  | -    '@items' => format_plural(count($entities), '1 item', '@count items'),
 | 
	
		
			
				|  |  | +    '@items' => format_plural(count($rows), '1 item', '@count items'),
 | 
	
		
			
				|  |  |    ));
 | 
	
		
			
				|  |  | -  $context['results']['progress'] += count($entities);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    views_bulk_operations_execute_finished(TRUE, $context['results'], array());
 | 
	
		
			
				|  |  |  }
 |