3

a client has now a shop with the following structure of categories:

 Base
   Shop
   --Menu 1
     ---Sub menu 1
     ---Sub menu 2
   --Menu 2
   --etc

Normal magento would only show "shop" in the menu. But i would like to start skip this subcategory and shop directly Menu 1, menu 2 etc in the menu.

I could remove the shop step, but thats not good for google, and would relate in many redirects in the .htaccess because the client has many categories (100+)

2
+50

Let's create a new module. We'll call it StackExchange_Topmenu.
you will need the following files.
app/code/StackExchange/Topmenu/registration.php - the registration file

<?php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'StackExchange_Topmenu',
    __DIR__
);

app/code/StackExchange/Topmenu/etc/module.xml - the module declaration file

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="StackExchange_Topmenu" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Catalog"/>
        </sequence>
    </module>
</config>

app/code/StackExchange/Topmenu/etc/frontend/di.xml - di file to declare a plugin

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Theme\Block\Html\Topmenu">
        <plugin name="stackexchange-topmenu" type="StackExchange\Topmenu\Plugin\Topmenu" />
    </type>
</config>

app/code/StackExchange/Topmenu/Plugin/Topmenu.php - the actual plugin

<?php
namespace StackExchange\Topmenu\Plugin;

class Topmenu
{
    protected $storeManager;
    public function __construct(
        \Magento\Store\Model\StoreManagerInterface $storeManager
    )
    {
        $this->storeManager = $storeManager;
    }

    public function beforeGetHtml(
        \Magento\Theme\Block\Html\Topmenu $subject,
        $outermostClass = '',
        $childrenWrapClass = '',
        $limit = 0
    ) {
        $storeIds = [4, 5];//replace with the id of your store.
        $currentStoreId = $this->storeManager->getStore()->getId();
        if (in_array($currentStoreId, $storeIds)) {
            $menu = $subject->getMenu();
            $newMenuItems = [];
            $firstLevel = $menu->getChildren();
            foreach ($firstLevel as $menuItem) {
                /** @var \Magento\Framework\Data\Tree\Node $menuItem */
                //check if menu is a category
                if (substr($menuItem->getId(), 0, strlen('category-node-')) == 'category-node-') {
                    //get all child nodes (second level) and save them in an array
                    $subItems = $menuItem->getChildren();
                    foreach ($subItems as $subItem) {
                        $newMenuItems[] = $subItem;
                    }

                } else { //if menu item is not a category, leave it in place
                    $newMenuItems[] = $menuItem;
                }
            }
            //remove all menu items
            foreach ($firstLevel as $childNode) {
                $menu->removeChild($childNode);
            }
            //put new menu items back;
            foreach ($newMenuItems as $newMenuItem) {
                $menu->addChild($newMenuItem);
            }
        }
    }
}

now run in the console bin/magento setup:upgrade to install your module.
Notice: This will remove any top level categories from the menu. If you only have one as you describe it will remove that one. If you have 2 or more, it will remove all top level categories and add the second level categories in the menu.
If you have other menu links that are not categories they will remain unchanged.

Edit

I added an if statement inside the plugin to make it apply for a single store. Check the id of the store and replace the 1 in $storeId = 1; with what you need.
If you want to do this in a prettier way, you can add a yes/no config setting that will determine if the store should use only second level categories, and read that value in the plugin.
If not, you can leave it like this and just change the store id.

  • Great, I Will try this. We have a multi store magento, and this is only for 1 store. The other ones do use the top level cats. How can I arrange this? – Ronny Jun 20 '17 at 7:57
  • 1
    you need to wrap everything in an if statement. I will get back to you in a few minutes with the way to do it. – Marius Jun 20 '17 at 7:59
  • 1
    See my update.. – Marius Jun 20 '17 at 8:05
  • You rock !!! one more question .... this is needed for 2 storeId's ... (4 and 5) Could you add that for me too? – Ronny Jun 21 '17 at 18:32
  • 1
    @Ronny, Updated. – Marius Jun 21 '17 at 18:36

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.