Unlimited levels menu (class="current" on child only)

Feed 4 posts, 2 voices

Avatar
18 posts

I need help adjusting the html output for some precise css styling, because the current implementation just doesn’t cut it.

Currently the selected menu entry gets the class=“current” which is fine as long as there aren’t any second-level menu entries. When the second-level menu entry is selected the class=“current” remains on the parent which I don’t want it to. Basically, what I want is this

(currently)
  <ul>
    <li>entry 1</li>
    <li class="current">entry 2
      <ul>
	<li>sub-entry 1</li>
	<li class="current">sub-entry 2</li>
      </ul>
    </li>
    <li>entry 3</li>
  </ul>

displayed as

  <ul>
    <li>entry 1</li>
    <li>entry 2
      <ul>
	<li>sub-entry 1</li>
	<li class="current">sub-entry 2</li>
      </ul>
    </li>
    <li>entry 3</li>
  </ul>

Help would be greatly appreciated!

My navigation snippet looks like this right now:

<?php
function 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>' : '';
    foreach($page->children($arr) as $menu) :
        echo '<li'.(in_array($menu->slug, explode('/', $current->url)) ? ' class="current"': null).'>'.$menu->link($menu->title);
        displayChildren($menu, $current, true, $limits);
        echo '</li>';
    endforeach;
    echo ($startmenu) ? '</ul>' : '';
  }
}
?>
<div id="nav">
<?php
  $page = $this->find('/');
  echo '<ul>';
  echo '<li'.(in_array($page->slug, explode('/', $this->url)) ? ' class="current"': null).'>'.$page->link($page->title).'</li>';
  echo displayChildren($page, $this, false, array('obvestila' => '3', 'a-sub-page' => '1'));
  echo '</ul>';
?>
</div>
 
Avatar
1493 posts

Are you using a suffix? You could check to see that there’s nothing after the slug in the URI for the “current” class to be added … I think.

 
Avatar
18 posts

I’m not really sure how it would be possible to distinguish active items by checking the slugs. Then again my php skills equals zero so if you could elaborate a bit more would really help :)

 
Avatar
1493 posts

@skye28 – the code below only applies the “current” class as you wish. BUT, since you are styling the <li>, child pages to “current” may get its style, too. Depends on your CSS, I suppose.

<?php
function 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>' : '';
    foreach($page->children($arr) as $menu) :
        // next line: if $current url matches looped url, get current class
        echo '<li'.(($menu->url() == $current->url()) ? ' class="current"': null).'>'.$menu->link($menu->title);
        displayChildren($menu, $current, true, $limits);
        echo '</li>';
    endforeach;
    echo ($startmenu) ? '</ul>' : '';
  }
}
?>
<div id="nav">
<?php
  $page = $this->find('/');
  echo '<ul>';
  echo '<li'.(in_array($page->slug, explode('/', $this->url)) ? ' class="current"': null).'>'.$page->link($page->title).'</li>';
  echo displayChildren($page, $this, false, array('obvestila' => '3', 'a-sub-page' => '1'));
  echo '</ul>';
?>
</div>

Hope that helps.

 
Avatar
18 posts

since you are styling the <li>, child pages to “current” may get its style, too. Depends on your CSS, I suppose.

You can always target child elements, but you can’t target the parents :)
Thanks for the code! I’ll try it out later.