How to Override / Rewrite Classes in Magento 1

Magento is one of the most powerful eCommerce platforms on the market. With it’s well-designed, open-source codebase, and modular structure, new features in Magento can be added by creating custom modules, thus providing unlimited possibilities to customize an online store. According to Ben Marks, on my personal autograph from him, editing Magento’s core code is […]

By Ledian Hymetllari

Magento is one of the most powerful eCommerce platforms on the market. With it’s well-designed, open-source codebase, and modular structure, new features in Magento can be added by creating custom modules, thus providing unlimited possibilities to customize an online store.

According to Ben Marks, on my personal autograph from him, editing Magento’s core code is a bad development practice “Keep that core clean”. Instead, Magento’s functionality can be modified by rewriting its classes. Changes to the core code without the rewrite class method can cause unexpected results, and these changes will be overwritten when Magento is upgraded or when a patch is applied. On the merchant’s side, this bad development practice results in thousands of dollars wasted in bad code, and a non-upgradable and a non-patchable website where the code has to be rewritten again from the beginning. To avoid this problem a developer must use the correct method, which is to override Magento classes using inheritance as defined by Magento’s object-oriented programming model (OOP).

Many agencies offer Magento website development, but for your Magento website to be successful and stable in the long run, it is important to select a company that has Magento certified developers who follow best practices. A certified developer has been trained to create custom Magento functionality correctly, without compromising the platform’s stability or security.

Here is a simple demonstration of how Magento classes can be rewritten. Included in this demonstration are the following classes:

  • Models
  • Blocks
  • Helpers
  • Controllers
  • Observers

We are naming our module Customermodule since we are doing our rewrites from the Customer module.

Rewriting Magento Models:

Let’s start overriding a Model class first. We have chosen Customer.php template and the method we will use to change the behavior is getName();

PATH: app/code/core/Mage/Customer/Model/Customer.php

First, we need to register our module. To register a module, create a new .xml file under app/etc/modules with name Packagename_Modulename.xml.

In our case we are going to name it Shero_Customermodule.xml with this content:



<!--
/**
* @author Sherodesigns Team
* @copyright Copyright (c) 2017 sherodesigns (https://sherocommerce.com/)
* @package Shero_Customermodule
* @Date MM/DD/YYYY
*/
-->

<config>
   <modules>
       <Shero_Customermodule> <!--This is the Packagename_modulename -->
           <active>true</active> <!--Set module as enabled/disabled true | false -->
           <codePool>local</codePool> <!--This tells Magento the codepool that your module is placed -->
           <edition>community</edition> <!--This tells Magento edition community | enterprise -->
       </Shero_Customermodule>
   </modules>
</config>

Clear the Magento cache, then navigate to Admin -> System -> Configuration -> Advanced-Advanced. There you will see that your module is enabled. If your module is not under this path, check to see if you have any errors under the app/etc/modules/package_module.xml file.

Magento Modules

This is how the file structure of our module will look:

Config.xml is the file where all our configurations for our module will be. Magento is different from other platforms; it is a configuration-based platform, meaning that we need to configure our models, blocks, helpers and observers in order to use them.

This is the content for config.xml:



<?xml version="1.0"?>
<!--
/**
* @author Sherodesigns Team
* @copyright Copyright (c) 2017 sherodesigns (https://sherocommerce.com/)
* @package Shero_Customermodule
* @Date MM/DD/YYYY
*/
-->
<config>
   <modules>
       <Shero_Customermodule> <!--This is the Packagename_modulename -->
           <version>1.0.0</version> <!--Module version that is saved on core_resource table-->
       </Shero_Customermodule>
   </modules>

   <global>
       <models>
           <!--Declaring our model path -->
           <customermodule>
               <class>Shero_Customermodule_Model</class>
           </customermodule>

           <!--Rewriting model-->
           <!--This is the tag that customer is using when declaring models in customer/etc/config.xml. This is the first parameter of Mage::getModel('customer/') method -->
           <customer>
               <rewrite> <!--Shows that we are rewriting a Model -->
                   <!--Customer here is the second parameter of Mage::getModel(' /customer') method. This is the class after Model folder -->
                   <customer>Shero_Customermodule_Model_Customer</customer>
               </rewrite>
           </customer>
       </models>
   </global>
</config>

Now the content for Customer.php template that we have overridden, placed under Shero/Customermodule/Model/Customer.php. We are using the same path structure of folders and files as Magento is using by convention, but if you want to add different path, you are free to do so. Just be sure to add the same path when declaring the class. For example, if you are adding your path as Shero/Customermodule/Model/Test/Customer, then the class should be the same:
class Shero_Customermodule_Model_Test_Customer




/**
* @author Sherodesigns Team
* @copyright Copyright (c) 2017 sherodesigns (https://sherocommerce.com/)
* @package Shero_Customermodule
* @Date MM/DD/YYYY
* @extends Mage_Customer_Model_Customer
*/

