The Navigation Cookbook
Jump to:
- MadeByFrog Sidebar navigation
- Unlimited levels and children
- Sitemap-like navigation for Sub-areas
- Four-level collapsing menu
- “Rolling” navigation in sidebar
- Inline (horizontal) navigation
MadeByFrog style submenus in the sidebar
This is the basic form of the links given in the sidebar of this site. For each “child” of “home” (usually the options in your main navigation), include this code in the sidebar:
<ul id="nav_sub">
<?php foreach ($this->children() as $child): ?>
<li><?php echo $child->link($child->title, (url_start_with($child->url) ? ' class="current"': null)); ?></li>
<?php endforeach; ?>
</ul>
You will need to work up some CSS for the nav_sub id, of course.
Unlimited levels and children
This is a recursive function that allows the user to display an unlimited number of levels and children in a static menu. It also allows you to limit the number of children that are displayed for particular pages. This is achieved with an array of slug/limit pairs. The function’s options are:
- required, The page from where you want to start displaying the menu;
- required, The current page;
- optional, If true, start with a
<UL> - optional, An array of slug/limit pairs where limit is the maximum number of children to display for that particular slug.
<?phpfunction displayChildren($page, $current, $startmenu = true, $limits = null) { if ($limits != null && array_key_exists($page->slug, $limits)) { $arr = array('order' => 'position ASC, published_on DESC', 'limit' => $limits[$page->slug]); } else $arr = array('order' => 'position ASC, published_on DESC');if ($page && count($page->children()) > 0) { echo ($startmenu) ? '<ul class="sidemenu">' : ''; foreach($page->children($arr) as $menu) : echo '<li>'.$menu->link($menu->title, (in_array($menu->slug, explode('/', $current->url)) ? ' class="current"': null)).'</li>'; displayChildren($menu, $current, true, $limits); endforeach; echo ($startmenu) ? '</ul>' : ''; } } ?>
Just add the above function to a Snippet or Layout. Then you can use the following code on a page somewhere to produce the actual menu:
<h1>Menu</h1>
<?php
$page = $this->find('/');
echo '<ul class="sidemenu">';
echo '<li>'.$page->link($page->title, (in_array($page->slug, explode('/', $this->url)) ? ' class="current"': null)).'</li>';
echo displayChildren($page, $this, false, array('articles' => '3', 'a-sub-page' => '1'));
echo '</ul>';
?>
Sitemap-like navigation for Sub-areas
You may wish to have sidebar navigation to the pages for each “main” or “top” page (i.e., child-of-homepage) in your site. This system “automates” such menus, no matter how many “top” pages you have or delete, and no matter how deep the navigation is below them. Here’s how:
1. Make this snippet; call it, e.g., sitemap_nav:
<?php function nav_sitemap($parent) { $out = ''; $childs = $parent->children(); if (count($childs) > 0) { $out = '<ul>'; foreach ($childs as $child) $out .= '<li>'.$child->link().nav_sitemap($child).'</li>'; $out.= '</ul>'; } return $out; } ?> <?php $topSlug = explode('/', $_SERVER['REQUEST_URI']); $areaSlug = $topSlug[1] ?><div id="sitemap_nav"> <?php if ($areaSlug == 'sitemap' || $areaSlug == '') { // put what to do if on Homepage or Sitemap here; current default is to do nothing } else { echo '<p><strong><a href="'. URL_PUBLIC .'" title="Home" >Home Menu</a></strong></p>'; echo '<p><strong>'.$this->find($areaSlug)->link().'</strong></p>'; // = Top of sub-area echo nav_sitemap($this->find($areaSlug)); } ?> </div>
2. In your Layout, add the following code in your sidebar DIV:
<!-- start sitemap nav -->
<?php $this->includeSnippet('sitemap_nav'); ?>
<!-- end sitemap nav -->
(You can omit the comment lines, of course!) And that’s it.
Notes:
- By default, this code puts nothing on your homepage or sitemap page (if you have one; and if you do, this code will not break your sitemap page).
- If your Frog site is in a subdirectory (e.g. www.example.com/frog/), then change
$topSlug[1]to$topSlug[2]. - It is possible that not using
mod_rewrite(thus leaving a “?” in the URL), or using a URL suffix (e.g.,.html), will throw off the search for the slug! - The code is a bit more verbose than it needs to be; this is to keep the layout choices a little more clear. Alter these to suit your own preferences. In particular, you might want to remove the “Home Menu” line, i.e., next line after
} else { - This is somewhat like mvdkleijn’s Unlimited levels and children system (above), but it lacks the control that his system gives you over certain aspects of the navigation.
Four-level collapsing menu
Unlike the previous example, this menu provides up to four-levels of navigation (not unlimited), but it expands/collapses depending on the children of the current page. For example, this menu:
- Home
- Classical
- Jazz
- Rock
could expand to this, if you click on “Classical”:
It works up to four levels, or graphically:
- Top 1
- Child 2
- Grandchild 3
- Great-granchild 4
- Grandchild 3
- Child 2
or in terms of URL structure:
http://www.example.com/top/child/grandchild/great-grandchild
Here is the code; some notes are below.
<?php $subPageId = explode('/', $_SERVER['REQUEST_URI']); $level2=$subPageId[1]; $level3=$subPageId[2]; $level4=$subPageId[3]; ?><h3>Navigation</h3><ul><!-- top level {1} = main nav --> <li><a<?php echo url_match('/') ? ' class="current"': ''; ?> href="<?php echo URL_PUBLIC; ?>">Home</a></li> <?php foreach($this->find('/')->children() as $menu): ?> <li><?php echo $menu->link($menu->title, (in_array($menu->slug, explode('/', $this->url)) ? ' class="current"': null)); ?><?php if ($level2 != '' && strpos($_SERVER['REQUEST_URI'],$menu->slug) == true) : ?> <?php $page2 = $this->find($level2); ?><ul><!-- child level {2} --> <?php foreach ($page2->children(array()) as $menu2): ?> <li><?php echo $menu2->link(); ?><?php if ($level3 != '' && strpos($_SERVER['REQUEST_URI'],$menu2->slug) == true) : ?> <?php $page3 = $this->find($level2.'/'.$level3); ?><ul><!-- grandchild level {3} --> <?php foreach ($page3->children(array()) as $menu3): ?> <li><?php echo $menu3->link(); ?><?php if ($level4 != '' && strpos($_SERVER['REQUEST_URI'],$menu3->slug) == true) : ?> <?php $page4 = $this->find($level2.'/'.$level3.'/'.$level4); if (count($this->find($level2.'/'.$level3.'/'.$level4)->children()) > 0) : ?><ul><!-- great-grandchild level {4} --> <?php foreach ($page4->children(array()) as $menu4): ?> <li><?php echo $menu4->link(); ?></li> <?php endforeach; ?> </ul> <?php endif; endif; ?></li> <?php endforeach; ?> </ul> <?php endif; ?></li> <?php endforeach; ?> </ul> <?php endif; ?></li> <?php endforeach; ?> </ul>
Notes
- This code might not be very efficient! Suggestions on the forum for improving it are welcome.
- N.b. It does not work with URL suffixes. There is a variation in the forum which works to three levels with an
.htmlURL suffix – see the very end of the thread. - The “explode” in the first line is the key to the variables, and the version here assumes Frog is in the root of your site (e.g., www.myfrogsite.com/), not a subdir (e.g., www.mywebsite.com/frog/). If your Frog site is in a subdirectory, then increase the value in each of the square brackets by 1 (e.g.,
$subPageId[1]becomes$subPageId[2],[2]goes to[3], etc.). - If you only need three levels of navigation, just strip out the middle 9 lines (8 code + 1 blank) most deeply indented in the middle of the code, from
<?php if ($level4 != ''...to the doubleendifline. - Because this code is bulky, it is probably easiest to create a snippet for it (e.g.,
collapsing-nav), and then put it in the sidebar of your homepage using
<?php $this->includeSnippet('collapsing-nav'); ?>.
“Rolling” navigation in sidebar
(HT: mvdkleijn)
This system works to any depth of levels you choose to use, but it only gives the navigation from the current page. It is “navigation lite”: it will always point from the current page “up” to its parent (if there is one), and always point “down” from the current page to its children (if there are any). It offers a nice secondary navigation system, complementing the main top-level navigation that Frog gives by default. The menu looks something like this:
Classical
↑
Baroque
↳ Bach
↳ Telemann
↳ Vivaldi
Use this code in your site’s layout: it will not work as an “inherited” snippet. You can either put this code in the layout itself, or make a snippet for it, but call the snippet (e.g., <?php $this->includeSnippet('extra_nav') ?>) in the layout. Include it inside the sidebar DIV, probably best at the top, but you can put it anywhere you like:
<!-- START SUBNAV SYSTEM -->
<p>
<?php if ($this->level() != 0) { echo $this->parent->link($this->parent->title()).'<br />↑<br />'; } ?>
<?php echo $this->title(); ?>
<?php
if (count($this->children()) > 0 && $this->title() != 'Articles') {
echo '<br />';
foreach($this->children() as $subMenu):
echo '↳ '.$subMenu->link($subMenu->title, (in_array($subMenu->slug, explode('/', $this->url)) ? ' class="current"': null)).'<br />';
endforeach;
};
echo (count($this->children()) > 0 && $this->slug() == 'articles') ? '<br />↓' : '';
?>
</p>
<!-- END SUBNAV SYSTEM -->
This menu system:
- checks to see whether you are “Home”, in which case the “upward” navigation is omitted;
- checks to see whether it is your “Articles” page,1 and if it is, points only to the Monthly Archives which are (by default) beneath it;
- prints the current page title (unlinked, of course);
- lists all the subpages to the current page with links.
You can always change the arrows/layout, etc., as you please. Note that this approach does not use a ul, but just a series of <br />’s.
1 If you have changed the name of your Articles page to “News” (or whatever), you will need to change the all the occurrences of “A/articles” in the subnav code to the new name (e.g. N/news).
Inline (horizontal) navigation
(HT: mvdkleijn)
This is simply a horizontal variation of the preceding example. Again, use this code in your site’s layout (it will not work as an “inherited” snippet). Also like the preceding example, it will always point from the current page “left” to its parent (if there is one), and always point “right” from the current page to its children (if there are any).
Classical ← Baroque → Bach | Telemann | Vivaldi |
One difference from the preceding is that if the current page is “Articles”, then it will point at monthly archive links produced by the navigation code itself, and not the sidebar’s default archive listing.
<!-- START INLINE NAV --> <?php $post = $this->find('articles'); ?> <?php $all_posts = $post->archive->archivesByMonth(); ?><div id="inlineNav"> <p> <?php if ($this->level() != 0) { echo $this->parent->link($this->parent->title()).' ← '; } ?> <?php echo $this->title(); ?> <?php if (count($this->children()) > 0 && $this->title() != 'Articles') { echo ' → '; foreach($this->children() as $inlineMenu): echo ''.$inlineMenu->link($inlineMenu->title, (in_array($inlineMenu->slug, explode('/', $this->url)) ? ' class="current"': null)).' |'; endforeach; }; if ($this->children() > 0 && $this->slug() == 'articles') { echo '→ '; foreach ($all_posts as $post_date): echo '<a href="'.$this->url.'/'.$post_date.URL_SUFFIX.'"> '.strftime('%B %Y', strtotime(strtr($post_date, '/', '-'))).'</a> |'; endforeach; } ?> </p> </div><!-- end #inlineNav --> <!-- END INLINE NAV -->
This codes functions just the same as the preceding, except for the variation with the monthly archive listing for “Articles”.1
To be continued…
