3

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!

1 Answer 1

4

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;
    }
}
2
  • Is possible to add a dynamically style class? Just like an available field in cms category admin? Commented Mar 14, 2018 at 19:24
  • how do you call _getMenuItemClasses()? what will be the variable Commented Jun 23, 2020 at 9:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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