Plugin Types — Before, After, Around
Plugin Declaration
<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_product_plugin"
type="Vendor\Module\Plugin\ProductPlugin"
sortOrder="10"/>
</type>
</config>
Before Plugin
Runs before the original method. Can modify arguments:
namespace Vendor\Module\Plugin;
class ProductPlugin
{
public function beforeSetName(
\Magento\Catalog\Model\Product $subject,
string $name
): string {
return strtoupper($name);
}
}
After Plugin
Runs after the original method. Can modify the return value:
public function afterGetName(
\Magento\Catalog\Model\Product $subject,
string $result
): string {
return $result . ' (Modified)';
}
Around Plugin
Wraps the original method. Has full control:
public function aroundGetName(
\Magento\Catalog\Model\Product $subject,
callable $proceed
): string {
$startTime = microtime(true);
$result = $proceed();
$elapsed = microtime(true) - $startTime;
$this->logger->info('getName took: ' . $elapsed);
return $result;
}
If $proceed() is not called, the original method is skipped.
Plugin Interception Mechanics
Generated Interceptor Class
When you create a plugin, Magento generates an interceptor class:
// Generated: var/classes/Vendor/Module/Plugin/ProductPluginInterceptor.php
namespace Vendor\Module\Plugin;
class ProductPluginInterceptor
{
public function aroundGetName(
\Magento\Catalog\Model\Product $subject,
callable $proceed
): string {
// Plugin logic here
$result = $proceed();
return $result;
}
}
How Interception Works
- DI generates interceptor classes for target classes with plugins
- ObjectManager returns the interceptor instead of the original class
- Each method is wrapped with plugin calls
- Execution order: before plugins -> original method -> after plugins
// ObjectManager returns interceptor
$product = $objectManager->get(\Magento\Catalog\Model\Product::class);
// $product is actually ProductInterceptor, not Product
Plugin Chain Execution
beforePlugin1 -> beforePlugin2 -> OriginalMethod -> afterPlugin2 -> afterPlugin1
Around plugins wrap the entire chain:
aroundPlugin1 -> { beforePlugin2 -> OriginalMethod -> afterPlugin2 } -> afterPlugin1
Regenerating Interceptors
After adding or removing plugins, regenerate:
php bin/magento setup:di:compile
php bin/magento cache:clean
Plugin Limitations
Cannot Plugin Non-Public Methods
Plugins only work on public methods:
// This will NOT work
<type name="Vendor\Module\Model\Product">
<plugin name="plugin" type="Vendor\Module\Plugin\Plugin"/>
</type>
// Target class
public class Product {
protected function validate() { /* ... */ } // Cannot plugin this
public function save() { /* ... */ } // Can plugin this
}
Cannot Plugin Final Classes or Methods
final class Product {
public function save() { /* ... */ } // Cannot plugin
}
// Also cannot plugin if method is final
public final function save() { /* ... */ }
Cannot Plugin Static Methods
public static function factory() { /* ... */ } // Cannot plugin
Cannot Plugin Methods Called via self::
class Product {
public function save() {
$this->validate(); // Can plugin this
self::doSave(); // Cannot plugin self:: calls
static::doSave(); // Can plugin this (late static binding)
}
}
Cannot Plugin Constructor
Constructors are never intercepted by plugins.
Performance Impact
Each plugin adds overhead. Profiling shows:
- Before plugin: ~0.1ms per call
- After plugin: ~0.1ms per call
- Around plugin: ~0.15ms per call
Heavy plugins on high-traffic methods accumulate overhead.
Generated Code Analysis
Interceptor Files Location
Generated interceptor classes are in:
var/classes/Vendor/Module/Plugin/ClassNameInterceptor.php
Analyzing Generated Code
// View generated interceptor
$file = BP . '/var/classes/Vendor/Module/Plugin/ProductInterceptor.php';
echo file_get_contents($file);
Plugin Configuration Methods
<type name="Magento\Catalog\Model\Product">
<plugin name="my_plugin"
type="Vendor\Module\Plugin\ProductPlugin"
sortOrder="10"
disabled="false"/>
</type>
| Attribute | Description |
|---|---|
| name | Unique plugin identifier |
| type | Plugin class |
| sortOrder | Execution order |
| disabled | Set true to disable |
Disabling Plugins
<type name="Magento\Catalog\Model\Product">
<plugin name="third_party_plugin" disabled="true"/>
</type>
Plugin on Interface
<!-- Plugin on interface applies to all implementations -->
<type name="Magento\Catalog\Api\ProductRepositoryInterface">
<plugin name="repo_plugin" type="Vendor\Module\Plugin\RepoPlugin"/>
</type>
This intercepts all classes implementing ProductRepositoryInterface.
Practice Problems
A plugin is declared but never executes. Diagnose the issue.
Quiz
1. What method must a before plugin return?
2. What happens if an around plugin does not call $proceed()?
3. Can you plugin a protected method?
4. What command regenerates plugin interceptor classes?
Flashcards
Question
What does a before plugin return?
Click to reveal answer
Answer
Modified arguments for the original method
Question
What does an after plugin receive?
Click to reveal answer
Answer
The original method's return value, which it can modify and return
Question
What does an around plugin receive?
Click to reveal answer
Answer
A callable $proceed that invokes the original method
Question
Can you plugin final classes?
Click to reveal answer
Answer
No, final classes and final methods cannot be plugged
Question
Where are generated interceptor classes stored?
Click to reveal answer
Answer
var/classes/ directory as ClassNameInterceptor.php
Revision Notes
Key Takeaways
- 1. Before plugins modify arguments, after plugins modify return values, around plugins wrap entire methods
- 2. Magento generates interceptor classes that wrap target methods with plugin calls
- 3. Plugins cannot intercept non-public, final, static, or constructor methods
- 4. sortOrder controls execution order; before plugins run in ascending order, after in descending
- 5. Run setup:di:compile after adding or removing plugins
- 6. Plugins on interfaces apply to all implementing classes
Interview Tips
- • Explain the difference between before, after, and around plugins
- • Discuss how Magento generates interceptor code for plugins
- • Know the limitations: no final, no static, no protected methods
- • Explain plugin execution order with multiple plugins
Cheat Sheet
Plugins Deep Dive Cheat Sheet
Plugin types:
- before: modify arguments, return modified args
- after: receive return value, return modified result
- around: wrap method with $proceed callable
Execution order:
before1 -> before2 -> original -> after2 -> after1
Limitations:
- Public methods only
- No final classes/methods
- No static methods
- No constructors
- self:: calls not intercepted
Config:
<type name="TargetClass">
<plugin name="name" type="PluginClass" sortOrder="10"/>
</type>
Regenerate: php bin/magento setup:di:compile