Skip Navigation

[Resolved] Creating a split collapsable bootstrap menu

This support ticket is created 7 years, 10 months ago. There's a good chance that you are reading advice that it now obsolete.

This is the technical support forum for Toolset - a suite of plugins for developing WordPress sites without writing PHP.

Everyone can read this forum, but only Toolset clients can post in it. Toolset support works 6 days per week, 19 hours per day.

Sun Mon Tue Wed Thu Fri Sat
- - 14:00 – 20:00 14:00 – 20:00 14:00 – 20:00 14:00 – 20:00 14:00 – 20:00
- - - - - - -

Supporter timezone: Asia/Ho_Chi_Minh (GMT+07:00)

This topic contains 8 replies, has 2 voices.

Last updated by Geoffrey Cleverley 7 years, 10 months ago.

Assisted by: Beda.

Author
Posts
#458581

Hey there.

So....

I am working migrating an old bootstrap html site to a WordPress.

hidden link

The original site has a split bootstrap fixed top menu. I did it a couple of years ago and hacked into the navbar to display an image above and a left and right menu.

Something like this:

<nav class="navbar navbar-default navbar-fixed-top">
    <div class="container">
    <a href="index.html"><img src="<em><u>hidden link</u></em>"></a>
      <div class="navbar-header">
        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNavbar">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>                        
        </button>
      </div>
      <div class="collapse navbar-collapse" id="myNavbar">
      <ul class="nav navbar-nav">
          <li></li>
          <li></li>//left aligned/floated nav menu
          <li></li>
      </ul>
      <ul class="nav navbar-nav navbar-right">
          <li></li>
          <li></li>//right aligned/floated nav menu
          <li></li>
      </ul>
      </div>
  </div>
</nav>

I wanted to do something similar using layouts, but need to create the two separate menu columns... which would collapse into two buttons. So I started looking for other ways to hack it together.

I found this forum post and associated tutorial:
https://toolset.com/forums/topic/creating-a-collapsable-menu-with-layouts-and-bootstrap/
hidden link

And actually got it to work pretty well... to a point...

First I had to follow the tutorial above, it was quite simple. I registered the nav menus I wanted to use, and include the custom wp_bootstrap_navwalker.php from the tutorial link into my theme folder.

I then installed a php shortcodes plugin, and created two shortcodes using the plugin interface that I could use:

[php-shortcode-1]

<?php
wp_nav_menu( array(
'theme_location' => 'left_menu',
'depth' => 4,
'container' => false,
'menu_class' => 'nav navbar-nav',
'fallback_cb' => 'wp_page_menu',
//Process nav menu using our custom nav walker
'walker' => new wp_bootstrap_navwalker())
);
?>

[php-shortcode-2]

<?php
wp_nav_menu( array(
'theme_location' => 'right_menu',
'depth' => 2,
'container' => false,
'menu_class' => 'nav navbar-nav navbar-right', //navbar-right so this menu floats right
'fallback_cb' => 'wp_page_menu',
//Process nav menu using our custom nav walker
'walker' => new wp_bootstrap_navwalker())
);
?>

I created a full width content template in my Header and Footer layout. Inside the content template I added the following code:

<nav class="navbar" role="navigation">
    <!-- Brand and toggle get grouped for better mobile display -->
<a class="navbar-brand" href="#homelink"><img src="http//:logoimage" style="width: 100%" class="img-responsive"></a> //logo image above
    <div class="navbar-header">
        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
        </button>
    </div>
 
    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse navbar-ex1-collapse">
        [php-shortcode-1]
        [php-shortcode-2]
    </div><!-- /.navbar-collapse --> 
</nav>

It worked... well, sort of... I got my split menu that collapsed into 1 button... Brilliant.

Well, I will use this in future, however it has it's limitations. It can only handle menu's with a depth of 2. I need a depth of 4 for this project.

Still for future use, I'm happy to have gotten it working, and if I'd read the comments all the way to the bottom of the tutorial I wouldn't have gotten there, as the guy who developed the custom navwalker responds to a couple of other people with my problem and after at first suggesting there was a fix using CSS, but then he gives up.

