0
votes

I have 2 different displays here. 1 for mobile and another for desktop. I need to output different html for both for just 1 menu item (the last 1) in a menu. For example, given the following Menu structure:

- Menu Item 1
-- Child 1
-- Child 2
-- Child 3
- Menu Item 2
-- Child 1
-- Child 2
-- Child 3
-- Child 4
- Menu Item 3
-- Child 1
-- Child 2
-- Child 3
-- Child 4
-- Child 5
-- Child 6

I need to be able to output the following structure for Desktop:

<ul>
    <li>Menu Item 1
    <ul>
        <li>Child 1</li>
        <li>Child 2</li>
        <li>Child 3</li>
    </ul>
    </li>
    <li>Menu Item 2
    <ul>
        <li>Child 1</li>
        <li>Child 2</li>
        <li>Child 3</li>
        <li>Child 4</li>
    </ul>
    </li>
    <li>Menu Item 3
    <ul>
        <li>Child 1</li>
        <li>Child 2</li>
        <li>Child 3</li>
    </ul>
    </li>
    <li>&nbsp;
    <ul>
        <li>Child 4</li>
        <li>Child 5</li>
        <li>Child 6</li>
    </ul>
    </li>
</ul>

The last parent menu item with $depth === 0 needs to be split in half into separate items. But on mobile display, it does not need to be split in half, it should display perfect for mobile.

So I have 2 different WP_Nav_Walker extending classes. 1 for Mobile and another for Desktop which handle the menu differently, however the problem I'm facing is how to get the total count of Submenu items. I understand how to know if a menu has children or not using $args->has_children, but how to get the total number of children??

I've created a variable to know which sub-menu item I'm on within the end_el function:

class Custom_Nav_Walker extends Walker_Nav_Menu {

    function __construct() {
        $this->boxitem_index = 0;
    }

    public function start_lvl(&$output, $depth = 0, $args = array())
    {
        if ($depth === 0 && $this->menu_type == 'header')
        {
            echo '<pre>', var_dump($item), '</pre>';
        }
    }
}

I have also set a custom property called menu_type that gets set within the start_el function that attaches to the last menu here, so I'm able to know that it's the menu I want.

Basically, I need to split it in half, not by 3, but I'm not able to know what half is. And ofcourse, I don't want to perform the if statement on the last item. So, it would help to know how many items we have that are $depth === 1 for the last parent menu. Is this possible?

The output I get for $item is this:

object(WP_Post)#723 (40) {
  ["ID"]=>
  int(73)
  ["post_author"]=>
  string(1) "1"
  ["post_date"]=>
  string(19) "2016-07-14 18:09:44"
  ["post_date_gmt"]=>
  string(19) "2016-07-14 18:09:44"
  ["post_content"]=>
  string(0) ""
  ["post_title"]=>
  string(11) "Quick Links"
  ["post_excerpt"]=>
  string(0) ""
  ["post_status"]=>
  string(7) "publish"
  ["comment_status"]=>
  string(6) "closed"
  ["ping_status"]=>
  string(6) "closed"
  ["post_password"]=>
  string(0) ""
  ["post_name"]=>
  string(13) "quick-links-3"
  ["to_ping"]=>
  string(0) ""
  ["pinged"]=>
  string(0) ""
  ["post_modified"]=>
  string(19) "2016-07-21 17:12:08"
  ["post_modified_gmt"]=>
  string(19) "2016-07-21 17:12:08"
  ["post_content_filtered"]=>
  string(0) ""
  ["post_parent"]=>
  int(0)
  ["guid"]=>
  string(30) "http://0b90b21a.ngrok.io/?p=73"
  ["menu_order"]=>
  int(12)
  ["post_type"]=>
  string(13) "nav_menu_item"
  ["post_mime_type"]=>
  string(0) ""
  ["comment_count"]=>
  string(1) "0"
  ["filter"]=>
  string(3) "raw"
  ["db_id"]=>
  int(73)
  ["menu_item_parent"]=>
  string(1) "0"
  ["object_id"]=>
  string(2) "73"
  ["object"]=>
  string(6) "custom"
  ["type"]=>
  string(6) "custom"
  ["type_label"]=>
  string(11) "Custom Link"
  ["title"]=>
  string(11) "Quick Links"
  ["url"]=>
  string(0) ""
  ["target"]=>
  string(0) ""
  ["attr_title"]=>
  string(0) ""
  ["description"]=>
  string(0) ""
  ["classes"]=>
  array(5) {
    [0]=>
    string(0) ""
    [1]=>
    string(9) "menu-item"
    [2]=>
    string(21) "menu-item-type-custom"
    [3]=>
    string(23) "menu-item-object-custom"
    [4]=>
    string(22) "menu-item-has-children"
  }
  ["xfn"]=>
  string(0) ""
  ["current"]=>
  bool(false)
  ["current_item_ancestor"]=>
  bool(false)
  ["current_item_parent"]=>
  bool(false)
}
1
"The last parent menu item with $depth === 0 needs to be split in half into separate items" - why? Please explain what you are actually trying to achieve. There might be other options, that don't create a sub-optimal HTML structure, and use CSS to achieve the desired effect. - CBroe
I am splitting into columns for desktop displays. This is only way to support IE8 as site already does. I am merging a site from ASP.NET (using Umbraco CMS) into PHP (using Wordpress) and need to maintain this HTML Structure for compatibility reasons. - Solomon Closson
Have you looked at what the $item data structure contains at that point? - CBroe
Yes, I'm putting the code in the wrong function, but it doesn't matter, cause after I put it into the start_lvl function still nothing to be able to get the count of children... will edit code now. - Solomon Closson
Edited code, output gives me parent menu item as post object. - Solomon Closson

1 Answers

4
votes

You can use this filter function to get two additional properties _children_count and _parent_children_count on each item, that you can later evaluate in your menu walker:

function my_wp_nav_menu_objects_filter($sorted_menu_items) {
    foreach($sorted_menu_items as &$item) {
        $item->_children_count = 0;
        for($i=1, $l=count($sorted_menu_items); $i<=$l; ++$i) {
            if($sorted_menu_items[$i]->menu_item_parent == $item->ID) {
                $item->_children_count++;
            }
        }        
    }
    foreach($sorted_menu_items as &$item) {
        $item->_parent_children_count = 0;
        for($i=1, $l=count($sorted_menu_items); $i<=$l; ++$i) {
            if($item->menu_item_parent == $sorted_menu_items[$i]->ID) {
                $item->_parent_children_count = $sorted_menu_items[$i]->_children_count;
                break;                    
            }
        }
    }
    unset($item);
    return $sorted_menu_items;    
}
add_filter('wp_nav_menu_objects', 'my_wp_nav_menu_objects_filter' );

Weirdly enough, it looks like the $sorted_menu_items array is numerically indexed starting at 1.
Added the _ in front of the new properties as pseudo-namespacing, to avoid collisions with possible future official properties.