Hiding all subpages of a page from the menu

Hi!

I’ve been building something along the lines of a blog - basically news articles which are added as seperate entries. This builds a lot of subpages of course, which I only got to sort properly by setting them as visible.

However, they now show up in the menu as subpages, which I don’t want. Is there any way to hide all the subpages of the “news” page from the menu?

Thanks!

What’s your code for your menu snippet / template? I think we can help easily if you provide what code you use to generate your menu :wink:

I don’t know your menu structure, but you can exclude pages with not():

<?php
foreach($pages->visible()->not('blog)->children()->visible()) {
//do stuff
}
?>

My menu snippet looks like this:

<nav role="navigation">    
  <ul class="menu">
    <?php foreach($pages->visible() as $p): ?>
    <li>
      <a <?php e($p->isOpen(), ' class="active"') ?> href="<?php echo $p->url() ?>"><?php echo $p->title()->html() ?></a>
      <?php if($p->hasVisibleChildren()): ?>
      <ul class="submenu">
        <?php foreach($p->children()->visible() as $p): ?>
        <li>
          <a href="<?php echo $p->url() ?>"><?php echo $p->title()->html() ?></a>
        </li>
        <?php endforeach ?>
      </ul>
      <?php endif ?>

    </li>
    <?php endforeach ?>
  </ul>
<a href="#" id="pull"></a>
</nav>

Which is basically the standard menu snippet I got from here. (looks a but messy, sorry!)

So it can be used to exclude all children too? I’ve tried to include it in the already existing code as

<ul class="menu">
    <?php foreach($pages->visible() as $p): ?>
    <li>
      <a <?php e($p->isOpen(), ' class="active"') ?> href="<?php echo $p->url() ?>"><?php echo $p->title()->html() ?></a>
      <?php if($p->hasVisibleChildren()): ?>
      <ul class="submenu">


        <?php foreach($p->not('news')->children()->visible() as $p): ?>
        <li>


          <a href="<?php echo $p->url() ?>"><?php echo $p->title()->html() ?></a>
        </li>
        <?php endforeach ?>
      </ul>
      <?php endif ?>

    </li>
    <?php endforeach ?>
  </ul>

But that doesn’t seem to work… As you can see, I’m still new to anything PHP, but thanks for your help!

I’m building a similar menu now. I’m not a proper developer so it will make real devs’ eyes bleed, but here’s how I did it so far.
I put the whole submenu in a different condition.
Instead of

<?php if($p->hasVisibleChildren()): ?>

I used

<?php if($p->hasVisibleChildren() && $p->template() != 'news'): ?>

Where ‘news’ is your template for the type of posts you don’t want to display in the menu.
There has to be a cleaner way though :sweat:

2 Likes

Huh, it’s a neat solution though. I’ll probably implement this for now!

Edit: Somehow it doesn’t work as of yet. I’ll try and see what causes that…

Alright, I got it in a bit of a hacky way, I added a css class for the page I didn’t want the submenu to appear:

<li <?php e($p->title() == 'News', ' class="ignore"') ?> href="<?php echo $p->url() ?>"> 

adds the .ignore class to the li.

Then I just added

 .menu > .ignore:hover .submenu {
display: none;}

To my CSS.

As a fellow non-proper dev, I can say I’ve done the same thing multiple times. Works for me, but I’d be interested in seeing a “properly clean” way to solve this problem.

My hint is clean, if your development is clean.

And you can use it within your menu and your sitemap.xml in the same way!

Instead of hardcoding pages in the template, you could also use a checkbox field in the parent pages (“Include subpages in menu?”) and then check if that field is true. That would make it more flexible in case there are other pages whose children are not supposed to appear in the menu (e.g. if the site is extended in the future).

3 Likes

Sorry for bringing this up again but I just wondered if someone can give a working example for excluding the children of a specific page. I tried all the suggestions above but didn’t manage to replicate a proper solution. I thought there might be a rather straight-forward way by adapting the example for a nested menu in the docs. I guess in this line (somehow) the magic could happen…

// get all children for the current menu item
      $children = $item->children()->visible();

I tried to exclude the children of the Blog page by adding ->not('blog')->children() but didn’t succeed.

Here is an example where the children of ‘home’ and ‘news’ are excluded from the submenu:

<nav class="main-nav" role="navigation">
  <ul class="menu">
    <?php foreach($pages->visible() as $p): ?>
      <li>
        <a <?php e($p->isOpen(), ' class="active"') ?> href="<?= $p->url(); ?>">
          <span class="menu-title"><?php echo $p->title()->html() ?></span>
          <span class="menu-description"><?php echo $p->menu_description()->html() ?></span>
        </a>
        <?php if((!($p->isHomepage() || $p->is(page('news')))) && $p->hasVisibleChildren()): ?>
          <ul class="submenu">
            <?php foreach($p->children()->visible() as $p): ?>
              <li>
                <a href="<?php echo $p->url() ?>"><?php echo $p->title()->html() ?></a>
              </li>
            <?php endforeach ?>
          </ul>
        <?php endif ?>
      </li>
    <?php endforeach ?>
  </ul>
</nav>
3 Likes

Sory for ultra basic question:
does "!" means "not" ? in <?php if((!($p->isHomepage() || $p->is(page('news')))) && $p->hasVisibleChildren()): ?>

Yes. That line means:

“If the page is not the homepage or the news page and if it has visible children, do the following”

You could also write:

<?php if(!$p->isHomepage() && !$p->is(page('news')) && $p->hasVisibleChildren()): ?>

Note that the || becomes an &&. That’s propositional logic. :wink:

1 Like