Fresh Create an after plugin in Magento

Video Lesson: Create an after plugin in Magento

Magento's after plugins are functions that let you modify data returned from another class method.

Published 2 days ago

Share with colleagues:

Lesson Content

After plugins let you modify data after a Magento method does it’s thing. They're perfect when you need to intercept and adjust a public method's output before it reaches the rest of your application, and without directly editing the core files.

Let's look at that "Default welcome msg!" text in the header. This code is traced back to the getWelcome() method of the Magento Theme module’s Header class:

// ...

/**
 * Retrieve welcome text
 *
 * @return string
 */
public function getWelcome()
{
    if (empty($this->_data['welcome'])) {
        $this->_data['welcome'] = $this->_scopeConfig->getValue(
            'design/header/welcome',
            ScopeInterface::SCOPE_STORE
        );
    }
    return $this->escaper->escapeQuote(__($this->_data['welcome'])->render(), true);
}

// ...

While there is a reference to the config value at design/header/welcome, we can't include dynamic data in it, such as the store name. But we can create a custom plugin that adds the store name from configuration.

Pro tip: The store name from configuration (general/store_information/name) is what merchants set in Admin under Stores > Configuration > General > Store Information > Store Name. This is typically what we want to display to customers.

Magento’s after plugins allow us to modify the return value of any public method. Since this method is public, we can tap into it with a plugin.

Note: If the plugin is not public, you’ll want to look into alternatives such as class preferences to modify the code.

We’ll name our plugin by taking the original method, getWelcome(), then capitalizing the first letter and prepending after.

We also have access to the original class with the $subject parameter, and the original result with $result:

<?php

declare(strict_types=1);

namespace Vendor\Module\Plugin;

use Magento\Framework\Escaper;
use Magento\Framework\Phrase;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\ScopeInterface;
use Magento\Theme\Block\Html\Header;

class StoreWelcome
{
    public function __construct(
        private readonly ScopeConfigInterface $scopeConfig,
        private readonly Escaper $escaper,
    ) {
    }

    public function afterGetWelcome(
        Header $subject,
        string $result,
    ): Phrase|string {
        $storeName = $this->scopeConfig->getValue(
            'general/store_information/name',
            ScopeInterface::SCOPE_STORE
        );

        if ($storeName) {
            $result = __('Welcome to %1!', $this->escaper->escapeHtml($storeName)).' '.$result;
        }

        return $result;
    }
}

And we’ll make it available by wiring it up into the DI configuration, specifying the class we are plugging into. The name defined here is just any arbitrary name, but typically follows the same plugin name, but in snake_case:

<?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\Theme\Block\Html\Header">
        <plugin name="vendor_module_store_welcome" type="Vendor\Module\Plugin\StoreWelcome"/>
    </type>
</config>

Since plugins are derived from generated interceptor code, we will need to recompile our assets with setup:upgrade to make our plugin active:

bin/magento setup:upgrade