Damienov Posted February 28, 2014 Share Posted February 28, 2014 Hi everyone, I've made a snippet update for the bootstrap 2.2.2 navbar by Soma to Bootstrap 3.x. I also added a multi level menu fix since it was removed from Bootstrap 3. Screenshot: topnav_inc <?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) { $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 <b class='caret'></b></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); Add to your CSS /* Bootstrap 3 navbar with multi level fix */ .dropdown-submenu{ position:relative; } .dropdown-submenu > .dropdown-menu { top:0; left:100%; margin-top:-6px; ; -webkit-border-radius:0 6px 6px 6px; -moz-border-radius:0 6px 6px 6px; border-radius:0 6px 6px 6px; } .dropdown-submenu:hover > .dropdown-menu{ display:block; } .dropdown-submenu > a:after{ display:block; content:" "; float:right; width:0; height:0; border-color:transparent; border-style:solid; border-width:5px 0 5px 5px; border-left-color:#cccccc; margin-top:5px; margin-right:-10px; } .dropdown-submenu:hover > a:after{ border-left-color:#ffffff; } .dropdown-submenu .pull-left{ float:none; } .dropdown-submenu.pull-left > .dropdown-menu{ left:-100%; margin-left:10px; -webkit-border-radius:6px 0 6px 6px; -moz-border-radius:6px 0 6px 6px; border-radius:6px 0 6px 6px; } note: My php skills are crappy , so feel free to add some fixes on the code 4 Link to comment Share on other sites More sharing options...
Joss Posted February 28, 2014 Share Posted February 28, 2014 If you want multi level navigation, the system on Foundation works better since it allows a way to navigate back through the levels. But a useful fix you have done here. Link to comment Share on other sites More sharing options...
Joss Posted February 28, 2014 Share Posted February 28, 2014 Currently, if you have a header item called About Us that links to a page, if it has a child, the item cannot be linkable because that wont work on mobile devices. What would be nice is in those circumstances to duplicate the About Us link and make it the first child of itself. So you get: About Us About Us Child Link to comment Share on other sites More sharing options...
Damienov Posted February 28, 2014 Author Share Posted February 28, 2014 Currently, if you have a header item called About Us that links to a page, if it has a child, the item cannot be linkable because that wont work on mobile devices. What would be nice is in those circumstances to duplicate the About Us link and make it the first child of itself. So you get: About Us About Us Child Since changing it would break the menu on mobile, perhaps adding an empty template+ empty placeholder trough processwire would be best? Link to comment Share on other sites More sharing options...
Joss Posted February 28, 2014 Share Posted February 28, 2014 Yes, my way round it previously has been to make parent items nothing. You can actually add a bit of code so that that if an item has children then $childUrl beomes # I added this to a foundation version (based on a later version of the bootstrap menu, I think - cant quite remember now) $has_children = count($child->children) ? true : false; if($has_children && $child !== $root) { $class .= 'has-dropdown'; // sub level Foundation dropdown li class $childUrl = "#"; // stop parents being clickable } else { $childUrl = $child->url; // if does not have children, then get the page url } But repeating the parent item as a child would be the ultimate - then use media queries to show or not to show. That way you can preserve your tree structure but still have it work. I have to say, I am tending to avoid complicated menus entirely now. 1 Link to comment Share on other sites More sharing options...
Damienov Posted February 28, 2014 Author Share Posted February 28, 2014 I have to say, I am tending to avoid complicated menus entirely now. I know, and simple (2 tier) keeps mobile compatibility. Link to comment Share on other sites More sharing options...
adrian Posted February 28, 2014 Share Posted February 28, 2014 Currently, if you have a header item called About Us that links to a page, if it has a child, the item cannot be linkable because that wont work on mobile devices. What would be nice is in those circumstances to duplicate the About Us link and make it the first child of itself. So you get: About Us About Us Child I actually love the way meanmenu handles this issue: http://www.meanthemes.com/demo/meanmenu/demo.html 1 Link to comment Share on other sites More sharing options...
Joss Posted February 28, 2014 Share Posted February 28, 2014 Thats kind of cute! Link to comment Share on other sites More sharing options...
adrian Posted February 28, 2014 Share Posted February 28, 2014 Thats kind of cute! Cute ? I actually thought it was pretty functional - nicer to be able to click on the parent item or expand it to access the children. You not sold on the idea? Link to comment Share on other sites More sharing options...
Joss Posted February 28, 2014 Share Posted February 28, 2014 Over in the uk, Cute used like this is saying it is good. Possibly a London thing ... not sure. 2 Link to comment Share on other sites More sharing options...
adrian Posted February 28, 2014 Share Posted February 28, 2014 Well the definition of cute that I remember from my Aussie upbringing was: "Ugly, but interesting" Glad we got that cleared up 1 Link to comment Share on other sites More sharing options...
artamteex Posted May 26, 2014 Share Posted May 26, 2014 EDITED OUT - found my mistake. How to add piece of html at the end of menu, before final </ul>? It doesn't execute additional echo at the end of the function. (want to add separate menu button with Call To Action)Not knowing php sucks :/ Link to comment Share on other sites More sharing options...
Marcel Epp Posted August 4, 2016 Share Posted August 4, 2016 Hi, how can i change the deepness? I only want to go to level 1 (Tier2). I only need the parent and the child's. How can i do that? Link to comment Share on other sites More sharing options...
flydev Posted August 5, 2016 Share Posted August 5, 2016 (edited) @Marcel Epp You could add a new parameter to the function. Assuming you are using the code shown in the first post, the following code should work (not tested) : function renderChildrenOf($pa, $maxDepth = 1, $output = '', $level = 0) // MODIFIED_CODE { $output = ''; $level++; foreach ($pa as $child) { $atoggle = ''; $class = ''; if ($child->numChildren(true) && count($child->parents) == 1) { $class .= 'dropdown'; $atoggle .= ' class="dropdown-toggle" data-toggle="dropdown"'; } else if ($child->numChildren(true) && count($child->parents) > 1 ) { $class .= ($maxDepth > 0) ? 'dropdown-submenu' : ''; // MODIFIED_CODE $atoggle .= ($maxDepth > 0) ? ' class="dropdown-toggle"' : ' '; // MODIFIED_CODE } else if ($child->numChildren(true) && $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(true) && count($child->parents) == 1) { // Add Caret if have children $output .= "<li$class><a href='$child->url'$atoggle>$child->title <b class='caret'></b></a>"; } else if ($child->numChildren(true) && 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(true) && $child->id != 1 && $maxDepth > 0) { // MODIFIED_CODE $maxDepth--; // MODIFIED_CODE $output .= renderChildrenOf($child->children, $maxDepth, $output, $level); // MODIFIED_CODE } $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); Search the comments MODIFIED_CODE to see whats going on in the function. Edited August 7, 2016 by flydev code tested// added @Horst suggestion : numChildren(true) 2 Link to comment Share on other sites More sharing options...
Marcel Epp Posted August 5, 2016 Share Posted August 5, 2016 Hi flydev, the code returns an internal server error. I will try to get it to work. Thank you. Link to comment Share on other sites More sharing options...
flydev Posted August 5, 2016 Share Posted August 5, 2016 I did a test on a fresh install and it work fine. How did you implemented it ? The tree Result with $maxDepth = 1 Result with $maxDepth = 2 3 Link to comment Share on other sites More sharing options...
horst Posted August 6, 2016 Share Posted August 6, 2016 On 5.8.2016 at 2:27 PM, flydev said: Assuming you are using the code shown in the first post, the following code should work (not tested) : @flydev: only one suggestion: it should be $child->numChildren(true) instead of $child->numChildren // what is the shortcut to $child->numChildren(false) Read here why: https://processwire.com/talk/topic/13950-show-image-childrens-children/#comment-125410 3 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now