1. 8.5.x core/includes/form.inc batch
  2. 8.0.x core/includes/form.inc batch
  3. 8.1.x core/includes/form.inc batch
  4. 8.2.x core/includes/form.inc batch
  5. 8.3.x core/includes/form.inc batch
  6. 8.4.x core/includes/form.inc batch
  7. 8.6.x core/includes/form.inc batch
  8. 6.x includes/form.inc batch
  9. 7.x includes/form.inc batch

Creates and processes batch operations.

Functions allowing forms processing to be spread out over several page requests, thus ensuring that the processing does not get interrupted because of a PHP timeout, while allowing the user to receive feedback on the progress of the ongoing operations.

The API is primarily designed to integrate nicely with the Form API workflow, but can also be used by non-Form API scripts (like update.php) or even simple page callbacks (which should probably be used sparingly).


$batch = array(
  'title' => t('Exporting'),
  'operations' => array(
  'finished' => 'my_finished_callback',
  'file' => 'path_to_file_containing_myfunctions',

// Only needed if not inside a form _submit handler.
// Setting redirect in batch_process.

Note: if the batch 'title', 'init_message', 'progress_message', or 'error_message' could contain any user input, it is the responsibility of the code calling batch_set() to sanitize them first with a function like \Drupal\Component\Utility\SafeMarkup::checkPlain() or \Drupal\Component\Utility\Xss::filter(). Furthermore, if the batch operation returns any user input in the 'results' or 'message' keys of $context, it must also sanitize them first.

Sample callback_batch_operation():

// Simple and artificial: load a node of a given type for a given user
function my_function_1($uid, $type, &$context) {

  // The $context array gathers batch context information about the execution (read),
  // as well as 'return values' for the current operation (write)
  // The following keys are provided :
  // 'results' (read / write): The array of results gathered so far by
  //   the batch processing, for the current operation to append its own.
  // 'message' (write): A text message displayed in the progress page.
  // The following keys allow for multi-step operations :
  // 'sandbox' (read / write): An array that can be freely used to
  //   store persistent data between iterations. It is recommended to
  //   use this instead of $_SESSION, which is unsafe if the user
  //   continues browsing in a separate window while the batch is processing.
  // 'finished' (write): A float number between 0 and 1 informing
  //   the processing engine of the completion level for the operation.
  //   1 (or no value explicitly set) means the operation is finished
  //   and the batch processing can continue to the next operation.
  $nodes = \Drupal::entityTypeManager()
    'uid' => $uid,
    'type' => $type,
  $node = reset($nodes);
  $context['results'][] = $node
    ->id() . ' : ' . SafeMarkup::checkPlain($node
  $context['message'] = SafeMarkup::checkPlain($node

// A more advanced example is a multi-step operation that loads all rows,
// five by five.
function my_function_2(&$context) {
  if (empty($context['sandbox'])) {
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['current_id'] = 0;
    $context['sandbox']['max'] = db_query('SELECT COUNT(DISTINCT id) FROM {example}')
  $limit = 5;
  $result = db_select('example')
    ->fields('example', array(
    ->condition('id', $context['sandbox']['current_id'], '>')
    ->range(0, $limit)
  foreach ($result as $row) {
    $context['results'][] = $row->id . ' : ' . SafeMarkup::checkPlain($row->title);
    $context['sandbox']['current_id'] = $row->id;
    $context['message'] = SafeMarkup::checkPlain($row->title);
  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];

Sample callback_batch_finished():

function my_finished_callback($success, $results, $operations) {

  // The 'success' parameter means no fatal PHP errors were detected. All
  // other error management should be handled using 'results'.
  if ($success) {
    $message = \Drupal::translation()
      ->formatPlural(count($results), 'One post processed.', '@count posts processed.');
  else {
    $message = t('Finished with an error.');

  // Providing data for the redirected page is done through $_SESSION.
  foreach ($results as $result) {
    $items[] = t('Loaded node %title.', array(
      '%title' => $result,
  $_SESSION['my_batch_results'] = $items;


core/includes/form.inc, line 535
Functions for form and batch generation and processing.


Namesort descending Location Description
batch_get core/includes/form.inc Retrieves the current batch.
batch_process core/includes/form.inc Processes the batch.
batch_set core/includes/form.inc Adds a new batch.
hook_batch_alter core/lib/Drupal/Core/Form/form.api.php Alter batch information before a batch is processed.
_batch_populate_queue core/includes/form.inc Populates a job queue with the operations of a batch set.
_batch_queue core/includes/form.inc Returns a queue object for a batch set.


akcakaya’s picture


I try to set a cron in linux crontab with wget but my batch URL don't work with wget and lynx. If I click it on browser it works fine but when I call from command line it's not working. Is there a way to call a batch script from crontab?


mxh’s picture

With wget or lynx, you usually make one request at all. However, batch processing requires multiple sequential requests to be finished at the end. With your browser it works fine because the browser does the subsequent requests for you, either via AJAX when Javascript is enabled or per HTML meta tags to let your browser know when and which request should be performed next. For the cronjob, you'll need to implement a script which reads the meta tags from the HTML code and does the subsequent requests after a specified amount of time. Alternatively you could look for a headless browser or something which is able to handle this for you.

gapple’s picture

If you're trying to process a large set of items during cron, the Queue API and hook_cron_queue_info() may be more appropriate.

hook_cron() can be used to enqueue items, and as many queue items as possible within the time limit for cron will be processed after all other hook_cron() implementations are complete.