Although this sounds really straight forward I can't work it out. All the existing methods seem to be for Magento 1.x

I would like to have all my CMS pages in the top menu.


8 Answers 8


I've done it in the following way without any changes in the code:

  1. Content from the page (PageA) is put in a new block (BlockA).
  2. I make a new category with only content and without products (CategoryA)
  3. In the Content section: Add CMS Block -> Add BlockA
  4. Change layout if needed and save.

That's it!

In case you still need PageA just delete content from it and add CMS Block (BlockA) as a widget.

  • 4
    How do you do step one "put in a new block (BlockA) while the block is created in step .3? Aug 14, 2017 at 9:51

You can create a static block with a list of your pages, then add it to your <Magento>/app/design/frontend/<Vendor>/<theme>/web/etc/default.xml file.

The CMS block would look something like:

<li class="level0 level-top"><a class="level-top ui-corner-all" href="{{store direct_url="about-us"}}">About Us</a></li>
<li class="level0 level-top"><a class="level-top ui-corner-all" href="{{store direct_url="contact-us"}}">Contact Us</a></li>

And the code in default.xml would be placed within the block:

<referenceContainer name="catalog.topnav">
    <block class="Magento\Cms\Block\Block" name="your_block_id">
            <argument name="block_id" xsi:type="string">your_block_id</argument>

Additional styling may be needed, but with the blank theme using the classes level0 and level-top in your CMS block should match up.


Without any extension,it's not possible.

But there is an alternative

Basically, we use cms page for cms content management.

As per my knowledge, there is a process in category system where you can manage cms content.

Just create a cms static block and assign that static block to the category from Display setting tab.

Then,set Display Mode as Static block only. Do not assign any products to that category.

If you don't want an alternative then you have to create custom module

Free extension available at Github

Or build the module yourself as per below steps:

Then create plugin for class Magento\Theme\Block\Html\Topmenu and and use before plugin on getHtml()

First, create a module.

Second: create di.xml where we will define plugin.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    <type name="Magento\Theme\Block\Html\Topmenu">
        <plugin name="add_cms_menu" type="{VendorName}{ModuleName}\Plugin\Topmenu" sortOrder="1" />

Third: Now create the plugin class where we will add a cms page link to the menu.

and also in this way we can add a cms page link at navigation.


namespace {VendorName}\{ModuleName}\Plugin;
use Magento\Framework\Data\Tree\NodeFactory;
class Topmenu
    protected $nodeFactory;
    protected $_storeManager;
    protected $_pageFactory;
    protected $_urlBuilder;

    public function __construct(
        NodeFactory $nodeFactory,
        \Magento\Cms\Model\PageFactory $pageFactory,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Framework\UrlInterface $urlBuilder
    ) {
        $this->nodeFactory = $nodeFactory;
        $this->_pageFactory = $pageFactory;
        $this->_storeManager = $storeManager;
        $this->_urlBuilder = $urlBuilder;
    public function beforeGetHtml(
        \Magento\Theme\Block\Html\Topmenu $subject,
        $outermostClass = '',
        $childrenWrapClass = '',
        $limit = 0
    ) {
        /* Showing  Cms page About us at menu */
        $page = $this->getCmspage('about-us');
        if($page == null){

        $node = $this->nodeFactory->create(
                'data' => [
                    'name' => $page->getTitle(),
                    'id' => $page->getIdentifier(),
                    'url' =>  $this->_urlBuilder->getUrl(null, ['_direct' => $page->getIdentifier()]),
                    'has_active' => false,
                    'is_active' => false // (expression to determine if menu item is selected or not)
                'idField' => 'id',
                'tree' => $subject->getMenu()->getTree()
    protected function getCmspage($identifier){

        $page = $this->_pageFactory->create();
        $pageId = $page->checkIdentifier($identifier, $this->_storeManager->getStore()->getId());

        if (!$pageId) {
            return null;
        if (!$page->load($pageId)) {
            return null;

        if (!$page->getId()) {
            return null;

        return $page;


self promotion

We made an OpenSource Module where you can link a category to a specific CMS page. So you have to create a Category for each CMS page and adjust the link via the module. In case you want to do it yourself, just have a look at the module :-)


  • After executing the composer command, im asked username and password. Is this my magento connect account?
    – NuWin
    Dec 19, 2016 at 4:48
  • I think the github account
    – Alex
    Dec 19, 2016 at 10:24

Note that if you have Magento Enterprise Edition, you can use the Hierarchy feature. That's precisely what it's intended to allow you to do (among other things).

  • Hierarchy affects the sidebar, not the main menu out of the box; docs.magento.com/m2/ee/user_guide/cms/page-hierarchy.html
    – joeyhoer
    Oct 2, 2017 at 19:31
  • Sorry, but that's just not true. If the docs claim it, theyre incorrect. I use this feature all the time. There's a specific setting for using top navigation as opposed to on page (which is, of course, there, too.)
    – Steve K
    Oct 2, 2017 at 19:35

You can create a plugin for the Magento\Theme\Block\Html\Topmenu block's getHtml method and use it to iterate through the CMS pages, inserting the links into the html.


Do you mean the top.links or the main navigation that's populated by categories?

Cause if you want page links in top.links (header.links for Luma), then just create the page and add to default.xml

<referenceContainer name="header.links">
    <block class="Magento\Framework\View\Element\Html\Link\Current" name="about-us" before="-">
        <argument name="label" xsi:type="string">About Us</argument>
        <argument name="path" xsi:type="string">about-us</argument>

That should link to your static pages.

  • yeah, at the moment it just display's categories. I want it to display, CMS pages, and the initial 'shop' page. Using your solution above, would I have to add each page in manually? ..sorry I'm completely new to Magento! Jun 30, 2016 at 17:30
  • My solution will only apply to the top navigation (the one right at the top of the page where the login/account links are) and all you would have to do is copy and paste the arguments with the page details you want to add. I'm sorry, I have no idea how to add to the categories nav. Jun 30, 2016 at 17:33

Want to add a link to the top navigation within <header>
Adding a link to CMS page, Gallery

Edit/Place default.xml here:


Add the following code:

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
        <referenceContainer name="catalog.topnav">
           <block class="Magento\Framework\View\Element\Html\Link\Current" name="gallery.link">
                    <argument name="label" xsi:type="string">Gallery</argument>
                    <argument name="path" xsi:type="string">gallery</argument>

This adds a link to CMS page, Gallery, with the following settings:

Title = Gallery
Url Key = gallery
Link = https://example.com/gallery/

Add the following styling to ensure the new link aligns correctly:

.navigation .nav.item {
margin: 0 10px 0 0;
display: inline-block;
position: relative;

Results of the code (Products is setup as a category for an example)

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.