5

We've been importing a lot of data into Magento CE using Magmi. It's creating our category tree for us.

However, we'd like to display our category tree in alphabetical order. Is there a way to sort the entire tree (20 top level categories, 100's of sub-categories in the tree) into alphabetical order?

Edit: for clarity, the sorting needs to be done programmatically in some way

  • Do you have only one language in your store? I mean is it ok to run a 'one time only' script that alters the position of the categories in order to have the alphabetically or the sorting must be alphabetically even if in the backend is not? – Marius Jul 12 '13 at 8:41
  • Where do you need it reordered, in the admin/frontend/both? – Jasuten Jul 12 '13 at 8:59
  • There is only one language in the store. The frontend needs to be alphabetical. It doesn't matter about the backend. New categories will be added every day by an import script so the solution needs to be runnable on a cron, or work on the frontend during page load. – fistameeny Jul 13 '13 at 10:57
  • How did this question not get any up votes until now??? Does anyone in magento.stackexchange vote on anything!?!?!??!? – SR_Magento May 27 '14 at 10:58
5

If you have only one language so there is only one way to sort categories alphabetically I recommend changing their position so you will let Magento do its magic.
If you have more than one language, or you need the categories sorted alphabetically only on frontend ignore this answer.

Here is a small script that sets the category position.
$parentId - it the category id for which we sort the children
$conn - is a database connection because there is no need to involve the full internal API for changing only one field. we can run queries directly on the DB. I know that this is a big 'NO-NO' but in this case it works.

function orderCategories($parentId, $conn){
    //The position field is in the main category table
    //add prefix if you have one
    $table = 'catalog_category_entity';
    //get the children for a specific category id
    $collection = Mage::getModel('catalog/category')->getCollection()
        ->addAttributeToSelect('name')
        ->addFieldToFilter('parent_id', $parentId);
    $categories = array();
    foreach ($collection as $category){
        //in case there are 2 categories with the same name we shouldn't skip them
        //but there shouldn't be
        $categories[$category->getName().'_'.$category->getId()] = $category->getId();
    }
    //sort categories by name
    ksort($categories);
    //set their position
    $position = 1;
    foreach ($categories as $name=>$id){
        $q = "UPDATE {$table} SET `position` = {$position} where `entity_id` = {$id}";
        $conn->query($q);
        $position++;
        //sort the current category children by calling the same function recursively
        orderCategories($id, $conn);
    }
}

Now that we have the function we just need to run it.
For this create a file. Let's call it categories.php and place it in the root of your Magento instance. The file should contain this:

<?php
//set error reporting to see if something is wrong.
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 1);
define('MAGENTO_ROOT', getcwd());
$mageFilename = MAGENTO_ROOT . '/app/Mage.php';
require_once $mageFilename;
//set developer mode for additional debug functionality
Mage::setIsDeveloperMode(true);
//instantiate Mage_Core_Model_App;
Mage::app();
//set the initial parameters for the function
$root = 1;
$conn = Mage::getSingleton('core/resource')->getConnection('core_write');
//sort categories
orderCategories($root, $conn);

You can add the function defined above in the same file below these lines

Now you just need to call in the browser mysite.com/categories.php.
Clear the cache and reindex the category flat data and you are done.
Just to make sure, backup your database before trying it.

| improve this answer | |
  • Thanks! That seems to work. I can run it on a cron every night, so it should do the job nicely. – fistameeny Jul 12 '13 at 10:23
  • @Marius - what happens if there is more than 1 store language? Is there any possibility of doing this for 1 language and not caring about the other? – SR_Magento May 27 '14 at 11:51
  • @sr_magento. The category position is global, so if the categories need to be sorted alphabetically in 2 languages, this won't work. You have to find a way to sort them on display, regardless of their sorting in the backend. – Marius May 27 '14 at 11:55
  • @Marius so hypothetically if I did this on a metalanguage store the first / default store will be the one sorted? – SR_Magento May 27 '14 at 17:43
  • The script above will sort your categories by the name they have in the default values. If the names are different in other languages they might not appear in alphabetical order in that language. – Marius May 28 '14 at 6:17
2

There is also another way:

This will not save, but only return the categories in alphabetic order:

