| Nathan Kelly
                                                                                                                             | Thursday 06 July 2006 2:54:28 am 
                                                                 Hi Martin, I have worked on 2 sites now that require main (top) navigation and sub (bottom) navigation to be on the page at once and here are my solutions (you may need to customise, I have some extra variables etc. in there): Suckerfish menu (drop down) 
				<ul id="main-menu">
{def $home=fetch('content', 'node', hash('node_id', $topnode_id) ) 
		$main_menu=fetch('content', 'list', hash('parent_node_id', 2,
			'sort_by', array( array( 'priority' ) ),
			'class_filter_type', include,
			'class_filter_array', array( 'folder' ) ) ) }
{def $m_count=$main_menu|count|dec()}
{foreach $main_menu as $m_index => $m_menu}
  					<li{if eq($module_result.path[1].node_id,$m_menu.node_id)} class="current"{/if}{if $m_index|eq($m_count)} id="last"{/if}><a href={$m_menu.url_alias|ezurl}><span><span>{$m_menu.name}</span></span></a>
{def $sub_menu=fetch( 'content', 'list', hash( 'parent_node_id', $m_menu.node_id,
			'sort_by', array( array( 'priority' ) ),
			'class_filter_type', include,
			'class_filter_array', array( 'folder', 'link' ) ) ) }
{def $s_count=$sub_menu|count|dec()}			
{if $sub_menu|count|gt(0)}
						<ul class="sub-menu">
{foreach $sub_menu as $s_index => $s_menu}
							<li{if $s_index|eq($s_count)} class="last"{/if}><a href={$s_menu.url_alias|ezurl}>{$s_menu.name}</a></li>
{/foreach}
						</ul>
{/if}
					</li>
{/foreach}
{undef}
				</ul>
Top main nav plus sidebar sub nav: 
<!-- top (main nav) -->
				<ul>
{def $home=fetch('content', 'node', hash('node_id', $topnode_id) ) 
		$main_menu=fetch('content', 'list', hash('parent_node_id', 2,
			'sort_by', array( array( 'priority' ) ),
			'class_filter_type', include,
			'class_filter_array', array('folder') ) ) }
{foreach $main_menu as $m_menu}
  					<li><a{if eq($module_result.path[1].node_id,$m_menu.node_id)} class="current"{/if} href={$m_menu.url_alias|ezurl}>{$m_menu.name}</a></li>
{/foreach}
{undef $home}
				</ul>	
<!-- sidebar (sub nav) -->
{def $sub_menu=treemenu($module_result.path, $module_result.node_id,
			array('standard_page','folder','contact_form','sub_page','link'), 1, 2) }
				<ul>
{def $last=0} 
{foreach $sub_menu as $s_menu}
{if and($last|ne(0), $last.level|gt($s_menu.level))}{* this if second level is open *}
					</ul>
					</li>
{/if}
					<li>
{if and($last|ne(0), $last.level|lt($s_menu.level))}{* this if there is no second level *}
					<ul>
					<li>{/if}<a{if $s_menu.is_selected} class="current"{/if} href={$s_menu.url_alias|ezurl}>{$s_menu.text}</a></li>
{set last=$s_menu}
{/foreach}
				</ul>
{undef $last}
{undef $sub_menu}
This code produces the menus found at:http://www.ccts.com.au/ccts/construction/construction_services
 Hope this helps. Cheers! Pardon me while I burst into flames...
                                                                 | 
                                                                                                    
                                                        | Philipp Simon
                                                                                                                             | Monday 10 July 2006 3:20:25 am 
                                                                 Hello guys! I rewrote the treemenu operator from scratch, so it does work recursively now. I tried to keep the old functionality, but "depth_skip" is now longer used. 'node_id' is now really used as start node. And last but not least I added an boolean value 'show_levels' to force the treemenu to show the whole subtree. Here is the code: 
