Last updated December 4, 2010. Created by willmoy on May 23, 2009.
Edited by figaro, InactiveUserWho.... Log in to edit this page.

Sometimes it is useful to display a confirmation message before processing a form, especially when doing something irreversible, like deleting content. To see examples in core, look at the list of functions which call confirm_form. This page explains how to adapt the Form API process to support confirmation messages. The process for multi-stage forms is very similar.

The Form API process is:

  1. Display the form to the user (using the form function)
  2. Validate (using form_validate)
  3. Submit (using form_submit) and process
  4. Display the result to the user

To put a confirmation form in the middle we end up running through that process twice because there are now two page views, so it looks something like this:

  1. Display the form to the user (using the form function)
  2. Validate (using form_validate)
  3. Submit (using form_submit) and rebuild the form
  4. Display the confirmation form to the user (using the form function)
  5. Validate (using form_validate)
  6. Submit (using form_submit) and process
  7. Display the result to the user and redirect if desired

So there are the following things to deal with compared to a normal form:

  • Making sure the _form, _validate, _submit functions all do the right thing at each stage
  • Making sure the information entered into the form at step 1 is still available to the submit handler at step 6. You can do this either with a session variable or with hidden form fields. Note that if you send the data back to the browser in a hidden form field, you will have to re-validate it before entering it your database, or you create a security hole.
  • Making sure the redirection happens by setting a hidden variable in the confirmation form

The code samples below assume your module is called 'example' and, for simplicity, that the form contains a single file upload element. Adding more elements to the form will not change what needs to be done with it. For brevity, the optional _validate functions are omitted but they would follow exactly the same principles and need no special tricks.

You can also check http://drupal.org/node/764816#comment-2821212 for similar guidelines.

Code samples: displaying the right forms

If your form is on a dedicated page, hook_menu will contain something like this, just like any form. It tells drupal that at the page example/add there will be a form, and that form will be generated by the function _example_add. For efficiency we specify that all these functions will be in a separate file.

<?php
  $items
['example/add'] = array(
   
'title' => 'Add Example',
   
'page callback' => 'drupal_get_form',
   
'page arguments' => array('_example_add'),
   
'access arguments' => array('create example content'),
   
'type' => MENU_CALLBACK,
   
'file' => 'example.add.inc',
  );
?>

_example_add is responsible for picking a form to display. It calls different functions depending on whether we need the initial form or the confirmation form. In the example below, we test whether a file has been uploaded. You could just as easily test the value of a hidden form field, which would be the basis for a multi-stage form.

<?php
/**
* Callback for example creation form
*/
function _example_add($form_state) {
 
// If a file has already been uploaded, we know we need the confirmation form
 
if (isset($form_state['values']['file'])) {
    return
_example_add_form_confirm($form_state);
  }
 
// But the default is the main form
 
return _example_add_form($form_state);
}
?>

The main form is what you would expect:

<?php
function _example_add_form($form_state) {
 
$form = array();
 
$form['#attributes'] = array('enctype' => 'multipart/form-data');
 
$form['#prefix'] = 'Upload a file.';
 
$form['file'] = array(
   
'#type' => 'file',
   
'#title' => 'File to upload',
  );
 
$form['submit'] = array(
   
'#type' => 'submit',
   
'#value' => 'Upload',
  );
  return
$form;
}
?>

The confirmation form uses the confirm_form function and adds a couple of extra fields. The process field is so that the _submit handler can tell that the destination field redirects to another page after processing the form. Otherwise it will simply display the initial form again.

<?php
function _example_add_form_confirm(&$form_state) {
 
$desc = 'The following new items will be created ... your code here';
 
// Tell the submit handler to process the form
 
$form['process'] = array('#type' => 'hidden', '#value' => 'true');
 
// Make sure the form redirects in the end
 
$form['destination'] = array('#type' => 'hidden', '#value' => 'example/todo');
  return
confirm_form($form,
                     
'Are you sure?',
                     
'example/add',
                     
$desc,
                     
'Continue',
                     
'Start again');
}
?>

Code samples: processing the form

In this example, the first time round the file is parsed and the result saved to a session variable. After confirmation, that variable is sent to another function to be added to the database. The only obligatory things about this example, however, are checking whether confirmation has happened (here, by testing a hidden form variable from the confirmation form) and specifying $form_state['rebuild'] = TRUE?.

<?php
function _example_add_submit($form_id, &$form_state) {
 
// If confirmation has been done, process the file
 
if (isset($form_state['values']['process'])) {
   
$insert = _example_file_add($_SESSION['example_tmp_file']);
   
drupal_set_message('... created.');
    return
TRUE;
  }
 
// Otherwise, accept the file and prepare the confirmation dialog
 
$_SESSION['example_tmp_file'] = _example_file_parse($file->filepath);
 
// This is vital so the values are there
 
$form_state['rebuild'] = TRUE;
}
?>

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

a page that tells me how to disable confirmations.