He may have given up, but it seems that Toolset has this problem fixed. You guys are implementing the bootstrap menus and in the layouts cell menu you have a choice of how many levels, so I figure that you guys solved this exact problem.

I know it's a big ask, and custom code etc, but what was the solution that wp-types implemented? ?

=====

That was a long winded way to get to my question, but it would be great to work it out... I did figure a different workaround using layouts to give me what I needed, which you can see here:

hidden link

But it's not efficient. The layout has 4 menu cells.

Above 1023px there is a row with 2 column cells displaying a left menu and a right menu.

Between 1023px and 768px there is a full width row with a single cell displaying a combined menu displaying.

Below 768px there is a full width row with a single cell displaying the combined menu, but with navbar-fixed-top class added.

I'm figuring I can use javascript to add the class I need to the single-combined menu at the breakpoint, which will get it down to 3 menu cells. I'll update when I work that out.

#458693

Regarding your current problem with the rows and it's breakpoints, this is just how Bootstrap collapses the Rows and menu.
You can not keep the middle image and the both menus down to it's smallest screen, as far I see this is also the exact same on your older site, right?

I do not fully follow the concern.

You can have a look at the Layout Menu Cell code in wpddl.cell_menu.class.php, where we register the cell, and our Menu Cell JS ddl-menu-cell-front-end.js.

Please let me know if this does not help.

#458710

Hey Beda,

Been a while, I hope you're doing well and thanks for replying on a Sunday, much appreciated.

My fault for not being clearer.

On the old site, the <nav.navbar> contains two different menus. a <ul.nav navbar-nav> and a <ul.nav navbar-nav navbar-right>

So when it collapsed down, there was only one <button.navbar-toggle>

With my current workaround, I am using two different menus, a left-menu and a right menu, each in it's own menu cell.

As each menu is a full <nav.ddl-navbar>, when the viewport reaches the breakpoint, they collapse down to 2 <button.navbar-toggle>s.

So I created a third full-width cell for a Unified-menu.

I also created a fourth full-width cell for the Unified-Menu, but I made it a <nav.navbar-fixed-top>

At screen sizes > 1023px
Display Left-Menu & Right-Menu
Do not display Unified-Menu
Do not display Unified-Menu with .navbar-fixed-top

At screen sizes < 1023px
Do not display Left-Menu & Right-Menu
Display Unified Menu.
Do not display Unified-Menu with .navbar-fixed-top

At screen sizes <768px
Do not display Left-Menu & Right-Menu
Do not display Unified-Menu
Display Unified-Menu with .navbar-fixed-top

So when the viewport reaches the 1023px the split menu falls into a centralised single menu, then when it reaches 768px it becomes a fixed top menu with a single button.

It is working, which is great. But it seems inefficient.

I am going to work out a way to negate the need for the fourth full width cell, by using javascript to add the .navbar-fixed-top class to its <nav> at the 768 breakpoint.

-------------

'You can not keep the middle image and the both menus down to it's smallest screen, as far I see this is also the exact same on your older site, right?'

