Hello :)

I am creating a web page. And after submitting the node I need to display a web page saying "Thank you for posting your content!" instead of the node itself.
The task looks simple, but it's not working as I expected. In Drupal 6 I could do

$form['#redirect'] = "somewhere";

but after some gooogling I found out that this was removed in Drupal 7, so now I need to do:

$form_state['redirect'] =  "somewhere";

Unfortunately it did not work - after submitting the node form the node was displayed. I had the fallowing code in my module:

/**
* Implementation of hook_form_alter()
*/
function MY_MODULE_form_alter(&$form, &$form_state, $form_id)
{
    switch($form_id) {
        case 'bylos_node_form':
            $form['#submit'][] = '_MY_MODULE_custom_submit';
            break;
        default:
            break;
    }
}
/**
* Custom submit handler
*/
function _MY_MODULE_custom_submit($form, &$form_state) {
    $form_state['redirect'] = url('thank-you', array('absolute' => true));
}

As I found out that after my custom submit the node_form_submit() (line 404 in node.pages.inc) function is called and after the line

$form_state['redirect'] = 'node/' . $node->nid;

my custom redirect fails.
I could do simpe core hack by replacing the line above with:

if (!isset($form_state['redirect'])) {
        $form_state['redirect'] = 'node/' . $node->nid;
}

But whenever I hack the core, a kitten dies. :)
So, how can I do simple form redirect without hacking the core? :)

Comments

antwanvdm’s picture

Can't you just use a drupal_goto() even if it's an ugly solution, or is the saving process not finished yet?

Maybe you can also try to look at the new option to hook a form of a specific ID, no idea if it will help your problem but it's worth looking at. (Check it)

If it doesn't work you might consider adding this to the bugtracklist, it feels like a problem because you're hook gets overwriting by core...

jide’s picture

I'm having the same issue. Can't figure out how to redirect to a different path on node form submission. Using drupal_goto() in hook_node_insert() is hacky, but works in the meanwhile.

jide’s picture

Just figured out how to make redirect override work. Simply add :

$form_state['rebuild'] = TRUE;

In your submit handler.

ernestas’s picture

Thanks a lot ;)

mry4n’s picture

This should not be true in the case of D7, according to the API:

If $form_state['rebuild'] is TRUE, the form is being rebuilt, and no redirection is done.

liezie_d’s picture

thanks, this was my problem

natehill’s picture

and I'm new to the module development end of things so i'm lost.
any idea why this code won't work for me?

//Implementation of hook_form_alter()
function custommade_form_alter(&$form, &$form_state, $form_id)
{
    switch($form_id) {
        case 'comment_node_article_form':
            $form['#submit'][] = 'custommade_custom_submit';
    }
}

//Custom submit handler
function _custommade_custom_submit($form, &$form_state) {
	$form_state['rebuild'] = TRUE;
    $form_state['redirect'] = 'whatever';
}
ernestas’s picture

Hey ;)

The name of your function is wrong:

$form['#submit'][] = 'custommade_custom_submit'; // WITHOUT the underscore

and later:

function _custommade_custom_submit($form, &$form_state) // WITH the underscore

So, fix the name of the function to: custommade_custom_submit($form, &$form_state) and it should be all right :)

natehill’s picture

Thanks! Yeah that was an oversight. I've got this working, but in case anyone out there is tuned in, there's another little problem-

What I really want is to redirect right back to the same node the form is on- I'm trying to get this redirect going so that when a user submits a comment form they are directed back to the same url rather than that url/comment/reply or whatever it is.

Anyways, I can't seem to get the nid right. Here's the code. Thoughts?

<?php

//Implementation of hook_form_alter()
function custommade_form_alter(&$form, &$form_state, $form_id){
    //drupal_set_message($form_id);
    if($form_id == 'comment_node_article_form'){
            $form['actions']['submit']['#submit'][] = 'custommade_custom_submit';

    //Custom submit handler
function custommade_custom_submit($form, &$form_state) {
//here is the problem, $form_state['node']->nid doesn't seem to retrieve the nid
    $form_state['redirect'] = 'node/' . $form_state['node']->nid;
   
}
}
}
rantebi’s picture

