1

Topic: Menu with unlimited levels and children

Hi modify suckerfish menu for wolf...  it works perfectly!
So I would like to assign a CSS class for  (the same as PERCIFORMES! example)
class="daddy" for sub pages which have children

Here's the code

<?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="container">
<h3>Pour WOLF</h3>
<?php
  $page = $this->find('/');
  echo '<ul id="nav">';
  echo '<li>'.$page->link($page->title, (in_array($page->slug, explode('/', $this->url)) ? ' class="current"': null)).'</li>';
  echo displayChildren($page, $this, false);
  echo '</ul>';
?>
</div>
</div>
My Wolf CMS website (not finished)
http://wolfcms.office-web.net/

Thumbs up

Re: Menu with unlimited levels and children

Works well on this PC with Ubuntu 9.10 and FF 3.5.7 smile

Wolf CMS founder and lead developer
Please always check the Support forums and Wiki before asking. (My Ohloh account.)
Like Wolf CMS? Consider making a financial contribution.

3

Re: Menu with unlimited levels and children

Thank's but the class is not displayed with the wolf version...

My Wolf CMS website (not finished)
http://wolfcms.office-web.net/

Thumbs up

4

Re: Menu with unlimited levels and children

Could try this, oweb -- replace (line 10?):

        echo '<li'.(in_array($menu->slug, explode('/', $current->url)) ? ' class="current"': null).'>'.$menu->link($menu->title);

with something like this:

if (count($menu->children()) > 0) { $daddy = ' class="daddy"'; }
echo '<li><a href="'. $menu->url() .'"'.  $daddy .'>'. $menu->title() .'</a>';

I have left off the "current" class, though. You would need the same thing for "$page" at the end of the snippet, too (for the first item in the menu).

Does that help??

5

Re: Menu with unlimited levels and children

Nearly that (you can verify my page)... but I would like not display the class for the "first" level

<?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) :

    if (count($menu->children()) > 0) { $daddy = ' class="daddy"'; }
    echo '<li><a href="'. $menu->url() .'"'.  $daddy .'>'. $menu->title() .'</a>';

        displayChildren($menu, $current, true, $limits);
        echo '</li>';
    endforeach;
    echo ($startmenu) ? '</ul>' : '';
  }
}
?>

<div id="container">
<h3>Pour WOLF</h3>
<?php
  $page = $this->find('/');
  echo '<ul id="nav">';
  echo '<li>'.$page->link($page->title, (in_array($page->slug, explode('/', $this->url)) ? ' class="current"': null)).'</li>';
  echo displayChildren($page, $this, false);
  echo '</ul>';
?>
</div>
</div>

Last edited by oweb (2010-02-25 14:33)

My Wolf CMS website (not finished)
http://wolfcms.office-web.net/

Thumbs up

6

Re: Menu with unlimited levels and children

oweb wrote:

Nearly there ... but I would like not display the class for the "first" level

Just comment out the "echo" line with the <li> ... </li> bit in the last section:

//  echo '<li>'.$page->link($page->title, (in_array($page->slug, explode('/', $this->url)) ? ' class="current"': null)).'</li>';

I *think* that should work (and "validate"? It isn't *required" to have an LI item in a UL section, is it?).

7

Re: Menu with unlimited levels and children

Sorry, but I lost the "home" link and nothing change for others pages...

<?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) :

    if (count($menu->children()) > 0) { $daddy = ' class="daddy"'; }
    echo '<li><a href="'. $menu->url() .'"'.  $daddy .'>'. $menu->title() .'</a>';

        displayChildren($menu, $current, true, $limits);
        echo '</li>';
    endforeach;
    echo ($startmenu) ? '</ul>' : '';
  }
}
?>

<div id="container">
<h3>Pour WOLF</h3>
<?php
  $page = $this->find('/');
  echo '<ul id="nav">';
//  echo '<li>'.$page->link($page->title, (in_array($page->slug, explode('/', $this->url)) ? ' class="current"': null)).'</li>';
  echo displayChildren($page, $this, false);
  echo '</ul>';
