Altering Magento 2 functionalities and inserting your changes is a necessity. So, today, we will go over some basic altering methods – Observer, Plugin, and Preference/Rewrite in your module and in your theme where you can override .phtml, .css, .xml, and .js files.
Starting with the presumption that you know how to make a basic module in Magento 2, let’s begin with the first method for altering functionalities.
Observer
Firstly, we could use the Observer. It should be used when you want to execute code after an event has been triggered. In other words, you are injecting your logic inside a Magento code.
events.xml and Observer Class
For the Observer, all you need are events.xml and an Observer Class. Here, we will take the order_cancel_after event which triggers when you cancel and order.
Add the following piece of code to your events.xml file:
<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="order_cancel_after">
<observer instance="Vendor\ModuleName\Observer\Order\CancelAfter" name="vendor_modulename_observer_order_cancelafter_order_cancel_after"/>
</event>
</config>
You should add the following to Vendor\ModuleName\Observer\Order\CancelAfter.php:
<?php
namespace Vendor\ModuleName\Observer\Order;
/**
* Class CancelAfter
*
* @package Vendor\ModuleName\Observer\Order
*/
class CancelAfter implements \Magento\Framework\Event\ObserverInterface
{
/**
* Execute observer
*
* @param \Magento\Framework\Event\Observer $observer
* @return void
*/
public function execute(
\Magento\Framework\Event\Observer $observer
) {
//Your observer code
}
}
In the execute function you can write your own code that will be executed when the above-stated event triggers.
Plugin
The second method would be a Plugin. Plugins are used when you want to alter a Magento function by running some custom code before, after or around a Magento function.
di.xml and Plugin Class
For a Plugin to work you would need di.xml and a Plugin Class. As an example, we’ll take the getPrice() method from Magento\Catalog\Model\Product.php.
beforeGetPrice
First, we’ll go with ‘before’ type Plugin. In di.xml you need to add:
<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Catalog\Model\Product">
<plugin disabled="false" name="Vendor_ModuleName_Plugin_Magento_Catalog_Model_Product" sortOrder="10" type="Vendor\ModuleName\Plugin\Magento\Catalog\Model\Product"/>
</type>
</config>
In your Plugin class Vendor\ModuleName\Plugin\Magento\Catalog\Model\Product.php:
<?php
namespace Vendor\ModuleName\Plugin\Magento\Catalog\Model;
/**
* Class Product
*
* @package Vendor\ModuleName\Plugin\Magento\Catalog\Model
*/
class Product
{
public function beforeGetPrice(\Magento\Catalog\Model\Product $subject)
{
//Your plugin code
return [];
}
}
The code you put here will be executed before the getPrice() method, thus altering the input for this method.
afterGetPrice
Now let’s take a look at the ‘after’ plugin. Your code in the ‘after’ plugin will be executed after the original method. You should use it if you want to alter the output of the method. Everything is the same, except for the name of your function, it should look like this.
public function afterGetPrice(
\Magento\Catalog\Model\Product $subject,
$result
) {
//Your plugin code
return $result;
}
aroundGetPrice
And now, for the third option, ‘around’.
public function aroundGetPrice(
\Magento\Catalog\Model\Product $subject,
\Closure $proceed
) {
//Your plugin code
$result = $proceed();
return $result;
}
The around plugin should be used if you want to alter both the input and output of the original method. But, there is a Magento warning about ‘around’ plugins:
“Avoid using around method plugins when they are not required because they increase stack traces and affect performance. The only use case for around method plugins is when the execution of all further plugins and original methods need termination. Use after method plugins if you require arguments for replacing or altering function results.”
Preference/Rewrite
Thirdly, you can extend the original file by creating a preference, or so-called rewrite, in your module. Inside this file, you can change as many methods as you wish from the original file. This should be used only if you want to change the Magento method completely, take this approach only if your changes can’t be done with Observer or Plugin.
di.xml and Rewrite Class
For this, you’ll need di.xml and Rewrite Class. Inside di.xml add <preference> tag with ‘for’ where you state the file that you wish to rewrite and ‘type’ where you state your file that should be used instead.
<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Catalog\Model\Product" type="Vendor\ModuleName\Rewrite\Magento\Catalog\Model\Product"/>
</config>
And in Vendor\ModuleName\Rewrite\Magento\Catalog\Model\Product.php:
<?php
namespace Vendor\ModuleName\Rewrite\Magento\Catalog\Model;
/**
* Class Product
*
* @package Vendor\ModuleName\Rewrite\Magento\Catalog\Model
*/
class Product extends \Magento\Catalog\Model\Product
{
//methods you wish to override
}
Theme Files
Inside your theme, you can change frontend files like .phtml, .css, .xml and .js. For .phtml, .css, and .xml you can just place them in the same path as they are in the original folder. For example, if the file you want to override is vendor/magento/module-downloadable/view/frontend/templates/customer/products/list.phtml
All you need to do in your theme is to put it at this location:
Vendor/YourTheme/Magento_Downloadable/templates/customer/products/list.phtml
As you can see, the path is not exactly the same, here you convert module-downloadable to Magento_Downloadable, after that you ignore ‘view/frontend’ and start from the ‘templates’ folder. The same goes for .xml and .css files.
For .js files, you can do that as well. But, the preferred way, that will work both from the theme and from the module is to add it to requrejs-config.js. In your theme, this file should be in the theme root directory. And in your module, it should be in Vendor/ModuleName/view/frontend/requirejs-config.js.
Also, you need to add this piece of code to requirejs-config.js:
var config = {
map: {
'*': {
'Magento_Checkout/js/proceed-to-checkout': 'Vendor_ModuleName/js/your-js-file
}
}
};
That is if you want to override that file, but if you want to extend it, you should add this:
var config = {
"config": {
"mixins": {
"'Magento_Checkout/js/proceed-to-checkout'": {
'js/your-js-file:true
}
}
}
};
Wrap Up
All in all, these are some of the basic ways to alter/override/extend Magento’s core functionalities. Hopefully, you will further explore altering methods and find the most suitable ones. Of course, some of them might be the scope of our future articles.
Of course, if you need any help with M2 Development or M2 functionalities, contact us at [email protected].