class Shero_Customermodule_Model_Customer extends Mage_Customer_Model_Customer
{
   /**
    * This is an overriden method from Mage_Customer_Model_Customer class.
    * This override is just for tutorial purposes
    * @return mixed
    */
   public function getName()
   {
       return "Sherodesigns";
   }
}

This is how it will look when you login in the frontend customer account. In the right top we see “SHERODESIGNS” instead of the customer account. Everywhere on the code that getName() function is executed, “Sherodesigns” will show instead of the user name.

TRICK: To check if the specific model class is overridden, you can create simple test.php file in the root of your Magento site and paste this code.



include "app/Mage.php";
Mage::app();


$customerModel = Mage::getModel('customer/customer');
var_dump(get_class($customerModel));

If you execute that test.php using $ php test.php in terminal or by opening www.your-magent-url/test.php in your browser, you will see string(35) "Shero_Customermodule_Model_Customer" instead of string(28) "Mage_Customer_Model_Customer". This means that the code rewrite was made successfully.

Rewriting Magento Blocks Classes

We rewrite blocks classes the same way we did for models. We are going to rewrite a method from app/code/core/Mage/Customer/Block/Form/Register.php

We are using the same module we created above, and we are going to add these files under config.xml to our module:



<blocks>
   <customermodule>
       <!-- This is our Block path-->
       <class>Shero_Customermodule_Block</class>
   </customermodule>

   <customer>
       <rewrite>
           <!--This is the Account folder and Dashboard.php class after Block directory from customer module -->
           <form_register>Shero_Customermodule_Block_Form_Register</form_register>
       </rewrite>
   </customer>
</blocks>

And the config file will look like this:



<?xml version="1.0"?>
<!--
/**
* @author Sherodesigns Team
* @copyright Copyright (c) 2017 sherodesigns (https://sherocommerce.com/)
* @package Shero_Customername
* @Date MM/DD/YYYY
*/
-->
<config>
   <modules>
       <Shero_Customermodule> <!--This is the Packagename_modulename -->
           <version>1.0.0</version> <!--Module version that is saved on core_resource table-->
       </Shero_Customermodule>
   </modules>

   <global>
       <models>
           <!--Declaring our model path -->
           <customermodule>
               <class>Shero_Customermodule_Model</class>
           </customermodule>

           <!--Rewriting model-->
           <!--This is the tag that customer is using when declaring models in customer/etc/config.xml. This is the first parameter of Mage::getModel('customer/') method -->
           <customer>
               <rewrite> <!--Shows that we are rewriting a Model -->
                   <!--Customer here is the second parameter of Mage::getModel(' /customer') method. This is the class after Model folder -->
                   <customer>Shero_Customermodule_Model_Customer</customer>
               </rewrite>
           </customer>
       </models>

       <blocks>
           <customermodule>
               <!-- This is our Block path-->
               <class>Shero_Customermodule_Block</class>
           </customermodule>

           <customer>
               <rewrite>
                   <!--This is Form folder and Register.php class after Block directory from customer module -->
                   <form_register>Shero_Customermodule_Block_Form_Register</form_register>
               </rewrite>
           </customer>
       </blocks>
   </global>
</config>

Under Customermodule/Block/Form/Register.php we will have this content:



/**
* @author Sherodesigns | Ledian <[email protected]>
* @copyright Copyright (c) 2017 sherodesigns (https://sherocommerce.com/)
* @package Shero_Customermodule
* @Date MM/DD/YYYY
* @extends Mage_Customer_Block_Form_Register
*/

class Shero_Customermodule_Block_Form_Register extends Mage_Customer_Block_Form_Register
{
   //here will be the method you want to override
}


TRICK: To check if the specific block class is overridden, you can create simple test.php file in the root of your Magento site using the method described above.




include "app/Mage.php";
Mage::app();


$customerBlock = Mage::getModel('customer/form_register');
var_dump(get_class($customerBlock));

The test file should output string(35) "Shero_Customermodule_Block_Form_Register" instead of string(28) "Mage_Customer_Block_Form_Register". This means that the code rewrite was done successfully.

Rewriting Magento Helper Classes

Rewriting Helpers is the same as rewriting blocks and models. This is how the configuration for helpers will look:



<helpers>
   <customermodule>
       <!--Declaring our helper classes -->
       <class>Shero_Customermodule_Helper</class>
   </customermodule>
   <customer>
       <!--This is the rewrite helper class.  -->
       <rewrite>
           <address>Shero_Customermodule_Helper_Address</address> <!--this tag <address> is the class after Helper folder -->
       </rewrite>
   </customer>
</helpers>

And the content for app/code/local/Shero/Customermodule/Helper/Address.php will be:



/**
* @author Sherodesigns | Ledian <[email protected]>
* @copyright Copyright (c) 2017 sherodesigns (https://sherocommerce.com/)
* @package Shero_Customermodule
* @Date MM/DD/YYYY
* @extends Mage_Customer_Helper_Address
*/


class Shero_Customermodule_Helper_Address extends Mage_Customer_Helper_Address
{
    // here will be the method you want to override
}