@natehill here's an example code...
http://drupal.org/node/290462#comment-1035899
It worked for me.

zorroposada’s picture

I can confirm that the following code snippet worked for me in Drupal 7.14
Place this snippet in your custom module:

/**
 * Implements hook_form_FORM_ID_alter(&$form, &$form_state, $form_id)
 * mynodetype
 */
function mymodule_form_mynodetype_node_form_alter(&$form, &$form_state, $form_id) {
    $form['actions']['submit']['#submit'][] = 'mymodule_mynodetype_node_form_submit'; // custom callback name
}
// custom callback
function mymodule_mynodetype_node_form_submit($form, &$form_state) {
  $form_state['redirect'] = 'mycustompage';
}
ndf’s picture

For me too.
"$form['#submit'][] =" didn't work
"$form['actions']['submit']['#submit'][] =" did work.
At least for a node form.

alamp’s picture

removed since it was not accurate.
Instead, please take a look at: https://drupal.org/node/1975230

Collins405’s picture

Thanks!

/chris

jide’s picture

Forget my previous comment, using $form_state['rebuild'] is not the solution, node won't be saved this way...
After banging my head on the wall for hours, I realized that the submit handler should be set on the submit button and NOT on the form itself :

$form['actions']['submit']['#submit'][] = 'MY_CALLBACK';
borgo’s picture

I can confirm this works. In this example you can also see how to redirect user to edit the same node again.

function MYMODULE_form_alter(&$form, $form_state, $form_id) {
   //drupal_set_message($form_id);
   if ($form_id == "drinks_node_form") {
      $form['actions']['submit']['#submit'][] = 'MYMODULE_submit';
   }
}

function MYMODULE_submit ($form, &$form_state) {
   //code here
   $form_state['redirect'] = 'node/'. $form_state['nid']. '/items'; //REDIRECTS TO STEP 2 after submit
}
betz’s picture

it is.

Wappie08’s picture

Thanks for all comments, especially jide:

   $form['actions']['submit']['#submit'][] = 'MY_CALLBACK';

works well for normal forms!


One addition: for comment forms you can just use:

   $form['#submit'][] = 'MY_CALLBACK';
linulo’s picture

I, too, can confirm
$form['actions']['submit']['#submit'][] = 'MY_CALLBACK';
does work while the documented
$form['#submit'][] = 'MY_CALLBACK';
does not. I still don't get why. I added a watchdog call in my submit handler and it happily logged and overwrote $form_state['redirect'] but to no effect. I never got redirected while with the first solution I was. Is this intended behaviour? If not, what's the reason for this?

aerozeppelin’s picture

Thank you, it works for me.

ndmaque’s picture

confirmed roadkill, it worked for me
thanks team

ygerasimov’s picture

There is another trick to do this -- to use $form['#action'] and destination GET var:

<?php
// In your hook_form_alter
$form['#action'] .= '?destination=thank-you';
?>
amaisano’s picture

I was trying to redirect the 'user/%/edit' form -- which by default doesn't go anywhere after submitting, just reloads -- and using the custom redirect handler worked, but none of the form information was saved to the database.

So this method worked when the other did not, and seemed to be very 'lightweight.'

Thanks for the tip!

babusaheb.vikas’s picture

Form redirection in drupal 7 does not work like drupal 6 way. For security purpose $form['redirect'] is removed from drupal 7 to make it more secure.

in drupal 7 you can use it this way :--

in form_alter hook of your new module use this

$form['actions']['submit']['#submit'][] = 'overrided_submit_handler';

now put this code

function overrided_submit_handler($form, &$form_state)
{

$form_state['redirect'] = 'redirect path';
}

Vikas kumar

jamix’s picture

The $form['actions']['submit']['#submit'][] approach generally works. However, I've come across the strange behavior where the custom redirect is lost if the user clicks the "Add another item" for a multiple-value field on the node form and then submits it. The $form['#action'] solution suggested by ygerasimov doesn't fail in this case so that's what I ended up using.

