2

I want to display the child categories of a category and I want to display them in the order they're in in the admin panel. I've read a lot about it and the simplest way seems to be to use getChildrenCategories as that returns the children in the right order.

However, I've found this only returns categories with Include in navigation set to yes whereas all the child categories have this set to no in my case.

I've tracked this down to _loadNodes in flat.php. I've included the relevant code from it below and you can see the hard coded where statement in the penultimate line.

My question is simply how can I stop this? Is there a simple way?

Thanks

protected function _loadNodes($parentNode = null, $recursionLevel = 0, $storeId = 0, $onlyActive = true)
{
    $_conn = $this->_getReadAdapter();
    $startLevel = 1;
    $parentPath = '';
    if ($parentNode instanceof Mage_Catalog_Model_Category) {
        $parentPath = $parentNode->getPath();
        $startLevel = $parentNode->getLevel();
    } elseif (is_numeric($parentNode)) {
        $selectParent = $_conn->select()
            ->from($this->getMainStoreTable($storeId))
            ->where('entity_id = ?', $parentNode)
            ->where('store_id = ?', $storeId);
        $parentNode = $_conn->fetchRow($selectParent);
        if ($parentNode) {
            $parentPath = $parentNode['path'];
            $startLevel = $parentNode['level'];
        }
    }
    $select = $_conn->select()
        ->from(
            array('main_table' => $this->getMainStoreTable($storeId)),
            array('entity_id',
                new Zend_Db_Expr('main_table.' . $_conn->quoteIdentifier('name')),
                new Zend_Db_Expr('main_table.' . $_conn->quoteIdentifier('path')),
                'is_active',
                'is_anchor'))

        ->where('main_table.include_in_menu = ?', '1')
        ->order('main_table.position');

1 Answer 1

2

You have two options: rewrite or observer.

Rewrite:

The rewrite DOM structure for this is a bit tricky because it is a resource model:

<global>
    <models>
        <catalog_resource>
            <rewrite>
                <flat>Your_Module_Model_Resource_Flat</flat><!-- for example -->
            </rewrite>
        </catalog_resource>
    </models>
</global>

Then in the class file for Your_Module_Model_Resource_Flat you would extend from the core flat category resource model and override this method, changing what you need to change.


Observer:

Register an observer in the frontend for the catalog_category_flat_loadnodes_before event in the frontend, which you can see is dispatched just below the code you referenced. In fact it is preceded by a note stating, "Allow extensions to modify select (e.g. add custom category attributes to select)". In your observing method, you will need to manipulate the select object which is passed in; I have untested peudo-y code here:

public function allowExcludedCategories($o)
{
    $select = $o->getSelect();
    $oWhere  = $select->getPart(Varien_Db_Select::WHERE);
    $select->setPart(Varien_Db_Select::WHERE,array_shift($oWhere));
}
4
  • Thanks @benmarks. I don't really want to rewrite it as it seems to be used elsehwere so I could add a new set of methods I guess. I've not done anything with observers before so I don't know if I can use that to provide a one-off change where I want it, I'll look into it.
    – PedroKTFC
    Apr 8, 2014 at 10:16
  • I've gone down the observer route but it always run so now my main menu includes everything. I need it only to fire for a particular call to getChildrenCategories. Is there a way of doing this (or having my observer know why it was triggered)? PS Your code was very close :o) but left a where clause starting with an ADD (I used a substr to remove it).
    – PedroKTFC
    Apr 8, 2014 at 23:09
  • You could make your observer a singleton and have it keep track of how many times it's been invoked. This is of course brittle as hell. Perhaps it's time to duplicate the _loadNodes() logic elsewhere and tie it into the context where you need it.
    – benmarks
    Apr 8, 2014 at 23:41
  • I just came across the following stackoverflow.com/questions/3340982/…. So I've simply set a session variable before I call getChildrenCategories, check if it's set in the observer, run the observer if so and clear it there too. Happy days!
    – PedroKTFC
    Apr 9, 2014 at 7:12

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.