Category Merchandising Rules in Magento 2
AI generated
M2
di.xml
Magento 2 · Merchandising · Categories · Catalog Index
Category Merchandising Rules in Magento 2
rule-based sorting without a Commerce license

The Visual Merchandiser is a Commerce feature, but category merchandising rules can be technically rebuilt in Magento Open Source as well. Coupling product order to stock level, margin and sales figures requires understanding position values, plugin points on the product collection, and the effect on the catalog index.

18 min read Sort rules · Product pinning · Catalog index Magento 2.4.x Open Source

1. What category merchandising means and why it drives revenue

Category merchandising describes deliberately controlling product order on category pages, guided by business goals instead of a neutral default sort. A product with high margin, currently strong availability, and high seasonal relevance should rank higher on a heavily trafficked category page than a product that does not meet those criteria, regardless of alphabet or raw creation date.

In Magento Commerce, the Visual Merchandiser handles this task with a graphical drag and drop interface. Magento Open Source lacks that tool, which tempts many projects to ignore merchandising rules entirely and sort products only by position or name. That is avoidable lost revenue, because the technical building blocks for rule-based category merchandising, collection plugins, custom sort attributes and index extensions, are fully available even without a Commerce license.

The economic leverage is genuinely measurable: category pages are often the entry point for customers without a specific product in mind, and the first visible products disproportionately influence the purchase decision. Good category merchandising deliberately directs that attention toward products that benefit the business most, without sacrificing relevance for the customer.

2. Sort order: static position vs. dynamic rules

Magento's default sort relies on a static position value per product category assignment, stored in catalog_category_product. These position values are maintained manually in the admin and do not change automatically when stock level or sales figures change. For small, rarely changing assortments, that is sufficient, but for dynamic catalogs with frequent price and stock changes, static positioning quickly becomes a maintenance burden.

Merchandising rules that react dynamically to current data need a different approach: instead of storing a fixed position, sort order gets computed at runtime from several attributes, for example a weighted combination of sales figures, margin and stock level. This computation can either happen directly in the product collection or, more performantly, already exist in the catalog index as a dedicated, precomputed sort attribute.

3. Implementing custom merchandising rules without Commerce

The most pragmatic entry point into custom merchandising rules is a plugin on the category page's product collection that applies a custom, computed sort logic instead of default attribute sorting when a specific sort option is selected. For performance critical cases, a cron job that periodically recalculates a sort score attribute and stores it in the product index is preferable, so that the actual sorting at runtime becomes a simple ORDER BY, or a sort on an indexed field.


<?php

declare(strict_types=1);

namespace Mironsoft\CategoryMerchandising\Cron;

use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Psr\Log\LoggerInterface;

/**
 * Recalculates a merchandising score attribute for every salable product.
 */
final class RecalculateMerchandisingScore
{
    private const SCORE_ATTRIBUTE = 'merchandising_score';

    /**
     * @param CollectionFactory $collectionFactory Product collection factory
     * @param ProductRepositoryInterface $productRepository Product repository for saving updates
     * @param LoggerInterface $logger Logger for cron diagnostics
     */
    public function __construct(
        private readonly CollectionFactory $collectionFactory,
        private readonly ProductRepositoryInterface $productRepository,
        private readonly LoggerInterface $logger,
    ) {
    }

    /**
     * Computes and persists a weighted merchandising score per product.
     *
     * @return void
     */
    public function execute(): void
    {
        $collection = $this->collectionFactory->create();
        $collection->addAttributeToSelect(['sales_count_30d', 'margin_percent', 'qty']);

        foreach ($collection as $product) {
            $score = (float) $product->getData('sales_count_30d') * 0.5
                + (float) $product->getData('margin_percent') * 0.3
                + min((float) $product->getData('qty'), 100) * 0.2;

            $product->setData(self::SCORE_ATTRIBUTE, round($score, 2));

            try {
                $this->productRepository->save($product);
            } catch (\Exception $exception) {
                $this->logger->error('Merchandising score update failed: ' . $exception->getMessage());
            }
        }
    }
}

This class shows the basic pattern for dynamic merchandising rules: several business signals are combined into a single weighted sort value, which then lands as a regular product attribute in the index, sortable there performantly. The concrete weights (0.5, 0.3, 0.2 in the example) should be aligned with the merchandising team and reviewed regularly.

4. Product pinning and rule-based hiding

Beyond the general sort logic, merchandising rules often need a way to manually pin individual products to a fixed position, for example for a current campaign, regardless of the computed score. The cleanest way to do this is an additional attribute such as pinned_position, which takes priority over the computed score inside the sort logic.

For deliberately hiding products, for example discontinued stock that is still sellable but should no longer be promoted, a separate visibility flag is a better fit than hard removing the category assignment. That way the product remains reachable via direct links and search, but deliberately disappears from category navigation. Both mechanisms, pinning and hiding, should be treated as standalone merchandising rules that apply before score based sorting, not as special cases within the same computation.

5. Rules based on stock level, margin and novelty

Three signals deliver the biggest practical effect for merchandising rules: stock level, margin and product novelty. Low stock should tend to push a product down, to avoid disappointment from sellouts, while very high stock (potential overstock) should push a product up, to encourage sell through. These two effects seem to contradict each other but can be cleanly separated by weighting stock level not linearly but with a curve that scores a moderate stock level as neutral.

