I am trying to develop a module to insert a lot of node at one time and I would like to use Batch-API to display the progress of operations.

I read the example into 'Example' module and I wrote this code.

But don't made anything. I can see the progress bar go head but it don't save any node.

Can anyone help me on this?

function custom_content_archive_import_contents_submit($form, &$form_state) {
    $file->status = FILE_STATUS_PERMANENT;
    drupal_set_message(t('The file @filename was uploaded successfully.', array('@filename' => $file->filename)));

    $path = drupal_realpath($file->uri);
    $importer = new CsvImporter($path, true, variable_get('custom_content_archive_file_delimiter'), variable_get('custom_content_archive_file_enclosure'));
    $data = $importer->get();

    $_SESSION['http_request_count'] = 0; // reset counter for debug information.
    $all_data = array(
        'ctype' => $form_state['values']['list'],
        'data' => $data,
        'user' => $form_state['values']['user'],
        'lang' => $form_state['values']['languages'],

function start_batch_creation_nodes($all_data) {
    $num_operations = count($all_data['data']);

    $operations = array();
    $i = 0;
    // leggo il file uploadato e creo i nodi
    foreach ($all_data['data'] as $node) {
         $operations[] = array('create_node', 
                                t('(Operation @operation)', array('@operation' => $i))

    $batch = array(
        'operations' => $operations,
        'finished' => 'custom_content_archive_import_contents_finished',
    return $batch;

function create_node($arrnode, $ctype, $user, $lang, $operation_details, &$context) {
    $node = new stdClass(); // Create a new node object
    $node->type = $ctype; // Or page, or whatever content type you like
    node_object_prepare($node); // Set some default values
    $node->uid = $user; // UID of the author of the node; or use $node->name
    $node->language = $lang; // Or e.g. 'en' if locale is enabled
    $node->promote = 0;

    foreach ($arrnode as $field => $value){
        switch ($field) {
            case 'title':
                $node->title = $arrnode['title'];
                $node->body[LANGUAGE_NONE][0]['value'] = nl2br($arrnode['body']);
                $node->body[LANGUAGE_NONE][0]['summary'] = text_summary($bodytext);
                $node->body[LANGUAGE_NONE][0]['format'] = 'filtered_html';
                $arrfield = field_info_field($field);
                switch ($arrfield['type']) {
                    case 'datetime':
                         $my_date = new DateTime($value);
                         $node->{$field}[LANGUAGE_NONE][0][value] = date_format($my_date, 'Y-m-d H:i:s');
                    case 'text':
                         $node->{$field}[LANGUAGE_NONE][0][value] = $value;
                    case 'email':
                         $node->{$field}[LANGUAGE_NONE][0][email] = $value;
                    case 'link_field':
                         $node->{$field}[LANGUAGE_NONE][0][url] = $value;

    if($node = node_submit($node)) { // Prepare node for saving
        workflow_execute_transition($node, 3, $comment = NULL, $force = TRUE);
        // Store some results for post-processing in the 'finished' callback.
        // The contents of 'results' will be available as $results in the
        // 'finished' function (in this example, batch_example_finished()).
        $context['results'][] = $node->nid . ' : ' . check_plain($node->title);

        // Optional message displayed under the progressbar.
        $context['message'] = t('Saving node "@title"', array('@title' => $node->title)) . ' ' . $operation_details;



function custom_content_archive_import_contents_finished($success, $results, $operations) {
    if ($success) {
        // Here we could do something meaningful with the results.
        // We just display the number of nodes we processed...
        drupal_set_message(t('@count results processed in @requests HTTP requests.', array('@count' => count($results), '@requests' => _custom_content_archive_import_contents_get_http_requests())));
        drupal_set_message(t('The final result was "%final"', array('%final' => end($results))));
    } else {
        // An error occurred.
        // $operations contains the operations that remained unprocessed.
        $error_operation = reset($operations);
        drupal_set_message(t('An error occurred while processing @operation with arguments : @args', array('@operation' => $error_operation[0], '@args' => print_r($error_operation[0], TRUE))));

function _custom_content_archive_import_contents_update_http_requests() {

function _custom_content_archive_import_contents_get_http_requests() {
    return !empty($_SESSION['http_request_count']) ? $_SESSION['http_request_count'] : 0;
  • 1
    In the "custom_content_archive_import_contents_submit" the last param is $form_stat and in your code you use $form_state, is a long shot but i think that could be the problem. Also, you do a "count($all_data['data'])" but in custom_content_archive_import_contents_submit the var $data is defined no where
    – Gnuget
    Jan 28, 2013 at 9:00
  • Thank's Gnuget, but was only a mistake. I've completed with all 'submit' code. Every comment is welcome.
    – umpire274
    Jan 28, 2013 at 9:26

1 Answer 1


I'll refrain from trying to debug your code - that is probably a bit too localized, but will instead give you some advice/help on how to use the batch API in general.

What you are doing should work, but you are still using the batch API the wrong way.

The intended use is, that you create a function that receive all the data, which can handle it in chunks and add that as a single operation. I'll try to illustrate this in code. The code is fictional but should give you an idea of how to do batch jobs. The main thing is that the batch job operation function should keep track of how far it is in the process and do a repeat job a certain number of times. The function will then be recalled with the same args, but the context variable will be updated from each repeated call.

function form_submit_handler_submit($form, &$form_state) {
  // $form_state['values']['nids'] is an array of nids to opperate on.
  $nids = $form_state['values']['nids'];
    'operations' => array('clone_nodes', array($nids)),
    'finihsed' => 'finised_callback',


function clone_nodes($nids, &$context) {
  if (empty($context['sandbox']['count'])) {
    $context['sandbox']['count'] = 0;

  $nids_to_handle = range($context['sandbox']['count'], $context['sandbox']['count'] + 49);

  foreach ($nids_to_handle as $key) {
    $node = node_load(nids[$key]);

  $context['sandbox']['count'] += 50;

  $context['finished'] = 1.0 * $context['sandbox']['count'] / count($nids);
  $context['message'] = t('Cloning node @current/@total', array('@current' => $context['sandbox']['count'], '@total' => count($nids));
  • This answer seems to follow the Drupal Batch API documentation: link. The OP follows the pattern in the Examples Module - batch_example link. I do not believe that the Examples Module uses the 'wrong' approach.
    – SpartyDan
    Feb 8, 2017 at 0:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.