wordpresswp-nav-walker

Adding a unique class to level 0 if there is level 2


I really need your help in solving my problem.

I am trying to customize a Wordpress menu using Walker.

My task is to find out at level 0 if level 2 exists. If level 2 exists, then I need to add a unique class.

The only thing I was able to find out is whether level 1 exists with help $args->walker->has_children.

Menu structure

<ul>
  <li> <!-- lvl 0, I'm here -->
    <a></a>
    <ul>
        <li> <!-- lvl 1 -->
            <a></a>
            <ul>
                <li> <!-- lvl 2, I need to find out if there are elements here -->
                    <a></a>
                </li>
            </ul>
        </li>
    </ul>
  </li>
</ul>

I want to supplement my question with Walker code. I am trying to add a class on <h4>. Now the condition is working: "If this is level 0, there is a child level 1 inside, then a class is added".

    /**
     * Starts the element output.
     *
     * @since 3.0.0
     * @since 4.4.0 The {@see 'nav_menu_item_args'} filter was added.
     *
     * @see Walker::start_el()
     *
     * @param string   $output Used to append additional content (passed by reference).
     * @param WP_Post  $item   Menu item data object.
     * @param int      $depth  Depth of menu item. Used for padding.
     * @param stdClass $args   An object of wp_nav_menu() arguments.
     * @param int      $id     Current item ID.
     */
    public function start_el( &$output, $item, $depth = 0, $args = null, $id = 0 ) {

        if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
            $t = '';
            $n = '';
        } else {
            $t = "\t";
            $n = "\n";
        }
        $indent = ( $depth ) ? str_repeat( $t, $depth ) : '';

        /**
         * Filters the arguments for a single nav menu item.
         *
         * @since 4.4.0
         *
         * @param stdClass $args  An object of wp_nav_menu() arguments.
         * @param WP_Post  $item  Menu item data object.
         * @param int      $depth Depth of menu item. Used for padding.
         */
        $args = apply_filters( 'nav_menu_item_args', $args, $item, $depth );

        $item_classes = '';
        if($depth == 0){
            if(in_array('menu-item-has-children', $item->classes)){ $item_classes = ' class="page-footer__item"';}
        }

        $output .= $indent . '<li' . $item_classes . '>';

        $atts           = array();
        $atts['title']  = ! empty( $item->attr_title ) ? $item->attr_title : '';
        $atts['target'] = ! empty( $item->target ) ? $item->target : '';
        if ( '_blank' === $item->target && empty( $item->xfn ) ) {
            $atts['rel'] = 'noopener';
        } else {
            $atts['rel'] = $item->xfn;
        }
        $atts['href']         = ! empty( $item->url ) ? $item->url : '';
        $atts['aria-current'] = $item->current ? 'page' : '';

        /**
         * Filters the HTML attributes applied to a menu item's anchor element.
         *
         * @since 3.6.0
         * @since 4.1.0 The `$depth` parameter was added.
         *
         * @param array $atts {
         *     The HTML attributes applied to the menu item's `<a>` element, empty strings are ignored.
         *
         *     @type string $title        Title attribute.
         *     @type string $target       Target attribute.
         *     @type string $rel          The rel attribute.
         *     @type string $href         The href attribute.
         *     @type string $aria_current The aria-current attribute.
         * }
         * @param WP_Post  $item  The current menu item.
         * @param stdClass $args  An object of wp_nav_menu() arguments.
         * @param int      $depth Depth of menu item. Used for padding.
         */
        $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );

        $attributes = '';
        foreach ( $atts as $attr => $value ) {
            if ( is_scalar( $value ) && '' !== $value && false !== $value ) {
                $value       = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
                $attributes .= ' ' . $attr . '="' . $value . '"';
            }
        }

        /** This filter is documented in wp-includes/post-template.php */
        $title = apply_filters( 'the_title', $item->title, $item->ID );

        /**
         * Filters a menu item's title.
         *
         * @since 4.4.0
         *
         * @param string   $title The menu item's title.
         * @param WP_Post  $item  The current menu item.
         * @param stdClass $args  An object of wp_nav_menu() arguments.
         * @param int      $depth Depth of menu item. Used for padding.
         */
        $title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth );

        $item_output  = $args->before;
        if($depth == 0){
            if($args->walker->has_children){
                $item_output .= '<h4 class="page-footer__list-title">'. $title .'</h4>';
            }
        }
        elseif ($depth == 1 && $args->walker->has_children){
            $item_output .= '<h4 class="page-footer__list-title ">'. $title .'</h4>';
        }
        else{
            $item_output .= '<a' . $attributes . ' class="page-footer__link" title="'. $title .'">';
            $item_output .= $args->link_before . $title . $args->link_after;
            $item_output .= '</a>';
        }
        $item_output .= $args->after;

        /**
         * Filters a menu item's starting output.
         *
         * The menu item's starting output only includes `$args->before`, the opening `<a>`,
         * the menu item's title, the closing `</a>`, and `$args->after`. Currently, there is
         * no filter for modifying the opening and closing `<li>` for a menu item.
         *
         * @since 3.0.0
         *
         * @param string   $item_output The menu item's starting HTML output.
         * @param WP_Post  $item        Menu item data object.
         * @param int      $depth       Depth of menu item. Used for padding.
         * @param stdClass $args        An object of wp_nav_menu() arguments.
         */
        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }

Solution

  • Here you can use the basic methodology behind the concept of the walker class. As your task is to add the unique class if there is any second level of hierarchy/inheritance or depth==2, so try this code to your snippet accordingly. This simply will help to get the depth of the tree and if any level 2 exists then you would be able to add elements and that unique class..

     //This function is responsible for adding "my-parent-item" class to parent menu item's
        function add_menu_parent_class( $items ) {
        $parents = array();
        foreach ( $items as $item ) {
            //Check if the item is a parent item
            if ( $item->menu_item_parent && $item->menu_item_parent > 0 ) {
                $parents[] = $item->menu_item_parent;
            }
        }
        
        foreach ( $items as $item ) {
            if ( in_array( $item->ID, $parents ) ) {
                //Add "menu-parent-item" class to parents
                $item->classes[] = 'my-parent-item';
            }
        }
        
        return $items;
        }
        
        //add_menu_parent_class to menu
        add_filter( 'wp_nav_menu_objects', 'add_menu_parent_class' ); 
    
    
    Or You can also publish it using jQuery if you are by any chance fond of it..
        $('ul li.menu-parent-item:has(ul ul)').addClass('your class');