?>
</div>
</div>
My Wolf CMS website (not finished)
http://wolfcms.office-web.net/

Thumbs up

8

Re: Menu with unlimited levels and children

oweb wrote:

I would like not display the class for the "first" level

Je suis un idiot! tongue

Can you try this? Replace:

    if (count($menu->children()) > 0) { $daddy = ' class="daddy"'; }

with this:

    if (count($menu->children()) > 0 &&  $menu->level() > 1) { $daddy = ' class="daddy"'; }

And do NOT comment out the "<li>...</li>" line near the end! Does that do it?

9

Re: Menu with unlimited levels and children

Great !
Thank's a lot cool

My Wolf CMS website (not finished)
http://wolfcms.office-web.net/

Thumbs up

10

Re: Menu with unlimited levels and children

David wrote:

...and "validate"? It isn't *required" to have an LI item in a UL section, is it?

Wrong! wink

Answer*:
<ul> and <ol> tags are containers of <li> tags.

Last edited by tokolo (2010-02-25 18:44)

11

Re: Menu with unlimited levels and children

oweb wrote:

Great !
Thank's a lot cool

Or not!

I noticed you were getting false 'class="daddy"' pages. I thought it was the result of something unusual in your site structure. In fact, it is the result of my bad code! To make sure that childless pages do NOT get a "daddy" class, replace this line:

    if (count($menu->children()) > 0 &&  $menu->level() > 1) { $daddy = ' class="daddy"'; }

with this line:

    $daddy = (count($menu->children()) > 0 && $menu->level() > 1) ? ' class="daddy"' : null;

Tested ... and should work better! (Sorry for being so slow!)

(I was getting quite a bit "wrong", eh axjezzy?! wink )

12

Re: Menu with unlimited levels and children

Hi,

