There is a feature in Magento where the category list can be sorted based on how the administrator sees fit. The problem is that most stores will want to sort the category list alphabetically. With a large catalog, the list quickly becomes a hassle to navigate and becomes a frustrating time sink.
The solution detailed here extends a Magento core file to sort the category list. It will sort the categories for both the Category Edit and the Product Edit Category tab.
Example of Alphabetically Sorted Magento Categories
The Quick Solution
The quick solution is to use the PHP method usort() on the array of categories in a Magento core file. Download the updated Magento core file here.
Place the folder in your /app/ directory, refresh the cache and recompile if needed.
Make note that the solution is for Magento 1.6.x, so if you have are on Magento 1.5 or earlier, it’s possible you will need to look at the solution below to implement the changes.
The Solution: A Closer Look
The two key areas to look for this problem would be in the adminhtml folder in both the core and design folders.
Let’s take a look at the design folder first, since the category tree is being built with Prototype. There is a bildCategoryTree function of particular interest. (Spelling error is that of Magento’s)
/app/design/adminhtml/default/default/template/catalog/product/edit/categories.phtml
function bildCategoryTree(parent, config){ if (!config) return null; if (parent && config && config.length){ for (var i = 0; i < config.length; i++){ config[i].uiProvider = Ext.tree.CheckboxNodeUI; var node; var _node = Object.clone(config[i]); if (_node.children && !_node.children.length) { delete(_node.children); node = new Ext.tree.AsyncTreeNode(_node); } else { node = new Ext.tree.TreeNode(config[i]); } parent.appendChild(node); node.loader = node.getOwnerTree().loader; if(config[i].children){ bildCategoryTree(node, config[i].children); } } } }
We are interested in the config variable, specifically. A quick console.log(config[i].children); will show that this is an array of the categories, but it isn’t sorted alphabetically. Doing a search on the bildCategoryTree method, we see that the config variable is being set as such:
/app/design/adminhtml/default/default/template/catalog/product/edit/categories.phtml
Ext.EventManager.onDocumentReady(function() { bildCategoryTree(root, <?php echo $this->getTreeJson() ?>); });
Using a Zend_Debug::dump() call or get_class($this) will tell us that $this is the class Mage_Adminhtml_Block_Catalog_Category_Tree.
With a little more snooping around in the class file we see that getTreeJson() encodes an array built in a protected class _getNodeJson. We will be adding a usort() call and creating our own function to compare arrays by their category name value.
/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tree.php Line 12
protected function _getNodeJson($node, $level = 0) { ... if ($node->hasChildren()) { $item['children'] = array(); if (!($this->getUseAjax() && $node->getLevel() > 1 && !$isParent)) { foreach ($node->getChildren() as $child) { $item['children'][] = $this->_getNodeJson($child, $level+1); } } // Sort the children category array usort($item['children'], array(get_class($this), 'compareChildText')); } if ($isParent || $node->getLevel() < 2) { $item['expanded'] = true; } return $item; } /** * Helper comparison function to return the category children array, sorted alphabetically * @param type $a * @param type $b * @return type */ static function compareChildText($a, $b) { return strnatcmp(strtolower($a['text']), strtolower($b['text'])); }
Once the new static function and the usort() call is added, your categories will be sorted as intended. This solution is not ideal, since it modifies the core directly. In your /app/local/ folder, create the same path to the file and copy it there. Consult the directory structure of the solution file if needed.
Keep in mind that since the list is always sorted alphabetically, you may no longer sort categories with the drag and drop feature. Odds are you don’t need this feature, but if you do use the custom sorting for the frontend, alphabetically sorting the list isn’t the proper solution for you.