WordPress.org

Ready to get started?Download WordPress

Forums

MAJpage Menu Class Extender
[resolved] Odd class to odd li's within 'sub-menu' ul's (3 posts)

  1. Luke Etheridge
    Member
    Posted 1 year ago #

    Hey duzymaju,

    Great plugin mate so props for making it ;)

    As I'm a theme developer I'd prefer not to rely on too many plugins so was wondering if you could just tell me how to do the following...

    Give an 'odd' class to all odd li's within all 'sub-menu' ul's.

    So that's the first 'sub-menu' after a parent, and all 'sub-menu' ul's within it.

    Here's the custom walker I'm currently using so if you could edit this that would be awesome!

    class Menu_With_Description extends Walker_Nav_Menu
    {
    
        	function start_lvl(&$output, $depth) {
            	$indent = str_repeat("\t", $depth);
            	$output .= "\n$indent<ul class=\"sub-menu level-".$depth."\">\n";
        	}
        	function end_lvl(&$output, $depth) {
            	$indent = str_repeat("\t", $depth);
            	$output .= "$indent<div class=\"fix\"></div></ul><div class=\"fix\"></div>\n";
        	}
    
        /**
         * Start the element output.
         *
         * @param  string $output Passed by reference. Used to append additional content.
         * @param  object $item   Menu item data object.
         * @param  int $depth     Depth of menu item. May be used for padding.
         * @param  array $args    Additional strings.
         * @return void
         */
         function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output )
    {
        $id_field = $this->db_fields['id'];
        if ( is_object( $args[0] ) ) {
            $args[0]->has_children = ! empty( $children_elements[$element->$id_field] );
        }
        return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }
    
        function start_el(&$output, $item, $depth, $args)
        {
    
            $classes     = empty ( $item->classes ) ? array () : (array) $item->classes;
    
            $class_names = join(
                ' '
            ,   apply_filters(
                    'nav_menu_css_class'
                ,   array_filter( $classes ), $item
                )
            );
    
            if ($args->has_children && $depth == 0){
            ! empty ( $class_names )
                and $class_names = ' class="'. esc_attr( $class_names ) . ' has_children"';
            }else{
             ! empty ( $class_names )
                and $class_names = ' class="'. esc_attr( $class_names ) . '"';
            }
    
            $output .= "<li id='menu-item-$item->ID' $class_names>" ;
            $attributes  = '';
    
            ! empty( $item->attr_title )
                and $attributes .= ' title="'  . esc_attr( $item->attr_title ) .'"';
            ! empty( $item->target )
                and $attributes .= ' target="' . esc_attr( $item->target     ) .'"';
            ! empty( $item->xfn )
                and $attributes .= ' rel="'    . esc_attr( $item->xfn        ) .'"';
            ! empty( $item->url )
                and $attributes .= ' href="'   . esc_attr( $item->url        ) .'"';
    
            // insert description for top level elements only
            // you may change this
            $description = ( ! empty ( $item->description ) and 0 == $depth )
                ? '<span class="description">' . esc_attr( $item->description ) . '</span>' : '';
    
            $title = apply_filters( 'the_title', $item->title, $item->ID );
    if ( $depth == 0 ) {//top level items
                $item_output = $args->before
                ."<div class='parent'><div class='cat-icon'></div><div class='title-desc'>"
                . "<a $attributes>"
                . $args->link_before
                . $title
                . '</a><br>'
                . $args->link_after
                . $description
                . '</div></div>'
                . $args->after;
            }else{//everything else
            $item_output = $args->before
                . "<a $attributes>"
                . $args->link_before
                . $title
                . '</a> '
                . $args->link_after
                . $args->after;
            }
            // Since $output is called by reference we don't need to return anything.
            $output .= apply_filters(
                'walker_nav_menu_start_el'
            ,   $item_output
            ,   $item
            ,   $depth
            ,   $args
            );
        }
    
    }

    http://wordpress.org/plugins/majpage-menu-class-extender/

  2. duzymaju
    Member
    Plugin Author

    Posted 10 months ago #

    Hello Luke,

    I'm sorry that I didn't respond for two months. Let me improve myself. :P

    That's my fast solution to your problem (but maybe someone find simpler one):

    1. Define protected/private variable for your walker class. This is an array with current items counters on every depth level. Because start_lvl method isn't called before first item of 0 level, you have to fill 0 index of your array by 0 value.
    protected $_itemsNoByDepth = array( 0 => 0 );

    2. When you start next level you have to set level counter to 0 in start_lvl method. Because first sub-level have $depth value 0 you have add 1 to this value.
    $this->_itemsNoByDepth[$depth+1] = 0;

    3. Finally you have to iterate proper counter in every occurrence of start_el method. After it you can use this counter to add required classes as a new $classes array indexes. In your case it will be:

    $this->_itemsNoByDepth[$depth]++;
    if( $depth > 0 && $this->_itemsNoByDepth[$depth] % 2 ) {
     $classes[] = 'odd';
    }

    but if you'd like to add eg. odd/even classes and classes with consecutive items numbers, you can do sth like:

    $this->_itemsNoByDepth[$depth]++;
    $classes[] = 'item-no-' . $this->_itemsNoByDepth[$depth];
    $classes[] = 'item-' . ( $this->_itemsNoByDepth[$depth] % 2 ? 'odd' : 'even' );

    Remember to put above code between $classes and $class_names variable declarations.

    After these three steps your code should looks like that:

    class Menu_With_Description extends Walker_Nav_Menu
    {
    
            protected $_itemsNoByDepth = array( 0 => 0 );
    
        	function start_lvl(&$output, $depth) {
                $this->_itemsNoByDepth[$depth+1] = 0;
            	$indent = str_repeat("\t", $depth);
            	$output .= "\n$indent<ul class=\"sub-menu level-".$depth."\">\n";
        	}
        	function end_lvl(&$output, $depth) {
            	$indent = str_repeat("\t", $depth);
            	$output .= "$indent<div class=\"fix\"></div></ul><div class=\"fix\"></div>\n";
        	}
    
        /**
         * Start the element output.
         *
         * @param  string $output Passed by reference. Used to append additional content.
         * @param  object $item   Menu item data object.
         * @param  int $depth     Depth of menu item. May be used for padding.
         * @param  array $args    Additional strings.
         * @return void
         */
         function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output )
    {
        $id_field = $this->db_fields['id'];
        if ( is_object( $args[0] ) ) {
            $args[0]->has_children = ! empty( $children_elements[$element->$id_field] );
        }
        return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }
    
        function start_el(&$output, $item, $depth, $args)
        {
    
            $classes     = empty ( $item->classes ) ? array () : (array) $item->classes;
    
            $this->_itemsNoByDepth[$depth]++;
            if( $depth > 0 && $this->_itemsNoByDepth[$depth] % 2 ) {
                $classes[] = 'odd';
            }
    
            $class_names = join(
                ' '
            ,   apply_filters(
                    'nav_menu_css_class'
                ,   array_filter( $classes ), $item
                )
            );
    
            if ($args->has_children && $depth == 0){
            ! empty ( $class_names )
                and $class_names = ' class="'. esc_attr( $class_names ) . ' has_children"';
            }else{
             ! empty ( $class_names )
                and $class_names = ' class="'. esc_attr( $class_names ) . '"';
            }
    
            $output .= "<li id='menu-item-$item->ID' $class_names>" ;
            $attributes  = '';
    
            ! empty( $item->attr_title )
                and $attributes .= ' title="'  . esc_attr( $item->attr_title ) .'"';
            ! empty( $item->target )
                and $attributes .= ' target="' . esc_attr( $item->target     ) .'"';
            ! empty( $item->xfn )
                and $attributes .= ' rel="'    . esc_attr( $item->xfn        ) .'"';
            ! empty( $item->url )
                and $attributes .= ' href="'   . esc_attr( $item->url        ) .'"';
    
            // insert description for top level elements only
            // you may change this
            $description = ( ! empty ( $item->description ) and 0 == $depth )
                ? '<span class="description">' . esc_attr( $item->description ) . '</span>' : '';
    
            $title = apply_filters( 'the_title', $item->title, $item->ID );
    if ( $depth == 0 ) {//top level items
                $item_output = $args->before
                ."<div class='parent'><div class='cat-icon'></div><div class='title-desc'>"
                . "<a $attributes>"
                . $args->link_before
                . $title
                . '</a><br>'
                . $args->link_after
                . $description
                . '</div></div>'
                . $args->after;
            }else{//everything else
            $item_output = $args->before
                . "<a $attributes>"
                . $args->link_before
                . $title
                . '</a> '
                . $args->link_after
                . $args->after;
            }
            // Since $output is called by reference we don't need to return anything.
            $output .= apply_filters(
                'walker_nav_menu_start_el'
            ,   $item_output
            ,   $item
            ,   $depth
            ,   $args
            );
        }
    
    }
  3. Luke Etheridge
    Member
    Posted 10 months ago #

    Thanks man!!

    Absolutely perfect bud, exactly what I wanted. And thanks for providing the edited walker function it's much appreciated.

    Luke

Topic Closed

This topic has been closed to new replies.

About this Plugin

About this Topic