Magento 1 – How to Override Core Controller Class

controllersmagento-1moduleoverrides

Note: This is intended as a canonical question that fully explains how controller rewrites work and can be used as duplicate target for more
specific "How do I override controller X" or "Why does my rewrite not work"
questions.

See also: Looking for canonical questions about Magento 1 overrides

Let's say, I have to make changes to a core controller class in a custom module (change methods or add methods). How do I do this, step by step?

Best Answer

There are multiple approaches but I'll start with how it's not done to clarify some common misconceptions:

  1. It's not possible to override controller classes by copying them to app/code/local. This is because controller classes are not loaded by Varien_Autoload, instead the files are explicitly included.
  2. It's not recommended to use <rewrite><controller><to> syntax anymore. This is an old technique which is obsolete since Magento 1.3 (see: Overwriting controller vs overwriting action controller request)

Add/override controller actions

To add controller actions to an existing controller, use the following in your config.xml:

<frontend>             <--- area (adminhtml or frontend)
    <routers>
        <checkout>     <--- front name (in admin always "adminhtml")
            <args>
                <modules>
                    <stack_checkout before="Mage_Checkout">Stack_Checkout</stack_checkout>
                                                  ^                ^
                                                  |                |
                                           module to override      |
                </modules>                 (in admin always        |
            </args>                        "Mage_Adminhtml")   your module
        </checkout>
    </routers>
</frontend>

Then create a controller in your module such as

class Stack_Checkout_OnepageController extends Mage_Core_Controller_Front_Action
{
    public function indexAction()
    {
        // here you override checkout/onepage/index
    }
    public function helloAction()
    {
        // here you create a new action checkout/onepage/hello
    }
}

You don't need to extend the original controller class because Magento will look in both classes, in the order defined by before="..."

If you need to extend the original class because you want to reuse other methods from it, you have to include it (remember, controllers are not autoloaded):

require_once(Mage::getModuleDir('controllers','Mage_Checkout') . DS . 'OnepageController.php');

Use observers to modify controller actions

If you don't add new actions, an alternative is to use observers to modify the behavior of existing actions. Every controller action triggers a dynamic "predispatch" event in the form controller_action_predispatch_$FRONTNAME_$CONTROLLER_$ACTION, for example controller_action_predispatch_checkout_onepage_index

In the observer you have access to the controller class itself using

$controller = $observer->getControllerAction();

If you don't want the original method to be triggered, tell Magento to not further dispatch the action:

$controller->setFlag('', Mage_Core_Controller_Front_Action::FLAG_NO_DISPATCH, true);

For the sake of completeness: You can also prevent "postdispatch" events in a similar way, but this is usually not necessary (here is an example where it's useful: XML has extra content):

$controller->setFlag('', Mage_Core_Controller_Front_Action::FLAG_NO_POST_DISPATCH);

Speaking of which, you can also add an observer for controller_action_postdispatch_$FRONTNAME_$CONTROLLER_$ACTION if you want to perform additional actions or modifications of the response after the original action has been executed.