Magento Plugin Development: Before, After, and Around Interceptors Explained

A Magento plugin, properly called an interceptor, is a class that modifies the behaviour of a public method on another class, before it runs, after it runs, or by wrapping it entirely, without editing the original code.

Tarun Sharma
Tarun Sharma Founder, Chetaru
|
Updated Jun 12, 2026
|
10 min read
Share

Need More Growth & Leads?

We are ready to work with your business and generate some real results…

Let's Talk

A Magento plugin, properly called an interceptor, is a class that modifies the behaviour of a public method on another class, before it runs, after it runs, or by wrapping it entirely, without editing the original code. It’s the most common way to change how Magento behaves: adjust a price calculation, validate an input, tweak a result, all by intercepting an existing method rather than rewriting it.

One thing to clear up first, because the term gets muddied everywhere: a “plugin” in Magento is not the same as an “extension” or a “module.” A module is the package you build; an extension is a packaged module you install; a plugin is a specific technique you use inside a module. This post is about that technique. For the container it lives in, see our Magento module development guide. Getting the distinction right matters, because using a plugin where you should use an observer (or vice versa) is one of the most common Magento mistakes.

Key Takeaways

  • A Magento plugin (interceptor) changes a public method’s behaviour without touching core, using a before, after, or around method.
  • “Plugin” is not a synonym for “extension” or “module”: a plugin is a technique used inside a module.
  • Use after plugins most, before plugins when you must change arguments, and around plugins rarely, they carry real performance and compatibility risk.
  • Plugins only work on public methods; for private or final methods, or to react to events, you need a different tool.

What is a Magento plugin (interceptor)?

A Magento plugin is a class that intercepts a call to a public method and runs your code before, after, or around the original method. Magento’s framework generates interceptor classes at compile time, so when something calls the target method, your plugin code runs as part of that call. The original class doesn’t know or care that it’s been intercepted, which is exactly why plugins are upgrade-safe.

This is Magento 2’s headline customisation mechanism, and it replaced Magento 1’s fragile class-rewrite approach precisely because multiple plugins can target the same method without conflicting. Each plugin is declared in configuration and runs in a defined order, so two extensions can both adjust the same price method and coexist. That coexistence is the whole reason the interceptor pattern exists, and it’s what keeps a store with dozens of extensions from collapsing into a pile of conflicting rewrites.

How is a plugin different from a module, extension, or observer?

A plugin is a technique; the others are either containers or a different technique entirely. This is the single most useful thing to get straight before writing any Magento customisation, because the words are used interchangeably in the wild and they shouldn’t be. Here’s the breakdown:

Term What it is Relationship
Module The package of code you build The container a plugin lives in
Extension A packaged, distributable module A module someone ships to you
Plugin (interceptor) A technique to modify a public method Lives inside a module
Observer A technique to react to a dispatched event Lives inside a module, an alternative to a plugin

The practical rule: you build a module, and inside it you choose a technique. Use a plugin to change how a specific method behaves. Use an observer to react to a business event (an order was placed, a customer registered) without caring which method fired it. The full set of module-level tools, dependency injection, plugins, observers, and the order to prefer them in, is covered in our Magento module development guide; here we go deep on plugins specifically.

What are before, after, and around plugins?

Magento gives you three plugin types, and each intercepts a method at a different point. Choosing the right one is most of the skill, and reaching for the wrong one (almost always around) is the most common plugin mistake. Here’s what each does:

  • before plugins run before the original method and can modify its arguments. Use one when you need to change what goes into a method. The method name is your target method prefixed with before.
  • after plugins run after the original method and can modify its return value. This is the most common and safest type, use it whenever you need to adjust a result. Prefixed with after.
  • around plugins wrap the entire method call, running code before and after, and they control whether the original even runs. They’re the most flexible and by far the most dangerous.

The hierarchy of preference is clear in practice: reach for after first, before when you genuinely need to alter inputs, and around only when neither will do. An around plugin forces Magento to wrap the call in a closure for every invocation, which adds measurable overhead, and if you forget to call $proceed(), you silently break the method for every other plugin and the core behaviour too.

