Running safe Magento 2 experiments with Claude Code.
What's the cleanest way to add a Plugin around Product::getPrice in Magento 2.4?
Wire it in etc/di.xml against Magento\Catalog\Pricing\Price\FinalPrice — notProduct::getPrice. Catalog price uses the price-pool pattern since 2.2: Product::getPrice returns the base attribute value, but the storefront and cart call FinalPrice via the price-info object. Plugin signature: around aroundGetValue(FinalPrice $subject, callable $proceed). Always call $proceed() first, mutate the float, return it — never short-circuit, or you break tier prices and catalog rules. Sample di.xml:
Should I use a Plugin or a Preference to extend a Magento class?
Plugins compose; preferences hammer. A plugin is a stackable interceptor — multiple modules can plug the same method and they all run, ordered by sortOrder. A preference is a one-winner replacement — the last module loaded wins, and any other module that wanted to extend the same class loses silently. Rules of thumb: use around/before/after plugins for behaviour changes; use preference only when you need to replace a non-public method, override a final class, or change the constructor signature (and even then, prefer a virtualType + plugin first). Two preferences on the same class is a merge conflict waiting to happen.
Was this helpful?
Why does my UIComponent listing return 'No records found' even though I see rows in the DB?
Nine times out of ten the data-source is wired to the wrong collection, or the idFieldName in ui_component/<listing>.xml does not match the primary key on the SearchResult collection. Check three things: (1) etc/di.xml has a virtualType for <listing_name>_data_source with the right collection class; (2) the collection extends Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult, not the legacy resource collection; (3) component="Magento_Ui/js/grid/provider" is on the dataSource node. The grid silently fails open on schema mismatches — tail var/log/exception.log while you reload, the real error is there.
Was this helpful?
How do I add a custom GraphQL resolver without breaking the schema cache?
Three files, in this order. (1) etc/schema.graphqls — declare the type and the field; (2) a Resolver class implementing Magento\Framework\GraphQl\Query\ResolverInterface; (3) wire it in the schema with @resolver(class: "Vendor\\Module\\Resolver\\Foo"). After every schema edit run bin/magento cache:clean config graphql_query_resolver_cache. Don't skip config — the schema-stitcher caches the parsed AST there, not under graphql_query_resolver_cache. If your new field still 404s, run bin/magento setup:di:compile; resolver-class autoloading goes through generated factories.
Was this helpful?
Observer or plugin for "after order placed" logic?
Use a plugin on Magento\Sales\Api\OrderManagementInterface::place. The historic sales_order_place_after observer still fires, but it runs inside the same DB transaction as the order save, so any exception you throw rolls back the order — rarely what you want. A plugin gives you a clean afterPlace($subject, $result) hook where you can dispatch an async queue message, send an email, or fire a webhook without endangering the order itself. If you need the quote rather than the order, use Magento\Quote\Api\CartManagementInterface::placeOrder instead — it returns the order ID.
Was this helpful?
Request a quote
I'll reply within 2-4 hours business with a written quote and timeline.