Plugin System Overview
Plugins (interceptors) in Magento 2 allow you to modify the behavior of any public method on any class without changing the original code. They are the preferred way to extend core functionality.
How plugins work:
- Magento generates interceptor classes during compilation
- Interceptors wrap the original class methods
- Plugin methods are called before, after, or around the original
- Multiple plugins can target the same method
Plugin types:
- Before - Executes before the original method
- After - Executes after the original method
- Around - Wraps the original method (before + after)
Plugin configuration:
<!-- app/code/Vendor/Module/etc/di.xml -->
<config>
<type name="Magento\Catalog\Model\ProductRepository">
<plugin name="vendor_product_after_save"
type="Vendor\Module\Plugin\ProductAfterSave"
sortOrder="10"/>
</type>
</config>
Plugin declaration attributes:
name- Unique identifier across all plugins for this targettype- Fully qualified plugin class namesortOrder- Execution order when multiple plugins target same methoddisabled- Set totrueto disable without removing
Before Plugins
Before plugins execute before the original method and can modify the arguments passed to it.
<?php
namespace Vendor\Module\Plugin;
use Magento\Catalog\Model\ProductRepository;
use Magento\Catalog\Api\Data\ProductInterface;
class ProductBeforeSave
{
/**
* Before plugin for save method
*
* @param ProductRepository $subject
* @param ProductInterface $product
* @return array Modified arguments
*/
public function beforeSave(
ProductRepository $subject,
ProductInterface $product
): array {
// Add custom attribute before save
$product->setData('last_modified_by', 'custom_module');
// Log the save operation
$this->logger->info('About to save product: ' . $product->getSku());
// Return modified arguments as array
return [$product];
}
}
Before plugin rules:
- Method name must be
before{MethodName} - First parameter is the subject (original class instance)
- Remaining parameters mirror the original method
- Must return an array of arguments (can modify or pass through)
- If no modification needed, return original args
Return modified arguments:
public function beforeSetPrice(
$subject,
$price
): array {
// Round price to 2 decimal places
return [round($price, 2)];
}
Return original arguments unchanged:
public function beforeSave(
$subject,
$product
): array {
// Just log, don't modify
$this->logger->info('Product save triggered');
return [$product];
}
After and Around Plugins
After plugins execute after the original method and can modify the return value.
public function afterSave(
ProductRepository $subject,
$result
) {
// $result is the return value of the original save() method
// Log the saved product
$this->logger->info('Product saved with ID: ' . $result->getId());
// You can modify the return value
$result->setData('custom_flag', true);
// Or return a different value
return $result;
}
Around plugins wrap the original method with before and after logic.
public function aroundSave(
ProductRepository $subject,
\Closure $proceed,
ProductInterface $product
) {
// Before logic
$startTime = microtime(true);
$this->logger->info('Starting product save');
// Call original method via $proceed
$result = $proceed($product);
// After logic
$duration = microtime(true) - $startTime;
$this->logger->info('Product save completed in ' . $duration . 's');
return $result;
}
Around plugin rules:
- Method name must be
around{MethodName} - Second parameter is
\Closure $proceed(the original method) - Must call
$proceed()to execute the original method - Can modify arguments before calling
$proceed() - Can modify the return value of
$proceed() - Can skip calling
$proceed()entirely (but dangerous)
Plugin execution order:
around1 → before1 → before2 → Original Method → after2 → after1 → around1 continues
Around plugins with lower sortOrder execute first. Before plugins execute in sortOrder order. After plugins execute in reverse sortOrder order.
Plugin Limitations and Best Practices
Plugins have specific limitations that affect when and how they can be used.
Cannot plugin:
- Final methods
- Final classes
- Private methods
- Static methods
- Classes without constructor injection
- Methods defined in the same class
Example of final method limitation:
// This class cannot have plugins
final class SomeFinalClass
{
public function someMethod() { /* ... */ }
}
// This method cannot have plugins
public final function finalMethod() { /* ... */ }
Plugin ordering:
<type name="Magento\Catalog\Model\ProductRepository">
<!-- Lower sortOrder = executes first -->
<plugin name="first_plugin"
type="Vendor\Module\Plugin\First"
sortOrder="10"/>
<!-- Higher sortOrder = executes later -->
<plugin name="second_plugin"
type="Vendor\Module\Plugin\Second"
sortOrder="20"/>
</type>
Best practices:
- Use plugins to extend, not replace, core functionality
- Keep plugin logic focused and minimal
- Don't add business logic that belongs in models
- Use around plugins sparingly (they add overhead)
- Name plugins descriptively:
{vendor}_{module}_{purpose} - Test plugins with the original method's test suite
Debugging plugins:
# List all plugins for a class
php bin/magento dev:di:info Magento\Catalog\Model\ProductRepository
# Check generated interceptor
grep -A 20 "class.*Interceptor" generated/code/Magento/Catalog/Model/ProductRepository/Interceptor.php
Quiz
1. What must an around plugin call to execute the original method?
2. What happens to after plugin sortOrder execution order?
3. Can you create a plugin for a final class?
Flashcards
Question
What are the three plugin types in Magento?
Click to reveal answer
Answer
before, after, around
Question
What is the naming convention for before plugins?
Click to reveal answer
Answer
before{MethodName} (e.g., beforeSave)
Question
What parameter does an around plugin receive for the original method?
Click to reveal answer
Answer
Closure $proceed
Question
How is plugin execution order determined?
Click to reveal answer
Answer
By sortOrder attribute - lower executes first for before, reverse for after
Revision Notes
Key Takeaways
- 1. Plugins modify any public method without changing original code
- 2. Three types: before (modify args), after (modify return), around (wrap)
- 3. Around plugins must call $proceed() to run original method
- 4. Cannot plugin final classes, final methods, or private methods
- 5. sortOrder controls execution order
- 6. Plugins are the preferred extension mechanism over events
Interview Tips
- • Explain before, after, and around plugins with examples
- • Discuss plugin ordering and how sortOrder works
- • Explain limitations of the plugin system
- • Compare plugins vs events vs preferences
- • Know when to use around plugins vs before/after
Cheat Sheet
Plugins Cheat Sheet
Types:
before{Method}()- Modify argumentsafter{Method}()- Modify return valuearound{Method}()- Wrap with $proceed
Config (di.xml):
<type name="Target\Class">
<plugin name="unique_name" type="Vendor\Module\Plugin\MyPlugin" sortOrder="10"/>
</type>
Execution Order:
around(10) → before(10) → before(20) → Method → after(20) → after(10)
Cannot Plugin: final classes, final methods, private methods, static methods