Magento Series: Creating a Plugin

When developing a Magento 2 (Adobe Commerce) app, you may need to change a function in a core class to make it work in a particular way, something that is not implemented by default.

When using block, model, controller, and helper in Magento 2, it’s not a good practice to modify by hand code pulled in a version-controlled package, for some obvious reasons:

  1. Modifying core files may have a certain influence on another program or module.
  2. Your modifications will be wiped out when you update the framework—those classes you modify will be replaced with new core files.
  3. Code in vendor is not (and should not be) controlled, so nobody will get the changes you make.

In this article, we’ll discuss what you can do instead.

How to modify files without touching the source code

When you have to modify a core class in Magento 2 (Adobe Commerce), you have two options:

  • Plugin – with which you can execute some code before, after, and around the code/target class’s function
  • Preference – with which you can extend a core class to rewrite the functions of that class; the new class is expected to be a complete implementation of the extended class

➡️ There are other ways of modifying functionality, such as changing di.xml parameters and event listeners, but we’re looking at plugins in this article.

What is a plugin?

A plugin is a class extension that allows for modifying the behavior of a public class or method. It works by interrupting a function call and then running code before, after, or around that intercepted function call. A plugin lets you “substitute or extend the behavior of original, public methods for any class or interface.”

Why and when should I use plugins?

Use plugins if you need to:

  • modify the return value of any method call
  • forward any method call
  • modify arguments of any method call

➡️ Plugins can not be used on the __construct method of a class.

What type of plugin should I use?

There are three types of plugins, namely:

  • Before – changes the arguments provided to a method or executes something before the method itself is executed
  • After – used to “rework” the output of a method or execute something based on the method result, i.e., after the method is executed
  • Around – modifies the behavior of a method; allows you to execute something before, after, or around the method—or you might even not call the original method at all!

How to create a plugin

It’s best to illustrate this using an example, so let’s create a sample plugin based on this class:

<?php

namespace Scandiweb\HelloWorld\Controller\Index;

class Example extends \Magento\Framework\App\Action\Action
{

	protected $title;

	public function execute()
	{
		echo $this->setTitle('Welcome');
		echo $this->getTitle();
	}

	public function setTitle($title)
	{
		return $this->title = $title;
	}

	public function getTitle()
	{
		return $this->title;
	}
}

1. Declare the plugin configuration

First and foremost, you have to declare your plugin for a class object, and this is done in the di.xml file in your module

Resources on module creation and folder structure in Magento 2 (Adobe Commerce):
Creating a Magento 2 Module
Dependency injection configuration

Plugin declaration syntax for a class object in di.xml file:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="<ORIGINAL CLASS NAME>">
      <plugin 
	name="<PLUGIN UNIQUE NAME>" 
	type="<PLUGIN CLASS NAME>" 
	sortOrder="1" 
	disabled="false" 
      />
    </type>
</config>

What does an example plugin declaration look like?

<config>
    <type name='MageCheck\Tutorial\Controller\Index\Example'>
        <plugin 
	 name='MageCheck_Tutorial_Plugin' 
	 type='MageCheck\Tutorial\Plugin\ExamplePlugin' 
	 sortOrder='10'
	 disabled='false'  
	/>
    </type>
</config>

You must specify these properties:*

  • type name – a class or interface which the plugin observes
  • plugin name – an arbitrary plugin name that identifies a plugin. Also used to merge the configurations for the plugin
  • plugin type – the name of a plugin’s class or its virtual type. Use the following naming convention when you specify this element: Vendor\\Module\\Plugin\\<ClassName>

The following properties are optional:*

  • plugin sortOrder – plugins that call the same method run them using this order
  • plugin disabled – to disable a plugin, set this element to true; the default value is false

*The descriptions of these properties are taken from the Adobe Developer Plugins page.

2. Define the Plugin class

Create a plugin class:

<?php

namespace Scandiweb\HelloWorld\Plugin;

class ExamplePlugin
{
 
}

3. Declare plugin methods

Before adding suffixes to any class method (before, after, or around it) you want to create a plugin for, capitalize the first letter of its name. This is considered a Magento best practice. For instance, if you are creating a plugin for the setName method of some class, you should write: beforeSetName, aroundSetName, afterSetName.

Before methods

In Magento (Adobe Commerce), before methods are run prior to the call to an observed method. 

A prerequisite for this is that the before methods have the same name as the observed method, prefixed with “before.” 

By returning a modified argument, before methods can change the arguments of an observed method. If there is no change in the argument of the observed method, the before method returns a null value.

Using the before method:

<?php

namespace Scandiweb\Tutorial\Plugin;

class ExamplePlugin
{

	public function beforeSetTitle
	   (\Scandiweb\Tutorial\Controller\Index\Example $subject, $title)
	{
	  $title = $title . ' to ';
	  echo __METHOD__ . '</br>';

	  return [$title];
	}

}

Around methods

Caution must be taken when using around methods as they can inflate stack traces and influence performance. Use them only when the implementation of all further plugins and the original methods need to be terminated. If you’re looking to replace or alter function results, use after methods instead.

You can override a method using around methods because they allow the code to execute before and after the observed method. It is a prerequisite that the around methods have the same name as the observed method, prefixed with “around.”

Before the list of the original method’s arguments, around methods receive a callable that will allow a call to the next method in the chain. When your code executes the callable, Magento calls the next plugin or the observed function.

If the around method does not call the callable, it will prevent the execution of all the plugins next in the chain and the original method call.

Adobe Developer

Using the around method:

<?php

namespace Scandiweb\Tutorial\Plugin;

class ExamplePlugin
{

  public function aroundGetTitle 
     (\Scandiweb\Tutorial\Controller\Index\Example $subject, callable $proceed, ...$args)
   {

	echo __METHOD__ . ' - Before proceed() </br>';
		 $result = $proceed();
	echo __METHOD__ . ' - After proceed() </br>';


	return $result;
   }

}

After methods

Magento (Adobe Commerce) runs all after methods right after the observed method is completed. These methods must have a return value and have the same name as the observed method, prefixed with “after.”

After methods can be used to change the result of an observed method by returning an altered result at the end of the method.

 Using the after method:

<?php

namespace Scandiweb\Tutorial\Plugin;

class ExamplePlugin
{

  public function afterGetTitle
	(\Scandiweb\Tutorial\Controller\Index\Example $subject, $result)
  {

     echo __METHOD__ . '</br>';

     return '<h1>'. $result . 'MageCheck.com' .'</h1>';

  }

}

➡️ In the documentation block for the plugin, include a “link” to the original method by including its full path. That way, it is easier to find and understand what the plugin is for—and some IDEs, including PhpStorm, allow the user to quickly navigate to the target method by ctrl+clicking.

How to set a plugin priority

Plugin prioritization is determined by the sortOrder property from the plugin node set in di.xml.

If sortOrder is not specified, or if more than one plugin has the same sortOrder value, the module load order is declared in the sequence node of module.xml , and the area will define the merge sequence.

In what order are plugin types executed?

Here’s a simplified view of the order in which plugins are executed in Magento (Adobe Commerce):

  1. The current plugin’s before method is executed
  2. The around method of the current plugin is then called
    • The first part of the around method is run
    • The around method runs the callable
    • The second part of the plugin’s around method is run
  3. The next plugin is processed

Need help with Magento (Adobe Commerce) development? scandiweb is the largest certified Magento developer team in the world. Ask us how you can get a dedicated eCommerce team and get the hassle out of web development, design, and the whole eCommerce optimization process. Or send us a message about your specific needs.

If you enjoyed this post, you may also like