Search code examples
zend-frameworkzend-navigation

How do I add a class name to <li> from Zend Navigation XML


Can someone please help me out, I'm totally stuck! I don't know how to add a class name to <li> tag in Zend navigation XML

This is my XML

<configdata>
    <nav>
        <home>
            <label>Home </label>
            <uri>/</uri> 
        </home>

        <request>
            <label>Quotes </label>
            <uri>/quote</uri>
        </request>

        <work>
            <label>How It Works</label>
            <uri>/how-it-works</uri>
        </work>

        <information>
            <label>Informations </label>
            <uri>/informations</uri>
        </information>

        <directory>
            <class> last </class>
            <label>Directory </label>
            <uri>/directory</uri>  
        </directory>
    </nav>
</configdata>

When I add <class>last</class> this is what i get:

<li>
    <a class="last" href="/directory">Directory </a>
</li>

Currently I'm getting <a class="last"> but I need <li class="last">

Thanks so much in advance! Cheers


Solution

  • I think that the best way to put css classes into li elements would be to write your own navigation menu helper, called for example My_View_Helper_NavigationMenu that extends original Zend_View_Helper_Navigation_Menu class. For this reason I prepared an example of such a helper that overloads _renderMenu() method. The code of the method seems long, but this is because original code is long. There are only few new/modified lines in overloaded _renderMenu():

    File: APPLICATION_PATH/views/helpers/NavigationMenu.php

    class My_View_Helper_NavigationMenu extends Zend_View_Helper_Navigation_Menu { 
    
         /**
         * Renders a normal menu (called from {@link renderMenu()})
         *
         * @param  Zend_Navigation_Container $container   container to render
         * @param  string                    $ulClass     CSS class for first UL
         * @param  string                    $indent      initial indentation
         * @param  int|null                  $minDepth    minimum depth
         * @param  int|null                  $maxDepth    maximum depth
         * @param  bool                      $onlyActive  render only active branch?
         * @return string
         */
        protected function _renderMenu(Zend_Navigation_Container $container,
                                       $ulClass,
                                       $indent,
                                       $minDepth,
                                       $maxDepth,
                                       $onlyActive)
        {
            $html = '';
    
            // find deepest active
            if ($found = $this->findActive($container, $minDepth, $maxDepth)) {
                $foundPage = $found['page'];
                $foundDepth = $found['depth'];
            } else {
                $foundPage = null;
            }
    
            // create iterator
            $iterator = new RecursiveIteratorIterator($container,
                                RecursiveIteratorIterator::SELF_FIRST);
            if (is_int($maxDepth)) {
                $iterator->setMaxDepth($maxDepth);
            }
    
            // iterate container
            $prevDepth = -1;
            foreach ($iterator as $page) {
                $depth = $iterator->getDepth();
                $isActive = $page->isActive(true);
                if ($depth < $minDepth || !$this->accept($page)) {
                    // page is below minDepth or not accepted by acl/visibilty
                    continue;
                } else if ($onlyActive && !$isActive) {
                    // page is not active itself, but might be in the active branch
                    $accept = false;
                    if ($foundPage) {
                        if ($foundPage->hasPage($page)) {
                            // accept if page is a direct child of the active page
                            $accept = true;
                        } else if ($foundPage->getParent()->hasPage($page)) {
                            // page is a sibling of the active page...
                            if (!$foundPage->hasPages() ||
                                is_int($maxDepth) && $foundDepth + 1 > $maxDepth) {
                                // accept if active page has no children, or the
                                // children are too deep to be rendered
                                $accept = true;
                            }
                        }
                    }
    
                    if (!$accept) {
                        continue;
                    }
                }
    
                // make sure indentation is correct
                $depth -= $minDepth;
                $myIndent = $indent . str_repeat('        ', $depth);
    
                if ($depth > $prevDepth) {
                    // start new ul tag
                    if ($ulClass && $depth ==  0) {
                        $ulClass = ' class="' . $ulClass . '"';
                    } else {
                        $ulClass = '';
                    }
                    $html .= $myIndent . '<ul' . $ulClass . '>' . self::EOL;
                } else if ($prevDepth > $depth) {
                    // close li/ul tags until we're at current depth
                    for ($i = $prevDepth; $i > $depth; $i--) {
                        $ind = $indent . str_repeat('        ', $i);
                        $html .= $ind . '    </li>' . self::EOL;
                        $html .= $ind . '</ul>' . self::EOL;
                    }
                    // close previous li tag
                    $html .= $myIndent . '    </li>' . self::EOL;
                } else {
                    // close previous li tag
                    $html .= $myIndent . '    </li>' . self::EOL;
                }
    
    
    
    
    
    
    
    
                // ***************** THESE ARE NEW LINES *************** //
                $liMyClass = $page->get('liclass') ? $page->liclass : '' ;
    
                if ($isActive) {
                    $liClass = " class=\"active $liMyClass\" ";
                } else {
                    $liClass = $liMyClass ? " class=\"$liMyClass\" ":'';
                }
    
                // ***************** END OF NEW STUFF *************** //
    
                // render li tag and page (ORGINAL LINE REMOVED)
                //$liClass = $isActive ? ' class="active "' : '';      
    
    
    
    
    
    
    
    
    
                $html .= $myIndent . '    <li' . $liClass . '>' . self::EOL
                       . $myIndent . '        ' . $this->htmlify($page) . self::EOL;
    
                // store as previous depth for next iteration
                $prevDepth = $depth;
            }
    
            if ($html) {
                // done iterating container; close open ul/li tags
                for ($i = $prevDepth+1; $i > 0; $i--) {
                    $myIndent = $indent . str_repeat('        ', $i-1);
                    $html .= $myIndent . '    </li>' . self::EOL
                           . $myIndent . '</ul>' . self::EOL;
                }
                $html = rtrim($html, self::EOL);
            }
    
            return $html;
        }
    }
    

    In your layout.phtml you need to indicate to the navigation view helper to use this new class. You can do this as follows:

    <?php  $this->navigation()->setDefaultProxy('navigationMenu'); ?>;
    

    Finally in your navigation.xml you could define a class for a li element using liclass tag (you can use whatever name you want for this tag):

    <directory>
        <class> last </class>
        <label>Directory </label>
        <uri>/directory</uri>
        <liclass>someclass</liclass>
    </directory>
    

    Hopefully this will be helpful to you. Ideally, I should have named the new class My_View_Helper_Navigation_Menu (located in APPLICATION_PATH/views/helpers/Navigation/Menu.php). However, I could not make Zend plugin loaders to load it and I went with My_View_Helper_NavigationMenu.