To check your work, you can create simple test.php file in the root of your Magento site and paste this code:




include "app/Mage.php";
Mage::app();


$customerHelper = Mage::helper('customer/address);
var_dump(get_class($customerHelper));

The output of test.php should read string(35) "Shero_Customermodule_Helper_Address"
instead of string(28) "Mage_Customer_Helper_Address". This means that the code rewrite was made successfully.

Rewriting a Magento Controller

Rewriting controllers is a little bit different from the above classes. Let’s use an example of overriding the AccountController class. Basically we are looking to our module first, then going to the customer module
This is the code under config.xml:



<frontend> <!--This is for frontend routers -->
   <routers>
       <customer>
           <args>
               <modules>
                   <!-- Before going to Customer controller we are going to our module first-->
                   <shero_customermodule before="Mage_Customer">Shero_Customermodule</shero_customermodule>
               </modules>
           </args>
       </customer>
   </routers>
</frontend>

And our class content will look like this:




/**
* @author Sherodesigns Team
* @copyright Copyright (c) 2017 sherodesigns (https://sherocommerce.com/)
* @package Shero_Customermodule
* @Date MM/DD/YYYY
* @extends Mage_Customer_AccountController
*/

//require_once(Mage::getModuleDir('controllers','Mage_Customer').DS. 'AccountController.php');

require_once "Mage/Customer/controllers/AccountController.php";
class Shero_Customermodule_AccountController extends Mage_Customer_AccountController
{
   //here you can override the method you want
}

To debug the controller rewrite see this link:
https://gist.github.com/grafikchaos/6685d51064b4b1da68b4

Rewriting Magento Observer Classes

Rewriting Observers is sometimes necessary when you have conflicts between extensions or if you want to change the behavior of observers. As an example, we will override an event from Magento. It looks a little bit hard rewriting observers, but it is not as hard as it looks. Follow the steps below.

This is the class we are rewriting: sales_quote_save_after
First we need to write a dependency in our module configuration under app/etc/modules/Shero_Customermodule.xml:



<?xml version="1.0"?>
<!--
/**
* @author Sherodesigns Team
* @copyright Copyright (c) 2017 sherodesigns (https://sherocommerce.com/)
* @package Shero_Customername
* @Date MM/DD/YYYY
*/
-->
<config>
   <modules>
       <Shero_Customermodule> <!--This is the Packagename_modulename -->
           <active>true</active> <!--Set module as enabled/disabled true | false -->
           <codePool>local</codePool> <!--This tells Magento the codepool that your module is placed -->
           <edition>community</edition> <!--This tells Magento edition community | enterprise -->
           <!-- We are doing dependency from Mage_Checkout module when overriding observers-->
           <depends>
               <Mage_Checkout />
           </depends>
       </Shero_Customermodule>
   </modules>
</config>

After that, in config.xml we are setting this configuration to disable set_checkout_quote_id observer and use our observer instead:



<!--Overriding Magento Observers -->

<frontend>
   <events>
       <sales_quote_save_after>
           <observers>
               <!--Ware disabling the other observer  -->
               <set_checkout_quote_id>
                   <type>disabled</type>
               </set_checkout_quote_id>
               <shero_customermodule_event>
                   <type>singleton</type>
                   <class>customermodule/observer</class>
                   <method>salesQuoteSaveAfter</method>
               </shero_customermodule_event>
           </observers>
       </sales_quote_save_after>
   </events>
</frontend>

Next we are going to add this code under the models section, so we are rewriting their observer as our normal Model.



   <!--Rewriting observer app/code/core/Mage/Checkout/Model/Observer.php as a normal model class -->
   <checkout>
       <rewrite>
           <observer>Shero_Customermodule_Model_Observer</observer>
       </rewrite>
   </checkout>
</models>

And finally the Observer.php class on our module will look like this:




/**
* @author Sherodesigns | Ledian <[email protected]
* @copyright Copyright (c) 2016 sherodesigns (https://sherocommerce.com/)
* @package Shero_Customermodule
* @Date 12/22/2016
* @extends Mage_Core_Customer_Model_Customer
*/

class Shero_Customermodule_Model_Observer extends Mage_Checkout_Model_Observer
{
   public function salesQuoteSaveAfter($observer)
   {
       die("work");
       $quote = $observer->getEvent()->getQuote();
       /* @var $quote Mage_Sales_Model_Quote */
       if ($quote->getIsCheckoutCart()) {
           Mage::getSingleton('checkout/session')->getQuoteId($quote->getId());
       }
   }
}

We are adding a die() function on salesQuoteSaveAfter method just to see if it works.
So at the time this observer is executed, you will see that “work” is visible in your page.

You can get the complete module from Github.

Conclusion

To summarize, following these simple steps, you can override a method from the Magento core without changing the core files themselves:

  1. Create module folders
  2. Enable the module in XML files
  3. Configure the rewrite in the config.xml of your module, then specify the class that you want to rewrite.

As with anything else, practice makes perfect! Keep testing these steps, and leave a comment below if you have any questions.

Back End Developer