4

How to display the category image in the topmenu?

I need to edit/overwrite the block file, but I can't get the code to actually extract the image.

  • you have to override Topmenu.php file. – Rakesh Jesadiya Aug 16 '16 at 11:57
  • Yes, that I know, it is the code to overwrite it with that I need – Memes Aug 16 '16 at 13:11
  • How about your current issue? There is an update from my answer, please check again. – Khoa TruongDinh Sep 3 '16 at 0:37
11

Look at

vendor/magento/module-catalog/etc/di.xml

<type name="Magento\Theme\Block\Html\Topmenu">
        <plugin name="catalogTopmenu" type="Magento\Catalog\Plugin\Block\Topmenu" />
</type>

As we can see, Magento uses Plugin - Magento\Catalog\Plugin\Block\Topmenu to override some methods of Magento\Theme\Block\Html\Topmenu class. We should see more vendor/magento/module-catalog/Plugin/Block/Topmenu.php.

We can disable the default plugin in your module and re-build your own Plugin which follow the logic of Magento\Catalog\Plugin\Block\Topmenu class.

Vendor\Module\etc\di.xml

 <type name="Magento\Theme\Block\Html\Topmenu">
        <plugin name="catalogTopmenu" disabled="true" />
        <plugin name="catalogTopmenuImage" type="Vendor\Module\Plugin\Block\Topmenu" />
 </type>

From my understanding, we should to rebuild some methods:

vendor/magento/module-catalog/Plugin/Block/Topmenu.php

...

/**
 * Convert category to array
 *
 * @param \Magento\Catalog\Model\Category $category
 * @param \Magento\Catalog\Model\Category $currentCategory
 * @return array
 */
private function getCategoryAsArray($category, $currentCategory)
{
    return [
        'name' => $category->getName(),
        'id' => 'category-node-' . $category->getId(),
        'url' => $this->catalogCategory->getCategoryUrl($category),
        'has_active' => in_array((string)$category->getId(), explode('/', $currentCategory->getPath()), true),
        'is_active' => $category->getId() == $currentCategory->getId(),
        'image_url' => $category->getImageUrl(), // Get image URL
    ];
}

/**
 * Get Category Tree
 *
 * @param int $storeId
 * @param int $rootId
 * @return \Magento\Catalog\Model\ResourceModel\Category\Collection
 * @throws \Magento\Framework\Exception\LocalizedException
 */
protected function getCategoryTree($storeId, $rootId)
{
    /** @var \Magento\Catalog\Model\ResourceModel\Category\Collection $collection */
    $collection = $this->collectionFactory->create();
    $collection->setStoreId($storeId);
    $collection->addAttributeToSelect('name');
    $collection->addAttributeToSelect('image'); // Select image
    $collection->addFieldToFilter('path', ['like' => '1/' . $rootId . '/%']); //load only from store root
    $collection->addAttributeToFilter('include_in_menu', 1);
    $collection->addIsActiveFilter();
    $collection->addUrlRewriteToResult();
    $collection->addOrder('level', Collection::SORT_ORDER_ASC);
    $collection->addOrder('position', Collection::SORT_ORDER_ASC);
    $collection->addOrder('parent_id', Collection::SORT_ORDER_ASC);
    $collection->addOrder('entity_id', Collection::SORT_ORDER_ASC);

    return $collection;
}

...

You can then use $child->getDataByKey('image_url') in Topmenu::_getHtml() (via an extending module, as explained here). For example, the below will replace the category name with the image (if there is one):

protected function _getHtml(
    \Magento\Framework\Data\Tree\Node $menuTree,
    $childrenWrapClass,
    $limit,
    $colBrakes = []
) {
    $html = '';

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

    $counter = 1;
    $itemPosition = 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);
        }

        if (count($colBrakes) && $colBrakes[$counter]['colbrake']) {
            $html .= '</ul></li><li class="column"><ul>';
        }

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

        // Use category image instead of name if available
        $html .= $child->getDataByKey('image_url') ? '<img src="' . $child->getDataByKey('image_url') . '">' : $this->escapeHtml($child->getName());

        $html .= '</span></a>' . $this->_addSubMenu(
            $child,
            $childLevel,
            $childrenWrapClass,
            $limit
        ) . '</li>';
        $itemPosition++;
        $counter++;
    }

    if (count($colBrakes) && $limit) {
        $html = '<li class="column"><ul>' . $html . '</ul></li>';
    }

    return $html;
}
| improve this answer | |
  • I saw that already, but what is the code to get the image? – Memes Aug 16 '16 at 13:12
  • We can disable the default plugin in your module and re-build your own Plugin which follows the logic of Magento\Catalog\Plugin\Block\Topmenu class. – Khoa TruongDinh Aug 16 '16 at 13:31
  • I do not have any folder vendor/magento/module-catalog/Plugin/Block. In vendor/magento/module-catalog/Plugin , I just got Model – Memes Aug 17 '16 at 1:59
  • I used Magento version 2.1: vendor/magento/module-catalog/Plugin/Block/Topmenu.php. Please check again. – Khoa TruongDinh Aug 17 '16 at 2:25
  • 1
    A solution with the same principle but cleaner can be found here: catgento.com/2017/03/20/… . Actually, it's not necessary to rewrite all the code, because the _getHtml function calls itself again and again. – PauGNU Apr 22 '17 at 4:11

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.