1

I want to add "natural sorting" functionality to Magento admin grid. I would like to understand how the Magento handles admin grid sorting so I know where to start. What functions/files etc. does Magento use to determine the order of values in the admin panel?

3
  • will you please explain more Commented Mar 19, 2017 at 11:46
  • I want to add a functionality like "natsort" in PHP, to admin panel sorting (catalog, sales, etc.) . There is very little info about this online. I found this code that in theory should help me: (magento.stackexchange.com/a/124324/51693), but I do not understand how to implement it. Commented Mar 19, 2017 at 12:03
  • _build_sorter function, to be exact Commented Mar 19, 2017 at 12:35

2 Answers 2

1

With grids in Magento, the database driver controls the sorting of data. The collection is passed the sort column and direction of sort (asc or desc) or the default is used. The data in the collection returned is output in that same order.

To change the sorting functionality in your own custom grid, you can just alter modify the _prepareCollection method to adjust the collection to what order you want.

In my custom grid, I would probably do something like this:

class My_Module_Block_Adminhtml_Module_Index_Grid extends Mage_Core_Adminhtml_Block_Widget_Grid
{
    // ...

    protected function _prepareCollection() {
        $myCollection = Mage::getModel('my_module/model')->getCollection();
        $this->setCollection($myCollection);
        parent::_prepareCollection();
    }

    // ...

    protected function _afterLoadCollection() {
        usort($this->_collection, array($this, '_natSortCollection'));
        return parent::_afterLoadCollection();
    }

    protected function _natSortCollection($a, $b) {
        return strnatcmp($a->getField(), $b->getField());
    }
}

Edit

See the updated code below to do what you want.

protected function _afterLoadCollection()
{
    $items = $this->_collection->getItems();
    /* To prevent duplicate items, and to not reload from the database
       we have to remove each item individually without "clear()"ing
       the collection. */
    array_walk(array_keys($items), array($this->_collection, 'removeItemByKey'));
    usort($items, array($this, '_natSortCollection'));

    /* Now add each item back to the collection in the new order */
    array_walk($items, array($this->_collection, 'addItem'));
    return parent::_afterLoadCollection();
}

protected function _natSortCollection($itemA, $itemB)
{
    return strnatcmp($itemA->getName(), $itemB->getName());
}
11
  • Thanks for the answer! Your example code is for a custom module. What changes are needed so that I could put it straight in the: \core\Mage\Adminhtml\Block\Widget\Grid.php ? Commented Mar 21, 2017 at 12:16
  • 1
    The above code was only meant to guide you, not be a full-fledged working example. I would never suggest you overwrite the core files, even temporarily for testing purposes. For the Mage/Adminhtml/Block/Catalog/Product/Grid.php file, you should only have to add the _afterLoadCollection and _natSortCollection methods. Without knowing the error you're running in to, I won't be able to help much
    – Brett
    Commented Mar 21, 2017 at 12:49
  • 1
    The core grid already has the _prepareCollection method so you don't need to add that. The _afterLoadCollection should be being called automatically. I would check the parent of the grid and make sure there is a reference to a call to _afterLoadCollection in it; otherwise, it won't work (but the feature exists in 1.9).
    – Brett
    Commented Mar 23, 2017 at 1:59
  • 1
    Just downloaded Magento 1.7.0.2. Mage/Adminhtml/Block/Catalog/Product/Grid extends Mage/Adminhtml/Block/Widget/Grid. The _prepareCollection method calls parent::_prepareCollection at the end which will call _afterLoadCollection. If you add the _afterLoadCollection method to the Mage/Adminhtml/Block/Catalog/Product/Grid it should execute. My guess here is that the collection is ignoring the reordering of items. Instead, you may need to create a new Varien_Data_Collection and manually add the items in the order you want.
    – Brett
    Commented Mar 23, 2017 at 20:29
  • 1
    So I just edited my post with another code snippet that works in Magento 1.9 and should work in Magento 1.7. Hope it helps.
    – Brett
    Commented Mar 23, 2017 at 20:51
0

From your comments in the previous answer, it may behoove you to use the MySQL SOUNDEX(<column_name>) function to naturally sort your data. You can even then add a LENGTH(<column_name>) call and finally <column_name>. For example:

    $this->getCollection()->addWebsiteNamesToResult();
    $this->getCollection()->getSelect()->reset(Zend_Db_Select::ORDER);
    $this->getCollection()->getSelect()->order(new Zend_Db_Expr(
        sprintf(
            'SOUNDEX(%1$s) %2$s, LENGTH(%1$s) %2$s, %1$s %2$s',
            $this->getParam($this->getVarNameSort(), $this->_defaultSort),
            $this->getParam($this->getVarNameDir(), $this->_defaultDir)
        )
    ));

This isn't perfect, but there isn't "natural sorting" in MySQL. So it's kind of as close as you can get to it. Using a separate method to alter the collection would add a layer of complexity and require work-arounds to make changing the sort column and direction to work 100% of the time.

This is just an alternative to the custom sort method above.

10
  • Hmm, either I'm implementing it wrong or it doesn't seem to be working, although I admit that I was not able to fully wrap my head around how the SOUNDEX and LENGHT together would create something similar to natsort. Currently I'm placing the code at the very end of _prepareCollection() right after the $this->getCollection()->addWebsiteNamesToResult(); that was already there. Commented Mar 24, 2017 at 9:56
  • That's where I had that code and it worked for me. Basically SOUNDEX() orders it alphabetically, then the LENGTH() is there to help with things with numbers after them (e.g. "Random String 1", "Random String 2", "Random String 11") and finally it sorts it as it normally would. So instead of getting "Random String 1", "Random String 11", "Random String 2", you get a properly ordered list.
    – Brett
    Commented Mar 24, 2017 at 12:57
  • Really odd, I must be doing something wrong then... Is this how it is supposed to look like link ? just to be sure- this is the only edit needed for this method to work, right? Commented Mar 24, 2017 at 20:34
  • Yeah, that should be all that's necessary. It's what I did and it worked.
    – Brett
    Commented Mar 25, 2017 at 0:08
  • Is it possible that I am missing something in the Zend_Db_Expr? Commented Mar 25, 2017 at 8:41

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.