0

I am creating a split menu (half the items on the left, logo in the middle, remaining items on the right). I don't really understand Walkers all that well, but I found this code snippet.

This was working well for me until my client wanted to add child items. The current code is counting all the menu items (10) when I want it to just count the top level items (currently 7).

How do I adjust this code so that it only counts the top level items?

class Split_Menu_Walker extends Walker_Nav_Menu {

    var $current_menu = null;
    var $break_point  = null;

    function start_el(&$output, $item, $depth, $args, $id=0) {

        global $wp_query;

        if( !isset( $this->current_menu ) )
            $this->current_menu = wp_get_nav_menu_object( $args->menu );

        if( !isset( $this->break_point ) )
            $this->break_point = ceil( $this->current_menu->count / 2 ) + 1;

        $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

        $class_names = $value = '';

        $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 ) );
        $class_names = ' class="' . esc_attr( $class_names ) . '"';

        $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
        $id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';

        if( $this->break_point == $item->menu_order )
            $output .= $indent . '</li></ul><ul><li' . $id . $value . $class_names .'>';
        else
            $output .= $indent . '<li' . $id . $value . $class_names .'>';

        $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
        $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
        $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
        $attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';

        $item_output = $args->before;
        $item_output .= '<a'. $attributes .'>';
        $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;

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

Calculation you talking about going here:

if( !isset( $this->break_point ) )
        $this->break_point = ceil( $this->current_menu->count / 2 ) + 1;

You can't get top-level items count this way. Instead you should count it yourself. You can do this using wp_get_nav_menu_items(). Every top-level item should have menu_item_parent set to '0'.

You should create additional variable where you calculate already displayed elements. So top of your file should looks like this:

class Split_Menu_Walker extends Walker_Nav_Menu {

    public $break_point = null;
    public $displayed = 0; 

function start_el(&$output, $item, $depth, $args, $id=0) {

    global $wp_query;

    if( !isset( $this->break_point ) ) {
        $menu_elements = wp_get_nav_menu_items( $args->menu );
        $top_level_elements = 0;

        foreach( $menu_elements as $el ) {
            if( $el->menu_item_parent === '0' ) {
                $top_level_elements++;
            }
        }
        $this->break_point = ceil( $top_level_elements / 2 ) + 1;
     }   


    $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
...
...
...

Then you should increment $this->displayed++; every time you display top level element (for example at the end of start_el() function):

if( $item->menu_item_parent === '0' ) {
    $this->displayed++;
}

Lastly instead of

if( $this->break_point == $item->menu_order ) 

you should use

if( $this->break_point == $this->displayed )
  • Thank you! This is now getting the correct break point, but since it is using if( $this->break_point == $item->menu_order ) to check if it's it's splitting it within a submenu. Is there a way to make sure that it only splits at a parent level? – clancimus Nov 17 '15 at 14:21
  • You can do this exactly the same way. Just check if $item has menu_item_parent set to '0', so something like this: if( $this->break_point == $item->menu_order && $item->menu_item_parent === '0' ) – Mateusz Marchel Nov 17 '15 at 15:10
  • This is the logic I initially thought of, however since it reaches the break point at a submenu, it just skips now and doesn't put the split in at all. The logic I'm thinking of is "If the break point has been reached and it's a parent item, put the break in. Else, continue on until the submenu has closed, then put the break in". I'm just not sure how to write this logic into the walker. – clancimus Nov 17 '15 at 15:38
  • Ok, I updated the answer, so now i think it's complete. If it helped you please mark this answer as correct. :) – Mateusz Marchel Nov 17 '15 at 16:34
  • I modified my code, but it's showing the way that it did in the beginning. I have the following menu structure: Parent Parent - Child - Child - Child Parent Parent Parent Parent Parent And it's splitting after the third child. Here is my updated code: pastebin.com/K7xan2qM – clancimus Nov 17 '15 at 16:38

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.