1

I want to add divs and classes to child [ li ] elements that come after [ ul class ="sub-menu" ] of the parent [ li ]. The problem is, when I try to modify the [ li ] in the start_el function, all [ li ] get modified, even the ones that are outside of the [ ul class ="sub-menu" ], the parent ones also get modified. Please help me to seperate the [ li ], so that I can only modify the ones that are inside [ ul class ="sub-menu" ] without Javascript.

public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
        if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
            $t = '';
            $n = '';
        } else {
            $t = "\t";
            $n = "\n";
        }
        $indent = ( $depth ) ? str_repeat( $t, $depth ) : '';

        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
        $classes[] = 'menu-item-' . $item->ID;

        $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
        $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
        $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args, $depth );
        $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';

        $output .= $indent . '<li' . $id . $class_names .'>';

        $atts = array();
        $atts['title']  = ! empty( $item->attr_title ) ? $item->attr_title : '';
        $atts['target'] = ! empty( $item->target )     ? $item->target     : '';
        $atts['rel']    = ! empty( $item->xfn )        ? $item->xfn        : '';
        $atts['href']   = ! empty( $item->url )        ? $item->url        : '';
        $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );

        $attributes = '';
        foreach ( $atts as $attr => $value ) {
            if ( ! empty( $value ) ) {
                $value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
                $attributes .= ' ' . $attr . '="' . $value . '"';
            }
        }
        $title = apply_filters( 'the_title', $item->title, $item->ID );

        $title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth );

        $item_output = $args->before;
        $item_output .= '<a'. $attributes .'>';
        $item_output .= $args->link_before . $title . $args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;

        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }
2

You don't need to make a whole new walker, you can do this with just a filter and some conditionals based on the function parameters.

The filter we need is walker_nav_menu_start_el which you can see at the bottom of your code sample.

And to make sure we only target the child pages we can use the $depth parameter from that function, see example below.

function ngstyle_child_menu_items($item_output, $item, $depth, $args)
{
    // Check we are on the right menu & right depth
    if ($args->theme_location != 'primary' || $depth !== 1) {
        return $item_output;
    }

    $new_output = $item_output;
    $new_output .= '<div class="super-mega-awesome"></div>'; // Add custom elems

    return $new_output;
}
add_filter('walker_nav_menu_start_el', 'ngstyle_child_menu_items', 10, 4);
0

If you want to dinamically insert those <div>s based on some condition or trigger you will need javascript (or jQuery or php). There´s no escaping from scripting languages.

The <li>´s coming out of this function are defined in this variable:

$output .= $indent . '<li' . $id . $class_names .'>';

So, if you to add a <div> inside it, you can try this:

$output .= $indent . '<li' . $id . $class_names .'>' . '<div class="class-1 class-2">';

However, if these <div>´s should be present at all times, you can just hardcode it in the php file it is coming from.

When it comes to applying style changes to only those specific <li>´s, if you´re doing it via CSS it´s quite simple and all you have to do is be specific about the <li> you want to target.

Like so:

ul.sub-menu li.the-li-class {
   property: value;
}

If you´re doing it using jQuery, for example, it´ll be something like this:

$('.sub-menu').find('.li-class');
   $(this).css({'property-1' : 'value', 'property-2' : 'value' });

There are other approaches when it comes to jQuery. It´s all about knowing how to traverse the DOM tree and you may want to dig deeper into this if you´re not familiar.

  • No, is possible. – ngearing Apr 19 '17 at 0:07
  • Well, sure, you can use php... but he started from a javascript approach. Maybe I should´ve mentioned that. Kindda impressed you took the time to downvote my answer based on just that and providing such an unhelpful and vague comment... How does that help anyone if you just won´t share your input? "No, is not possible" .... "you can also do such and such". Shame on you. – Diogo Apr 19 '17 at 0:24
  • He asked for "without Javascript". He did not ask for a javascript approach – ngearing Apr 19 '17 at 0:27
  • And I did share my input, see my answer above. – ngearing Apr 19 '17 at 0:32
  • He said "modify the <li>´s inside the <ul> without javascript. He started saying he wanted <div>s inside the <li>´s and those <li>s are being dinamically generated. He never stated HOW he wanted to insert the <div>s – Diogo Apr 19 '17 at 0:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.