That's correct, but on the old site, with the two

    menu's inside the single <nav> they stayed separate all the way down to the 768px breakpoint, before collapsing into the single dropdown menu button.

    I initially wanted to repeat this behaviour.

    Due to some strangeness regarding the menu widths in my another support forum post:
    https://toolset.com/forums/topic/left-aligned-bootstrap-menu-has-loads-of-extraneous-left-space/#post-458586
    (which I am again thankful you have responded to on a Sunday, indebted for that)

    Due to the above, I found that menu items were dropping to the next level prior to reaching the 768px breakpoint.

    That's why I implemented the hidden single menu that replaces the split menu at the 1023px breakpoint.

    Mind you, having stared at it for a day, I actually quite like it, it gives greater responsive variation in style and looks quite like an art poster. Problem is the Artist loves her split menu hahah.

    -----------

    The tutorial and code I posted initially gave me exactly what I used to have, 2 menus inside 1 <nav>

    The problem was it only allowed for menus with a depth of 2. The guy who wrote it never solved the problem of allowing deeper menus.

    In the tutorial, they use a custom wp_bootstrap_navwalker.php

    Since your implementation of the bootstrap menu allows all depths of menu, perhaps if I use your navwalker in the shortcode php:

    <?php
    wp_nav_menu( array(
    'theme_location' => 'left_menu',
    'depth' => 4,
    'container' => false,
    'menu_class' => 'nav navbar-nav',
    'fallback_cb' => 'wp_page_menu',
    //Process nav menu using our custom nav walker
    'walker' => // Use the toolset navwalker here
    );
    ?>
    

    I will experiment with this, and have a look through those files you pointed out, see what I can understand.

    Thanks again Beda.

#458736

Your support in the other post:
https://toolset.com/forums/topic/left-aligned-bootstrap-menu-has-loads-of-extraneous-left-space/#post-458702

Has fixed the extra width my split menus were taking up, with styling I can keep the split menu all the way down to 768px.

This means I can get rid of the centralised full width menu that kicks in at 1023px.

I'm still going to see if I can get the tutorial to work, having the split menus combined into 1 <nav> would let me append it with the navbar-fixed-top class at the 768px breakpoint, maybe get all of this functionality built into one menu.

I'll update with any results.

Thanks again 😀

Jeff

#458873

OK, please let me know.
I'll pass some info in your other tickets as soon as possible as well.

#459080

Hey Beda,

Your support and generous provision of snippets in my other support thread here:
https://toolset.com/forums/topic/scrolling-within-a-collapsed-bootstrap-dropdown-mobile-menu/#post-458875

Helped me get some sort of solution going here:
hidden link

The custom navwalker from your snippet allows a depth of 3, which is probably all most people need, but for some reason not 4. Which is a pity.

I combined your navwalker with the above php snippet method to get it working. I may attempt to register a cell to see if that makes a difference, but need a bit more time.

In full width content template layout cell:

<nav class="navbar navbar-default navbar-fixed-top">
  <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
              <span class="sr-only">Toggle navigation</span>
              <span class="icon-bar"></span>
              <span class="icon-bar"></span>
              <span class="icon-bar"></span>
            </button>
          </div>
    </div>
    
    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse">
 		[php snippet=1]
      	[php snippet=2]
      
    </div><!-- /.navbar-collapse -->

  <!-- /.container-fluid -->
</nav> 

In php snippet 1:

<?php 
wp_nav_menu( array(
      'theme_location' => 'art',
      'depth' => 4,
      'container' => false,
      'menu_class' => 'nav navbar-nav',
      'fallback_cb' => 'wp_page_menu',
      //Process nav menu using our custom nav walker
     'walker' => new Bootstrap_Walker_Nav_Menu())
);
?>

In php snippet 1:

<?php 
wp_nav_menu( array(
      'theme_location' => 'details',
      'depth' => 2,
      'container' => false,
      'menu_class' => 'nav navbar-nav',
      'fallback_cb' => 'wp_page_menu',
      //Process nav menu using our custom nav walker
      'walker' => new Bootstrap_Walker_Nav_Menu())
);
?>

In functions php:

Registered my navs under easily recognisable names, then set them in the menu admin

// Register navs for bootstrap custom menu

function mytheme_setup() {

register_nav_menus(
    array(
        'art' => __( 'art', 'bootpress' ),
        'details' => __( 'details', 'bootpress' )
        )
    );

}
add_action( 'after_setup_theme', 'mytheme_setup' );

Then setup your Bootstap Navwalker:

// Custom Walker Class for Bootstrap Menu
add_action( 'after_setup_theme', 'bootstrap_setup' );

if ( ! function_exists( 'bootstrap_setup' ) ):

function bootstrap_setup(){

    class Bootstrap_Walker_Nav_Menu extends Walker_Nav_Menu {


        function start_lvl( &$output, $depth = 0, $args = array() ) {

            $indent = str_repeat( "\t", $depth );
            $output    .= "\n$indent<ul class=\"dropdown-menu\">\n";

        }

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

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

            $li_attributes = '';
            $class_names = $value = '';

            $classes = empty( $item->classes ) ? array() : (array) $item->classes;
            $classes[] = ($args->has_children) ? 'dropdown' : '';
            $classes[] = ($item->current || $item->current_item_ancestor) ? 'active' : '';
            $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 ) . '"' : '';

            $output .= $indent . '<li' . $id . $value . $class_names . $li_attributes . '>';

            $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        ) .'"' : '';
            $attributes .= ($args->has_children)        ? ' class="dropdown-toggle" data-toggle="dropdown"' : '';

            $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 .= ($args->has_children) ? ' <b class="caret"></b></a>' : '</a>';
            $item_output .= $args->after;

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

        function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {

            if ( !$element )
                return;

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

            //display this element
            if ( is_array( $args[0] ) ) 
                $args[0]['has_children'] = ! empty( $children_elements[$element->$id_field] );
            else if ( is_object( $args[0] ) ) 
                $args[0]->has_children = ! empty( $children_elements[$element->$id_field] ); 
                $cb_args = array_merge( array(&$output, $element, $depth), $args);
            call_user_func_array(array(&$this, 'start_el'), $cb_args);

            $id = $element->$id_field;

            // descend only when the depth is right and there are childrens for this element
            if ( ($max_depth == 0 || $max_depth > $depth+1 ) && isset( $children_elements[$id]) ) {

                foreach( $children_elements[ $id ] as $child ){

                    if ( !isset($newlevel) ) {
                        $newlevel = true;
                        //start the child delimiter
                        $cb_args = array_merge( array(&$output, $depth), $args);
                        call_user_func_array(array(&$this, 'start_lvl'), $cb_args);
                    }
                    $this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
                }
                unset( $children_elements[ $id ] );
            }

            if ( isset($newlevel) && $newlevel ){
                //end the child delimiter
                $cb_args = array_merge( array(&$output, $depth), $args);
                call_user_func_array(array(&$this, 'end_lvl'), $cb_args);
            }

            //end this element
            $cb_args = array_merge( array(&$output, $element, $depth), $args);
            call_user_func_array(array(&$this, 'end_el'), $cb_args);

        }

    }

}