guypark’s picture

It seems that $form['actions']['submit']['#submit'][] will work on normal forms, but not on the 'node' forms. Which I believe is the original question.

For some stupid unknown reason, node forms always seem to magically override my submits and will set it to just the 'node_form_submit' function. (very annoying)

Adding any other handlers for the node form either wipes the custom handlers, or hook_form_alter will only ever add the handlers BEFORE node's submit handler, which is where the 'redirect' happens.

If anyone knows how to get around this 'node' form issue (the right way), then please share, as I am wasting waaaaaaay to much time on a stupid node form.

tommcadam’s picture

I had the same problem on node forms. The second approach mentioned above works with node forms. Use:

$form['#action'] = '?destination=your_path';

selvamkf’s picture

Thanks, but the drupal_set_message() in submit handler is lost. After redirection I would expect the "Successfully saved" kind of message.

Update: I guess the form submission is not happening at all, http://drupal.org/node/330087#comment-1092257

mry4n’s picture

You do need to make a custom submit handler and put your redirect in there, but you don't want to completely override node_form_submit.

See this documentation page I just wrote for more details.

johnhanley’s picture

This is an old issue, but one that still stumps people from time to time.

Interestingly $form_state['redirect'] redirects correctly when defined as follows in hook_form_alter():

$form['#validate'] = array('custom_form_validate');

However the redirect fails when defined as:

$form['#submit'] = array('custom_form_submit');

The solution is indeed as follows:

$form['actions']['submit']['#submit'][] = 'custom_form_submit';
texas-bronius’s picture

Labas-
Another reason neither neither form_state['redirect'] nor drupal_goto worked in my case (just discovered) is because my form has to do with logging in a user, and part of the process invokes the hook_user_login (which happened to be implemented on this particular site by login_destination contrib module). What grief!

More: My custom form attempts to look up a user by other meta data or create a new user, and then logs in that user. After issuing user_login_finalize() (which in turn invokes hook_user_login) to make it all official, I couldn't do *anything* with redirecting like this. By the way, my drupal_set_message()s did still work.

My solution in this case was to either invoke hook_user_login like:

function mymodule_user_login(&$edit, $account) {
	dsm('logged in user ' . $account->uid);
	drupal_goto('user/' . $account->uid . '/edit');
}

or add an exception to the login_destination configuration to not act when on this custom module's route/path. I implemented the latter and excluded my subscription lookup form page's path.

--
http://drupaltees.com
80s themed Drupal T-Shirts

r0ber’s picture

This work for me!


// Ensure to set in the last position of $form['#submit'], array.
 array_push($form['#submit'], 'redirect_to_edit_profile');

// Custom submit handler redirect to profile
function redirect_to_edit_profile($form, &$form_state) {
   $form_state['redirect'] = 'profile-user/' .$form_state['profile2']->uid. '/edit';
}
nortmas’s picture

Take a look on the https://api.drupal.org/api/drupal/includes!form.inc/function/drupal_redi...

There are several exceptions to the "usual" behavior described above:

If $form_state['programmed'] is TRUE, the form submission was usually invoked via drupal_form_submit(), so any redirection would break the script that invoked drupal_form_submit() and no redirection is done.
If $form_state['rebuild'] is TRUE, the form is being rebuilt, and no redirection is done.
If $form_state['no_redirect'] is TRUE, redirection is disabled. This is set, for instance, by ajax_get_form() to prevent redirection in Ajax callbacks. $form_state['no_redirect'] should never be set or altered by form builder functions or form validation/submit handlers.
If $form_state['redirect'] is set to FALSE, redirection is disabled.
If none of the above conditions has prevented redirection, then the redirect is accomplished by calling drupal_goto(), passing in the value of $form_state['redirect'] if it is set, or the current path if it is not. drupal_goto() preferentially uses the value of $_GET['destination'] (the 'destination' URL query string) if it is present, so this will override any values set by $form_state['redirect']. Note that during installation, install_goto() is called in place of drupal_goto().

In my case there was a $_GET['destination'], which overrode my $form_state['redirect'].