class eZTreeMenuOperator
{
    /*!
     */
    function eZTreeMenuOperator( $name = 'treemenu' )
    {
        $this->Operators = array( $name );
    }
    /*!
    */
    function &operatorList()
    {
        return $this->Operators;
    }
    /*!
    */
    function namedParameterList()
    {
        return array( 'path' => array( 'type' => 'array',
                                       'required' => true,
                                       'default' => false ),
                      'node_id' => array( 'type' => 'int',
                                          'required' => true,
                                          'default' => false ),
                      'class_filter' => array( 'type' => 'array',
                                               'required' => false,
                                               'default' => false ),
                      'depth_skip' => array( 'type' => 'int',
                                             'required' => false,
                                             'default' => false ),
                      'max_level' => array( 'type' => 'int',
                                            'required' => false,
                                            'default' => false ),
                      'show_levels' => array( 'type' => 'int',
                                            'required' => false,
                                            'default' => false ),
                      'is_selected_method' => array( 'type' => 'string',
                                                     'required' => false,
                                                     'default' => 'tree' ),
                      'indentation_level' => array( 'type' => 'int',
                                                    'required' => false,
                                                    'default' => 15 ),
                      'language' => array( 'type' => 'string|array',
                                           'required' => false,
                                           'default' => false ) );
    }
    /*!
    */
    function modify( &$tpl, &$operatorName, &$operatorParameters, &$rootNamespace, &$currentNamespace, &$operatorValue, &$namedParameters )
    {
        $pathArray        = array();
        $tmpModulePath    = $namedParameters[ 'path'               ];
        $indentationLevel = $namedParameters[ 'indentation_level'  ];
        $isSelectedMethod = $namedParameters[ 'is_selected_method' ];
        $classFilter      = $namedParameters[ 'class_filter'       ];
        $depthSkip        = $namedParameters[ 'depth_skip'         ];        
        $language         = $namedParameters[ 'language'           ];
        $maxLevel         = $namedParameters[ 'max_level'          ];
        $showLevels       = $namedParameters[ 'show_levels'        ];
        $node_id          = $namedParameters[ 'node_id'            ];        
        if( $classFilter == 'false' )
        {
            $classFilter = array();
        }
        else if ( count( $classFilter ) == 0 )
        {
            $classFilter = array( 1 );
        }
        if ( $node_id === false )
        {
            $node_id = 2;
        }
        if ( $maxLevel === false )
        {
            $maxLevel = 2;
        }
        $cur_node_id = $node_id;
        $cur_node = eZContentObjectTreeNode::fetch( $cur_node_id );
        $cur_node_depth = $cur_node->attribute( "depth" );
        $params = array();
        $params[ 'Depth'            ] = 1;
        $params[ 'Offset'           ] = 0;
        $params[ 'SortBy'           ] = $cur_node->sortArray();
        $params[ 'Language'         ] = $language;
        $params[ 'ClassFilterType'  ] = 'include';
        $params[ 'ClassFilterArray' ] = $classFilter;
        $cur_children = eZContentObjectTreeNode::subTree( $params, $cur_node_id );
        eZContentObject::fillNodeListAttributes( $cur_children );
        $this->traverseChildren( $cur_children, $tmpModulePath, $cur_node_depth, $maxLevel, $showLevels, $isSelectedMethod, $indentationLevel, $params, $pathArray );
        $operatorValue = $pathArray;
    }
    /*!
    */
    function traverseChildren( & $nodeArray, $modulePath, $rootDepth, $maxDepth, $showDepths, $isSelectedMethod, $indentationLevel, $params, & $pathArray )
    {
        $keys = array_keys( $nodeArray );
        foreach ( $keys as $key )
        {
		$absDepth      = $nodeArray[ $key ]->attribute( "depth" );
		$relDepth      = $absDepth - $rootDepth - 1;
            $dataMap       = $nodeArray[ $key ]->attribute( 'data_map' );
            $contentObject = $nodeArray[ $key ]->attribute( 'object' );
            $childrenCount = $nodeArray[ $key ]->attribute( 'children_count' );
            $name          = $nodeArray[ $key ]->attribute( 'name' );
            $tmpNodeID     = $nodeArray[ $key ]->attribute( 'node_id' );
            $url           = "/content/view/full/$tmpNodeID/";
            $urlAlias      = "/" . $nodeArray[ $key ]->attribute( 'url_alias' );
            $mainNodeID    = $nodeArray[ $key ]->attribute( 'main_node_id' );
            $indent        = $indentationLevel * ($relDepth+1);
            $isMainNode = false;
            if( $mainNodeID == $tmpNodeID )
            {
                $isMainNode = true;
            }
            $hasChildren = false;
            if( $childrenCount > 0 )
            {
                $hasChildren = true;
            }
            $isActive = false;
            $isSelected = false;
            if( $modulePath[ $absDepth-1 ][ 'node_id' ] == $tmpNodeID )
            {
                $isActive = true;
                if( $isSelectedMethod == 'tree' || count( $modulePath ) == $absDepth )
                {
                    $isSelected = true;
                }
            }
            $pathArray[] = array( 'id' => $nodeArray [ $key ]->attribute( "node_id" ),
                                  'level' => $relDepth,
                                  'data_map' => $dataMap,
                                  'class_name' => $contentObject->classname(),
                                  'is_main_node' => $isMainNode,
                                  'has_children' => $hasChildren,
                                  'indent' => $indent,
                                  'url_alias' => $urlAlias,
                                  'url' => $url,
                                  'text' => $name,
                                  'is_selected' => $isSelected,
                                  'node' => $nodeArray [ $key ] );
            if( $hasChildren && ( $showDepths || $isActive ) && ( $maxDepth > ($relDepth+1) ) )
            {
                $params[ 'SortBy' ] = $nodeArray[ $key ]->sortArray();
                $subNodeArray = eZContentObjectTreeNode::subTree( $params, $tmpNodeID );
                eZContentObject::fillNodeListAttributes( $subNodeArray );
                if( $subNodeArray && count( $subNodeArray ) > 0 )
                {
                    $this->traverseChildren( $subNodeArray, $modulePath, $rootDepth, $maxDepth, $showDepths, $isSelectedMethod, $indentationLevel, $params, $pathArray );
                }
            }
        }
    }
    /// \privatesection
    var $Operators;
};
And here is my test template for the left menu. I added support for internal as well as external links. (external opens a new window) And I added support for links like "ezNode://66", which will fetch the node and use its url_alias then. So when changing the target url, the link will still be valid. One word about the root node fetching. My menu looks like this: 
- ROOT (ID=2)- - Home (ID=80)
 - - Service
 - - - Service 1
 So when I am on the ROOT (entry site), I will fetch the menu of the folder "Home". I wanted to keep the url unchanged, but have an own home sidemenu. So whatever you do, you have to tweak this for your own use. 
