Create an around plugin in Magento

Modify the behavior of a public method in Magento by creating an around plugin.

M Bytes Newsletter
Get the developer newsletter

    Fresh bytes every Thursday. No spam, ever. Unsubscribe anytime.

    Join 9,000+ developers and get three free video lessons every week.

    Around plugins let you wrap existing Magento functions with your own code. They're incredibly powerful - you can run code before or after the original function, modify its parameters, or even prevent it from running entirely.

    Important note: Around plugins are the most powerful but also the most dangerous plugin type. They can make debugging tricky and increase the size of the call stack, which impacts performance. Before reaching for an around plugin, first check if before/after plugins or class preferences could solve your problem instead.

    Let's build some functionality that blocks customer logins coming from specific email domains. We can do this by tapping into any public function that allows us to carry out our task.

    We'll create a plugin for the Customer model's loadByEmail function.

    vendor/magento/module-customer/Model/Customer.php
    public function loadByEmail($customerEmail)
    {
        $this->_getResource()->loadByEmail($this, $customerEmail);
        return $this;
    }

    Now let's create our plugin class, naming it with a descriptive name of the action it is doing:

    Plugin/PreventLogin.php
    <?php
     
    declare(strict_types=1);
     
    namespace Vendor\Module\Plugin;
     
    use Magento\Customer\Model\Customer;
     
    class PreventLogin
    {
        public function aroundLoadByEmail(
            Customer $subject,
            callable $proceed,
            $email,
        ) {
            // Custom code goes here
        }
    }

    Our plugin method needs two or more parameters:

    • $subject - The original class instance we're plugging into
    • $proceed - A callable that lets us execute the original function
    • Then, any parameters from the original function (in this case, $email)

    Let's implement our domain blocking logic:

    Plugin/PreventLogin.php
    public function aroundLoadByEmail(
        Customer $subject,
        callable $proceed,
        $email,
    ) {
        $result = $proceed($email);
        $failuresNum = $subject->getData('failures_num');
     
        if (str_contains($email, 'example.com')) {
            $result->setData([
                'is_active' => 0,
                'failures_num' => $failuresNum + 1,
            ]);
        }
     
        return $result;
    }

    This code first runs the original function using$proceed. Then it checks if the email contains "example.com". If it does, we mark the account as inactive and increment the failure counter. We then either return the original customer data, or the modified version with the account marked as inactive β€” effectively blocking these users from logging in.

    Finally, we need to tell Magento about our plugin. We'll do this by adding it to our module'sdi.xmlfile. It’s also a good idea to prefix our plugin names with our vendor and module name to avoid potential namespace collisions:

    etc/di.xml
    <?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\Customer\Model\Customer">
            <plugin name="vendor_module_prevent_login" type="Vendor\Module\Plugin\PreventLogin"/>
        </type>
    </config>

    And we also need to tell Magento to recompile dependencies by either running setup:upgrade, or removing related classes in the generated/code directory:

    bin/magento setup:upgrade

    That's it! Our plugin will now block any login attempts which originate from our specified domain.