Jump to content

Excluding Pages from bootstrap Menu


louisstephens
 Share

Recommended Posts

Hello,

How many pages do you want to display in the footer?

Do they all have the same (direct) parent (that is a direct child of the homepage(?))?

Or are they located a little bit everywhere (but under a direct child of the homepage(?))?

Do they use the same template?

You could "call" them directly.

Perhaps you could add a field to the template used for the pages, and try something like this in the template file:

if($homepage->children->displayed_in_the_footer_menu) {
    // code displayed if the field is checked

I haven't used something like that for a menu yet, but I have in order to display content on the homepage, for example.

You will have of course to hide these pages in the backend if you don't want them to show up in the top menu.

And will perhaps have to use $homepage->children("include=hidden") (with single or double quotes), instead of just $homepage->children

Can you give more details?

Link to comment
Share on other sites

Thanks Christophe for the  reply. I actually did just what you suggested (using a check box) for the bottom nav. Much easier than what I was originally thinking. 

But to Clarify for the main navigation hurdle: The bootstrap menu is currently pulling in all fields under "Home" in the tree which is nice. However, I need to remove about 8 pages from it )the ones in the footer. As you suggested, I had thought about changing those pages to "hidden" as a quick fix, but I am afraid having the pages greyed out in the admin will confuse the user. The bootstrap code:


	function renderChildrenOf($pa, $output = '', $level = 0)
	{
	    $output = '';
	    $level++;

	    foreach ($pa as $child) {
	        $atoggle = '';
	        $class = '';

	        if ($child->numChildren && count($child->parents) == 1) {
	            $class .= 'dropdown';
	            $atoggle .= ' class="dropdown-toggle" data-toggle="dropdown"';
	        } else if ($child->numChildren && count($child->parents) > 1 ) {
	            $class .= 'dropdown-submenu';
	            $atoggle .= ' class="dropdown-toggle"';
	        } else if ($child->numChildren && $child->id != 1) {
	            $class .= 'dropdown-menu';
	        }

	        // Makes the current page and it's top level parent add an active class
	        $class .= ($child === wire("page") || $child === wire("page")->rootParent) ? " active" : '';
	        $class = strlen($class) ? " class='" . trim($class) . "'" : '';

	        if ($child->numChildren && count($child->parents) == 1) {
	            // Add Caret if have children
	            $output .= "<li$class><a href='$child->url'$atoggle>$child->title</a>";
	        } else if ($child->numChildren && count($child->parents) > 1) {
	            $output .= "<li$class><a tabindex='-1' href='$child->url'$atoggle>$child->title</a>";
	        } else {
	            $output .= "<li$class><a href='$child->url'$atoggle>$child->title</a>";
	        }

	        // If this child is itself a parent and not the root page, then render it's children in their own menu too...
	        if ($child->numChildren && $child->id != 1) {
	            $output .= renderChildrenOf($child->children, $output, $level);
	        }
	        $output .= '</li>';
	    }
	    $outerclass = ($level == 1) ? "nav navbar-nav" : 'dropdown-menu';
	    return "<ul class='$outerclass'>$output</ul>";
	}

	// bundle up the first level pages and prepend the root home page
	$homepage = $pages->get(1);
	$pa = $homepage->children;
	$pa = $pa->prepend($homepage);

	// Set the ball rolling...
	echo renderChildrenOf($pa);?>

Link to comment
Share on other sites

Currently you're getting your top-level menu items with:

$pa = $homepage->children;

Try changing to a find selector. If there is some common attribute of the pages you want for the footer menu (template, value of a field, etc) you could use that to exclude the pages, otherwise you'll need to exclude them by name or id.

$pa = $pages->find("parent=1, id!=1050|1051|1052");

Edit: just noticed that you have added a checkbox to select pages for the footer nav. So you can do:

$footer_nav = $pages->find("parent=1, footer_checkbox=1");
$main_nav = $pages->find("parent=1, footer_checkbox!=1");
  • Like 1
Link to comment
Share on other sites

Thank you Robin S! Just a question on this though, I know using "find" uses a pageArray, so wouldnt I need to use a foreach to handle that? As it stands (looking through the original code), I am confusing myself on where to actually include the "includeFooter !=1" . I tried:


	<?php
	/*
	Navigation for ProcessWire using the Bootstrap 2.2.2 markup
	This menu was written by Soma based on work by NetCarver and a bit thrown in by Joss

	Navigation Bootstrap 3 update by Damienov, with multi level dropdown support fix
	*/

	function renderChildrenOf($pa, $output = '', $level = 0)
	{
			$excludePages = $page->includeFooter= 1;
	    $output = '';
	    $level++;

	    foreach ($pa as $child) {
	        $atoggle = '';
	        $class = '';

	        if ($child->numChildren && count($child->parents) == 1) {
	            $class .= 'dropdown';
	            $atoggle .= ' class="dropdown-toggle" data-toggle="dropdown"';
	        } else if ($child->numChildren && count($child->parents) > 1 ) {
	            $class .= 'dropdown-submenu';
	            $atoggle .= ' class="dropdown-toggle"';
	        } else if ($child->numChildren && $child->id != 1) {
	            $class .= 'dropdown-menu';
	        }

	        // Makes the current page and it's top level parent add an active class
	        $class .= ($child === wire("page") || $child === wire("page")->rootParent) ? " active" : '';
	        $class = strlen($class) ? " class='" . trim($class) . "'" : '';

	        if ($child->numChildren && count($child->parents) == 1 && $excludePages != 1) {
	            // Add Caret if have children
	            $output .= "<li$class><a href='$child->url'$atoggle>$child->title</a>";
	        } else if ($child->numChildren && count($child->parents) > 1) {
	            $output .= "<li$class><a tabindex='-1' href='$child->url'$atoggle>$child->title</a>";
	        } else {
						//controls links for all
	            $output .= "<li$class><a class='bob' href='$child->url'$atoggle>$child->title</a>";
	        }

	        // If this child is itself a parent and not the root page, then render it's children in their own menu too...
	        if ($child->numChildren && $child->id != 1) {
	            $output .= renderChildrenOf($child->children, $output, $level);
	        }
	        $output .= '</li>';
	    }
	    $outerclass = ($level == 1) ? "nav navbar-nav" : 'dropdown-menu';
	    return "<ul class='$outerclass'>$output</ul>";
	}

	// bundle up the first level pages and prepend the root home page
	// Change $homepage to find in order to exclude pages from top
	// $homepage = $pages->get(1);

	$homepage = $pages->get(1);

	$pa = $homepage->children;
	$pa = $pa->prepend($homepage);

	// Set the ball rolling...
	echo renderChildrenOf($pa);?>

