Jump to content

How can I keep second level menu item active on third level subpage?


ljones
 Share

Recommended Posts

I am working on a simple photo gallery site where I have

level one: Home, Galleries, Statement

level two: Set 1, Set 2, Set 3 etc. (under Galleries)

level three: a template that cycles through the child photos of Set 1, Set 2 or Set 3 set by using this code:

if ($page->prev->id) {
 echo "<a href='{$page->prev->url}'></a>";
} else {
 $lastpage = $page->siblings->last();
 echo "<a href='$lastpage->url'></a>";
}

echo "<a href='{$page->parent->url}'></a>";

if ($page->next->id) {
 echo "<a href='{$page->next->url}'></a>";
} else {
 $firstpage = $page->siblings->first();
 echo "<a href='$firstpage->url'></a>";
}

echo "<img class='centered' src ='{$page->images->first()->url}'";

The level one and two navigation menus show the the active links as "on" and highlighted according to my CSS declarations at level two. For example:

Home Galleries Statement

[set One] [set Two] [set Three]

[Thumbnail 1] [Thumnail 2] [Thumbnail 3]

But clicking on the Thumnail 2 and cycling through turns off the Set Two link:

Home Galleries Statement

[set One] [set Two] [set Three]

<prev [image detail] next>

What do I need to add or change to make the second level navigation show as being "on"?

This is the code I am using in the header included in all templates at level 1, 2, and 3:

<div id="primary-menu">
<?php

// Create the top navigation list by listing the children of the homepage.
// If the section we are in is the current (identified by $page->rootParent)
// then note it with <a class='on'> so we can style it differently in our CSS.
// In this case we also want the homepage to be part of our top navigation,
// so we prepend it to the pages we cycle through:

$homepage = $pages->get("/");
$children = $homepage->children;
$children->prepend($homepage);

foreach($children as $child) {
 $class = $child === $page->rootParent ? " class='on'" : '';
 echo "<a$class href='{$child->url}'>{$child->title}</a>";
 echo "       ";
}

?>

</div>
		   <div id="secondary-menu">

<?php
 echo "<hr>";
// Output subnavigation
//
// Below we check to see that we're not on the homepage, and that
// there are at least one or more pages in this section.
//
// Note $page->rootParent is always the top level section the page is in,
// or to word differently: the first parent page that isn't the homepage.
if($page->path != '/' && $page->rootParent->numChildren > 0) {
 // We have determined that we're not on the homepage
 // and that this section has child pages, so make navigation:

 foreach($page->rootParent->children as $child) {
  $class = $page === $child ? " class='on'" : '';
  echo "<a$class href='{$child->url}'>{$child->title}</a>";
  echo "       ";
 }
echo "<hr>";
	 }
  ?>
Link to comment
Share on other sites

  • 1 year later...

Hello all,

I'm new here and this is my first post. Found PW a couple of weeks ago and working on my first project. So far I can say it is fun developing with PW. I like the whole concept, the documentation is great and the forum is the best I have seen so far.

I had the same problem with highlighting parent menu items when one of their children is the current page. Reading this thread and following the link in previous post, I came up with a solution that is working great for me. Here's my piece of code:

foreach($page->rootParent->children as $child) {

	$class = $page === $child || $child->children->has($page) ? " class='active'" : ''; ?>
						
	<li><a<?php echo $class; ?> href='<?php echo $child->url ?>'><?php echo $child->title ?></a></li>
<?php } ?>

The bit that does the highlighting for parent menu items is

$child->children->has($page)

As easy as that  :)

I was first trying to solve it with native PHP strpos funtion before I realised that the PW API offers the has() function which really makes life a lot easier.

If there are better ways to achieve the same goal, I would love to learn them.

Cheers

gerhard

  • Like 1
Link to comment
Share on other sites

In the same line of thought.... I have a menu with months and a submenu with days for every month. The idea is to click on a month's name, then a day's number and see a list of pages that have a matching 'month' and 'day' field. 'months' is a parent with 12 children (january, february,....), every month is a parent with 29, 30 or 31 children (january_01, january_02,....).

When I'm on the 'months' page I see the '12-months' menu, when I click on a month I see the 'days menu'. But when I click on a day, the 'days menu' disappears. While the list of items for that month and day shows up correct.

In the code below, where is my 'days menu' disappearing?

<!-- NAVIGATION FOR MONTHS -->
	<div>
	<ul id='topnavmonths'>
	<?php			
	$monthpage = $pages->get("/events/months/"); 
	$children = $monthpage->children;
	foreach($children as $child) {
	$class = $child === $page ? " class='on'" : '';
	echo "<li><a$class href='{$child->url}'>{$child->title}</a></li>";
	};
	?>
	</ul>
	</div>
	<br>
