Jump to content
Sign in to follow this  
dlen

A recursive navigation of selectable pages containing home, with parent menu items not having their own page to show

Recommended Posts

Hi there,

i just want to share the code of what the subject line says.

The pages to appear in the menu have a custom field "in_main_menu" of type checkbox checked.

The item <li>s of the actually shown page and in the direttissima upwards - except home - get the class "current".

The item <ul>s of submenus get the class "submenu".

This is basically Ryans Code from here run through a meatgrinder.

I hope useful for any beginners like me looking for a solution to a similar problem.

Any improvement welcome!

Now the code:

/**
* A recursive menu containing home. (It is added to the list of menu items while $level =1).
* In order to be included, a page must have a custom field "in_main_menu" of type "checkbox",
* and the latter has to be checked.
* All submenu <ul>s get class "submenu".
* All <li>s in the direttissima upwards of the page shown - except home - get the class "current".
* Takes $root out of the recursion in order to not have all pages twice.
* All menu items, that have children, do not have a link to their content, but act merely as switches.
* You can switch this behaviour off by replacing
*
*       $href = (  $item == $root  ||  !$item->numChildren  ?   "$item->url"  :  "#"  );
*
* with
*
*       $href = $item->url;
*
* Or you can make it conditional by querying a second custom field "has_own_page", e.g.
*
*       $href = (  $item == $root  ||  !$item->numChildren  || $item->has_own_page  ?   "$item->url"  :  "#"  );
*
* Intended to be used without arguments, i.e.   "selectiveMenu();"  , i.e. always starting with site root.
*/

function selectiveMenu(Page $root = null) {

        $shownPage = wire('page');
        if(is_null($root)) $root = wire('pages')->get('/');

        $level = count($root->parents);
        $ul_class_string = (($level > 0)  ?  "class='submenu'"  :  "");

        $out = "\n<ul {$ul_class_string}>";

        $parents = $shownPage->parents;
        $items = $root->children;
        if ($level == 0) $items->prepend($root);

        foreach( $items as $item) {

                if ($item->in_main_menu) {

                        $s = '';

                        $li_class_string = ( ( $parents->has($item) && $item !== $root ) || $item === $shownPage  ? "class='current'" : "" );

                        if($item->numChildren && $item !== $root) {
                                $s = str_replace("\n", "\n\t\t", selectiveMenu($item));
                        }

                        $href = (  $item == $root  ||  !$item->numChildren  ?   "$item->url"  :  "#"  );

                        $out .= "\n\t<li {$li_class_string}>\n\t\t<a href='{$href}'>{$item->title}</a>$s\n\t</li>";
                }
        }
        $out .= "\n</ul>";
        return $out;
}
  • Like 1

Share this post


Link to post
Share on other sites

An updated version with some more features

/** 
* A recursive menu containing home. 
* If no root page is given, site root will be taken.
* If and only if the second parameter is given, only pages will be included, that have a custom field of type "checkbox",
* and the latter has to be checked. This field is the parameter to be given. Example with field "in_main_menu":
* 
*      selectiveMenu(null, $fields->in_main_menu);
*
* All submenu <ul>s get class "submenu".
* All <li>s in the direttissima upwards of the page shown - except home - get the class "current".
* All menu items, that have the template name 'no_content' do not have a link to their content, but act merely as switches 
* to their subpages. This template must have also the selector field, if the parameter is given.
* 
* Intended to be used without arguments, i.e.   "selectiveMenu();"  , i.e. always starting with site root.
*
* @param Page                       root page of the menu
* @param Field menu_selector_field  pages with this "checkbox" field in their template set to "checked" are represented
* @param string menu_id             The id the outermost ul - tag gets.
* @return string
*/

function selectiveMenu(Page $root = null, Field $menu_selector_field = null, $menu_id = null) {

        $shownPage = wire('page');
        if(is_null($root)) $root = wire('pages')->get('/');

        $level = count($root->parents); 
        $ul_class_string = (($level > 0)  ?  "class='submenu'"  :  "");
        $ul_id_string = ($menu_id  ?  "id='$menu_id'"  :  "");

        $out = "\n<ul {$ul_class_string} {$ul_id_string}>";

        $parents = $shownPage->parents;
        $items = $root->children;
        if ($level == 0) $items->prepend($root); 

        foreach( $items as $item) {

                if ($item->$menu_selector_field || !$menu_selector_field) {

                        $s = '';

                        $li_class_string = ( ( $parents->has($item) && $item !== $root ) || $item === $shownPage  ? "class='current'" : "" );

                        if($item->numChildren(true) && $item !== $root) {
                                $s = str_replace("\n", "\n\t\t", selectiveMenu($item, $menu_selector_field));
                        }

                        $href_attr = (  $item == $root  ||  $item->template->name != 'no_content'  ?   "href='$item->url'"  :  ""  );

                        $out .= "\n\t<li {$li_class_string}>\n\t\t<a $href_attr>{$item->title}</a>$s\n\t</li>";
                }
        }
        $out .= "\n</ul>";
        return $out;
}

