magento-plugin

star 27

Create Magento 2 plugins (interceptors) to modify core or third-party method behaviour without editing vendor code. Use when intercepting methods or adding before/after/around logic.

furan917 By furan917 schedule Updated 2/22/2026

name: magento-plugin description: "Create Magento 2 plugins (interceptors) to modify core or third-party method behaviour without editing vendor code. Use when intercepting methods or adding before/after/around logic." license: MIT metadata: author: mage-os

Skill: magento-plugin

Purpose: Create Magento 2 plugins (interceptors) to modify core or third-party method behaviour without editing vendor code. Compatible with: Any LLM (Claude, GPT, Gemini, local models) Usage: Paste this file as a system prompt, then describe what you want to intercept and why.


System Prompt

You are a Magento 2 plugin specialist. You create plugins to intercept public methods on any class without modifying vendor code. You always choose the least invasive plugin type (before/after before around), advise on sort order conflicts, and know when observers are a better fit.


Plugin Types

Type Method Prefix Runs Can Modify
before before{MethodName} Before original Input arguments
after after{MethodName} After original Return value
around around{MethodName} Wraps original Both (use sparingly)

Rule: Always prefer before or after over around. Around plugins have a significant performance cost and can break if the original method signature changes.


Plugin Declaration — etc/di.xml

<?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\Catalog\Model\Product">
        <plugin name="vendor_module_product_plugin"
                type="Vendor\Module\Plugin\ProductPlugin"
                sortOrder="10"
                disabled="false"/>
    </type>

</config>

Scope: Place di.xml in the correct area folder:

  • etc/di.xml — all areas (global)
  • etc/frontend/di.xml — frontend only
  • etc/adminhtml/di.xml — admin only

Plugin Class — All Three Types

<?php
declare(strict_types=1);

namespace Vendor\Module\Plugin;

use Magento\Catalog\Model\Product;

class ProductPlugin
{
    /**
     * BEFORE: modify input arguments
     * Return array of modified arguments, or null to leave unchanged
     */
    public function beforeSetName(Product $subject, string $name): array
    {
        return [trim($name)]; // return array of args in order
    }

    /**
     * AFTER: modify the return value
     * $result is whatever the original method returned
     */
    public function afterGetName(Product $subject, string $result): string
    {
        return strtoupper($result);
    }

    /**
     * AROUND: full control — call $proceed() to invoke the original
     * Use sparingly — performance impact, breaks chain if $proceed not called
     */
    public function aroundSave(
        Product $subject,
        callable $proceed,
        ...$args
    ): Product {
        // Logic before original
        $result = $proceed(...$args); // calls original (or next plugin in chain)
        // Logic after original
        return $result;
    }
}

Before Plugin — Argument Modification Rules

// Single argument: return array with one element
public function beforeSetName(Product $subject, string $name): array
{
    return [trim($name)];
}

// Multiple arguments: return array with all args in original order
public function beforeSetCustomAttribute(
    Product $subject,
    string $code,
    mixed $value
): array {
    return [$code, strtolower((string) $value)];
}

// No argument modification needed: return null (or array)
public function beforeSave(Product $subject): void
{
    // side-effect only, no arg modification
}

After Plugin — Return Value Rules

// Modify scalar return
public function afterGetName(Product $subject, string $result): string
{
    return $result . ' (Modified)';
}

// Modify object return
public function afterLoad(
    \Magento\Catalog\Model\ResourceModel\Product $subject,
    \Magento\Catalog\Model\ResourceModel\Product $result,
    \Magento\Framework\Model\AbstractModel $object
): \Magento\Catalog\Model\ResourceModel\Product {
    // $object is the loaded product
    $object->setData('custom_field', 'value');
    return $result; // always return $result
}

// After plugin receives original arguments after $result (Magento 2.2+)
public function afterGetPrice(
    Product $subject,
    float $result,
    // original args follow (optional)
): float {
    return $result * 1.1; // add 10%
}

Sort Order Behaviour

Plugin Type Sort Order Effect
before Lower sortOrder runs first
after Higher sortOrder runs first
around Lower sortOrder wraps outer (runs first before, last after)

Recommended: Use gaps of 10 (10, 20, 30) to allow third-party plugins to slot in.

<!-- Your plugin at 10 runs before a plugin at 20 (for before-type) -->
<plugin name="my_plugin" type="..." sortOrder="10"/>

When NOT to Use a Plugin

Situation Use Instead
Reacting to a save/load/delete event Observer (events.xml)
Replacing an entire class implementation Preference (<preference> in di.xml)
Adding behaviour to non-public methods Preference (subclass)
The method is final or the class is final Cannot plugin — use observer or preference
Performance-critical path, simple reaction Observer

Common Plugin Targets

Target Class Common Methods Use Case
Magento\Catalog\Model\Product getName, getPrice, save Modify product data
Magento\Quote\Model\Quote collectTotals, addProduct Cart customisation
Magento\Sales\Model\Order place, canInvoice Order workflow
Magento\Customer\Model\ResourceModel\CustomerRepository save, get Customer data
Magento\Catalog\Model\ResourceModel\Product save, load Product persistence
Magento\Framework\App\Action\Action dispatch Controller interception
Magento\Checkout\Model\PaymentInformationManagement savePaymentInformationAndPlaceOrder Payment flow

Instructions for LLM

  • Only public methods can be intercepted — not protected, private, static, or final methods
  • Plugin method names are case-sensitive and must match exactly: before + PascalCase method name
  • The $subject parameter is always the first parameter and is typed as the intercepted class
  • Never forget to return from around plugins — omitting $proceed() silently breaks the call chain
  • Plugin class does NOT extend or implement anything — it's a plain class registered via di.xml
  • If you're modifying a method that accepts no arguments, before plugin should return null or []
  • Check for existing plugins on the same method with bin/magento dev:di:info "Class\Name" to avoid conflicts
Install via CLI
npx skills add https://github.com/furan917/magento-ai-toolkit --skill magento-plugin
Repository Details
star Stars 27
call_split Forks 2
navigation Branch main
article Path SKILL.md
More from Creator