<div id="leftmenu">
<div id="leftmenu-design">
<h3 class="hide">{"Left menu"|i18n("design/base")}</h3>
<div class="toolbox">
<div class="toolbox-design">
{let $root_node=fetch( content, node, hash( node_id, is_set( $module_result.path[1].node_id )|choose( 80, $module_result.path[1].node_id ) ) )}
<h2>{$root_node.name}</h2>
     
<div class="toolbox-content">
{let docs=treemenu( $module_result.path,
                    $root_node.node_id,
                    ezini( 'MenuContentSettings', 'LeftIdentifierList', 'menu.ini' ),
                    0,
                    3,
                    true() )
                    depth=1
                    last_level=0}
<ul>
{section var=menu loop=$:docs last-value}
    {set last_level=$menu.last|is_array|choose( $menu.level, $menu.last.level )}
    {section show=and( $last_level|eq( $menu.level ), $menu.number|gt( 1 ) )}
        </li>
    {section-else}
        {section show=and( $last_level|gt( $menu.level ), $menu.number|gt( 1 ) )}
            </li>
            {"</ul>
            </li>"|repeat(sub( $last_level, $menu.level ))}
        {/section}
    {/section}
    {section show=and( $last_level|lt( $menu.level ), $menu.number|gt( 1 ) )}
        {'<ul><li>'|repeat(sub($menu.level,$last_level,1))}
        <ul>
        <li class="menu-level-{$menu.level}">
    {section-else}
        <li class="menu-level-{$menu.level}">
    {/section}
    {if eq( $menu.class_name, 'Link' )}
        {def $link_content = $menu.node.object.data_map.location.content}
        {if $link_content|contains( 'ezNode' )}
            {def $tmpNodeParts = $link_content|explode( '//' )}
            {def $tmpNodeId = $tmpNodeParts[ 1 ]}
            {let $tmpNode=fetch( content, node, hash( node_id, $tmpNodeId ) )}
                » <a href={$tmpNode.url_alias|ezurl}>{$menu.text|shorten( 25 )}</a>
            {/let}
            {undef $tmpNodeParts}
            {undef $tmpNodeId}
        {elseif $link_content|contains( 'http://' )}
            » <a href={$link_content} target="_new">{$menu.text|shorten( 25 )}</a>
        {else}
            » <a href={$link_content|ezurl}>{$menu.text|shorten( 25 )}</a>
        {/endif}
    {else}
        » <a {$menu.is_selected|choose( '', 'class="selected"' )} href={$menu.url_alias|ezurl}>{$menu.text|shorten( 25 )}</a>
    {/endif}
    {set depth=$menu.level}
{/section}
</li>
{section show=sub( $depth, 0 )|gt( 0 ) loop=sub( $depth, 0 )}
    </ul>
    </li>
{/section}
</ul>
{/let}
{/let}
</div>
</div>
</div>
</div>
</div>
<b>Although I did a fast test, I am not sure about bugs. So be careful using this code! If you find bugs, please report them to me.</b> Have fun! Phil |