I often find myself writing calls to CRM_Utils_Redirect in my postProcess methods.

But in core code I don't see this. I see the use of methods like $session->replaceUserContext and postProcess functions that end seemingly without telling me where to go next.

I feel like CiviCRM is often clever enough to go to load different pages on form submission based on where you came from. I have no solid proof of that but lets give Civi the benefit of the doubt on that one :)

I'm guessing there is a structure somewhere that is telling CiviCRM what page to load next but I have failed to spot what that is.

I'm interested in the canonical way that CiviCRM does this (if there is a canoncial way) and knowing how legacy that is, and also what I should be doing.

If anyone could enlighten me, I'd be grateful :)

PS. I am not so interested in "you should write that in angular" enlightenment, at least not in the answer to this question.


Here is what I do in a page:

$session = CRM_Core_Session::singleton();
$session->pushUserContext(CRM_Utils_System::url('civicrm/pumexpenseclaims/page/claimlevel', 'reset=1', true));

Then in the form I do nothing in the postProcess. The only thing I take into consideration is when I press something like delete on the page where I take an action but do not need a form. If that is the case I tend to do this:

$session = CRM_Core_Session::singleton();

Mind you, it could well be that this pattern no longer works in 4.7? What are the issues you run in to?


Use the built in button types and corresponding CRM_Core_QuickForm_Action_* classes that are invoked when those buttons are clicked.

For example, clicking on a button created with

    'type' => 'submit',
    'name' => ts('Submit'),
    'isDefault' => TRUE,

Will call CRM_Core_QuickForm_Action_Submit->perform() which redirects you to the value of $form->controller->_destination (and if $form->controller->_destination is not set, will display the form again).

So in the simplest case, you can just add a line along the lines of the following to your form:

$this->controller->_destination = CRM_Utils_System::url('civicrm/something', 'reset=1');

Probably the best way to understand the other actions is to have a look at the perform() methods in the CRM_Core_QuickForm_Action_Submit_* classes.

GinkgoFJG's answer (and possibly Erik's) works when the button type is 'done', which makes sense when you have a look at the comments the inline code documentation for CRM_Core_QuickForm_Action_Done->perform().

// Processes the request.
// [...] validate the page
// and if success, call post process
// when done processing pop to user context
  • Michael, you did quite some investigation...but is not totally clear to me. So what do I do if I want to 'interrupt' the form processing and end it what do I do exactly? Aug 1 '17 at 15:24
  • @ErikH-CiviCooP - hmm, would you like to flesh out some details - maybe as a new question? - and I'll do my best to answer as I think that the answer probably depends on what exactly you mean by 'interrupt' and 'end' :) Aug 1 '17 at 16:57
  • will do. I have a solution but it might be interesting for other visitors too :-) Aug 2 '17 at 7:25
  • Here is my new question: civicrm.stackexchange.com/questions/19743/… Aug 2 '17 at 7:57

I tend to set the userContext in my page, which will then make my form return to where I wanted it. Does that make sense?

  • I did try doing that, but didn't get it working - do you want to expand on your answer with an example? stackexchange will reward your quality answer handsomely, I am sure ;) Feb 2 '17 at 10:49
  • 1
    If you could also explain if there is anything to take into account when the page is loaded via a pop up vs normally, many riches will flow your way... Feb 2 '17 at 10:53

Here's how Volunteer does it:

  • This didn't work for me initially. I dug around in a few of the relevant classes CRM_Core_Controller, HTML_QuickForm_Controller, CRM_Core_QuickForm_Action and CRM_Core_QuickForm_Action_*` * including *=Submit and *=Done and found that this approach works when the type of the submit button is 'done'. Mar 31 '17 at 8:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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