Redirecting Users After Submitting a Form in Drupal 5 and 6

Last modified: June 19, 2009 - 15:20

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 Forms API, a clever way to craft HTML forms using logical and extremely flexible arrays.

Drupal Forms 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 Forms API in a future article. If you can't wait I suggest taking a look at the Forms 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 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.

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';.

To be precise

kingandy - November 19, 2008 - 14:49

Every form submission function, boogeeks_notify_form_submit() in our example, needs to return a value

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

Works great for me - thank you!

Aminto - April 16, 2009 - 14:05

Works great for me - thank you!

Need more control over redirect destination

zchandler - May 5, 2009 - 18:45

$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

joshk - May 5, 2009 - 21:11

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.

Correction

slashwalk - May 21, 2009 - 02:15

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 6, its not $form_state['#redirect'], its just $form_state['redirect']

Multi step forms in D6

omerida - May 12, 2009 - 16:06

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.

 
 

Drupal is a registered trademark of Dries Buytaert.