nikola Posted June 21, 2011 Share Posted June 21, 2011 How can I accomplish this kind of navigation: <ul> <li><a href="#">Top Menu Item 1</a> <ul> <li><a href="#">Submenu Item 1</a></li> <li><a href="#">Submenu Item 2</a></li> <li><a href="#">Submenu Item 3</a></li> </ul> </li> <li><a href="#">Top Menu Item 2</a> <ul> <li><a href="#">Submenu Item 1</a> <ul> <li><a href="#">Sub Submenu Item 1</a></li> <li><a href="#">Sub Submenu Item 2</a></li> <li><a href="#">Sub Submenu Item 3</a></li> </ul> </li> <li><a href="#">Submenu Item 2</a></li> </ul> </li> <li><a href="#">Top Menu Item 3</a></li> </ul> News page must not list it's children (news entries). Selected page in the tree must have an "selected" class appended to it. I've used to do it this way in WolfCMS: <ul> <li><a<?php echo url_match('/') ? ' class="selected"': ''; ?> href="<?php echo URL_PUBLIC; ?>">Home page</a></li> <?php foreach($this->find('/')->children() as $menu): ?> <?php if($menu->slug() == 'news') : ?> <li><?php echo $menu->link($menu->title, (in_array($menu->slug, explode('/', $this->url)) ? ' class="selected"': null)); ?></li> <?php endif; ?> <li><?php echo $menu->link($menu->title, (in_array($menu->slug, explode('/', $this->url)) ? ' class="selected"': null)); ?> <ul> <?php foreach($menu->children() as $child):?> <?php if($child->slug() == 'news') : ?> <li><?php echo $child->link() ?></li> <?php endif; ?> <?php if($child->childrenCount() > 0 && $child->slug() != 'news') : ?> <li><?php echo $child->link($child->title, (in_array($child->slug, explode('/', $this->url)) ? ' class="selected"': null)); ?> <ul> <?php foreach ($child->children() as $grandchild) : ?> <li><?php echo $grandchild->link($grandchild->title, (in_array($grandchild->slug, explode('/', $this->url)) ? ' class="selected"': null)); ?> <?php endforeach; ?> </ul> <?php endif; ?> <?php if($child->childrenCount() == 0) : ?> <li><?php echo $child->link() ?></li> <?php endif; ?> <?php endforeach; ?> </ul> </li> <?php endforeach; ?> </ul> Thanks Link to comment Share on other sites More sharing options...
almonk Posted June 21, 2011 Share Posted June 21, 2011 Please see this post http://processwire.com/talk/index.php/topic,128.msg790.html#msg790 for some information on how to do this. Link to comment Share on other sites More sharing options...
apeisa Posted June 21, 2011 Share Posted June 21, 2011 Yes, almonk has the right example. Here is my modified version, that is used at lukio.fi site: <?php function treeMenu(Page $page = null, Page $rootPage = null, $id = null) { if(is_null($page)) $page = wire('page'); if(is_null($rootPage)) $rootPage = wire('pages')->get('/'); if(!is_null($id)) $id = " id='$id'"; $out = "\n<ul$id>"; $parents = $page->parents; // This is where we get pages we want. You could just say template!=news-item foreach($rootPage->children('template!=post, template!=faq-item, template!=gallery') as $child) { $class = "level-" . count($child->parents); $s = ''; if($child->numChildren && $parents->has($child)) { $class .= " on on_path"; $s = str_replace("\n", "\n\t\t", treeMenu($page, $child)); } else if($child === $page) { $class .= " on on_page"; if($page->numChildren) $s = str_replace("\n", "\n\t\t", treeMenu($page, $page)); } $class .= " page-{$child->id}"; $class = " class='$class'"; $out .= "\n\t<li$class>\n\t\t<a$class href='{$child->url}'>{$child->title}</a>$s\n\t</li>"; } $out .= "\n</ul>"; return $out; } Link to comment Share on other sites More sharing options...
nikola Posted June 21, 2011 Author Share Posted June 21, 2011 Thank you both, I'll try it and will get back to you. Link to comment Share on other sites More sharing options...
drilonb Posted August 21, 2011 Share Posted August 21, 2011 I try to make one but i am not sure with this and i cant fix it , i have like this original navi <ul id="nav" class="dropdown dropdown-horizontal"> <li><a href="./">Gallery</a></li> <li><a href="./">Delta</a></li> <li class="dir rtl"><a href="#">Contact Us</a> <ul> <li><a class="active" href="#">Enquiry Form</a></li> <li><a href="#">Your Feedback</a></li> </ul> </li> </ul> and i need to put in processwire demo here http://demo1.sherbimeonline.com/ thanks, Link to comment Share on other sites More sharing options...
ryan Posted August 21, 2011 Share Posted August 21, 2011 Assuming I'm reading it right, I think the only thing that seems different here is the classes you are applying on the opened 'Contact Us' link. What do those classes "dir rtl" mean in terms of how they should affect the behavior of this nav? Thanks, Ryan Link to comment Share on other sites More sharing options...
drilonb Posted August 21, 2011 Share Posted August 21, 2011 ignore it its not necessary dir rtl its only to show which link have a sub nav on it, this is in html but i have trouble to put in PW . Link to comment Share on other sites More sharing options...
ryan Posted August 22, 2011 Share Posted August 22, 2011 I may be confused, because think the previous example Antti posted should do this? The only thing I can think of is if you don't want it to expand the Gallery or Delta menus (assuming they have subpages) or if you want it to include/exclude certain items from the Contact menu. The example you posted is how you want it to look, is this correct? If so, can you post another example with how it appears using that treeMenu function? Also note in that treeMenu function you'll want to exclude this text "template!=post, template!=faq-item, template!=gallery", which is specific to the context Antti posted, but wouldn't be to yours. I think once we see what's different from your desired result you posted earlier, then it would be simpler for us to solve it. I think that you will just want to call that function like this: echo treeMenu($page); Link to comment Share on other sites More sharing options...
drilonb Posted August 22, 2011 Share Posted August 22, 2011 mmm look this is a menu in process wire Pages and Children Home Service Delta Alfa Tango Help Tech Marketing Analytic About Contact another demo here http://www.sohtanaka.com/web-design/examples/drop-down-menu/ http://www.cssplay.co.uk/menus/dd_valid.html i just like to make drop down menu i try to make it with your suggestions and apesia but i am confuse with class where to add or how they are added in code. <?php function treeMenu(Page $page = null, Page $rootPage = null, $id = null) { if(is_null($page)) $page = wire('page'); if(is_null($rootPage)) $rootPage = wire('pages')->get('/'); if(!is_null($id)) $id = " id='$id'"; $out = "\n<ul$id>"; $parents = $page->parents; // This is where we get pages we want. You could just say template!=news-item foreach($rootPage->children('template!=post, template!=faq-item, template!=gallery') as $child) { $class = "level-" . count($child->parents); $s = ''; if($child->numChildren && $parents->has($child)) { $class .= " on on_path"; $s = str_replace("\n", "\n\t\t", treeMenu($page, $child)); } else if($child === $page) { $class .= " on on_page"; if($page->numChildren) $s = str_replace("\n", "\n\t\t", treeMenu($page, $page)); } $class .= " page-{$child->id}"; $class = " class='$class'"; $out .= "\n\t<li$class>\n\t\t<a$class href='{$child->url}'>{$child->title}</a>$s\n\t</li>"; } $out .= "\n</ul>"; return $out; } Link to comment Share on other sites More sharing options...
apeisa Posted August 22, 2011 Share Posted August 22, 2011 Put that function somewhere which is loaded by every page. Easiest solution might be to add that to your head.inc file (if you are building from demo site). That function doesn't do nothing if you don't use it. So if you want it to have some output, put this in your template file, wherever you want you menu: echo treeMenu(); If you need more help, just post your full template so I can take a better look at it. You can also send it by private message if you don't want to post it here. Also email is ok: antti.peisa -- gmail EDIT: Also note that treeMenu expands from root level to the current page. You can give it parameters to have it start and end from different pages than root and current page. Link to comment Share on other sites More sharing options...
drilonb Posted August 22, 2011 Share Posted August 22, 2011 Yes i know for it but the problem is like this i like to know, ok i will comment classes <?php function treeMenu(Page $page = null, Page $rootPage = null, $id = null) { if(is_null($page)) $page = wire('page'); if(is_null($rootPage)) $rootPage = wire('pages')->get('/'); if(!is_null($id)) $id = " id='$id'"; $out = "\n<ul$id>"; $parents = $page->parents; // This is where we get pages we want. You could just say template!=news-item foreach($rootPage->children('template!=post, template!=faq-item, template!=gallery') as $child) { $class = "level-" . count($child->parents); // for what is this class $s = ''; // for what is this if($child->numChildren && $parents->has($child)) { $class .= " on on_path"; // for what is this class $s = str_replace("\n", "\n\t\t", treeMenu($page, $child)); } else if($child === $page) { $class .= " on on_page"; if($page->numChildren) $s = str_replace("\n", "\n\t\t", treeMenu($page, $page)); } $class .= " page-{$child->id}"; $class = " class='$class'"; // for what is this class $out .= "\n\t<li$class>\n\t\t<a$class href='{$child->url}'>{$child->title}</a>$s\n\t</li>"; } $out .= "\n</ul>"; return $out; } Link to comment Share on other sites More sharing options...
apeisa Posted August 22, 2011 Share Posted August 22, 2011 Those classes are just for styling purposes, so you can edit them if needed. It doesn't output any css, that is something you have to write yourself. Also if you are building dropdown menu, then you have to add css/js also (not sure how well the markup suits for dropdown). Link to comment Share on other sites More sharing options...
drilonb Posted August 22, 2011 Share Posted August 22, 2011 Thanks for all Problem solved now menu is working like charm, Link to comment Share on other sites More sharing options...
doolak Posted August 29, 2011 Share Posted August 29, 2011 Hello there, thanks for that snippet - helped me to make my multilevel menu working! (Although i don't understand the entire code yet...). I have just one little problem: my homepage ("Home") - the root of the website is not shown in the menu - do i have to add that or should it be displayed with that code-snippet? Kind regards, Christian Link to comment Share on other sites More sharing options...
ryan Posted August 29, 2011 Share Posted August 29, 2011 I haven't tried it, but I think it would probably work if you added this right above the foreach(): $children = $rootPage->children; if($rootPage->id == 1) $children->prepend($rootPage); Then your foreach would be changed to this: foreach($children as $child) { You'll also need to add something to prevent it from going recursive on the homepage, otherwise you'll get a double menu. So I think you could take this approach -- anywhere that says $page->numChildren or $child->numChildren, change it to $page->numChildren && $child->id > 1, like this: if($child->numChildren && $child->id > 1 && $parents->has($child)) { and if($page->numChildren && $page->id > 1) $s = str_replace(...); Let me know if this works... Link to comment Share on other sites More sharing options...
doolak Posted August 29, 2011 Share Posted August 29, 2011 Hm, still not working... To be sure that i did it right, here's the code: <?php function treeMenu(Page $page = null, Page $rootPage = null) { if(is_null($page)) $page = wire('page'); if(is_null($rootPage)) $rootPage = wire('pages')->get('/'); $out = "\n<ul>"; $parents = $page->parents; $children = $rootPage->children; if($rootPage->id == 1) $children->prepend($rootPage); foreach($rootPage->children as $child) { $class = ''; $s = ''; if($child->numChildren && $child->id > 1 && $parents->has($child)) { $class = 'active'; $s = str_replace("\n", "\n\t\t", treeMenu($page, $child)); } else if($child === $page) { $class = "active"; if($page->numChildren && $page->id > 1) $s = str_replace("\n", "\n\t\t", treeMenu($page, $page)); } if($class) $class = " class='$class'"; $out .= "\n\t<li$class>\n\t\t<a href='{$child->url}'>{$child->title}</a>$s\n\t</li>"; } $out .= "\n</ul>"; return $out; } echo treeMenu(); ?> Link to comment Share on other sites More sharing options...
ryan Posted August 29, 2011 Share Posted August 29, 2011 Change this: foreach($rootPage->children as $child) { to this: foreach($children as $child) { The reason why that's necessary is because every time you call Page::children it's returning a new PageArray. So you need to specifically use the one that you ran the prepend($rootPage) on. Link to comment Share on other sites More sharing options...
doolak Posted August 29, 2011 Share Posted August 29, 2011 Yep - that did it! Thank you very much for the quick help again! And: Congratulations to your 1000th post... ;-) Link to comment Share on other sites More sharing options...
ryan Posted August 29, 2011 Share Posted August 29, 2011 Wow, 1000 posts didn't realize that. Thanks! Link to comment Share on other sites More sharing options...
Pete Posted August 30, 2011 Share Posted August 30, 2011 Must spam to catch up (kidding). I was just looking for some examples of multi-level menus for another project so this is yet another useful thread I've now got bookmarked! Link to comment Share on other sites More sharing options...
doolak Posted August 30, 2011 Share Posted August 30, 2011 Hello again... While setting up a newspage i discovered that all newsitems are listed as sub-pages in the multilevel-menu. I tried to avoid this by excluding the news-template in the modified code from above: <?php function treeMenu(Page $page = null, Page $rootPage = null) { if(is_null($page)) $page = wire('page'); if(is_null($rootPage)) $rootPage = wire('pages')->get('/'); $out = "\n<ul>"; $parents = $page->parents; $children = $rootPage->children; if($rootPage->id == 1) $children->prepend($rootPage); foreach($children('template!=news') as $child) { $class = ''; $s = ''; if($child->numChildren && $child->id > 1 && $parents->has($child)) { $class = 'active'; $s = str_replace("\n", "\n\t\t", treeMenu($page, $child)); } else if($child === $page) { $class = "active"; if($page->numChildren && $page->id > 1) $s = str_replace("\n", "\n\t\t", treeMenu($page, $page)); } if($class) $class = " class='$class'"; $out .= "\n\t<li$class>\n\t\t<a href='{$child->url}'>{$child->title}</a>$s\n\t</li>"; } $out .= "\n</ul>"; return $out; } echo treeMenu(); ?> but i get the following error: Unable to complete this request due to an error Without the part "('template!=news')" everything works fine - just the second level from news is shown. Kind regards, Christian --- Update: Found a solution - i changed this part: $children = $rootPage->children; if($rootPage->id == 1) $children->prepend($rootPage); foreach($children('template!=news') as $child) { to this: $children = $rootPage->children('template!=news_article'); if($rootPage->id == 1) $children->prepend($rootPage); foreach($children as $child) { So the excluding syntax only works when its used in a $abc->xyz context or would there be another way to have the exclusion in the "foreach($children as $child)" - part? Link to comment Share on other sites More sharing options...
Pete Posted August 30, 2011 Share Posted August 30, 2011 It has to be done that way because essentially what it's building is a database query. It's technically a bit more efficient too as you're excluding that template so it's not placing the pages you don't want into an array then. Link to comment Share on other sites More sharing options...
ryan Posted August 30, 2011 Share Posted August 30, 2011 Any time you get "Unable to complete this request because of an error", you can get more details about the error by either enabling debug mode (in site/config.php) or looking in your log file at /site/assets/logs/errors.txt. I don't see any reason why it should be erroring out, so am curious to find out more. But I did notice that one one example you referred to a "news" template and another the "news_article" template... are these two separate templates? Link to comment Share on other sites More sharing options...
doolak Posted December 27, 2012 Share Posted December 27, 2012 @ryan: Somehow i must have missed your answer in those days, sorry! There were two seperate templates, one for the news section and one for the articles. At last everything worked fine - but right now I recognized now that hiding the childs the way i did leaves the empty <ul></ul> - tag for those childs and opened a thread about that problem: After all i found the module "MarkupSimpleNavigation" from Soma now and this makes almost everything possible without digging through code. I thank you all very much for your help! 1 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