How do you create a Magento plugin?

You create a plugin by declaring it in your module’s di.xml, then writing the plugin class with the appropriately-named method. There’s no separate registration beyond the module itself, the plugin is wired up entirely through dependency injection config. The steps are short:

  1. Declare the plugin in di.xml, naming the target class (type), your plugin class, and a unique name.
  2. Create the plugin class in your module’s Plugin/ directory.
  3. Write the interceptor method, beforeMethodName, afterMethodName, or aroundMethodName, matching the public method you’re targeting.
  4. Run bin/magento setup:di:compile so Magento regenerates the interceptor classes.

The di.xml declaration also accepts a sortOrder (controlling the sequence when multiple plugins target the same method) and a disabled flag. Forgetting the compile step is the classic “why isn’t my plugin running?” trap: in production mode, Magento serves pre-generated interceptors, so an uncompiled plugin simply doesn’t fire. This compile-and-deploy rhythm is the same discipline that underpins all Magento module development.

What does a Magento plugin look like in code?

A plugin is two small pieces: a di.xml declaration that wires it to a target, and a class with one interceptor method. Seeing both together makes the pattern concrete. Here’s a complete after plugin that appends a label to a product’s name, the kind of small, safe change plugins are made for.

First, the declaration in etc/di.xml:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Catalog\Model\Product">
        <plugin name="vendor_module_product_name_suffix"
                type="Vendor\Module\Plugin\ProductNamePlugin"
                sortOrder="10"/>
    </type>
</config>

Then the plugin class in Plugin/ProductNamePlugin.php:

<?php
namespace Vendor\Module\Plugin;
use Magento\Catalog\Model\Product;
class ProductNamePlugin
{
    public function afterGetName(Product $subject, $result)
    {
        return $result . ' (Online Exclusive)';
    }
}

Two things to notice. The method is afterGetName, the after prefix plus the capitalised target method getName. And it receives $subject (the intercepted object) and $result (the original return value), returning a modified result. A before plugin would instead return an array of modified arguments; an around plugin would take a callable $proceed it’s responsible for invoking. This signature pattern is the same for every plugin you’ll ever write.

What do developers commonly use plugins for?

Plugins show up wherever you need to nudge existing Magento behaviour rather than build something new. The recurring real-world uses cluster around a few areas: adjusting how prices are calculated or displayed (adding fees, applying custom discounts), modifying product or category data before it renders, validating or transforming input on cart and checkout actions, and altering the data returned by an API endpoint before it reaches the client.

What these share is a pattern: there’s an existing public method doing almost what you want, and you need to tweak its input or output. That’s the plugin’s natural habitat. When instead you’re adding wholly new behaviour, a new admin screen, a new API, a new database table, that’s module-level work covered in Magento module development, not a plugin.

When should you use a plugin versus an observer?

Use a plugin to change how a specific method behaves; use an observer to react to a named event. They solve different problems, and picking the wrong one leads to brittle code that breaks on upgrade. The distinction comes down to coupling:

A plugin is tightly bound to a specific method signature. If Adobe changes that method in a future release, your plugin can break. That’s an acceptable trade when you genuinely need to alter that method’s input or output. An observer, by contrast, listens for a dispatched event by name (sales_order_place_after, for example) and is decoupled from any particular method, so it survives refactoring better. As a rule: if your job is “modify what this method returns,” use a plugin; if your job is “do something when X happens in the business,” use an observer. Choosing well keeps the module clean and is part of the same upgrade-safe thinking behind Magento theme development and the platform as a whole.

What are the limits of Magento plugins?

Plugins only work on public, non-final methods of classes instantiated through dependency injection, and that rules out several common targets. Knowing the limits up front saves hours of debugging a plugin that was never going to fire. Plugins cannot intercept:

  • Private or protected methods, only public ones are interceptable.
  • Final methods or final classes, the generated interceptor can’t extend them.
  • Static methods, there’s nothing for the object manager to wrap.
  • Objects created with new rather than through dependency injection.
  • Methods called internally by the same class (a public method calling another method on $this won’t trigger the second method’s plugin).