juangalf’s picture

nortmas is right. I struggle a lot with my form alter because sometimes there was a destination parameter in the URL that was overriding my $form_state['redirect'].
The solution for me was to write directly on the $_GET variable in the HOOK_form_alter:

function mymodule_form_alter(&$form, &$form_state, $form_id){
  if ( $form_id == 'form-I-want-to-alter' ) {
    $_GET['destination'] = 'destination/url';
  }
}

This will always avoid the overriding. :-)
Thanks a lot nortmas.

quickdraw6907’s picture

From eck.entity.inc (version 7.x-2.0-rc6):

463: $uri = eck__entity__uri($entity);
464: $state['redirect'] = $uri['path'];

So, if you are relying on the default ECK form submit handler, you have three choices:

1) Roll your own submit handler
2) Implement hook_drupal_goto_alter()
3) Use $_GET['destination']

Note that on #2 you will only have access to the destination set by ECK to work with. In my case I had a component called schedule, so ECK overrode $form_state['redirect'] and set it to "component/schedule/xxx". This is most unfortunate. That meant I had to reload the entity just saved with entity_load_single() to get the parts and pieces I needed to rebuild my redirect URL.

I ended up doing #3.

skaught’s picture

i've re-run into this trick myself.. i believe the trick is in ensuring that through all your _form functions to be sure to keep ($form, &$form_state) in all 3 grouped form functions. And follow expected form function name pattern (Drupal auto-magic)

function thismodule_form(($form, &$form_state){
 $form = array();
//...... build form elements
return $form;
}

function thismodule_form_validate($form, &$form_state){
//...... do stuff to validate your form

}


function thismodule_form_submit($form, &$form_state){
//......  do stuff to submit your form

  drupal_set_message( t('The "!title" has been added', array('!title'=>$title)), 'status');
  $form_state['redirect'] = 'go-back/to/this-page';
}

the _alter method will work..but remembering to follow FAPI basics is the answer.

m.attar’s picture

You can use the $_GET['destination']:

function HOOK_form_alter(&$form, &$form_state, $form_id){
       $form['#submit'][] = 'submit_callback_redirect_form';
    }
 
 
function submit_callback_redirect_form($form, &$form_state){
    $_GET['destination'] = 'PAGE_REDIRECT';
}

johnhanley’s picture

I've found $form_state['redirect'] doesn't work in certain instances, but $_GET['destination'] always works without fail.

RAWDESK’s picture

This was the only solution working for me on a webform submit :

function hook_form_alter(&$form, &$form_state, $form_id) {
  global $theme;
  if(path_is_admin(current_path()) || $theme == variable_get('admin_theme', 'seven')) {
		$path = ltrim(parse_url($_SERVER['HTTP_REFERER'])['path'],'/');
		$form['#action'] .= '?destination='. $path;
		return;
	}
}

$form_state['redirect'] = $path; inside a custom form submit somehow lost the original HTTP_REFERER as seen in form_alter.

My use case was :
Return, after edit action from a webform submissions admin view row, back to the original view.

EvanCo’s picture

With an inherited codebase, I was unable to get redirects working with
$form_state['redirect'] on a very messy custom user_profile_form (WSOD crashes).

I ended up just appending a ?destination= query string to $form['#action']
ie. $form['#action'] .= '?destination=url/';

delta’s picture

$form_state['redirect'] work just fine.

If $_GET['destination'] is set, it must be a reason for that you have three option:

1) override the redirection:

unset($_GET['destination']);
$form_state['redirect'] = 'your/redirection';

2) Carry the destination to the page you redirect your form: 

$form_state['redirect'] = ['your/redirection', ['query' => drupal_get_destination()]];
unset($_GET['destination']);

3) set $form_state['redirect'] and if $_GET['destination'] is set it will be used instead of your redirection

slhemanthkumar’s picture

Thank you! It works like a charm!!! 

huntelaer’s picture

For me #redirect works in drupal 7:

function my_form_submit($form, &$form_state) {
  // User is redirected to some-url after form submit.
  $form_state['#redirect'] = 'some-url';
}