HOW AND WHEN TO USE PLUGINS(INTERCEPTOR) IN MAGENTO 2

The very first thing is, don’t confuse it with the “module”, since modules are called plugins in some platforms, for example, WordPress. In this case, the plugin is a part of a module that is used for intercepting a function call in Magento.

Introduction

A plugin, or interceptor, is a whole new concept introduced in Magento 2. In Magento 1, to customize different classes and methods, you would have to rewrite a class. This was a very powerful way of customization but with a cost of flexibility as no two modules could rewrite the same class. In addition, rewrite conflicts created a lot of instability in the Magento 1 platform.

Magento 2 created a new customization method to remedy this issue, called a plugin or interceptor.

A plugin, or an interceptor, is a class that modifies the behavior of public class functions by intercepting a function call and running the code before, after, or around that function’s call. This allows you to substitute or extend the behavior of the original, public methods for any classes or interfaces. Actually, there is a design pattern named “Interception” used in plugins. So, an interception in technical terms means “inserting code dynamically without changing the original class behavior”, which is exactly what a plugin does in Magneto 2.

Why Use a Plugin?

There are several main reasons for using plugins:

  1. It helps overcome the issue of rewriting the system.
  2. With plugins, we can customize the same method in different modules.
  3. We can prevent collisions between plugins by using the sort order attribute of the plugin. The plugin can be called sequentially according to a sort order, so it does not conflict with any other plugin class.
  4. We can modify the return value of any method call that is used with an object manager controlled object.
  5. We can modify the arguments of any method call that is used with an object manager controlled object.

Magento 2 Plugin Restrictions

Plugins can’t be used with any of the following:

  1. Final methods
  2. Final classes
  3. Non-public methods
  4. Static methods
  5. __construct
  6. Virtual types
  7. Objects that are instantiated before Magento\Framework\Interception is bootstrapped
  8. Objects that are not instantiated by the ObjectManager (e.g. by using new directly)

Types of Plugins in Magento 2

In Magento 2, we can create and use three types of Plugins:

  1. Before listener Plugin
  2. After listener Plugin
  3. In between listener Plugin

1. Before Listener Plugin

Before listeners are used to change the arguments of an original method or to add some behavior before an original method is called.

Before listener is called by adding the prefix ‘before’ to the method name and setting the first letter of the original method to capital.

Prototype: beforeMethodname()

Example: beforeAddProduct()

Original Method: public function addProduct(<ARGUMENTS>)

Plugin Method: public function beforeAddProduct(<ARGUMENTS>)Note: The “before listener” methods don’t need to have a return value.

2. After listener Plugin

After listeners are used to change the values returned by the original method or to add some behavior after the original method is called.

After listener is called by adding a prefix after the method name and capitalizing the first letter of the original method. 

Prototype: afterMethodname()

Example: afterGetName()

Original Method: public function getName(<ARGUMENTS>)

Plugin Method: public function afterGetName(<ARGUMENTS>)Note: The after listener methods do not need to have a return value.

3. Around (in between) listener plugin

By definition, the code of the Around methods is run both before and after the observed method. This allows you to completely override a method. The after plugin is used to change both the arguments and the returned values of the original method or to add some behavior before and after the original method is called.

Around listener is called by adding a prefix around the method name and capitalizing the first letter of the original method. 

Prototype: aroundMethodname()

Example: aroundAddProduct()

Original Method: public function addProduct(<ARGUMENTS>)

Plugin Method: public function aroundAddProduct(<ARGUMENTS>)
Note: The around listener methods must have a return value.

How to Create a Magento 2 Plugin

Step 1: Declaration of the plugin

To use plugins, first of all, we have to define it in di.xml.

<config>
      <type name="{ObservedType}">
            <plugin name="{pluginName}" type="{PluginClassName}" sortOrder="1" disabled="false"/>
      </type>
</config>

Explanation

Required elements:

There are three elements required.

Type name: A class, an interface, or a virtual type, which is observed by a plugin.

Plugin name: An arbitrary plugin name that identifies a plugin.

Plugin type: The name of a plugin’s class or its virtual type. Use the following naming convention when specifying this element: \Vendor\Module\Plugin\<ModelName>Plugin.

Optional elements:

These two elements are optional

Plugin sortOrder: The order in which plugins that call the same method are run.Plugin disabled: To disable a plugin, set this element to true. The default value is false.

Step 2: Create a Plugin Class

Now we will create a plugin class that you define in di.xml as type= “{PluginClassName}” and will use before, after or around the method as per our need. For example:-

<?php
namespace Vendor\Module\Plugin;
class ExamplePlugin{
 }

Plugin Examples

Let us create some plugins so we can understand all types of plugins.

1. Before Listener Plugin

In this example, we will change qty to 5 so that it always adds 5 quantities of product whenever we add to the cart.

Step 1: create di.xml in etc folder

<?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\Checkout\Model\Cart">
           <plugin name="exampleofbefore" type="Bizspice\Beforelistener\Plugin\Cart" sortOrder="1" />
     </type>
</config>

Step 2: Now create Cart.php in Bizspice\Beforeplugin\Plugin\

<?php
namespace Bizspice\Beforelistener\Plugin;
class Cart
{
    public function beforeAddProduct( \Magento\Checkout\Model\Cart $subject, $productInfo, $requestInfo = null ) {
          $requestInfo['qty'] = 5;  
          // increasing quantity to 10
            return array($productInfo, $requestInfo);
     } 
}

2. After Listener Plugin

In this example, we will change the product price that will be reflected everywhere on the website including the list page, product page, cart page, and order page.

Step 1: create di.xml in etc folder

<config>
     <type name="Magento\Catalog\Model\Product">
            <plugin name="change_product" type=" Bizspice\Afterlistener\Plugin\Product " sortOrder="1" />
     </type>
</config>

Step 2: Now create Product.php in Bizspice\Afterlistener\Plugin\

<?php
namespace Bizspice\Afterlistener\Plugin;
class Product 
{
     public function afterGetPrice(\Magento\Catalog\Model\Product $subject, $result) {
        return $result*2;
     } 
}

3. Around Listener Plugin

Step 1: create di.xml in etc folder

<config>
     <type name="Magento\Catalog\Model\Product">
         <plugin name="change_cart" type=" Bizspice\Aroundlistener\Plugin\Cartplugin " sortOrder="1" />
    </type>
</config>

Step 2: Now create Cartplugin.php in Bizspice\Aroundlistener\Plugin\

<?php
namespace Bizspice\Afterlistener\Plugin;
class Cartplugin 
{
     public function aroundAddProduct(\Magento\Checkout\Model\Cart $subject,$proceed){
         // before adding product to cart 
         $productId = (int)$this->request->getParam('product', 0);
         $qty = (int)$this->request->getParam('qty', 1);
         // this will run the core addProduct function
         $returnValue = $proceed(); 
         // below code is executed after product is added to cart
         if ($returnValue)
         {
            // after adding product to cart
         }
          return $returnValue;
      } 
}