When a plugin can’t reach your target, the alternatives are an event observer (if there’s a relevant event), a preference (replacing the class via di.xml, used sparingly), or requesting an upstream change. Hitting one of these walls is common, and recognising it early is the difference between a clean solution and an hour lost wondering why nothing happens.

How do plugins affect site performance?

Plugins add overhead, and poorly written ones are a real cause of slow Magento stores, especially overused around plugins. Every intercepted method carries a small cost, and while one well-written after plugin is negligible, hundreds of plugins (common on stores with many extensions) add up. The usual culprits are predictable:

around plugins are the worst offenders because they wrap every call in a closure whether or not the wrapping logic runs. Heavy logic inside a plugin on a frequently-called method (anything in a product-list or price loop) multiplies fast. And plugins that trigger their own uncached database queries can quietly tank page-render time. The fix is discipline: prefer after plugins, keep plugin logic minimal, never put a slow operation in a hot path, and profile with Magento’s built-in profiler when pages drag. This is a core thread in Magento website speed optimization, where badly-behaved plugins show up again and again.

How do you test and debug a Magento plugin?

Test plugins with unit and integration tests, and debug them by confirming they’re compiled, declared correctly, and targeting an interceptable method. A plugin that “doesn’t work” has usually fallen into one of a few well-known traps, so debugging is mostly a checklist. Start here:

  • Did you compile? Run bin/magento setup:di:compile, in production mode an uncompiled plugin never fires.
  • Is the method public and DI-instantiated? If it’s private, final, static, or new-ed, the plugin can’t intercept it.
  • Is the method name exactly right? afterGetPrice for a getPrice method, capitalisation matters.
  • Check the generated interceptor in generated/code to confirm Magento wired it up.
  • Log inside the plugin with the PSR-3 logger to confirm it’s being called at all.

For automated coverage, write PHPUnit unit tests for the plugin’s logic in isolation and integration tests to confirm it behaves correctly against a real Magento instance. Catching plugin bugs before launch matters as much here as in any Magento module development work, since a broken plugin can silently corrupt prices, orders, or checkout.

What are the best practices for Magento plugin development?

Prefer after over around, keep plugins small and focused, declare a sensible sort order, and never use a plugin where an observer or configuration would do. Good plugin development is mostly about restraint, the temptation is to reach for an around plugin because it can do anything, and that’s exactly why you shouldn’t. The practices that hold up:

  • Default to after plugins. Use before only to change arguments, around only as a genuine last resort.
  • Always call $proceed() in an around plugin (unless you deliberately mean to short-circuit), or you break the chain.
  • Keep plugin logic tiny. Heavy work belongs elsewhere, not in an intercepted hot path.
  • Set sortOrder when multiple plugins target one method, so ordering is explicit, not accidental.
  • Don’t use a plugin to react to events, use an observer; don’t use one to replace a whole class, use a preference.
  • Test and re-test after upgrades, since plugins are coupled to method signatures that can change.

Follow these and your plugins stay fast, predictable, and upgrade-safe. Ignore them, and plugins become the hardest-to-debug layer of the whole store. If you’re hiring this out, a developer who reaches for around plugins by default is a warning sign worth probing, the same vetting logic as choosing any Magento development company.

Frequently asked questions

A plugin (formally an interceptor) is a class that modifies the behaviour of a public method on another class, before, after, or around its execution, without editing the original code. It’s Magento 2’s main customisation technique. Importantly, “plugin” here does not mean a downloadable extension; it’s a specific code pattern used inside a module to change how an existing method behaves.

Final thoughts

Magento plugin development comes down to one disciplined idea: change a method’s behaviour by intercepting it, not by rewriting core. Get the vocabulary right first, a plugin is a technique inside a module, not a synonym for an extension, and then choose the right interceptor: after by default, before to change inputs, around almost never. Respect the limits (public methods only) and the performance cost, and plugins become a clean, upgrade-safe way to bend Magento to your needs.

The recurring lesson is restraint and tool-matching: plugins for modifying methods, observers for reacting to events, preferences for wholesale replacement, each in its place. For the container all of this lives in, read our Magento module development guide, and for the wider build, Magento web development.