endif;

In this case, I need the extra menu level so I've stuck with my previous solution for now:
hidden link

But again, I must say, I've looked around online, via the tutorials you provided and through a couple of days of searching... and so far the only people I've found with a fixed bootpress top navbar with internal scrolling and unlimited depths of dropdowns is the layouts bootstrap menu navwalker implementation.

I haven't clicked resolved yet on this thread, purely to get your opinion on this, I am happy enough with the way I have the menu working. But curious how layouts managed it. lol

Your snippets and direction have been invaluable, and I am looking forward to using them more 😀

Thanks again Beda

Jeff

#459312

I went over it with our Layouts developer and we do our magic in this 2 files:
classes/cell_types/wpddl.cell_menu.class.php
inc/gui/editor/js/ddl-menu-cell-script.js
(but mainly in the first)

Please let me know if that helps, or if I need to help you analyse it / compare it to the one I provided you.

#459317

Hey Beda,

Pass on my regards towards the Layouts JuJu in those files, some good magic.

You mentioned them earlier, and now I have your and the other custom navwalker, I'll see what I can understand, and get back to you with questions after I've tried playing around a little.

I see the custom navwalker from line 196 downwards. Firstly I'll see about just trying to use this in the php snippets:


new DDL_Wpbootstrap_Nav_Walker()

See how that plays out.

Nice one

Jeff

#460416

Just cut and pasting the Layouts navwalker in was a backwards step. It resulted in only 1 level of dropdown menu working.

I will mark this thread as resolved, as I have a working solution for my split menu.

I will have a deeper look into those two files and compare them to the other navwalkers and later. If I have any question regarding them, I'll open a new forum post.

Thanks again Beda.

Jeff

This ticket is now closed. If you're a Toolset client and need related help, please open a new support ticket.