Drupal 6 Multistep forms
Written by Andrew Yager   
Tuesday, 03 June 2008
I've been trying for the last three or four days to understand how Drupal 6 Multistep forms work. There is a quickstart guide that shows how to write them, but it only deals with two pages, and isn't very extensible. There are a number of examples, but it turns out that these examples are generally wrong and do not work in Drupal 6. So... I sat down to work out how one would write a multistep form, and came up with this working example for Drupal 6.2. It's really basic, but should serve as a reasonable framework for someone else trying to work out what to do. (There is no finishing or submission logic in the form... just a storage engine that holds state).

Thanks to Brian McMurray for the correcting the function name formDemo_menu!

So... here is the example:

 

 <?php
function formDemo_menu() {
  $items['registration/form'] = array(
    'title' => t('My form'),
    'page callback' => 'formDemo_form',
    'access arguments' => array('access content'),
    'description' => t('My form'),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

function formDemo_form() {
    return drupal_get_form('formDemo_my_form');
}

//helper function that isn't needed, but I thought it was needer
function formDemo_dv($setValue, $default='') {
    return ($setValue===null)?$default:$setValue;
}

function formDemo_my_form($form_state) {

    if (empty($form_state['storage']['step'])) {
        // we are coming in without a step, so default to step 1
        $form_state['storage']['step'] = 1;
    }
    
    //demo different fields on different steps
    switch ($form_state['storage']['step']) {
        case 1:
          $form['field1'] = array (
            '#type' => 'textfield',
            '#default_value' => formDemo_dv($form_state['storage']['values'][1]['field1']),
            '#title' => t('Test Field'));    
          break;
        case 2:
         $form['field2'] = array (
            '#type' => 'textfield',
            '#default_value' => formDemo_dv($form_state['storage']['values'][2]['field2']),
            '#title' => t('Test Field 2'));
          break;
        case 3:
         $form['field3'] = array (
            '#type' => 'textfield',
            '#default_value' => formDemo_dv($form_state['storage']['values'][3]['field3']),
            '#title' => t('Test Field 3'));
          break;
        default:
            ///blah blah, really you should never get here
          break;
    }
    
    //don't show back button on first tab
    if ($form_state['storage']['step'] > 1) {
        $form['previous'] = array(
            '#type' => 'submit',
            '#value' => '<< Previous'
          );
    }
    
    //show next button all the time in this demo
    $form['next'] = array(
        '#type' => 'submit',
        '#value' => 'Next >>'
      );
    return $form;
}


function formDemo_my_form_submit($form, &$form_state) {
    //save the values for the current step into the storage array
    $form_state['storage']['values'][$form_state['storage']['step']] = $form_state['values'];
    
    // check the button that was clicked and action the step chagne
    if ($form_state['clicked_button']['#id']=='edit-previous') {
        $form_state['storage']['step']--;
    } elseif ($form_state['clicked_button']['#id']=='edit-next') {
        $form_state['storage']['step']++;
    }
    
    //tell Drupal we are redrawing the same form
    $form_state['rebuild'] = TRUE;
    
}

Last Updated ( Wednesday, 28 January 2009 )