4

We have added some custom navigation items to the navigation using default.xml and is working just fine, but for the life of me I can't figure out how to add child items to these parent navigation items.

My goal is to add direct links to catalog filters -- such as Mens or Womens under each parent navigation item.`

Here is the XML I'm using, many thanks in advance!

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="catalog.topnav">
           <block class="Magento\Framework\View\Element\Html\Link\Current" name="Shoes">
                <arguments>
                    <argument name="label" xsi:type="string">Shoes</argument>
                    <argument name="path" xsi:type="string">shoes</argument>
                </arguments>
          </block>
           <block class="Magento\Framework\View\Element\Html\Link\Current" name="Shorts">
                <arguments>
                    <argument name="label" xsi:type="string">Shorts</argument>
                    <argument name="path" xsi:type="string">shorts</argument>
                    <argument name="class" xsi:type="string">shorts</argument>
                </arguments>
            </block>
       </referenceContainer>
    </body>
</page>
1
  • 1
    The top navigation menu in Magento is showing category tree data. However, like most things, you can of course hook custom data to it. Can you confirm that is what you are trying to do and possibly provide a screenshot of your site. As many details to understand what you are aiming for? are you trying to do something that exists already but with different data? Commented Sep 16, 2018 at 7:51

1 Answer 1

4

Well, if you have a look at the default template for catalog.topnav block you can see that it's setup to render any child block after the menu:

<nav class="navigation" data-action="navigation">
    <ul data-mage-init='{"menu":{"responsive":true, "expanded":true, "position":{"my":"left top","at":"left bottom"}}}'>
        <?= /* @escapeNotVerified */ $_menu ?>
        <?= /* @escapeNotVerified */ $block->getChildHtml() /* THIS IS WHAT RENDERS YOUR BLOCKS */ ?>
    </ul>
</nav>

Your blocks use the Magento\Framework\View\Element\Html\Link\Current which is fine to render a single link but doesn't really let you have multiple "child links".

Solution #1

So you have a few options here, probably the easiest one would be set a template to your custom blocks and set the markup for your links there:

Layout

<block class="Magento\Framework\View\Element\Html\Link\Current" name="Shoes">
    <arguments>
        <argument name="label" xsi:type="string">Shoes</argument>
        <argument name="path" xsi:type="string">shoes</argument>
        <argument name="template" xsi:type="string">Magento_Theme::menu/shoes.phtml</argument>
    </arguments>
</block>

Magento_Theme/templates/menu/shoes.phtml

<li class="level0 nav-5 level-top parent">
    <a href="/shoes.html" class="level-top"><span>Shoes</span></a>
    <!-- YOUR SUBMENU -->
    <ul class="level0 submenu">
        <li class="level1 nav-5-1 first last">
            <a href="/shoes/high-heels.html"><span>High Heels</span></a>
        </li>
    </ul>
</li>

Solution #2

Now if you want to keep a similar flexibility as the one you have for the top level items you could create a new Block class that extends the Current class you're already using and add support for multiple submenu items by extending the _toHtml function:

Vendor\Submenu\Block\Element\Html

class LinkWithSubmenu extends \Magento\Framework\View\Element\Html\Link\Current
{
    /**
     * Render block HTML
     *
     * @return string
     */
    protected function _toHtml()
    {
        if (false != $this->getTemplate()) {
            return parent::_toHtml();
        }

        $submenu = '';

        if ($this->getSubmenu() && !empty($this->getSubmenu())) {
            $submenu = '<ul>';

            foreach ($this->getSubmenu() as $link) {
                $submenu .= '<li class="">';
                $submenu .= '<a href="' . $this->escapeHtml($this->getUrl($link['path'])) . '">';
                $submenu .= $this->escapeHtml((string)new \Magento\Framework\Phrase($link['label']));;
                $submenu .= '</a></li>';
            }

            $submenu .= '</ul>';
        }

        $highlight = '';

        if ($this->getIsHighlighted()) {
            $highlight = ' current';
        }

        if ($this->isCurrent()) {
            $html = '<li class="nav item current">';
            $html .= '<strong>'
                . $this->escapeHtml((string)new \Magento\Framework\Phrase($this->getLabel()))
                . '</strong>';
            $html .= $submenu;
            $html .= '</li>';
        } else {
            $html = '<li class="nav item' . $highlight . '"><a href="' . $this->escapeHtml($this->getHref()) . '"';
            $html .= $this->getTitle()
                ? ' title="' . $this->escapeHtml((string)new \Magento\Framework\Phrase($this->getTitle())) . '"'
                : '';
            $html .= $this->getAttributesHtml() . '>';

            if ($this->getIsHighlighted()) {
                $html .= '<strong>';
            }

            $html .= $this->escapeHtml((string)new \Magento\Framework\Phrase($this->getLabel()));

            if ($this->getIsHighlighted()) {
                $html .= '</strong>';
            }

            $html .= '</a>';
            $html .= $submenu;
            $html .= '</li>';
        }

        return $html;
    }
}

Layout

<block class="Vendor\Submenu\Block\Element\Html\LinkWithSubmenu" name="Shoes">
    <arguments>
        <argument name="label" xsi:type="string">Shoes</argument>
        <argument name="path" xsi:type="string">shoes</argument>
        <argument name="submenu" xsi:type="array">
            <item name="highHeels" xsi:type="array">
                <item name="label" xsi:type="string">High Heels</item>
                <item name="path" xsi:type="string">shoes/high-heels</item>
            </item>
            <item name="clogs" xsi:type="array">
                <item name="label" xsi:type="string">Clogs</item>
                <item name="path" xsi:type="string">shoes/clogs</item>
            </item>
        </argument>
    </arguments>
</block>
1
  • great, thank you i was able to get this to work perfectly by using this. really appreciate it.
    – EtotheJ
    Commented Oct 13, 2018 at 21:58

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.