Plugins are one of the new concepts in Magento world – they were introduced in Magento 2 and are here to stay. Taking into account that Magento team wants developers to go by ‘composition over inheritance’ principle means that every developer should become familiar with them. As a side note – in my opinion calling this feature “plugin” is a bit unfortunate as it can be mistaken for “module” since that’s how modules are called in the world of WordPress. So, how about we just use “interceptors”?

Ok, so what are the said Interceptors? Well… They intercept selected public methods and modify them. What it means to the developers is that, instead of extending a class and overloading some methods, we can just create a class, write a method and use it to modify the original one! We can also configure the order in which the plugins will be executed. Cool, don’t you think? The fight between modules for rewriting core functions is now a thing of the dark and cold past.

There are three kinds of interceptors – before, after and around. They are used for the following:
– before – run before the original method letting you to modify the parameters that will be used,
– after – run after the original method letting you to modify the output,
– around – run both before and after the original method letting you to effectively overload the original function.

One of the config parameters you have to provide when registering your interceptor is sortOrder, which determines whether your plugin is run before other plugins intercepting the same method or after them. What’s important to mention is that you can actually stop the plugin propagation in an around interceptor and prevent the other around methods from firing.

I always provide some examples in my articles, so let’s write a module that will change user redirection after successfully sending mail through the contact form. Without a plugin, we would have to write a preference for Magento\Contact\Controller\Index\Post and create a class that would extend the original controller and allow us to overload the execute method. We would have to rewrite the most important method of the class simply to change the redirect!

I’ll assume that you already have the Magently_TableTennis module from the previous article or that you can take care of the module boilerplate by yourself.

Since we want to modify behaviour of Magento\Contact\Controller\Index\Post class we have to tell Magento that it’s our target. We can do this by creating the di.xml file under /etc//di.xml. The code is pretty much self-explanatory:


<?xml version="1.0"?>
<config xmlns:xsi="" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Contact\Controller\Index\Post">
        <plugin name="contactPostControllerPlugin" type="Magently\TableTennis\Plugin\Post" sortOrder="1" />

(Please mind that in the real world it’s a good practice to imitate the path of the original class when creating an interceptor class file.)

Now, let’s create our interceptor:


namespace Magently\TableTennis\Plugin;

class Post
    // It's just a regular constructor with classes we want to use in our code
    public function __construct(
        Magento\Framework\App\Request\DataPersistorInterface $dataPersistor,
        Magento\Framework\App\Action\Context $context
    ) {
        $this->dataPersistor = $dataPersistor;
        $this->context = $context;

    // We have to pass the original class as the first parameter of every interceptor
    // The $result parameter is the result of the original execute method and is present only in the after plugins
    public function afterExecute(\Magento\Contact\Controller\Index\Post $subject, $result)
        // In the original method, dataPersistor is cleared if a message has been sent
        // so we can use it as an indicator to whether a user can be redirected somewhere else
        // or fall back to the result of the original method
        if (!$this->dataPersistor->get('contact_us')) {
            return $this->context->getResultRedirectFactory()->create()->setPath('/');
        return $result;

And that’s it, our interceptor doesn’t even have to extend any other class – it’s just simple and clean code that’s easy to write and maintain. To find more information on the topic I really recommend you to simply read up the article on Magento Dev Docs – it includes good examples and answers most of the questions you might still have: .