$categories = Mage::getResourceModel('catalog/category_collection')
                  ->addAttributeToSelect('name')
                  ->addAttributeToSort('name','ASC');
| improve this answer | |
  • This will get you the categories sorted by name, but it will get you ALL the categories. The level and parents will be ignored. You will have to process the result in order to rebuild the category tree. – Marius Dec 5 '13 at 7:40
0

you can drag and drop the category names in whatever order you want

| improve this answer | |
  • Indeed, but I need a programmatic way of doing it. There are far too many categories to do it manually. – fistameeny Jul 12 '13 at 6:16
0

First backup your topmenu.phtml then replace the following code in your new topmenu.phtml file

<?php $_helper = Mage::helper('catalog/category') ?>
<?php $_categories = $_helper->getStoreCategories() ?>
<?php

function array_sort($array, $on, $order=SORT_ASC){
    $new_array = array();
    $sortable_array = array();

    if (count($array) > 0) {
        foreach ($array as $k => $v) {
            if (is_array($v)) {
                foreach ($v as $k2 => $v2) {
                    if ($k2 == $on) {
                        $sortable_array[$k] = $v2;
                    }
                }
            } else {
                $sortable_array[$k] = $v;
            }
        }

        switch ($order) {
            case SORT_ASC:
            asort($sortable_array);
            break;
            case SORT_DESC:
            arsort($sortable_array);
            break;
        }

        foreach ($sortable_array as $k => $v) {
            $new_array[$k] = $array[$k];
        }
    }

    return $new_array;
}

?>
<?php
$layer = Mage::getSingleton('catalog/layer');
$_category = $layer->getCurrentCategory();
$currentCategoryId= $_category->getId();
?>
<div class="nav-container">
    <ul id="nav">
    <?php $_helper = Mage::helper('catalog/category') ?>
    <?php $_categories = $_helper->getStoreCategories() ?>
    <?php $currentCategory = Mage::registry('current_category') ?>
    <?php if (count($_categories) > 0){ ?>
        <?php foreach($_categories as $_category){ ?>
            <?php $_category = Mage::getModel('catalog/category')->load($_category->getId()) ?>
            <li><a href="<?php echo $_helper->getCategoryUrl($_category) ?>"><span><?php echo $_category->getName(); ?></span></a>
            <?php $catList = array();?>
            <?php $_subcategories = $_category->getChildrenCategories() ?>
            <?php foreach($_subcategories as $_subCategory){ ?>
                <?php $catList[] = array('name' => $_subCategory->getName(), 'url' => $_subCategory->getUrl(), 'id' => $_subCategory->getId());?>
            <?php } ?>
            <?php $catList = array_sort($catList, 'name', SORT_ASC);?>
            <ul>
            <?php if (count($catList) > 0){ ?>
                <?php $subcat=0?>
                <?php foreach($catList as $_subCategory){ ?>
                    <li><a href="<?php echo $_subCategory['url'] ?>"><span><?php echo $_subCategory['name'] ?></span></a>
                    <?php $subCatList = array();?>
                    <?php $_subSubCat = Mage::getModel('catalog/category')->load($_subCategory['id']);
                    $_subSubCategories = $_subSubCat->getChildrenCategories();?>
                    <?php foreach($_subSubCategories as $_subSubCategory){ ?>
                        <?php $subCatList[] = array('name' => $_subSubCategory['name'], 'url' => $_subSubCategory['url']);?>
                    <?php } ?>
                    <?php $subCatList = array_sort($subCatList, 'name', SORT_ASC);?>
                    <?php if (count($subCatList) > 0){ ?>
                        <ul>
                            <?php foreach($subCatList as $_subSubCat){ ?>
                                <li><a href="<?php echo $_subSubCat['url'] ?>"><span><?php echo $_subSubCat['name'] ?></span></a>
                            <?php } ?>
                            </li>
                        </ul>
                    <?php } ?>
                    </li>
                <?php } ?>

                <?php } ?>
            </ul>
            </li>
        <?php } ?>
    <?php } ?>
    </ul>
</div>
| improve this answer | |
  • I recommend to do the sorting only once in the database, doing it all the time costs a lot of performance. – Fabian Blechschmidt May 27 '14 at 10:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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