4.7 system.module confirm_form($form_id, $form, $question, $path, $description = NULL, $yes = NULL, $no = NULL, $name = 'confirm')
5 system.module confirm_form($form, $question, $path, $description = NULL, $yes = NULL, $no = NULL, $name = 'confirm')
6 system.module confirm_form($form, $question, $path, $description = NULL, $yes = NULL, $no = NULL, $name = 'confirm')
7 system.module confirm_form($form, $question, $path, $description = NULL, $yes = NULL, $no = NULL, $name = 'confirm')

Generates a form array for a confirmation form.

This function returns a complete form array for confirming an action. The form contains a confirm button as well as a cancellation link that allows a user to abort the action.

If the submit handler for a form that implements confirm_form() is invoked, the user successfully confirmed the action. You should never directly inspect $_POST to see if an action was confirmed.

Note - if the parameters $question, $description, $yes, or $no could contain any user input (such as node titles or taxonomy terms), it is the responsibility of the code calling confirm_form() to sanitize them first with a function like check_plain() or filter_xss().


$form: Additional elements to add to the form. These can be regular form elements, #value elements, etc., and their values will be available to the submit handler.

$question: The question to ask the user (e.g. "Are you sure you want to delete the block <em>foo</em>?"). The page title will be set to this value.

$path: The page to go to if the user cancels the action. This can be either:

  • A string containing a Drupal path.
  • An associative array with a 'path' key. Additional array values are passed as the $options parameter to l().

If the 'destination' query parameter is set in the URL when viewing a confirmation form, that value will be used instead of $path.

$description: Additional text to display. Defaults to t('This action cannot be undone.').

$yes: A caption for the button that confirms the action (e.g. "Delete", "Replace", ...). Defaults to t('Confirm').

$no: A caption for the link which cancels the action (e.g. "Cancel"). Defaults to t('Cancel').

$name: The internal name used to refer to the confirmation item.

Return value

The form array.

43 calls to confirm_form()
aggregator_admin_remove_feed in modules/aggregator/aggregator.admin.inc
Deletes a feed.
block_custom_block_delete in modules/block/block.admin.inc
Form constructor for the custom block deletion form.
book_remove_form in modules/book/book.pages.inc
Form constructor to confirm removal of a node from a book.
comment_confirm_delete in modules/comment/comment.admin.inc
Form builder; Builds the confirmation form for deleting a single comment.
comment_multiple_delete_confirm in modules/comment/comment.admin.inc
List the selected comments and verify that the admin wants to delete them.

... See full list

1 string reference to 'confirm_form'
system_theme in modules/system/system.module
Implements hook_theme().


modules/system/system.module, line 2869
Configuration system that lets administrators modify the workings of the site.


