Most of you are probably familiar with using the Form API (either via hook_form_alter or when building your own form) to set the destination a user is sent to after submitting a form.
<?php
function mymodule_form_alter($form_id, &$form) {
if ($form_id == 'page_node_form') {
$form['#redirect'] = 'my/new/page';
}
}
?>This usually works, but today I came across a special case.
What if you want to redirect users back to the referring page after they submit a new node? Sounds simple enough, right? You'd probably do something like this:
<?php
function mymodule_form_alter($form_id, &$form) {
if ($form_id == 'page_node_form') {
$form['#redirect'] = $_SERVER['HTTP_REFERER'];
}
}
?>Wrong! In fact, not only is it not working, but it's actually taking you back to the submission form rather than your original destination or the default behaviour of the newly created node. Odd.
And here's why: http://drupal.org/node/63730
In a nutshell, your form is effectively submitted twice during the process of the Form API doing it's thing. The first time your redirect is correct, but the second time the referer is actually the node submission form, and this over-writes your original, intended redirect path.
Let's think about this. We can't do this while we build or alter our form, but one of the last things that happens in the Form API process is the form's submit function, so why can't we hijack that in our module? Well, we could. But we need the function called node_form_submit to fire on submit in order to create our content and it contains the redirect to the newly created node, which we'll need to somehow override, since we're not using the Form API any more. To do this you effectively have to keep a re-written copy of at least one core function in your own module, which sucks! You've just created code you have to maintain to keep step with Drupal updates. =(
But there is an approach which will allow you to achieve your redirect to the referring page, without duplicating any core functions or creating anything nasty which you have to maintain. I documented it here:
http://drupal.org/node/134000#comment-799369
Basically, you store the referring URL (either in the session or in a custom CCK field in your content type) and use the 'insert' operation of hook_nodeapi to handle your message setting and redirection. Perfect!
Note, this is not necessary in Drupal 6.x - there is a new form history part of the API allowing you to pick out the prior redirect and use it. Much neater! =)

Some updates
Posted April 9th, 2008 by greg.harveyI've been chatting on IRC with Marek and, as ever, he had some other ideas I hadn't thought of, focussing on the destination parameter you can place in a querystring in Drupal.
If you don't mind the URL containing a querystring, you can use a link like this in your menu to redirect after form submission:
node/add/page?destination=my/destination/pathAlternatively, you could also probably achieve the same by messing with the '#action' field in the form, something like:
<?php$form['#action'] = $form['#action'] . '?destination=my/destination/path';
?>
I haven't attempted either yet, but both seem like reasonable solutions. =)
Destination
Posted May 17th, 2008 by AnonymousWhat about drupal_get_destination?
http://api.drupal.org/api/function/drupal_get_destination/5
Bad idea!
Posted July 3rd, 2008 by AnonymousBen just pointed out to me that the above solution (linked to in the blog post) is bad because it causes Drupal to bypass any subsequent node.module code - which includes the bit where node.module sets the access for the node. So if you interrupt node.module during your nodeapi code then it will never set nodeaccess settings. =(