Last updated July 22, 2010. Created by Steven Jones on April 5, 2007.
Edited by xenophyle, Jonah Ellison, traxer, jergason. Log in to edit this page.
If you create web sites based on Drupal you know that controlling forms, how they are themed, validated and processed, is a highly valued skill for any serious developer. This article will discuss a few ways to redirect your users to another page after they've submitted a form, overriding Drupal's defaults.
Drupal 5 provides developers with a Form API, a clever way to craft HTML forms using logical and extremely flexible arrays.
Drupal Form API also allows developers to theme every little detail of a form. For simpler cases using the #prefix and #suffix properties can be enough, but if you need extreme power, and sooner or later you will, then you can use forms-exclusive theme functions and drupal_render().
I'll explain the basics of Form API in a future article. If you can't wait I suggest taking a look at the Form API Quickstart Guide. For now let's focus on redirecting users after form submission in Drupal.
In the beginning was the form function
Every form in Drupal starts as a function that creates an array, usually named $form. Then the function's name is passed to drupal_get_form().
As with every function in a module, a form creation function should start with the name of the module, for example:
boogeeks_notify_form()
First, this assumes my module is named boogeeks, the first word in my function's name. I'm separating each word with an underscore and I suggest you do the same.
Second, I've chosen the verb notify to have a clear idea of what the form will do. I used something like this in a recent project for hacking a form where users opt-in to receive email alerts.
Third, I added form, helpful when you have many functions in your module and need a quick way to tell apart the ones creating forms.
Notice that the only requirement for naming your form function is the first one, starting with your module name, the other two are my suggestions for cleaner and easier to understand code.
Theme, validate and submit
Now that we have boogeeks_notify_form() taking charge of form creation we need a few additional functions, all of them named based on the original.
- theme_boogeeks_notify_form(): Will take care of the looks of your form, this is the theming function.
- boogeeks_notify_form_validate(): Will check if user entered information that validates according to rules established here.
- boogeeks_notify_form_submit(): Will process the form and redirect the user to other page.
For this article's purposes we are interested in the third function, the one ending in _submit.
Where to go now?
Every form submission function, boogeeks_notify_form_submit() in our example, needs to return a value. This value is the url where the user will go after successfully submitting a form.
So, if you want to thank your user after opting in to receive email alerts then you can finish boogeeks_notify_form_submit() with something like:
return 'thankyou-for-subscribing';
That's the url of some page with the usual thank-you-we-love-you-dear-visitor stuff. You can also return an array. In that case, the values are passed as arguments to drupal_goto(). This way you can also set the query, the fragment and HTTP response of your redirect.
All Drupal provided forms have pre-defined values in their submit functions. Two well known and often used ones are user_login() and user_register(), used to create new accounts. Both are created in user.module.
How to override default form redirection in Drupal
There are two ways to override default form redirection: with a destination parameter in a url, and using the #redirect property of Forms API (I know this could be obvious to hardcore Drupal developers but it's still useful for new-comers). After some testing I determined the redirection processing flow is as follows:
- The url returned from the form submit function,
- which is overriden by #redirect,
- which is overriden by destination passed in the url.
You'll need to modify a form using hook_form_alter() to use #redirect.
If you want to work with destination you'll have to include it in the url used to call the page showing your form.
Now you can take your users whenever you want after submitting a form, no matter if it's a Drupal provided form or one that you've coded.
In Drupal 6, one method is:
Create a custom module custom.module and place this code in it:
function custom_form_alter(&$form, $form_state, $form_id) {
switch ($form_id) {
case 'contact_mail_page':
$form['#redirect'] = 'thank-you-page';
break;
}
}Create a file custom.info and place this code in it:
; $Id: custom.info,v 1.0 2009/01/01 21:55:00 author Exp $
name = Custom
description = Custom module
package = Other
core = 6.x
version = "6.x"
project = "custom"
datestamp = "1229018427"Then place custom.module and custom.info in a folder 'custom' and upload it to /sites/all/modules/. Enable the module in Administer > Modules > check 'Custom'.
Create the 'thank-you-page' page and voila! If you want your thank you page to be node/22, then change $form['#redirect'] = 'thank-you-page'; to $form['#redirect'] = 'node/22';.
As with Drupal 5, you can append a query and a fragment and set the HTTP response of your redirect by using an array as the destination of the redirect:
$form['#redirect'] = array('user/login', 'destination=node');
Comments
To be precise
Not so. You have the option of not returning anything, in which case your form will redirect to itself. It is still a redirection, though, so any unsaved data will be lost. The form behaves as though it's a fresh load. This could be useful for forms that are intended for multiple submissions; polite developers will use drupal_set_message() in their submission function to let their users know the form has processed successfully (or not).
It's also worth mentioning that your submission function can return false, in which case the form will not redirect after submission, though this is not nearly as useful as you may think unless used in conjunction with the #multistep property (q.v.).
Finally developers should be aware that the #redirect form property can be declared directly on the $form array, if you're really certain you know where you're going to redirect your users and no post-processing is required. It's marginally more convenient than declaring a _submit that just returns false.
--Andy
Developing Drupal websites for Livelink New Media
In D6 returning the
In D6 returning the destination in the submit function doesn't do it - it should be put in the the $form_state[redirect] eg
$form_state['redirect'] = 'node/'. $node->nid;see:
http://api.drupal.org/api/function/node_form_submit
http://zero-dev.co.uk
This may not work if
This may not work if you are using the login block (I say login Block, not login Page (sitename.com/user will work ). Neither using drupal_goto() on hook_user $op='login' is going to work. see http://drupal.org/node/580144#comment-3368072 for a solution. It help me alot
See a < href="http://www.xhelos.com" >Xhelos - Battle Organisms.A Drupal Based RTS Game. Its in early Alpha stage but is testeable, now in english!
Works great for me - thank you!
Works great for me - thank you!
Need more control over redirect destination
$form['#redirect'] = 'this has to be a path'What I am trying to do is send users to the OG Invite page, specific to their group, after submission of an OG group node. As a destination path I need og/invite/$gid where $gid is the group id of the og node just submitted.
I already have a custom module and tried
function node_type_form_submit()but it didn't work because I was already using hook_form_alter() for that same node type ... or something like that. Yeah, did I mention I'm not exactly a php wizard?
Is there a way to get where I want to go with the Form API, or is this more of an OG question?
Thanks.
Tricky
This is tricky, because neither ?destionation or #redirect answer this question because you need to get at a node-id that's being created. You don't know your destination on the way in, and you need to change it on the way out. In Drupal 6, this is pretty easy, but in Drupal 5 it requires a little work.
In Drupal 6, you can add an additional submit handler and use the node data in $form_state to alter $form_state['#redirect'].
In Drupal 5 you need to do is specify your own form_submit handler, and wrap a little tiny function around the existing node_form_submit:
http://api.drupal.org/api/function/node_form_submit/5
As you can see, the positive result of that function is to return 'node/'. $node->nid; This places the user on the node that was just created. What you want to do is create your own submit handler like so:
$form['#submit'] = array('my_form_submit' => array());
Note, this is a bit different than adding a submit hander, because you don't want the normal node_form_submit to fire. You want to own the whole process and call it yourself, like so:
<?php
function my_form_submit($form_id, $form_values) {
$node_url = node_form_submit($form_id, $form_values); // do the normal submitting
$url_pieces = split('/', $node_url); // split a url like node/55 into an array.
if ($url_pieces[0] != 'node') {
// the [0] element is first, so should be node; if not, there's an error so just return whatever it was for fallback purposes.
return $node_url;
}
// most likely that didn't happen though, so let's set a message and move on.
drupal_set_message("Your group has been created. Now invite your friends!"); // give the user context.
return 'og/invite/'. $url_pieces[1]; // [1] is the second element ofthe split array, so that should be 55.
}
What will happen now is zachs_awesome_form_submit() will get called when the form passes validation. Since you completely overrode the #submit value, you don't double-call node_form_submit, but rather call it once, get the normal return value, and then send back your modified result url.
------
Personal: Outlandish Josh
Professional: Pantheon
Correction
In Drupal 6, its not $form_state['#redirect'], its just $form_state['redirect']
I am using $form['#redirect']
I am using $form['#redirect']
http://www.geoffgolder.com/
http://www.911insidejobshirt.com/
Multi step forms in D6
Something I just encountered, when working with a multi-step form, if you have anything in $form_state['storage']['values'], the form will not redirect. I did a unset($form_state['storage']['values']) in the last step of my form to get it to redirect.
http://musketeers.me/ Creating next-generation websites with precision and care.
http://BytesInTheMargin.com/ Blog
Because of checks in drupal_process_form
You need to emtpy the entire $form_state['storage'].
It is because of the following in "form.inc" line 440:450 (function drupal_process_form)
// If no submit handlers have populated the $form_state['storage']
// bundle, and the $form_state['rebuild'] flag has not been set,
// we're finished and should redirect to a new destination page
// if one has been set (and a fresh, unpopulated copy of the form
// if one hasn't). If the form was called by drupal_execute(),
// however, we'll skip this and let the calling function examine
// the resulting $form_state bundle itself.
if (!$form['#programmed'] && empty($form_state['rebuild']) && empty($form_state['storage'])) {
drupal_redirect_form($form, $form_state['redirect']);
}
Hiking up the Drupal learning developer curve
That was useful! Thanks.
That was useful! Thanks. I just couldn't figure out why I am redirected to the form after the final submit (of a multistep form), but emptying $form_state['storage'] solved the problem!
Thanks a lot!
Thank you so much. Was wracking my brain trying to figure out why my multi-page form would not correctly process the Cancel submit after it had gone to page 2 or beyond.
Makes tons of sense now and you saved me time and from using an ugly solution (drupal_goto).
Does not work is any of your
Does not work is any of your module files have white space at the top! I think this is because white spaces causes output, which prevents the redirect. Wasted 30 minutes fixing this, so making a note here in case I forget.
My drupal sites:
http://www.financialcharting.com
http://www.pokersoftwareanalysis.com
http://www.borhon.com
http://www.newbornbabyclothes101.com/
My cheapskate site:
http://www.cheapskatemate.com
Hey chaps, I've made this
Hey chaps, I've made this into a module, that lets you specify the destination address on a per content type basis. I'm surprised this hasn't already been done before.
Check out: node_destination
Cheers.
Blog: akb.id.au | Twitter: @alexbergin
Depreciated in Drupal 7
The '#redirect' property has been depreciated for D7, in favor of $form_state['redirect'].
SEE http://drupal.org/node/224333#fapi_changes
redirect to site outside drupal
the form api cleans up the url to prevent user from changing destination to some offsite location, but if you want the form to go to another site (in my case a moodle site that's on the same server) how do you do that? is there some place put the url in the form function or the submit function where the hackers cant get to it?
~~~~~(\_~~~~~
'external'
The $form_state is completely secure from hackers (it never leaves the server, apart from $form_state['values'] which is populated from the form submission), so there shouldn't be any risk in setting $form_state['redirect'].
$form_state['redirect'] takes the same values as drupal_goto(), which itself uses url() to generate its destination path. It should be possible to add an array of options including 'external=TRUE' to your redirect value.
<?php$form_state['redirect'] = array('http://www.example.com/my-external-path', array('external' => TRUE));
?>
That said - the url() docs do say that "If you provide a full URL, it will be considered an external URL." So I'm not completely sure why it would be cleaning up that URL. In what was was it being cleaned?
--Andy
Developing Drupal websites for Livelink New Media
D6
Whoops, all of that advice was for Drupal 7, I missed that this was a D6 post. D6's $form['#redirect'] behaves slightly differently - mainly because drupal_goto() doesn't take the $options array - but still, it ends up in url(), which again, should preserve external links.
--Andy
Developing Drupal websites for Livelink New Media