Skip to content
intermediate Phase 63 · Extension Points

Plugin Ordering — Sort Order, Conflicts, and Resolution

Understanding plugin sort order, resolving plugin conflicts when multiple plugins target the same method, and managing plugin execution chains

45m
1 problems
Topic Progress 0%

sortOrder Basics

How sortOrder Works

Plugins with lower sortOrder execute first:

<type name="Magento\Catalog\Model\Product">
    <plugin name="first" type="Vendor\A\Plugin\A" sortOrder="10"/>
    <plugin name="second" type="Vendor\B\Plugin\B" sortOrder="20"/>
    <plugin name="third" type="Vendor\C\Plugin\C" sortOrder="30"/>
</type>

Execution for getName():

A::beforeGetName -> B::beforeGetName -> C::beforeGetName
  -> Product::getName()
C::afterGetName -> B::afterGetName -> A::afterGetName

Before plugins: ascending sortOrder
After plugins: descending sortOrder (LIFO)

Default sortOrder

If no sortOrder is specified, plugins execute in config merge order:

<!-- These run in unpredictable order -->
<plugin name="a" type="Vendor\A\Plugin\A"/>
<plugin name="b" type="Vendor\B\Plugin\B"/>

Always specify sortOrder for predictable behavior.

sortOrder Ranges

Range Purpose
10-99 Core Magento plugins
100-199 Third-party extensions
200-299 Custom application plugins
300+ Late-execution plugins

Around Plugin Execution Order

Around Plugins Stack

Around plugins nest like layers:

<type name="Magento\Catalog\Model\Product">
    <plugin name="outer" type="Vendor\Outer\Plugin" sortOrder="10"/>
    <plugin name="inner" type="Vendor\Inner\Plugin" sortOrder="20"/>
</type>

Execution:

outer::aroundGetName {
    inner::aroundGetName {
        Product::getName()
    }
}

Around + Before/After Mixing

<type name="Magento\Catalog\Model\Product">
    <plugin name="around_1" type="Vendor\Around1" sortOrder="10"/>
    <plugin name="before_1" type="Vendor\Before1" sortOrder="15"/>
    <plugin name="around_2" type="Vendor\Around2" sortOrder="20"/>
    <plugin name="before_2" type="Vendor\Before2" sortOrder="25"/>
</type>

Execution:

around_1::around {
    around_2::around {
        before_2::before
        before_1::before
        Product::getName()
        before_1::after
        before_2::after
    }
    around_2::after
}
around_1::after

Around plugins at lower sortOrder wrap the entire inner chain.

Plugin Conflicts and Resolution

Common Conflict Scenario

Two modules plugin the same method with conflicting logic:

// Vendor A: converts name to uppercase
public function afterGetName($subject, $result) {
    return strtoupper($result);
}

// Vendor B: adds prefix
public function afterGetName($subject, $result) {
    return 'Product: ' . $result;
}

Result depends on sortOrder. If A=10, B=20:

  1. Original: "Widget"
  2. A after (sortOrder 10): "WIDGET" (after runs in reverse)
  3. B after (sortOrder 20): "Product: WIDGET"

Disabling Conflicting Plugins

<type name="Magento\Catalog\Model\Product">
    <plugin name="conflicting_plugin" disabled="true"/>
</type>

Using di.xml Override Pattern

<!-- Module A di.xml -->
<type name="Magento\Catalog\Model\Product">
    <plugin name="module_a_plugin" type="Vendor\A\Plugin" sortOrder="10"/>
</type>

<!-- Module B di.xml - can override via plugin name -->
<type name="Magento\Catalog\Model\Product">
    <plugin name="module_a_plugin" disabled="true"/>
    <plugin name="module_b_better" type="Vendor\B\Plugin" sortOrder="10"/>
</type>

Conflict Resolution Strategies

  1. Use specific sortOrder values to control order
  2. Disable conflicting plugins from other modules
  3. Use around plugins to wrap and modify behavior
  4. Check for existing plugins before implementing
  5. Document plugin sort order in README

Debugging Plugin Order

Inspecting Plugin Configuration

$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$config = $objectManager->get(\Magento\Framework\Interception\Config\ConfigInterface::class);
$plugins = $config->getPlugins('Magento\Catalog\Model\Product');
print_r($plugins);

Plugin Profiling

public function aroundGetName($subject, callable $proceed)
{
    $start = microtime(true);
    $result = $proceed();
    $elapsed = microtime(true) - $start;
    $this->logger->info(static::class . '::getName: ' . round($elapsed, 4) . 's');
    return $result;
}

CLI Debug Commands

# List plugins for a class
php bin/magento dev:di:info Magento\\Catalog\\Model\\Product

# Check generated interceptor
cat var/classes/Magento/Catalog/Model/ProductInterceptor.php

# Verify plugin configuration
php bin/magento setup:di:compile -vvv

Common Issues

Issue Cause Fix
Plugin not executing Missing di:compile Run setup:di:compile
Wrong execution order Missing sortOrder Add explicit sortOrder
Plugin applies to wrong class Interface vs class mismatch Check type in di.xml
Around plugin breaks original $proceed not called Always call $proceed unless intentional

Practice Problems

0 / 1 solved
Plugin Order Debug

Three plugins on the same method produce unexpected results. Determine the correct sortOrder to achieve the desired output.

Quiz

1. In what order do before plugins execute?

Question 1 options

2. In what order do after plugins execute?

Question 2 options

3. How do you disable a third-party plugin?

Question 3 options

4. What happens if sortOrder is not specified?

Question 4 options

Flashcards

Question

What order do before plugins execute?

Answer

Ascending sortOrder — lowest value first

Question

What order do after plugins execute?

Answer

Descending sortOrder — highest value first (LIFO)

Question

How do around plugins nest?

Answer

Lower sortOrder wraps outer; higher sortOrder wraps inner

Question

How to disable a plugin from another module?

Answer

Set disabled="true" on the plugin name in your di.xml

Question

What command inspects plugins for a class?

Answer

php bin/magento dev:di:info ClassName

Revision Notes

Key Takeaways

  • 1. Before plugins: ascending sortOrder; after plugins: descending sortOrder (LIFO)
  • 2. Around plugins at lower sortOrder wrap the entire inner chain
  • 3. Always specify sortOrder for predictable plugin execution order
  • 4. Disable conflicting plugins with disabled="true" in di.xml
  • 5. Use dev:di:info to inspect plugin configuration for a class

Interview Tips

  • Explain before/after sortOrder behavior with a concrete example
  • Describe how around plugins nest and wrap inner chains
  • Discuss strategies for resolving plugin conflicts between modules
  • Know how to debug plugin execution order

Cheat Sheet

Plugin Ordering Cheat Sheet

Before plugins: sortOrder 10, 20, 30
-> executes: 10 -> 20 -> 30

After plugins: sortOrder 10, 20, 30
-> executes: 30 -> 20 -> 10

Around plugins: sortOrder 10, 20
-> 10 wraps { 20 wraps { original } }

Disable plugin:

<plugin name="name" disabled="true"/>

Debug:
php bin/magento dev:di:info ClassName