0

I mean:

<ul>
  <li>
    <ul class="sub-menu">
      <li>
        <ul>
          <li></li>
          <li></li>
          <li></li>
        </ul>
      </li>
      <li></li>
      <li></li>
    </ul>
  </li>

  <li>
    <ul class="sub-menu">
      <li></li>
      <li></li>
      <li></li>
    </ul>
  </li>
  <li></li>
</ul>

I need to add an exra class to the first, big submenu. In other words, I need to style the sub-menus that contain more sub-menus in a different way mfrom sub-menusn that only contain final list items.

I can extend the Walker_Nav_Menu class, but after taking a look to it, it seems there's no way to know when an sub-menu will contain other sub-menu, because there's no data available about its children.

Apparently.

So what?

2
  • Could you not put the HTML class on all submenus then use the CSS > selector to only apply big submenu styles to the first level? e.g. ul > li > ul.sub-menu? Most Menu styling problems can be solved with a little extra CSS knowledge, no need for Walker_Nav_Menu based solutions
    – Tom J Nowell
    Commented Mar 14, 2019 at 16:51
  • As an aside, this is an XY problem, you've fallen into the trap of asking how to implement your solution, rather than how to solve your problem. Asking about your original problem, and suggesting the css class on the first menus as a possible solution in the question, means you could have gotten a lot more interest, and even solutions that don't involve the CSS class but work better/faster/easier
    – Tom J Nowell
    Commented Mar 14, 2019 at 16:54

2 Answers 2

1

I can extend the Walker_Nav_Menu class, but after taking a look to it, it seems there's no way to know when an sub-menu will contain other sub-menu, because there's no data available about its children

You may want to look again mate.

The Walker::display_element(...) method take the "List of elements to continue traversing" (understand children list) as second parameter : array $children_elements

If you do a

var_dump($children_elements);

You will see every entry of your menu. In order to know if an entry got children, you can check if $children_elements[$id] is empty, with $id beeing the id of the element in question :

$this->has_children = ! empty( $children_elements[ $id ] );

So you could check for each entry of your menu if it has children, and if yes, check if any children have children of his own :

<?php
/**
* menu_walker
*
* @since 1.0.0
* @package My Theme Wordpress
*/

if ( ! class_exists( 'MyThemeWP_Top_Menu_Walker' ) ) {
class MyThemeWP_Top_Menu_Walker extends Walker_Nav_Menu {

  /**
  * Find menu elements with children containing children and give them the super-parent-class class
  * Then call the default display_element method
  */
  public  function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ){
    if ( ! $element ) {
      return;
    }

    $id_field = $this->db_fields['id'];
    $id = $element->$id_field; 

    //var_dump($children_elements[ $id ]); // List the children elements of the element with $id

    $this->has_children = ! empty( $children_elements[ $id ] );
    if ( isset( $args[0] ) && is_array( $args[0] ) ) {
      $args[0]['has_children'] = $this->has_children; // Back-compat.
    }

    // If this element have children
    if ( ! empty( $children_elements[$id] ) //&& ( $depth == 0 ) // Remove this comment to apply the super-parent-class only to root elements
    //|| $element->category_post != '' && $element->object == 'category'
    ) {

      // var_dump($children_elements[$id]);

      // Loop through it's children
      foreach ($children_elements[$id] as &$child_element) {
        //var_dump($child_element->ID);
        //var_dump(! empty( $children_elements[$child_element->ID] ));

        // If this child has children of it's own, add super-parent-class to it's parent
        if ( ! empty( $children_elements[$child_element->ID] ) ){
          $element->classes[] = 'super-parent-class';
        }
      }
    }

    // Call default method from virtual parent class
    parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }

  } // class MyThemeWP_Top_Menu_Walker END
}
?>
1
  • It would be helpful to explain your answer in a bit more detail. For example, what does this code do? Why is it important? Commented Mar 15, 2019 at 23:38
-1

Not a real answer, but a real solution at least to the primary task: style differently.

I still don't know how to tell if a menu has other sub-menus via php, but in fact I know it because I manually built the menus with the admin editor. So when the are items that contains other deep submenus, I can add a class to them item via admin, then style accordingly.

1
  • -1? As always, it's far better to ask stackoverflow than this site. Too many useless cops here. No surprise that doesn't grow that fast. Commented Mar 15, 2019 at 17:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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