0

Like this question: Magento: HOW-TO add active products in a drop-down in Main Navigation Menu

...I want to list the products from a category in the main menu. I have attempted to use the code provided but it's still not working. I'm using Magento ver. 1.7.0.2 so I think this may be the issue.

Any help would be appreciated.

Community
  • 1
  • 1
GarethWyn
  • 51
  • 1
  • 6
  • Please define "not working" more precisely. Do you get errors? If so, post the error messages – Jürgen Thelen Jul 12 '13 at 15:51
  • OK - So I've now worked out that it doesn't appear to be working because the file I need to be editing is **Mage_Page_Block_Html_Topmenu** but I can't apply the code from the original question (link above) because it doesn't contain the correct class. Any ideas? – GarethWyn Jul 15 '13 at 10:35

1 Answers1

1

I had the same problem and after some hours I have a solution now. I'm using Magento 1.9.1 and I also needed to edit the Topmenu.php file. Probably it's not the best way to do it, but it works. I tried to comment everything, so maybe it's easier to understand.

I changed '_getHtml' function to include the products and to change classes of 'li'-tags, if necessary:

protected function _getHtml(Varien_Data_Tree_Node $menuTree, $childrenWrapClass, $correctClasses = 0)
{
    $html = '';

    $children = $menuTree->getChildren();
    $parentLevel = $menuTree->getLevel();
    $childLevel = is_null($parentLevel) ? 0 : $parentLevel + 1;

    $counter = 1;
    $childrenCount = $children->count();

    $parentPositionClass = $menuTree->getPositionClass();
    $itemPositionClassPrefix = $parentPositionClass ? $parentPositionClass . '-' : 'nav-';

    foreach ($children as $child) {

        $child->setLevel($childLevel);
        $child->setIsFirst($counter == 1);
        $child->setIsLast($counter == $childrenCount);
        $child->setPositionClass($itemPositionClassPrefix . $counter);

        $outermostClassCode = '';
        $outermostClass = $menuTree->getOutermostClass();

        if ($childLevel == 0 && $outermostClass) {
            $outermostClassCode = ' class="' . $outermostClass . '" ';
            $child->setClass($outermostClass);
        }

        // avoid 'last'-class if there are products after categories
        $renderedAttributes = $this->_getRenderedMenuItemAttributes($child);
        if($correctClasses = 1) {
            $renderedAttributes = str_replace(' last', '', $renderedAttributes);
        }

        // add 'category' class to category elements
        $renderedAttributes = str_replace('class="', 'class="type-category ', $renderedAttributes);

        $html .= '<li ' . $renderedAttributes . '>';
        $html .= '<a href="' . $child->getUrl() . '" ' . $outermostClassCode . '><span>' . $this->escapeHtml($child->getName()) . '</span></a>';

        // check if there are more categories or products inside
        $hasProducts = $this->hasProducts($child);
        if ($child->hasChildren() || $hasProducts) {

            if (!empty($childrenWrapClass)) {
                $html .= '<div class="' . $childrenWrapClass . '">';
            }

            // build ul-wrapper
            $html .= '<ul class="level' . $childLevel . '">';

            // if categories and products are in this category
            if($child->hasChildren() && $hasProducts) {
                $correctClasses = 1;
                $html .= $this->_getHtml($child, $childrenWrapClass, $correctClasses);
                $html .= $this->getProducts($child, $childLevel, $correctClasses);
            // if only categories are in this category
            } elseif($child->hasChildren()) {
                $html .= $this->_getHtml($child, $childrenWrapClass);
            // if only products are in this category
            } elseif($hasProducts) {
                $html .= $this->getProducts($child, $childLevel);
            }
            $html .= '</ul>';

            if (!empty($childrenWrapClass)) {
                $html .= '</div>';
            }
        }
        $html .= '</li>';

        $counter++;
    }

    return $html;
}

Additionally I wrote 3 new functions to process everything.

One new small function to get the product collection from current category:

// get product collection    
protected function getProductCollection($child) {
    // get current category
    $catId = str_replace('category-node-', '', $child->getId());
    $curCategory = Mage::getModel('catalog/category')->load($catId);

    // get prouct collection from current category
    return Mage::getResourceModel('catalog/product_collection')->addCategoryFilter($curCategory)->setOrder('position','ASC');
}

A function to check if there are any products in current category:

// check if there are products in this category
protected function hasProducts($child) {
    // get number of products in current (sub-)category
    $productCount = $this->getProductCollection($child)->count();

    if($productCount > 0) {
        return 1;
    } else {
        return 0;
    }
}

And one function to build the html for the product list items:

// get product html
protected function getProducts($child, $level, $correctClasses = 0) {
    $productCollection = $this->getProductCollection($child);

    // set product counter
    $p = 1;

    // get number of products in current (sub-)category
    $productCount = $productCollection->count();

    $pChild = '';
    if ($productCount > 0) {
        $level++;
        foreach ($productCollection as $product) {

            // get current product in loop
            $curProduct = Mage::getModel('catalog/product')->load($product->getId());

            // check if current product in loop is activated
            if ($curProduct->getStatus()) {

                // build list-item with classes
                $pChild .= '<li';
                $pChild .= ' class="type-product level'.$level;
                if ($p == 1 && $correctClasses == 0) {
                    $pChild .= ' first';
                }
                if ($p == $productCount) {
                    $pChild .= ' last';
                }
                $pChild .= '">'."\n";
                $pChild .= ' <a href="'.$curProduct->getProductUrl().'">'.$this->htmlEscape($curProduct->getName()).'</a>'."\n";
                $pChild .= '</li>';

                // increment product counter
                $p++;
            }
        }
    }

    return $pChild;
}

Hopefully it helps someone! If someone has suggestions to write it more clean or to add some functionality, post something or comment it! :)

sagacity
  • 341
  • 3
  • 7