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.


4 Answers 4


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? Commented Aug 1, 2017 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' :) Commented Aug 1, 2017 at 16:57
  • will do. I have a solution but it might be interesting for other visitors too :-) Commented Aug 2, 2017 at 7:25
  • Here is my new question: civicrm.stackexchange.com/questions/19743/… Commented Aug 2, 2017 at 7:57

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?

  • when you say "in a page", where do you mean, specifically? I've added a call to pushUserContext in buildQuickForm but it doesn't seem to have any effect. Commented Feb 7, 2017 at 19:11
  • In most cases I have a list of items on a page, which then leads to an action on a form? Strange that the pushUserContext has no effect.... Commented Feb 8, 2017 at 7:24
  • hey @erik. so in your code, a redirect, or similar, must be happening somewhere (in core, I presume) but I don't know where. Do you? Knowing where that happens might help me debug why it isn't happening in my case. Commented Feb 8, 2017 at 12:38
  • I do not know either, I would expect that at some point in the CRM_Core_Form it would revert back to the user context? Commented Feb 8, 2017 at 12:40

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 ;) Commented Feb 2, 2017 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... Commented Feb 2, 2017 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'. Commented Mar 31, 2017 at 8:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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