but that doesnt seem to exclude any items from the navigation. Sorry if I missed something (Im still learning PHP and how to handle this all.

Link to comment
Share on other sites

If the renderChildrenOf() function is producing the markup (classes, etc) you need for a Bootstrap menu then you won't need to make any changes within the function. It already contains a foreach within the function so you just need to give it the PageArray of the top-level menu items.

$homepage = $pages->get(1);
$main_nav = $pages->find("parent=1, includeFooter!=1");
$main_nav = $main_nav->prepend($homepage);
echo renderChildrenOf($main_nav);

Depending on what you want for the footer menu you might use renderChildrenOf() for that too, or write your own foreach for $footer_nav

Link to comment
Share on other sites

Yeah, sorry for being a pain Robin. I looked it over last night and I understand what you are doing, but for some reason it still only displaying the "Home" Link.

<?php

function renderChildrenOf($pa, $output = '', $level = 0)
	{
	    $output = '';
	    $level++;

	    foreach ($pa as $child) {
	        $atoggle = '';
	        $class = '';

	        if ($child->numChildren && count($child->parents) == 1) {
	            $class .= 'dropdown';
	            $atoggle .= ' class="dropdown-toggle" data-toggle="dropdown"';
	        } else if ($child->numChildren && count($child->parents) > 1 ) {
	            $class .= 'dropdown-submenu';
	            $atoggle .= ' class="dropdown-toggle"';
	        } else if ($child->numChildren && $child->id != 1) {
	            $class .= 'dropdown-menu';
	        }

	        // Makes the current page and it's top level parent add an active class
	        $class .= ($child === wire("page") || $child === wire("page")->rootParent) ? " active" : '';
	        $class = strlen($class) ? " class='" . trim($class) . "'" : '';

	        if ($child->numChildren && count($child->parents) == 1) {
	            // Add Caret if have children
	            $output .= "<li$class><a href='$child->url'$atoggle>$child->title</a>";
	        } else if ($child->numChildren && count($child->parents) > 1) {
	            $output .= "<li$class><a tabindex='-1' href='$child->url'$atoggle>$child->title</a>";
	        } else {
	            $output .= "<li$class><a href='$child->url'$atoggle>$child->title</a>";
	        }

	        // If this child is itself a parent and not the root page, then render it's children in their own menu too...
	        if ($child->numChildren && $child->id != 1) {
	            $output .= renderChildrenOf($child->children, $output, $level);
	        }
	        $output .= '</li>';
	    }
	    $outerclass = ($level == 1) ? "nav navbar-nav" : 'dropdown-menu';
	    return "<ul class='$outerclass'>$output</ul>";
	}

	// bundle up the first level pages and prepend the root home page
	$homepage = $pages->get(1);
$main_nav = $pages->find("parent=1, includeFooter!=1");
$main_nav = $main_nav->prepend($homepage);
echo renderChildrenOf($main_nav);

?>

Again, I appreciate your help on all of this.

post-3676-0-01479800-1462280469_thumb.pn

Link to comment
Share on other sites

Hi Louis,

This is a strange one. I did some testing (as opposed to just writing code in the browser like I did previously) and it seems the problematic part of the selector is:

includeFooter!=1

I took this construction from a post here on the forum that suggests that this matches unchecked checkboxes but for some reason this doesn't seem to work.

This works:

includeFooter=0

and this:

includeFooter=''

But the weird thing is that neither 0 nor '' equals 1 so I don't understand why the !=1 construction doesn't work.

Maybe someone can explain this.

Link to comment
Share on other sites

I got it working! Thank you Robin so much for the help. Instead of using:

includeFooter!=1

I used

!includeFooter=1

and it appears to be working the correct way now. (idea from here)

Did you see the Issue at the end of that thread: https://github.com/ryancramerdesign/ProcessWire/issues/378 - this was supposed to be fixed Feb 2014. Are you using a really old version of PW? If not, it might be worth adding a comment to that issue to say that there are still issues.

Link to comment
Share on other sites

@adrian, in the thread you linked to you say

Now I understand that there is no entry in the hide_from_top_menu field for a page until the checkbox is checked and I guess that is the problem.

Do you mean that this is actually the correct/desirable behaviour for an empty checkbox and therefore it is not a bug that checkbox!=1 does not match pages with empty checkboxes?

Soma's Github issue is worded a bit differently so am thinking of opening a new issue, but just want to confirm that checkbox!=1 is expected to match an empty checkbox.

Link to comment
Share on other sites

Do you mean that this is actually the correct/desirable behaviour for an empty checkbox and therefore it is not a bug that checkbox!=1 does not match pages with empty checkboxes?

No, I don't think it is the correct/desirable behaviour, but I thought it might explain why it was happening.

but just want to confirm that checkbox!=1 is expected to match an empty checkbox.

That is correct - it should match an empty checkbox.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...