Question

I'm looking for a way to add a custom css class to each menu item into the Topmenu.

I already tried to it using interceptor method in Topmenu

public function beforeGetHtml(
    \Magento\Theme\Block\Html\Topmenu $subject,
    $outermostClass = '',
    $childrenWrapClass = '',
    $limit = 0
) {
    $rootId = $this->storeManager->getStore()->getRootCategoryId();
    $storeId = $this->storeManager->getStore()->getId();
    /** @var \Magento\Catalog\Model\ResourceModel\Category\Collection $collection */
    $collection = $this->getCategoryTree($storeId, $rootId);
    $currentCategory = $this->getCurrentCategory();
    $mapping = [$rootId => $subject->getMenu()];  // use nodes stack to avoid recursion
    foreach ($collection as $category) {
        if (!isset($mapping[$category->getParentId()])) {
            continue;
        }
        /** @var Node $parentCategoryNode */
        $parentCategoryNode = $mapping[$category->getParentId()];

        $categoryNode = new Node(
            $this->getCategoryAsArray($category, $currentCategory),
            'id',
            $parentCategoryNode->getTree(),
            $parentCategoryNode
        );
        $parentCategoryNode->addChild($categoryNode);

        $mapping[$category->getId()] = $categoryNode; //add node in stack
    }
}

and then:

private function getCategoryAsArray($category, $currentCategory)
{
    return [
        'name' => $category->getName(),
        'id' => 'category-node-' . $category->getId(),
        'class' => 'MY_CUSTOM_CLASS',
        'url' => $this->catalogCategory->getCategoryUrl($category),
        'has_active' => in_array((string)$category->getId(), explode('/', $currentCategory->getPath()), true),
        'is_active' => $category->getId() == $currentCategory->getId()
    ];
}

However the classes are added only to submenu items instead of add to parent as well.

Thank you!

Was it helpful?

Solution

Try following code:

  1. app/code/[VendorName]/[ModuleName]/registration.php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    '[VendorName]_[ModuleName]',
    __DIR__
);
  1. app/code/[VendorName]/[ModuleName]/etc/module.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="[VendorName]_[ModuleName]" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Theme" />
        </sequence>
    </module>
</config>
  1. app/code/[VendorName]/[ModuleName]/etc/di.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Theme\Block\Html\Topmenu" type="[VendorName]\[ModuleName]\Block\Html\Topmenu" />
</config>
  1. app/code/[VendorName]/[ModuleName]/Block/Html/Topmenu.php
<?php

namespace [VendorName]\[ModuleName]\Block\Html;

class Topmenu extends \Magento\Theme\Block\Html\Topmenu
{
    protected function _getMenuItemClasses(\Magento\Framework\Data\Tree\Node $item)
    {
        $classes = [];

        $classes[] = 'level' . $item->getLevel();
        $classes[] = $item->getPositionClass();

        if ($item->getIsFirst()) {
            $classes[] = 'first';
        }

        if ($item->getIsActive()) {
            $classes[] = 'active';
        } elseif ($item->getHasActive()) {
            $classes[] = 'has-active';
        }

        if ($item->getIsLast()) {
            $classes[] = 'last';
        }

        if ($item->getClass()) {
            $classes[] = $item->getClass();
        }

        if ($item->hasChildren()) {
            $classes[] = 'parent';
        }

        $classes[] = 'MY_CUSTOM_CLASS';

        return $classes;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top