Jump to content

Search the Community

Showing results for tags 'menu'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


  • Welcome to ProcessWire
    • News & Announcements
    • Showcase
    • Wishlist & Roadmap
  • Community Support
    • Getting Started
    • Tutorials
    • FAQs
    • General Support
    • API & Templates
    • Modules/Plugins
    • Themes and Profiles
    • Multi-Language Support
    • Security
    • Jobs
  • Off Topic
    • Pub
    • Dev Talk

Product Groups

  • Form Builder
  • ProFields
  • ProCache
  • ProMailer
  • Login Register Pro
  • ProDrafts
  • ListerPro
  • ProDevTools
  • Likes
  • Custom Development

Find results in...

Find results that contain...

Date Created

  • Start


Last Updated

  • Start


Filter by number of...


  • Start





Website URL







  1. In this tutorial I want to write about handling special cases and change requests by clients gracefully without introducing code bloat or degrading code quality and maintainability. I'll use a site's navigation menu as an example, as it's relatable and pretty much every site has one. I'll give some examples of real situations and change requests I encountered during projects, and describe multiple approaches to handling them. However, this post is also about the general mindset I find useful for ProcessWire development, which is more about how to handle special cases and still keep your code clean by making the special case a normal one. The problem: Special cases everywhere Since ProcessWire has a hierarchical page tree by default, as a developer you'll usually write a function or loop that iterates over all children of the homepage and displays a list of titles with links. If the site is a bit more complex, maybe you additionally loop over all grandchildren and display those in drop-down menus as well, or you even use a recursive function to iterate over an arbitrary amount of nested child pages. Something like this: function buildRecursiveMenu(Page $root): string { $markup = ['<ul class="navigation">']; foreach ($root->children() as $child) { $link = '<a class="navigation__link" href="' . $child->url() . '">' . $child->title . '</a>'; $children = $child->hasChildren() ? buildRecursiveMenu($child) : ''; $markup[] = "<li class="navigation__item">{$link}{$children}</li>"; } $markup[] = '</ul>'; return implode(PHP_EOL, $markup); } But then the requests for special cases come rolling in. For example, those are some of the requests I've gotten from clients on my projects (by the way, I'm not saying the clients were wrong or unreasonable in any of those cases - it's simply something I needed to handle in a sensible way): The homepage has the company's name as it's title, but the menu link in the navigation should just say "Home". The first page in a drop-down menu should be the top-level page containing the drop-down menu. This was requested because the first click on the top-level item opens the sub-navigation instead of navigating to that page (espcially on touch devices, such as iPads, where you don't have a hover state!), so some visitors might not realize it's a page itself. Some top-level pages should be displayed in a drop-down menu of another top-level page, but the position in the page tree can't change because of the template family settings. The menu needs to contain some special links to external URLs. For one especially long drop-down menu, the items should be sorted into categories with subheadings based on a taxonomy field. In general, my solutions to those requests fall into three categories, which I'll try to elaborate on, including their respective benefits and downsides: Checking for the special case / condition in the code and changing the output accordingly (usually with hard-coded values). Separating the navigation menu from the page tree completely and building a custom solution. Utilizing the Content Management Framework by adding fields, templates and pages that represent special states or settings. Handling it in the code This is the simplest solution, and often the first thing that comes to mind. For example, the first request (listing the homepage as "Home" instead of it's title in the navigation) can be solved by simply checking the template or ID of the current page inside the menu builder function, and changing the output accordingly: // ... $title = $child->template->name === 'home' ? 'Home' : $child->title; $link = '<a class="navigation__link" href="' . $child->url() . '">' . $title . '</a>'; // ... This is definitely the fastest solution. However, there are multiple downsides. Most notably, it's harder to maintain, as each of those special cases increases the complexity of the menu builder function, and makes it harder to change. As you add more special conditions, it becomes exponentially harder to keep changing it. This is the breeding ground for bugs. And it's much harder to read, so it takes longer for another developer to pick up where you left (or, as is often cited, for yourself in six months). Also, now we have a hard-coded value inside the template, that only someone with access to and knowledge of the template files can change. If the client want's the link to say "Homepage" instead of "Home" at some point, they won't be able to change it without the developer. Also, each special case that is hidden in the code makes it harder for the client to understand what's going on in terms of template logic - thus increasing your workload in editorial support. That said, there are definitely some times where I would go with this approach. Specifically: For smaller projects that you know won't need to scale or be maintained long-term. If you are the only developer, and/or only developers will edit the site, with no "non-technical" folk involved. For rapid prototyping ("We'll change it later") Building a custom solution My initial assumption was that the main navigation is generated based on the page tree inside ProcessWire. But of course this isn't set in stone. You can just as easily forgo using the page tree hierarchy at all, and instead build a custom menu system. For example, you could add a nested repeater where you can add pages or links on a general settings page, and generate the menu based on that. There are also modules for this approach, such as the Menu Builder by @kongondo. This approach is not the quickest, but gives the most power to the editors of your site. They have full control over which pages to show and where. However, with great power comes great responsibility, as now each change to the menu must be performed manually. For example, when a new page is added, it won't be visible in the menu automatically. This is very likely to create a disconnect between the page tree and the menu (which may be what you want, after all). You may get ghost pages that are not accessible from the homepage at all, or the client may forgot to unpublish pages they don't want to have any more after they've removed them from the menu. I would only go with this approach if there are so many special cases that there hardly is a "normal case". However, even then it might not be the best solution. The direct relationship between the page tree, the menu structure and page paths are one of the strongest features of ProcessWire in my opinion. If many pages need to be placed in special locations without much structure in regards to what templates go where, maybe you only need to loosen up the template family settings. I have built one site without any template family restrictions at all - any page of any template can go anywhere. It's definitely a different mindset, but in this case it worked well, because it allowed the client to build custom sections with different page types grouped together. It's a trade-off, as it is so often, between flexibility and workload. Weigh those options carefully before you choose this solution! Utilizing the CMF This is the middle ground between the two options above. Instead of building a completely custom solution, you keep with the basic idea of generating a hierarchical menu based on the page tree, but add fields and templates that allow the editor to adjust how and where individual pages are displayed, or to add custom content to the menu. of course, you will still write some additional code, but instead of having hard-coded values or conditions in the template, you expose those to the client, thereby making the special case one of the normal cases. The resulting code is often more resilient to changing requirements, as it can not one handle that specific case that the client requested, but also every future change request of the same type. The key is to add fields that enable the client to overwrite the default behaviour, while still having sensible defaults that don't require special attention from the editor in most cases. I'll give some more examples for this one, as I think it's usually the best option. Example 1: Menu display options This is probably the first thing you thought of for the very first change request I mentioned (displaying the homepage with a different title). Instead of hard-coding the title "Home" in the template, you add a field menu_title that will overwrite the normal title, if set. This is definitely cleaner than the hard-coded value, since it allows the client to overwrite the title of any page in the menu. I'll only say this much in terms of downsides: Maybe the menu title isn't really what the client wanted - instead, perhaps they feel limited because the title is also displayed as the headline (h1) of the page. In this case, the sensible solution would be an additional headline field that will overwrite the h1, instead of the menu_title field. Which fields are really needed is an important consideration, because you don't want to end up with too many. If each page has fields for the title, a headline, a menu title and an SEO-title, it's much more complicated than it needs to be, and you will have a hard time explaining to the client what each field is used for. Another example in this category would be an option to "Hide this page in the menu". This could be accomplished by hiding the page using the inbuilt "hidden" status as well, but if it's hidden it won't show up in other listings as well, so separating the menu display from the hidden status might be a good idea if your site has lots of page listings. Example 2: "Menu link" template One solution that is quite flexible in allowing for custom links to pages or external URLs is creating a menu-link template that can be placed anywhere in the page tree. This templates can have fields for the menu title, target page and/or external target URL. This way, you can link to another top-level page or an external service inside a drop-down menu, by placing a Menu Link page at the appropriate position. This is also a clean solution, because the navigation menu will still reflect the page tree, making the custom links visible and easily editable by the editors. A minor downside is that those templates are non-semantical in the sense that they aren't pages with content of their own. You'll need to make sure not to display them in listings or in other places, as they aren't viewable. It may also require loosening up strict family rules - for example, allowing for Menu Link pages to be placed below the news index page, which normally can only hold news pages. Example 3: Drop-down menu override This one is a more radical solution to override drop-down menus. You add a repeater field to top-level pages, similar to the one mentioned as a custom solution, where you can add multiple links to internal pages or URLs. If the repeater is empty, the drop-down menu is generated normally, based on the sub-pages in the page tree. But if the repeater contains some links, it completely overrides the drop-down menu. It's similar to the fully custom solution in that as soon as you override a sub-menu for a top-level page, you have to manually manage it in case the page structure changes. But you can make that decision for each top-level page individually, so you can leave some of them as is and only have to worry about the ones that you have overwritten. Again, this offers sensible defaults with good customizability. A downside is that the mixed approach may confuse the client, if some changes to the page tree are reflected in the drop-down menu directly, while others don't seem to have any effect (especially if you have multiple editors working on a site). Finding the right solution So how do you choose between the approaches? It depends on the client, the requirements, and on what special cases you expect and want to handle. Sometimes, a special request can be turned down by explaining how it would complicate editorial workflows or have a negative impact on SEO (for example, if you risk having some pages not accessible from the homepage at all). Also, make sure you understand the actual reason behind a change request, instead of just blindly implementing the suggestion by the client. Often, clients will suggest solutions without telling you what the actual problem is they're trying to solve. For example: In one case, I implemented the drop-down override mentioned in example three. However, what the client really wanted was to have the top-level page as the first item in the drop-down menu (see the example requests mentioned above). So they ended up overwriting every single drop-down menu, making the menu harder to maintain. In this case, it would have been better to go with a more specialized solution, such as adding a checkbox option, or even handling it in the code, since it would have been consistent throughout the menu. Another example was mentioned above: If the client requests an additional "Menu title" field, maybe what they really need is a "Headline" field. I recommend reading Articulating Design Decisions by Tom Greever; it includes some chapters on listening to the client, finding out the real reason behind a change request, and responding appropriately. It's written from a design perspective, but is applicable to development as well, and since UX becomes more important by the day, the lines between the disciplines are blurred anyway. Conclusion I realize now this reads more like a podcast (or worse, a rant) than an actual tutorial, but hopefully I got my point across. ProcessWire is at is greatest if you utilize it as a Content Management Framework, creating options and interfaces that allow for customizability while retaining usability for the client / editor. I usually try to hit a sweet spot where the editors have maximum control over the relevant aspects of their site, while requiring minimal work on their part by providing sensible defaults. Above, I listed some examples of requests I've gotten and different solutions I came up with to handle those with custom fields or templates. Though in some cases the requirements call for a custom solution or a quick hack in the template code as well! What are some of the special requests you got? How did you solve them? I'd love to get some insights and examples from you. Thanks for reading!
  2. I want to remove the "Home" page from the navbar, but keep the other pages (About, Templates, etc) on the navbar? How is this done?
  3. Hello PW Community, really glad that discovered this CMS recently, it is very strange it took so long That idea of no front design limitations is just awesome! Need to say that I have a bit of knowledge of html and css, but almost no php, so I need your help. What I want to do is an article posting cms, with this structure: - Homepage - Projects - Articles -- Category 1 --- Articles of category 1 -- Category 2 --- Articles of category 2 - About - Contact Found this ProcessWire Profile https://github.com/tutsplus/how-to-create-an-ajax-driven-theme-for-processwire It covers almost all my needs, except the menu. When I add a childpage for this page http://artist.nicegrp.com/publications/world-world/ , World:World doesn't appear under Writings & Publications. I need a menu that works like a breadcrumb, that shows on the menu the category that you are viewing. So when I'm in articles page, on the menu it shows only articles and it's categories. When I get into a category, that category takes state active link but doesn't show on the menu links and titles for contained articles. How can I do that? Sorry for my long writing and English, it is not my native but I hope you understood what I need. Can you help me with that? Thank you
  4. hi everyone I am trying get a full width sub-menu on 3rd item in menu or navbar which is coming from a loop. i was hoping this can be done by using jquery by targeting 3rd element in navbar but jquery is blocked in some browser by default so is there any other method I can do this
  5. I'm trying to understand how I could have users log in as "members", provide them with a customized experience, but still serve them cached pages? For example let's say I have 3 roles Guest Member SuperUser And let's say I have a NavBar type component that has a menu. Plus it has "log in!" if guest, or "logged in as Mike Smith" I would want guests to see a cached site with guest-only page access. Members should also see cached pages, but their menu may have access to members-only pages or fields or information. Furthermore they might have a "logged in as Mike Smith" element. SuperUsers can stay uncached. How does one go about creating that cache so that visitors aren't constantly re-creating the menu? Or that when "Sally Baker" logs in, she doesn't see a homepage that is cached for "Mike Smith" with all his elements? Thank you in advance for any replies.
  6. I tried the demo template and discovered that also other menu builders are using the Status field of a page called "Hidden: Excluded from lists and searches" for the decision if a page should be part of the menu or not. $children = $homepage->children(); // does obviously read all non-hidden pages foreach($children as $child) {...} The admin should be able to decide: [ x ] show in menu [ x ] hidden from searches Combining those options into one field is by design wrong. Or have I missed any other option here?
  7. how do i prepend home (root) to my rekursive menu this is the original code from ryan <?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; foreach($rootPage->children as $child) { $class = "level-" . count($child->parents); $s = ''; if($child->numChildren && $parents->has($child)) { $class .= " on_parent"; $s = str_replace("\n", "\n\t\t", treeMenu($page, $child)); } else if($child === $page) { $class .= " on_page"; if($page->numChildren) $s = str_replace("\n", "\n\t\t", treeMenu($page, $page)); } $class = " class='$class'"; $out .= "\n\t<li>\n\t\t<a$class href='{$child->url}'>{$child->title}</a>$s\n\t</li>"; } $out .= "\n</ul>"; return $out; } echo treeMenu(); ?>
  8. I am using @Damienov's tweaked bootstrap menu for a project, but ran into a snag. I have a few pages that I dont want to display in the header navigation (but will be used in the footer, another hurtle). Does anyone have any advice on how to achieve this?
  9. Hello, i am trying to build one Page in CMS for menu Building. i have created a field name "menu_page" Page type & one text filed name "depth" now i have crated a new repeater name "menus" with above both fields. menus (repeater) menu_page (page type, single page) depth (text) now i add it one page name "header" and added values as bellow menus1 menu_page "about us" depth (0) menus2 menu_page "About Company" depth (1) menus3 menu_page "Products" depth (3) menus4 menu_page "Contact Us" depth (0) in my template file i have code as bellow <ul> <?php $menus=$pages->get("/header/"); foreach($menus as $menu) { ?> <li><a href="<?php echo $menu->url;?>"><?php echo $menu->title;?></a></li> <?php } ?> </ul> This shows TOP menu Menu but how to get SUB menu according to Dept of each menu. Thanks
  10. i want to output a menu with just one dropdown-option and an class="active" if the user is on the active page this is my tree – root –– page A –––– child page A –––– child page A –––– … –– page B ––– child page B ––– child page B ––– child page B –– page C ––– child page C ––– child page C and the output should be like this –– page A (just dropdown, no link! just text) –––– child page A (link) –––– child page A (link) –––– … –– page B (link) (children should not be listed) –– page C (link) (children should not be listed) and if the current page matches A, B and C matches on any level a class should be added to page A or B or C this my code so far but i dont how to make page B and C an link and page A just text and how not to output the children of page B and C <?php $root = $pages->get("/"); $children = $root->children(); foreach($children as $child) { $class = $child === $page->rootParent ? " class='on'" : ""; echo "<li $class ><a >{$child->title}</a>"; echo "<ul>"; foreach($child->children as $grandchild) { echo "<li ><a href='{$grandchild->url}'>{$grandchild->title}</a></li>"; } echo "</ul></li>"; } ?>
  11. Hi all, happy to have found ProcessWire a while ago - yet another MODX refugee - and glad to have discovered PocketGrid recently I now am looking for a simple responsive menu (pure CSS or CSS+jQuery) which nicely integrates with PocketGrid. (Something like the menu in Pure - but this depends on their own grid.) Any hints? To not forget: Kudos to Ryan and to the great community!
  12. Hello I'm totaly new to PW and for now I find it very understanding, all but navigations. I tried to find some videos or tutorials explaining about this but noting helpfull comes up. I read i most of the tutorials on the forum that I could find but stil cant find the right answer. I'm making my first template and need your help on how do I create a menu like this in WP. I'm not a coder ... but understand a little. <ul class="nav navbar-nav"> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">Home <i class="fa fa-angle-down"></i></a> <ul class="dropdown-menu"> <li><a href="index-1.html">Masonry</a></li> <li><a href="index-3.html">Masonry v1</a></li> </ul> </li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">Pages <i class="fa fa-angle-down"></i></a> <ul class="dropdown-menu"> <li><a href="about-us.html">About Us</a></li> <li><a href="services.html">Services</a></li> </ul> </li> </ul> right now I'm here but it's not working right. <ul class="nav navbar-nav"> <?php $root = $pages->get("/"); function visit(Page $parent, $enter, $exit=null) { foreach ($parent->children() as $child) { call_user_func($enter, $child); if ($child->numChildren > 0) { visit($child, $enter, $exit); } if ($exit) { call_user_func($exit, $child); } } } visit( $pages->get(1) , function(Page $page) { echo '<li class="dropdown"><a href="' . $page->url . '" class="dropdown-toggle" data-toggle="dropdown">' . $page->title; if ($page->numChildren > 0) { echo '<ul class="dropdown-menu"> <li><a href="$page->url"></li> '; } else { echo '</a>'; } } , function(Page $page) { echo '</li>'; if ($page->numChildren > 0) { echo '</ul>'; } } ); ?> And I want my HOME page also to be shown. Any ideas? Thank you in advance R.
  13. In the $content .= renderNav($page->children) I was expecting a submenu like a dropdown but it's a. Now how do you make a dropdown menu using the Processwire way? Or just code like usual HTML5/CSS3 li, ul tags using "foreach ($page->children as" construct?
  14. I'm just having some trouble with my main menu, it's started happening all of a sudden across a few of my processwire sites (completely separate). I'm using MarkupSimpleNavigation to generate the menu. But when i look at the menu the Home (id 1) goes into the second position in the menu rather than the first. But when i login and check again, it's back to normal. The tree structure obviously has Home as the root. <?php $topMenu = $pages->find('id=1|1018|1026|1019|1020|1021|1023, sort=sort'); ?> <?php $treeMenu = $modules->get('MarkupSimpleNavigation'); $currentRoot = $page->rootParent(); echo $treeMenu->render( array('max_levels'=>1, 'parent_class'=>'parent', 'current_class' => 'current'), null, $topMenu ); ?> This is the code i'm using to generate the menu. Any help on this would be great. Thanks
  15. Hey there guys, Current situation: The page structure looks like this: Home ->About ->->Page 1 ->->Page 2 ->Test This structure comes back in the navbar menu. I'm using bootstrap as css/js framework. "About" is the visible container for the dropdown menu of Page 1 and Page 2. I click on About and then I see Page 1 and Page 2 which is great. What I would like to have is this: Home ->About ->Page 1 ->Page 2 ->Test and still have "About" as the visible container for Page 1 and Page 2 in the navbar so it acts like it's parent (without being an actual parent). Is there any way in processwire to have such parent page without an actual page? To get the bootstrap navbar working with the processwire page structure I was following this tutorial http://wiki.processwire.com/index.php/Bootstrap_Navbar
  16. Hello, i want to create two custom menus on my website and want to have option to add some pages in one menu and some in second page. i have created one template called top-menu this template is using repeater name "menu_pages" for page, so that i can add as many pages i want. filed name in repeater is "menu_page" after that i am calling that page in my template like that <ul class="sf-menu "> <li class="current active"><a href="<?=$config->urls->root;?>">Home</a></li> <?php $top_menu=$pages->get("/top-menu/"); foreach($top_menu->menu_pages as $menu_page) { ?> <li class=""><a href="<?php echo $menu_page->url ;?>"><?php echo $menu_page->page-tile ;?></a></li> <?php } ?> </ul> but i am getting output Home | 0 | 0 | 0 also i want to check if page have child pages then again sub menu will be created every time page have child page. i can't figure out how to do that. i saw few plugins but i want to write it myself. Thanks
  17. It struck me today, as I was working on a large site, that it would be really nice if the Setup -> Fields fly-out menu would implement the "Tags" feature to group fields into sub-menus. I use Tags (defined under the 'Advanced' tab when editing a field) to neatly organize fields on the actual Setup->Fields page. It would be great if the menu was also organized the same way. A single fly-out menu of 50+ un-grouped fields isn't so useful... What do you think?
  18. Hello there! I have a question regarding the "renderNav" function used in the ‘intermediate’ site-profile. I have a multi-level menu system going by using the renderNav function, and I’d like to extend the default "renderNav" function to also mark all the parents of any given page with "current". I think I have to modify this line from the "renderNav" function: $out .= $item->id == wire('page')->id ? "<li class='current'>" : "<li>"; … specifically adding something along the lines of foreach parent of the itemid "<li class='current'>" else "<li>", but is there a neat way of putting that into the existing line? Or how would you do it? Thanks!
  19. Hi, I have a frontend menu which is built using pages and a page select; it is output using a function that cycles through the pages and creates the menu; for this menu I wanted to also have the ability to select on some menu items which roles can see those items; I made a new field called menu_roles which selects the role; I didn't use built in roles field because it is permanent and i couldn't get rid of it off one of my templates once i added it. When i'm cycling through the pages, i'm using this to check if the current user should see the menu: $menuVis = true; if($child->menu_roles->count()) { foreach($child->menu_roles as $cmr) { $menuVis = true; $cmrRole = wire('roles')->get("$cmr->name"); if (!wire("user")->hasRole("$cmrRole") ) $menuVis = false; } } if($menuVis == false) continue; Edit: this sort of doesn't work... i can't figure out how to check multiple roles against a user at once, to get the visibility variable to be correct...Aarrgh! logic
  20. I need to outsource some navigation / menu work. If you are interested, please PM me and I can send you full requirements Basically, I need to outsource A 2-level drop down menu First level of links should be determined by the Page Field. 2nd level are just child pages Incorporate the drop down menu into http://www.meantheme...ugins/meanmenu/ I can handle the styling. Really need someone to just create the mechanism, simple CSS and PHP, This is a paid job. Thanks
  21. Hello ProcessWire community, I'm brand new to this great CMS and used to work before with Joomla. I'm trying to understand more and more how ProcessWire works as I actually realize an project with it. I'm not an developer an my skills are yet restricted - I'm still learning . So far I'm doing fine until I sumbled over the navigation... I searcherd and read a lot here in the forum but I guess it would be great if someone could give an idea, the right path or a solution for what I need to realize: - Home (only an menu-icon) -> on click the next children show (got that done with a little jquery) - Child 1 - Sub-Child 1 - Sub-Child 2 - Sub-Child 3 - Child 2 - Child 3 ... -> Now, on mouseover of an child, I need the Sub-Children to show up -> toggle - Child 1 will swap to Sub-Child 1, Sub-Child 2, Sub-Child 3) but the main link remains still to parent (Child 1). Any help or ideas are very appreciated. Regards, Bacelo
  22. My second PW site, theanodyne.com, features info for a local bar & pool hall and is designed to look like a vintage menu. They love how easy it is to update the site.
  23. Hello, I am trying to set up a multi-level menu in nested unordered lists. Specifically, I want to get pages from the first three levels in the page hierarchy. Since the page structure is somewhat complex and I wanted it to be flexible in the future, I added a checkbox field named "in_main_menu" that I can then use as a selector, in case some pages should not appear in the menu. The top level menu was easy: $main_menu = $pages->find('parent=/, in_main_menu=1, sort=sort, limit=7'); Then, as I was thinking through how to set up the nested navigation under each main menu item, I was thinking a "maximum depth" selector would be handy. Return all pages matching this selector that are no more than 3 levels deep in the hierarchy. I could not find a way to do that with selectors, though. I believe such a method would not return the pages in the exact order I want, anyway. My next thought was that I can just perform a find that returns all pages with in_main_menu, then process the results and build an array in the desired format. I'm not totally sure how that processing would work; I think it would be a bit complicated. Rather than dive into that . . . my final attempt (before posting now ) was to loop through the main menu pages and call children() on each of those. Then repeat for the third level. This seems to work, except for the third level, where I get an error. # loop: main menu pages foreach ( $main_menu as $main ) { // output top-level menu item # if: secondary menu if ( $secondary_menu = $main->children('in_main_menu=1') ) { # loop: secondary menu pages foreach ( $secondary_menu as $second ) { // output second-level menu item # if: tertiary menu if ( $tertiary_menu = $second->children('in_main_menu=1') ) { # loop: tertiary menu pages foreach ( $tertiary_menu as $third ) { // output third-level menu item } # end loop: tertiary menu pages } # end if: tertiary menu } # end loop: secondary menu pages } # end if: secondary menu } # end loop: main menu pages And it looks like this will work! My question, though, is whether I'm overlooking a simpler method. I would welcome your feedback. I realize I could abstract my code into a function (that would also allow N-levels), but I'm curious if there's even easier ways with the PW API.
  24. Recently I've been working on a site where it seemed like it was going to be impossible to keep the page tree and the needs of the site's main menu in harmony; So to solve this I setup a separate page tree under a hidden page called 'Main Menu', with each menu item having three fields: title, menu-link-page, and menu-link-url. All of the menu items are also hidden, so the code below uses the include=all parameter when getting the pages for the tree. To generate the main menu markup, i adapted the great code that was developed by Soma for Joss's bootstrap menu, and modified it to output links to the menu-link-page or menu-link-url; (Entering a value in the menu-link-url field overrides any selection in the menu-link-page.) This solution has enabled me to setup the menu exactly how the site needs it, even if the menu heirarchy is not the same as the page heirarchy, and has solved a lot of problems and made things easier for this scenario. For example, menu items can easily contain external URLs, to subdomain pages, or other related site's pages. (In this case the client has a separate web store for selling parts). Also, all of the parent menu items had to use a javascript:void() as the href, in order for the accordion version to work right on mobile; So this was easy to do by putting that into the menu-item-link field. In the code below, page #1271 contains the menu tree, so it is specified as a parameter to the $root variable. I think this sort of setup, using a custom menu tree, could solve a lot of the questions I've seen recently on the forum; I probably wouldn't use this technique on small sites since it is more work, but for larger ones where you might need a lot of menus, this could be helpful. Also, if you had to setup a Mega Menu, with images and icons, this might make it easier to manage. <?php /** * render custom markup menu for bootstrap nested navigation * * @param PageArray $pa pages of the top level items * @param Page $root root page optional, if you use other root than home page (id:1) * @param string $output for returned string collection * @param integer $level internally used to count levels * @return string menu html string */ function renderChildrenOf($pa, $root = null, $output = '', $level = 0) { if(!$root) $root = wire("pages")->get(1); $output = ''; $level++; foreach($pa as $child) { $class = ''; $has_children = count($child->children('include=all')) ? true : false; if($has_children && $child !== $root) { if($level == 1){ $class .= 'parent'; // first level boostrap dropdown li class //$atoggle .= ' class="dropdown-toggle" data-toggle="dropdown"'; // first level anchor attributes } } // make the current page and only its first level parent have an active class if($child->menu_item_page === wire("page")){ $class .= ' active'; } else if($level == 1 && $child !== $root){ if($child->menu_item_page === wire("page")->rootParent || wire("page")->parents->has($child)){ $class .= ' active'; } } $class = strlen($class) ? " class='".trim($class)."'" : ''; if($child->menu_item_url) {$childlink = $child->menu_item_url; } else { $childlink = $child->menu_item_page->url; } $output .= "<li$class><a href='$childlink'>$child->title</a>"; // If this child is itself a parent and not the root page, then render its children in their own menu too... if($has_children && $child !== $root) { $output .= renderChildrenOf($child->children('include=all'), $root, $output, $level); } $output .= '</li>'; } $outerclass = ($level == 1) ? "accordmobile" : ''; return "<ul class='$outerclass'>$output</ul>"; } // bundle up the first level pages and prepend the root home page // $root = $pages->get(1); // $pa = $root->children; // $pa = $pa->prepend($root); // Set the ball rolling... // echo renderChildrenOf($pa); // example with pages further down in the tree $root = $pages->get("1271"); $pa = $root->children('include=all'); // $pa = $pa->prepend($root); // add the root as the second parameter echo renderChildrenOf($pa,$root);
  25. If I go into the Processwire admin and select 'Home->Chidren' I'm presented with a list of pages underneath home. The 'sort settings' sections has a set of instructions that reads "Leave the sort field blank if you want to be able to drag-n-drop to your own order." Unfortunately, there is no way to make the drop down blank, and that's also somewhat counterintuitive since Drag-n-drop as an option makes perfect sense. In any event, none of the pages are draggable in order to sort them—are they draggable somewhere else in the admin?
  • Create New...