function confirm_form($form, $question, $path, $description = NULL, $yes = NULL, $no = NULL, $name = 'confirm') {
  $description = isset($description) ? $description : t('This action cannot be undone.');

  // Prepare cancel link.
  if (isset($_GET['destination'])) {
    $options = drupal_parse_url(urldecode($_GET['destination']));
  elseif (is_array($path)) {
    $options = $path;
  else {
    $options = array('path' => $path);

  drupal_set_title($question, PASS_THROUGH);

  $form['#attributes']['class'][] = 'confirmation';
  $form['description'] = array('#markup' => $description);
  $form[$name] = array('#type' => 'hidden', '#value' => 1);

  $form['actions'] = array('#type' => 'actions');
  $form['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => $yes ? $yes : t('Confirm'),
  $form['actions']['cancel'] = array(
    '#type' => 'link',
    '#title' => $no ? $no : t('Cancel'),
    '#href' => $options['path'],
    '#options' => $options,
  // By default, render the form using theme_confirm_form().
  if (!isset($form['#theme'])) {
    $form['#theme'] = 'confirm_form';
  return $form;


Could someone perhaps provide a simple usage example combined with another form? I can't get this working :(

Here is a code example I made to have a blueprint of a form with a confirmation step. It's probably not ideal, but it works for me. (I didn't know how to get around the session variable to keep my information around until the last step.)


 *  Form with confirmation step

function my_module_form($form, &$form_state) {
$path = current_path(); // path to return to if "cancel" is pressed

  // create a form with a "confirm" step.
  // Initial form first:

if( !isset( $form_state['storage']['confirm'] ) ) {


$form['your-field'] = array(
'#type' => 'textfield',
'#title' => t('Enter something here'),
'#description' => t('Description: You will have a chance to review before submitting.'),
'#required' => FALSE,
'#size' => 40,
'#maxlength' => 40,
'#attributes' => array(
'placeholder' => t('enter whatever here')


$form['confirm'] = array(
'#type' => 'submit',
'#value' => 'Submit',
'#submit' => array('my_module_form_submit'),


// The form shown during the confirmation step:
/*     dpm($form_state); // debug: show the form state */
    // some dummy content:
$content = '<h4>Confirmation dialog</h4>
    <p> This is shown before the final submit step... </p>

    <p> You have entered "'

. $form_state['values']['your-field'] . '"! <p>';


$content .= '<p> But "' . $form_state['values']['your-field'] . '" has not been submitted yet. Click "Really" below to actually submit. </p>';


$form['intro'] = array('#markup' => $content);


// create a confirm form:
    // confirm_form($form, $question, $path, $description = NULL, $yes = NULL, $no = NULL, $name = 'confirm');


return confirm_form($form, $question="Do you really want to make the change?", $path, $description = "Warning, this is the last step before form gets submitted", $yes = "Really?");


// end of function

// Our submit function
// (Name of the submit function has to be the name of above function + "_submit"!)

function my_module_form_submit($form, &$form_state) {

  if( !isset(

$form_state['storage']['confirm'] ))
// not confirmed yet.
$_SESSION['our_variable'] = $form_state['values']['your-field']; // add our field into a session variable to keep it around for later
      // NOTE: The variable is no longer in $form_state['values']['your-field'] by the time I'm printing out the final confirmation message. I'm
      // not sure session variables are the best solution, but this worked for me.
$form_state['storage']['confirm'] = TRUE; // this will cause the form to be rebuilt, entering the confirm part of the form
$form_state['rebuild'] = TRUE;


// Confirmed: processing of the form happens here:
/*     dpm($form_state); // debug output of $form_state */
$our_var = $_SESSION['our_variable']; // get back the variable (I don't know how $form_state can be preserved from the earlier stage.)


drupal_set_message('Now the form got processed and you entered ' . $our_var);



// end of function

Thanks, your example was great. the only change i would recommend is instead of using session to store the variable, just store the values in the $form_state['storeage'] that way you have all the variables of the first form available.

$form_state['storage']['values'] = $form_state['values'];

Instead of

$_SESSION['our_variable'] = $form_state['values']['your-field']

The example displays user input without sanitising it, creating a XSS scenario. You should run the $form_state['values'] data through the check_plain() function before you output it, use a safe placeholder in the t() function or at least filter_xss() it.

.= '<p> But "' . check_plain($form_state['values']['your-field']) . '" has not been submitted yet. Click "Really" below to actually submit. </p>';


.= t('<p> But "@value" has not been submitted yet. Click "Really" below to actually submit. </p>', array('@value' => $form_state['values']['your-field']));

In the second example, the <p> tag should not be included in the string that is run through t().

It should be more like this:

.= '<p>' . t('But "@value" has not been submitted yet. Click "Really" below to actually submit.', array('@value' => $form_state['values']['your-field'])) . '</p>';

to use the tweak from Brian.Harris, you may also need to include:
$form_state['rebuild'] = TRUE;
in the form submit callback to ensure the form_state is passed back to the form rather than just rebuilt

See node_menu, node_delete_confirm and node_delete_confirm_submit.

Basically, node_menu adds a path to node/%/delete, which resolves to node_delete_confirm


I use js instead of 'confirm_form', for your reference:

('(function($){ $(function(){$("#edit-xxxxxx").click(function(){return confirm("confirm do that ?")});}); })(jQuery);', array('type' => 'inline'));

If you are not validating the CSRF threat on the server side (using drupal token) while deleting any of drupal content using GET method, then you are introducing one using only Javascript confirm on the client side.

For eg,
If some logged in user has permission to delete the node, term, then if other user comments on any page using
<img src='http://admin/structure/term/1/delete'>

Then if logged in user visits that page, then term 1 will get delete without him knowing!!

A simple straight-forward usage example:

* implements hook_menu()
function example_menu() {
$items = array();

$items['example/list'] = array(
'title' => 'Test list',
'page callback' => 'example_list',
'access callback' => TRUE,

$items['example/%/delete'] = array(
'title' => 'Delete item',
'page callback' => 'drupal_get_form',
'page arguments' => array('example_delete', 1),
'access callback' => TRUE,
'type' => MENU_CALLBACK,

return $items;

function example_list() {
$header = array('#', 'Item', 'Action');
$rows = array(
array(1, 'Apple', l('Delete', 'example/1/delete')),
array(2, 'Android', l('Delete', 'example/2/delete')),
array(3, 'Blackberry', l('Delete', 'example/3/delete')),

return theme('table', array('header' => $header, 'rows' => $rows));

function example_delete($form, &$form_state, $the_id) {
$form = array();
$form['the_id'] = array(
'#type' => 'value',
'#value' => $the_id,

return confirm_form(
t('Are you sure you want to delete this item?'),
t('This action cannot be undone.'),

return $form;

* submit handler for the example_delete
* this function is invoked only when the user clicks confirm button
* clickin on cancel, the user goes back to the $path
function example_delete_submit($form, &$form_state) {

if ($form_state['values']['the_id'] == 1) {
// do some this here

drupal_set_message('You confirmed item ' . $form_state['values']['the_id'] . '.');
$form_state['redirect'] = 'example/list';

Why do you include the line return $form when it will never be executed?