Margin based merchandising rules need to be handled with care: overly aggressive favoring of high margin products can be perceived as manipulation by customers specifically searching for a particular product, if actual relevance suffers as a result. A proven compromise is to use margin only as a small factor within a larger score formula, instead of making it the dominant sort criterion. Product novelty, measured by creation date, is usually less problematic and can be modeled well with a time decaying bonus that favors new products for a few weeks before automatically expiring.

6. Anchor vs. non-anchor categories and generated lists

For the technical implementation of merchandising rules, the difference between anchor and non-anchor categories matters. Anchor categories automatically include products from subcategories and use the catalog index for the product list, while non-anchor categories only show directly assigned products and rely more heavily on the database collection. Custom sort scores work in both cases, but the performance characteristics differ noticeably.


<?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\ResourceModel\Product\Collection">
        <plugin name="mironsoft_merchandising_sort_order"
                type="Mironsoft\CategoryMerchandising\Plugin\ApplyMerchandisingSortPlugin"
                sortOrder="20"/>
    </type>
</config>

For anchor categories with many subcategories, it is worth precomputing the sort score attribute fully in the index, instead of assembling it from several raw attributes at runtime, since the number of products to sort here can be significantly larger than in a single non-anchor category.

7. A/B testing sort strategies

Merchandising rules without success measurement remain guesswork. A clean test compares two sort strategies over the same period, either through a real session level A/B split or a time shifted comparison with seasonal control. Relevant metrics are the click through rate on products in the top positions, category page conversion rate, and, especially important for merchandising rules with a margin component, the average contribution margin per order generated through that category page.

A common mistake in testing is looking only at conversion rate while ignoring contribution margin. A sort strategy that slightly lowers conversion rate but notably raises average contribution margin can be more beneficial for the business overall than a strategy optimized purely for maximum clicks.

8. Performance impact of complex sort rules

Complex merchandising rules that combine several raw attributes at runtime noticeably slow down the product list, especially for large categories with many subcategories. The most reliable performance lever is not computing the final sort value at runtime, but determining it in advance via a cron job or indexer and storing it as a simple, sortable attribute in the catalog index.

A second lever concerns update frequency: not every component of merchandising rules needs to update on the same cadence. Stock level changes frequently and should feed in near real time, while margin changes rarely and stays sufficiently current even with daily updates. Treating these different update frequencies separately reduces computational load significantly compared to a blanket recalculation of every signal on the same interval.

9. Merchandising approaches compared

The following table compares common approaches to merchandising rules in Magento Open Source.

Approach Effort Dynamism Typical use
Static position Very low No automatic reaction Small, stable assortments
Cron job score in the index Medium Daily/hourly current Larger, dynamic catalogs
Runtime collection plugin High (performance risk) Near real time Small, high priority categories
Manual pinning Low Needs manual upkeep Campaigns, promoted products

In practice, successful projects usually combine a cron job score as the baseline with manual pinning for campaign products, rather than relying on a single approach.

Mironsoft

Magento merchandising, catalog index and conversion optimization

Do your category pages show the right products first?

We build rule-based merchandising logic for Magento Open Source, with score computation in the index, product pinning for campaigns, and measurable A/B testing of sort strategy.

Score model

Weighted combination of stock level, margin and sales figures

Product pinning

Fixed positions for campaign products without a Commerce license

A/B testing

Measurable comparisons including contribution margin per order

10. Summary

Merchandising rules for categories can be fully implemented in Magento Open Source without a Commerce license, once position values, collection plugins and the catalog index are understood as one connected system. A weighted score from stock level, margin and sales figures, precomputed via cron job and stored in the index, forms the performant baseline, complemented by manual pinning for campaign products.

The decisive difference between successful and ineffective category merchandising lies in measurement: click through rate, conversion rate and, above all, contribution margin per order show whether a sort strategy actually benefits the business. Consistently comparing these metrics, instead of relying on a sort order set up once and left alone, produces a lasting advantage over competitors with purely alphabetical or position based sorting.

Category Merchandising Rules in Magento 2 — Key Takeaways

Score instead of static position

Weighted combination of business signals, precomputed and indexed.

Separate pinning from hiding

Standalone rules ahead of score based sorting, not a special case within it.

Performance through precomputation

Cron job instead of runtime computation, different update cadences per signal.

Measure success

Compare click through rate, conversion and contribution margin per order, not just clicks.

11. FAQ: Category Merchandising Rules in Magento 2

1What are merchandising rules?
Rules aligning product order with business goals like margin and stock level instead of a neutral default sort.
2Do you need Commerce?
No, rule based merchandising works with plugins, attributes and cron jobs in Open Source too.
3How to compute the score?
Weighted combination of sales figures, margin and stock level, computed via cron job and indexed.
4How does product pinning work?
Via an additional attribute that takes priority over the computed score and is maintained manually.
5Low stock in sorting?
Tends to push down, very high stock tends to push up, with a non-linear curve.
6How much margin to include?
As a small factor, not the dominant criterion, otherwise it can feel manipulative.
7Anchor vs. non-anchor?
Anchor includes subcategories via the index, non-anchor shows only directly assigned products.
8How to test a sort strategy?
Via A/B split, measured by click through rate, conversion and contribution margin per order.
9Why not compute at runtime?
Noticeably slows the product list, precomputing via cron job and index is more performant.
10Same update frequency for all?
No, stock level near real time, margin sufficient with daily updates.