• Resolved omii

    (@omii)


    Hi All,

    I’d like to just print the main level of navigation on my theme, but capture just the subnav of the immediately selected nav item (if there is one).

    I copied the standard Walker class to extend it and made extremely light changes. Essentially at the top of start_el/start_lvl/end_lvl/end_el I check the depth and anything above 0 I just return;.

    Pastebin example:
    http://pastebin.com/YXXS0ChE

    At the bottom of the pastebin you can see what I’m getting for output. To put it here for ease, it’s very simple.

    My menu is simple like:

    Menu 1
       Subnav 1
    Menu 2
    Menu 3

    I want to print the main “Menu #” items. The problem is I’m getting an empty <ul class=”sub-nav”> inside of Menu 1. I do not get the < li > items inside it, just the empty container.

    Anyone have any idea why I would get this empty <ul class=”sub-nav”>?

    I know I can set the $args to have depth => 1, or just set .sub-nav{display:none;} but I’d really like to understand the Walker class a bit better to start making better navigations.

    Thanks for any tips!

Viewing 6 replies - 1 through 6 (of 6 total)
  • Hi,

    nav walkers are a tough subject, I learned much from this article. Perhaps it can help you too.

    Thread Starter omii

    (@omii)

    Hi,

    They’re a very approachable subject although some people can get lost in recursive functions. They’re hard to debug.

    This isn’t my first nav walker extend. I made it conform to Bootstrap previously and had no such issues.

    I am practically doing the same exact thing as the “advanced” walker. If ( 0 != $depth ) return; is the inverse of the tutorials if ($depth == 0) return; because we want inverse things. I want only main nav items, they want only nav items under the current nav.

    The bit unorthodox 0 != $depth instead of $depth > 0 is just a JavaScript habit for other reasons but the statement doesn’t work any way I lay it out anyhow.

    I even put an extra debug line in start/end_lvl() where the offending <ul class=”sub-menu”> and are being invalidly created. I put it right under the $depth check, and it prints out! This is one of these “but that’s just not possible” times. e.g.:

    function start_lvl(...){
      if ($depth > 0) { return; }
      print "<!-- debug, huh how am I here? -->";
      print "<ul class=\"sub-nav222222\" ...";
    }

    If the $depth is above 0 there is no freaking way that should print. start_el and end_el do not print, they respect the return. However, both the comment is printed (ONLY around the main nav, not this offending sub-nav), and I verified the class was sub-nav222222 just to make sure this
    < ul > wasn’t being printed from something I’m inheriting. Nope, the class was sub-nav222222 so I know that function is printing it.

    This makes no sense! I’m sure there’s a reason but if anyone knows how this possible, please save my sanity!

    Otherwise the only thing I see from here is needing to make the walker class specifically to get secondary nav items from the current selection and set the depth => 1 in arguments on the main menu, essentially making me walk nav twice. I should be able to get the main nav and the subnav of the selected item in a single walk. That or I’m going to need to set .sub-nav{display:none;} which is equally impure.

    Moderator bcworkz

    (@bcworkz)

    The <ul class="sub-menu"> is coming from $parent::display_element(), in a way. The method calls start_lvl() for sub-menus during the main level walk for any main level element that has children. At that point the level is still 0 (on the initial pass) even though the output is for a level 1 sub-menu. display_element() then recurses for the children, which you’ve effectively suppressed. Only then is $level incremented to 1 in the recursive call to display_element(). Look at the original Walker class declaration (wp-includes/class-wp-walker.php lines 157 & 159).

    I haven’t fully verified this, but it appears the $level value in start and end level is always 1 greater than the equivalent $level in start and end element, given the same menu level. While not intuitive, you can think of the outer sub-menu wrapper as “belonging” to the parent level. Only the repeating sub-menu elements belong to their own level.

    Thread Starter omii

    (@omii)

    Thanks very much for pointing that out. I’m not even sure if they intend this or if messing with any of this code is going to desync anything internally (I thought perhaps classes), but it doesn’t appear to.

    I’m now overriding display_element grabbed from class-wp-walker.php and just added $depth+1 on line 156, which was:

    $cb_args = array_merge( array(&$output, $depth), $args);

    But is now:

    $cb_args = array_merge( array( &$output, $depth + 1 ), $args);

    I’d love to know their reasoning on why the depth should start at 0 and I’ve run through my many-tier menus and they all work just fine with this change. The code clearly states “$newlevel = true;”, so why wouldn’t you consider adding a depth? Most importantly it doesn’t feel hacky, no classes changed and the way I wanted to do it now works perfectly fine with:

    if ( $depth > 0 ) { return; }

    Thanks a bunch for pointing me to those lines bcworkz!

    Again I’m not sure if there is a context in which doing this is going to break the menu system output, but so far it’s working perfectly fine. If anyone thinks this is a bad practice please let me know as well as a better way to do it!

    Moderator bcworkz

    (@bcworkz)

    You’re welcome!
    I imagine depth starts at 0 just because array indexing and other counting systems in coding various languages invariably start at 0. It’s just a matter of conforming to the usual practice.

    Why not increase it for the <ul> sub-menu wrapper? Because then it’d have to be reduced again for the remainder of the level 0 output. The current iteration is mainly for level 0. It’s just a matter of expediency to output the outer sub-menu wrapper at this point because it occurs only once for each level 0 item having children. It’d be more work to manage the output during the next level.

    The intention was not to be user friendly and intuitive, it was to work well and be flexible with various inputs without unnecessary code 🙂

    I think what you’ve done for your situation is perfectly fine.

    Thread Starter omii

    (@omii)

    I totally agree with starting at 0. However where the next depth starts should be extremely clean and clear to me. In that case, it’s the next container of nav.

    For example in a typical nested unordered list, this makes sense to me:

    <ul depth=0>
      <li>
        <ul depth=1>
          <li>
            <ul depth=2> .. </ul>
          </li>
         </ul>
      </li>
    </ul>

    But how it is right now, this happens:

    <ul depth=0>
      <li>
        <ul>
          <li depth=1>
            <ul>
              <li depth=2></li>
            </ul>
          </li>
         </ul>
      </li>
    </ul>

    To the navigation elements themselves which are in the < li > list items the depth will work fine but from any other angle I look at this it’s just invalid markup.

    The depth doesn’t need to be reduced for the rest of the original < ul >s content on the main menu because the $depth+1 is being passed as an argument to the function, never actually affecting the functions current $depth.

    I can create navs all day and this prints reliably, such as:

    Main 1
      Sub 1
        Sub 2
    Main 2
    Main 3
      Sub 1
    Main 4
      Sub 1
        Sub 2
          Sub 3
            Sub 4
          Sub 3

    And that is exactly how it prints out when I print $indent+$depth:

    0
      1
        2
    0
    0
      1
        2
          3
            4
          3

    I can’t see how this is more desirable which is what I get if I don’t use $depth+1:

    0
      0
        1
    0
    0
      0
        1
          2
            3
          2

    Perhaps there’s just still something internal I don’t understand about that being desirable but nonetheless this is working perfectly for me. Thank you again!

Viewing 6 replies - 1 through 6 (of 6 total)
  • The topic ‘Nav Walker, why do you hate me? (I'm missing something here)’ is closed to new replies.