<!-- NAVIGATION FOR DAYS -->
	<div>
	<ul id='topnavmonths'>
	<?php
	if ($page->parent->name==months) {
	$daypage = $pages->get("/events/months/$page->name/");
	}
	else {
	$daypage = $pages->get("/events/months/$page->parent->name/");
	};
	$children = $daypage->children;	
	foreach($children as $child) {
	$class = $child === $page ? " class='on'" : '';
	echo "<li><a$class href='{$child->url}'>{$child->bfd_day->title}</a></li>";
	};
	?>
	</ul>
	</div>

For a (not) working example: http://www.birthfactdeathcalendar.net/bfd_processwire/events/

Link to comment
Share on other sites

When I'm on '/events/months/january/january-02/' $page->parent->name=january

I added a bit of code on the page to make it visible:

	<?php echo "<br><br>page name = {$page->name} / parent name = {$page->parent->name}<br>";
	 if ($page->parent->name==months) {
	 echo "parent=/months/<br>";
	 }
	 elseif ($page->parent->name==january) {
	 echo "parent=/january/"; 
	 }
	 else {
	 echo "nope";
	 };
	 ?>
Link to comment
Share on other sites

Huh, less is more I guess. Anyway, it works. Thank you!

One more (additional) question: how do I keep the 'class' 'on' for months when events are shown?

$class = $child === $page ? " class='on'" : '';

Keeps the parent 'on' but it should keep the parent of parent 'on' as well to have a better idea of the navigation.

ps @ gebeer -> http://www.birthfactdeathcalendar.net/bfd_processwire/the-eyes/1-january-2000-bangkok-thailand/

Link to comment
Share on other sites

Glad it helped.

For keeping class on for month when you are on the day page:

$class = $page === $child || $child->children->has($page) ? " class='active'" : ''; 

Worked fine for my case.

Or the other way around like diogo suggested a few posts above:

$class = $page === $child || $page->parents->has($child) ? " class='active'" : ''; 

Hope it helps.

PS: nice picture from Bkk

 

  • Like 3
Link to comment
Share on other sites

This doesn't change anything. The status of 'events' is 'on', months are off and days is 'on'. Same with all three solutions, my original one, yours and Diogo's.

As soon as I've completed some more coding I'll start adding more content, including more BKK pictures into 'the eyes'.

Link to comment
Share on other sites

Where did you add the code?

It should go into the code for the month menu

<!-- NAVIGATION FOR MONTHS -->
	<div>
	<ul id='topnavmonths'>
	<?php			
	$monthpage = $pages->get("/events/months/"); 
	$children = $monthpage->children;
	foreach($children as $child) {
	$class = $page === $child || $child->children->has($page) ? " class='on'" : '';
	echo "<li><a$class href='{$child->url}'>{$child->title}</a></li>";
	};
	?>
	</ul>
	</div>

$page and $child represent the month page that you are currently on.

$child->children represents the day pages of that month.

has($page) now checks if the page we are currently on is in the day pages of the month we are in.

This should do the trick.

  • Like 1
Link to comment
Share on other sites

  • 1 year later...
$class = $page === $child || $child->children->has($page) ? " class='active'" : ''; 

nice one gebeer, thanks for sharing!

didn't made it for me properly because then the homepage menu would be active too. But it pointed me in the right direction

so I'm successfully using this now

$item->child("id=$page->id") === $page

$item would be $child in the above examples

  • Like 1
Link to comment
Share on other sites

  • 9 months later...

just had to do a simple 1-level menu on my new website and was once again surprised how easy things can be with the great API. i was doing navigations like in the examples above but today i took a slightly different approach that in my opinion is a little bit better to read and maybe easyer/cleaner to understand:

function renderMenu($page) {
    // get the root page
    $hp = wire('pages')->get('/');

    // set pages that should have "active" class
    // remove root page otherwise this would always be active
    // if current page == rootpage it will be appended and set active
    $active = $page->parents
        ->remove($hp)
        ->append($page);

    // set pages that should be shown in the menu
    // easy in this case because it is only 1-level
    $menuitems = $hp->children
        ->prepend($hp);

    // return the markup
    $out = '';
    foreach($menuitems as $item) {
        $cls = ($active->has($item)) ? ' class="uk-active"' : '';
        $out .= '<li' . $cls . '><a href="' . $item->url . '">' . $item->title . '</a></li>';
    }
    return $out;
} 

or with less comments and most on one line:

function renderMenu($page) {
    $hp = wire('pages')->get('/');
    $active = $page->parents->remove($hp)->append($page);
    $menuitems = $hp->children->prepend($hp);

    $out = '';
    foreach($menuitems as $item) {
        $cls = ($active->has($item)) ? ' class="uk-active"' : '';
        $out .= '<li' . $cls . '><a href="' . $item->url . '">' . $item->title . '</a></li>';
    }
    return $out;
} 

of course that is really a little difference to the examples above, but sometimes for me it got a little confusing to handle the "active" class with some IFs and ORs and ANDs and the approach with prepend() append() add() or remove() may be more elegant.

another thread for reference if anybody is having trouble https://processwire.com/talk/topic/288-solved-navigation-current/

  • Like 3
Link to comment
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
 Share

×
×
  • Create New...