I have used this code also (http://www.wolfcms.org/wiki/navbook:unlimited)
But i have problem with the limits
this works fine

<?php displayChildren($page, $this, false, array('blog' => '2') ); ?>

but if i limit to 1 than php crash and if limit to 0 than shows all menus instead if its limit

<?php displayChildren($page, $this, false, array('blog' => '0') ); ?>

Could someone please help?
thanks
Gabor

Thumbs up

13

Re: Menu with unlimited levels and children

Hi Gabor - I don't have time to look more closely just now, but I can confirm that I get the same behaviour as you describe, so it's not just you!

I recall this same thing happened with the Advanced Find plugin but it was fixed for revision 1.03, if you can find any clues there. Others might be able to help out before I can get back to this, though.

Re: Menu with unlimited levels and children

The problem is in the displayChildren function assuming the result of fetching a page's children is always an array, which in your case (setting Limit to 1) is not.

You get a Page object, not an array and this object is being passed to the foreach loop.

So, you will need to modify the function accordingly.

Btw, you may want to change:

 count($page->children()) > 0

inside the if statement, for at least, the childrenCount function. Calling the children function with no parameters will fetch all the page's children, which in some cases (i.e: Articles section) can be a considerable amount.

Thumbs up

Re: Menu with unlimited levels and children

Try this:

<?php
    function displayChildren($page, $current, $startmenu = true, $limits = null) {
        $arg = array('order' => 'position ASC, published_on DESC');
        $single = false;

        if($limits != null && array_key_exists($page->slug, $limits)) {
            $arg['limit'] = (int) $limits[$page->slug];
            $single = $arg['limit'] == 1;
        }

        if($page) {
            $childs = $page->children($arg);

            if( $childs != false && count($childs) > 0) {
                echo ($startmenu) ? '<ul>' : '';

                if(!$single) {
                    foreach($childs as $child) {
                        echo '<li'.(in_array($child->slug, explode('/', $current->url)) ? ' class="current"': null).'>'.$child->link($child->title);
                        displayChildren($child, $current, true, $limits);
                        echo '</li>';
                    }
                }
                else {
                    $child = is_array($childs) ? array_shift($childs) : $childs;

                    echo '<li'.(in_array($child->slug, explode('/', $current->url)) ? ' class="current"': null).'>'.$child->link($child->title);
                    displayChildren($child, $current, true, $limits);
                    echo '</li>';
                }

                echo ($startmenu) ? '</ul>': '';
            }
        }
    }
?>

Thumbs up

16

Re: Menu with unlimited levels and children

limit=1 works
limit=0 fails, shows all

Thumbs up

Re: Menu with unlimited levels and children

Well...
limit 0 it's the same as declaring no limit, so it's supposed to return all children.

If you want to exclude certain pages take a look at this example and customize it to your needs or you could try the adv-find plugin.

Thumbs up

Re: Menu with unlimited levels and children

Here's a variation of the function which allows finer control.

Tested using all the code parts below inside a single snippet(i.e: menu) and included in the layout.

First define a few variables needed by the function.

The $arg variable is an array of page slugs which value is another array where you can declare the same arguments as in the children function.

If you want to exclude a page (and it's descendants) from the menu set the limit to '-1'.

<?php
    // Menu setup
    $root  = Page::findByUri('/');
    $crumbs  = explode('/', CURRENT_URI);
    $current = array_pop($crumbs);

    // Page arguments
    $arg = array(
        'a'  => array('limit' => '2'),
        'b'  => array(
            'order' => 'title ASC',
            'offset' => '1',
            'limit' => '1'
        ),
        'd' => array('limit' => '-1'),
        'articles' => array('limit' => '-1')
    );
?>

Some html and the call to the function

<h3>Menu</h3>
<ul id="sidemenu">
    <li<?php if(!count($crumbs) && empty($current)) echo ' class="current"'; ?>><?php echo $root->link($root->title);?></li>
<?php echo displayChildren($root, false, $arg, $crumbs, $current); ?>
</ul>

The Function:

<?php

function displayChildren($page, $nested = true, &$arg = null, $crumbs=array(), $current='') {
    $slug = $page->slug;
    $params = array();
    $exclude = false;
    $single = false;

    if($arg != null && array_key_exists($slug, $arg)) {
        if(isset($arg[$slug]['limit'])) {
            $limit =  (int) $arg[$slug]['limit'];
            switch($limit) {
                default:
                break;
                case '1':
                    $single = true;
                break;
                case '-1':
                    $exclude = true;
                break;
            }
        }
        if(!$exclude)
            $params = $arg[$slug];

        unset($arg[$slug]);
    }

    if(!$exclude && $page) {
        $childs = $page->children($params);

        if($childs != false && count($childs) > 0 ) {
            // if limit was 1 we got an object
            if($single)
                $childs = array($childs);

            echo $nested ? PHP_EOL.'<ul>' : '';

            foreach($childs as $child) {
                $class = ($child->slug == $current) ? ' class="current"' : ( in_array($child->slug, $crumbs) ? ' class="has_current"' : '' );
                echo PHP_EOL.'<li'.$class.'>'.$child->link($child->title);
                displayChildren($child, true, $arg, $crumbs, $current);
                echo '</li>';
            }

            echo $nested ? PHP_EOL.'</ul>'.PHP_EOL: '';
        }
    }
}
?>

Each li element parent of the current page will have a class 'has_current', the current li element, the 'current' class.

So set some simple styles:

#sidemenu ul { margin:0 0 0 20px; padding:0 }
#sidebar ul li { margin:2px 0; padding:0; list-style-type:disc }
#sidemenu li.has_current > a:link, #sidemenu li.has_current > a:visited { color:#b4b4b4 }
#sidemenu li.current > a:link, #sidemenu li.current > a:visited { color:#323232 }

And you get

Sample menu

Thumbs up

Re: Menu with unlimited levels and children

You may want to replace the displayChildren function in the wiki. The one I wrote is still from Froggy days... smile (i.e. very old and far from the best)

Wolf CMS founder and lead developer
Please always check the Support forums and Wiki before asking. (My Ohloh account.)
Like Wolf CMS? Consider making a financial contribution.