20

In one of my forms, I'm trying to set a $form_state['redirect'] so the form will go to that destination after the user clicks one of the action buttons.

If I inspect $form_state['redirect'] both before and after I add the redirect, it is NULL before, and after contains the proper array. Here's how I'm setting up the redirect:

$form_state['redirect'] = array(
  'my/custom/path/' . $nid,
  array('query' => drupal_get_destination()),
);

I want to preserve the destination from the form that the user's viewing to the next path (that's why I'm calling drupal_get_destination(), which returns an array with 'destination' => 'some/path/here' inside.

It seems that, because there's already a destination in the path of the current form, the form redirects to that destination no matter what I put in my own form submit handler (see above code). I even tried using drupal_goto() and that didn't redirect the user either.

0

3 Answers 3

28

When a form is processed, the value of $form_state['redirect'] is sent to drupal_goto(), and drupal_goto() always favors $_GET['destination'] over its own $path parameter.

For the sake of completeness, in Drupal 6, you were somewhat out of luck without setting your own headers in hook_exit():

function mymodule_exit($destination = NULL) {
  $my_destination = 'foo/bar';
  header('Location: ' . url($my_destination));
  exit;
}

In Drupal 7, hook_drupal_goto_alter() was added for this specific use case:

function mymodule_drupal_goto_alter(&$path, &$options, &$http_response_code) {
  $path = 'foo/bar';
}

Another option for Drupal 7, which is closer to what you want to do, is to reset the static cache for drupal_get_destination() in your submit handler using drupal_static_reset():

function mymodule_form_submit($form, &$form_state) {
  // See note
  $form_state['redirect'][] = drupal_get_destination();
  $form_state['redirect'][] = 'foo/bar';

  unset($_GET['destination']);
  drupal_static_reset('drupal_get_destination');
  drupal_get_destination();
}

Since you call drupal_get_destination() immediately after the reset, Drupal is blissfully unaware of the destination parameter for the rest of the page build, including when it calls drupal_goto().

Note: I changed the code for defining $form_state['redirect'] because you never want to overwrite the variable: other submit handlers might've defined their own redirects. Drupal will always use the last item in the array, so if you want foo/bar to override the destination parameter (and every other redirect defined up to that point), it needs to be last.

1
  • Perfect, and very good explanation. I actually found a little more by working through the flow of a processed form - drupal_goto() is ultimately the reason my simple 'redirect' wasn't working. I needed to overwrite $_GET['destination'] too. Jun 19, 2011 at 23:46
4

Thanks for this, but for some reason this didn't work when I tried it. I got a fatal error -- the data sent in the example answer above doesn't satisfy the requirements of drupal_goto()

It may be because this answer is rather old, but I was able to get it work with this instead:

function mymodule_form_submit($form, &$form_state) {


  $form_state['redirect'] = array(
    'foo/bar', array(
      'query' => drupal_get_destination()
    )
  );

  unset($_GET['destination']);
  drupal_static_reset('drupal_get_destination');
  drupal_get_destination();

}

I know this violates this note:

you never want to overwrite the variable: other submit handlers might've defined their own redirects.

But, in this case, you do definitely want to overwrite the variable. You wouldn't be setting this value unless you wanted to disregard other module's set values. Also, I think you have to because of the way drupal_goto() works with the query parameter. This may also be why the original answer was throwing fatal errors on my site.

1
  • This answer helped me realize that in some circumstances, you may want to completely override the $form_state['redirect'], or you may get a WSOD with competing redirects. Sep 15, 2015 at 3:31
-2

set form #action

global $base_path;
$form['#action'] = $base_path . '/node/'.$form_state['node']->nid.'/mytab';
3
  • -1 I think calling drupal_goto() in hook_node_insert() will screw things up (because drupal_goto() calls drupal_exit() preventing the new node from being saved).
    – Andy
    Jul 22, 2014 at 10:52
  • true - in a node_insert hook .. (edited the answer)
    – rémy
    Sep 11, 2014 at 20:34
  • 1
    This doesn't issue a redirect as OP asked, but submits the form to a different path.
    – Andy
    Sep 16, 2014 at 8:52

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