Share this post


Link to post
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
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By louisstephens
      I have not really had to make a site from the ground up in quite a bit as I have been mainly focused on internal apps using processwire. However, I have now been tasked with creating a site and I was quite excited. I started down the path of using bulma as it seemed like a good fit. I got the whole site coded statically and was not moving on to porting it over to processwire. I pretty much have the the whole site figured out save for tackling the navbar. My current navbar is set up as so:
      <section id="nav"> <nav class="navbar" role="navigation" aria-label="main navigation"> <div class="navbar-brand"> <a class="navbar-item is-size-3 has-text-primary" href="#">Logo goes here</a> <a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample"> <span aria-hidden="true"></span> <span aria-hidden="true"></span> <span aria-hidden="true"></span> </a> </div> <div id="navbarBasicExample" class="navbar-menu"> <div class="navbar-end"> <a class="navbar-item">Home</a> <div class="navbar-item has-dropdown is-hoverable"> <a class="navbar-link">Services</a> <div class="navbar-dropdown"> <a class="navbar-item">Subpage</a> <a class="navbar-item">Subpage</a> <a class="navbar-item">Subpage</a> <a class="navbar-item">Subpage</a> </div> </div> <a class="navbar-item">Gallery</a> <a class="navbar-item">Contact Us</a> </div> </div> </nav> </section> I guess my question is how would you go about setting this up in processwire? All pages will obviously be subpages of Home with the following structure
      Home
      --Services
      ----Subpage
      ----Subpage
      ----Subpage
      ----Subpage
      --Gallery
      --Contact Us
       
    • By anderson
      Hi,
      Please take a look at this:
      https://templatemag.com/demo/Good/
      The upper nav bar, including dropdowns like "pages" and "portfolios", what do you call this whole thing? At first I guess it's called "dropdown nav bar", but seems not.
      AND of course, what's the simplest way/module to achieve this in PW?
      Thanks in advance.
    • By ridgedale
      Reference: PW 3.0.111 and uikit3 based site using the Regular-Master profile.
      I was wondering if there is a way to restrict user navigation to specific pages.
      Login (home.php - not to be displayed)
          |__  About (not to be displayed)
          |__  Clubs (not to be displayed)
          |            |__ Club (to be displayed)
          |                       |__  Club Members (to be displayed)
          |__ League (not to be displayed)
          |            |__Season (not to be displayed)
          |                       |__  Match (not to be displayed)
          |__  News (blog.php -  to be displayed)
          |
      etc, etc
      Based on the above the navigation needs to appear simply as:
      ---------------------------------------------------------------------------
                           Club    Club Members    News    
      ---------------------------------------------------------------------------
      Any thoughts appreciated.
    • By joe_ma
      Hi
      Trying to setup a customized navigation.
      Page tree looks like this:
      home
      – upcoming exhibitions
      –– exhibition 1
      –– exhibition 2
      –– …
      – about
      – archive
      –– arch 1
      –– arch 2
      –– …
      – impressum
      Now I'd like to have a navigation, that lists only the subnav of "upcoming exhibitions" but not the one of "archive".
      I modified a snippet I found here in the forum. It looks like this so far:
      <nav class="mainNav"> <ul> <?php $homepage = $pages->get('/'); // first item links to the homepage echo "<li><a href='$homepage->url'>Aktuelle Ausstellung / current exhibition</a></li>"; $children = $homepage->children(); // render an <li> for each top navigation item foreach ( $children as $child ) { if ( $child->id == $page->rootParent->id ) { // this $child page is currently being viewed (or one of it's children/descendents) // so we highlight it as the current page in the navigation echo "<li class='active'><a href='$child->url'>$child->title</a></li>"; // if upcoming page has children, list them } elseif($child->id == 1020 && count($child->children)){ // build the subnav and list all items echo "<li><a href='$child->url'>$child->title</a><ul class='upcoming'>"; foreach($child->children as $c){ echo "<li><a href='$c->url'>$c->title<br>{$c->date_from}–{$c->date_to}</a></li>"; } echo "</ul><li>"; // otherwise list only main items } else { echo "<li><a href='$child->url'>$child->title</a></li>"; } } ?> </ul> </nav> This puts out the navigation as wanted, but only for main items (see fig. nav-open.png).
      As soon as "upcoming exhibitions" or one of its children is active, the navigation collapses (see fig. nav-closed.png).
      I cannot find out, where I went the wrong way.
      Thanks for help.


    • By JimSee
      FIRST: I am brand new and am trying to add a Navigation Tree to the beginner site. When I put renderNavTree($page, 4) into _head.php, I get a menu list like the graphic.
      This is great EXCEPT, I don't know how to make a horizontal menu out of it with CSS. Can someone help (please) or direct me to an example of the css?
      SECOND: That list is great for the Home page but when I click "program," the list only shows:

      How can I get the whole (visible) menu on every page?
      Thank you in advance! jim
       
×
×
  • Create New...