5

When adding a product to a category, a sorting order value can be specified.

Imaging now we have a Category "P" set to "Anchor" and various categories "C1" and "C2" which are childs of "P".

How is the order of those products defined, which are only in the sub categories, but displayed when opening the parent category?

1

3 Answers 3

12

Take a look at Mage_Catalog_Model_Resource_Category_Indexer_Product::_refreshAnchorRelations specially these lines:

$position = 'MIN('.
            $adapter->getCheckSql(
                'cp.category_id = ce.entity_id',
                'cp.position',
                '(cc.position + 1) * ('.$adapter->quoteIdentifier('cc.level').' + 1) * 10000 + cp.position'
            )
        .')';

cc and ce are the same catalog_category_entity table and cp is catalog_category_product table.

A product can be in more than one child categories so the product position is a minimum between multiple values.
So basically the product position in the parent category is the minimum between the positions relative to each categories from the table catalog_category_product following this formula:

(child category position + 1) * (child category level + 1) * 10000 + ( product position in catalog_category_product + 1)  

[EDIT]
Conclusion: products in a category with a position higher in the tree will be shown before the ones below.

4
  • I can't compute by hand the exact position values indexed in catalog_category_product_index (I'm getting numbers much larger), but I get the idea.. @Marius, have you ever tried manually modifying these indexed position values? It doesn't seem to affect anything else when I mess around with them on a dev.
    – laketuna
    Sep 25, 2013 at 17:31
  • @Youn Sorry I've never tried to modify them
    – Marius
    Sep 25, 2013 at 18:44
  • do you understand the logic behind this formula? It's completely the opposite of how I would have weighed things.. unless, of course, you like to assign large position numbers.
    – laketuna
    Sep 25, 2013 at 20:30
  • You also have to adjust Mage_Catalog_Model_Resource_Category_Indexer_Product::reindexAll. May 27, 2014 at 11:56
1

As Marius and Andreas suggested, you have to rewrite the Mage_Catalog_Model_Resource_Category_Indexer_Product class to change the comportement of _refreshAnchorRelations and reindexAll.

For _refreshAnchorRelations

You have by default

'(cc.position + 1) * ('.$adapter->quoteIdentifier('cc.level').' + 1) * 10000 + cp.position'

change it for

'cp.position + 10000'

For reindexAll

You have by default

'('.$idxAdapter->quoteIdentifier('ce.position').' + 1) * '
.'('.$idxAdapter->quoteIdentifier('ce.level').' + 1 * 10000)'
.' + '.$idxAdapter->quoteIdentifier('cp.position')

change it for

'('.$idxAdapter->quoteIdentifier('cp.position').' + 10000)'

So it will only take the minimum product position. I have added + 10000 because some of our customers enter a negative position.

1
  • hm I do not want to change anything - the question was just about knowing how that stuff works :) thanks anyways
    – Alex
    Oct 13, 2016 at 14:39
0

Note there is a huge mistake between Mage_Catalog_Model_Resource_Category_Indexer_Product::_refreshAnchorRelations() and Mage_Catalog_Model_Resource_Category_Indexer_Product::reindexAll() methods, which will obviously lead to some strange behaviors:

In _refreshAnchorRelations():

$position = 'MIN('.
    $adapter->getCheckSql(
        'cp.category_id = ce.entity_id',
        'cp.position',
        '(cc.position + 1) * ('.$adapter->quoteIdentifier('cc.level').' + 1) * 10000 + cp.position'
    )
.')';

Note that here we have brackets that are surrounding the expression, which gives us this result: (cc.position + 1) * (cc.level + 1) * 10000 + cp.position.

_refreshAnchorRelations() is a protected method called by the following three methods in the same class:

  • catalogProductSave()
  • catalogProductMassAction()
  • catalogCategorySave()

These last are called when you are saving a category or a product in the backend.

In reindexAll():

$position = 'MIN('.
    $idxAdapter->getCheckSql(
        'ca.category_id = ce.entity_id',
        $idxAdapter->quoteIdentifier('cp.position'),
        '('.$idxAdapter->quoteIdentifier('ce.position').' + 1) * '
        .'('.$idxAdapter->quoteIdentifier('ce.level').' + 1 * 10000)'
        .' + '.$idxAdapter->quoteIdentifier('cp.position')
    )
.')';

Here, the brackets surrounding the expression are positioned differently, which give us: (ce.position + 1) * (ce.level + 1 * 10000) + cp.position.

With the priority of the operators, the result obtained here will not be the same at all than with _refreshAnchorRelations() method.

As its name may suggest, the reindexAll() method occurs when you launch the reindexing of catalog_category_product index ("Category Products").

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.