Navbar

by Dawid Adach,

Final result preview
Live preview

After all boring "administrative" work the time has come to some exciting stuff. Let's start real development.

We will begin from the top by creating navbar for our blog. Furthermore, we will connect it to WP in the way that we will be able to change the menu content without touching a single line of code.

  1. Paste the following code inside header.php just below <body> tag.
  2. 
    <header>
        <!--Navbar-->
        <nav class="navbar navbar-expand-lg navbar-dark light-blue accent-4">
            <div class="container">
                <a class="navbar-brand" href="#">Navbar</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
                    aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <ul class="navbar-nav mr-auto">
                        <li class="nav-item active">
                            <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" href="#">Features</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" href="#">Pricing</a>
                        </li>
                        <li class="nav-item btn-group">
                            <a class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown 
                            </a>
                            <div class="dropdown-menu dropdown-primary" aria-labelledby="navbarDropdownMenuLink">
                                <a class="dropdown-item" href="#">Action</a>
                                <a class="dropdown-item" href="#">Another action</a>
                                <a class="dropdown-item" href="#">Something else here</a>
                            </div>
                        </li>
                    </ul>
                    <form class="form-inline">
                        <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
                    </form>
                </div>
            </div>
        </nav>
        <!--/.Navbar-->
    </header>
                

    Navbar customization

    Check our Navbar documentation for more layouts/skins.

    This is standard MDB navbar. However, this is plain HTML, and that means that content inside (links, text) is hard coded. Every time we want to change anything (i.e. add new/modify existing link) we will have to edit our header.php file and upload it to a server. That's definitely not what we want. Let's make it more dynamic.

  3. Create a new folder and call it inc. Enter folder, create a new file with name mdb_bootstrap_navwalker.php and place the following code into it:
  4. 
    <?php
    /**
     * Extended Walker class for use with the
     * Material Design for Bootstrap toolkit in Wordpress.
     * Based on https://gist.github.com/3765640
     * 
     */
    class MDBBootstrapNavMenuWalker extends Walker_Nav_Menu {
      function start_lvl( &$output, $depth = 0, $args = array() ) {
        $indent = str_repeat( "\t", $depth );
        $submenu = ($depth > 0) ? ' sub-menu' : '';
        $output    .= "\n$indent<ul class=\"dropdown-menu$submenu depth_$depth\">\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;
        
        // managing divider: add divider class to an element to get a divider before it.
        $divider_class_position = array_search('divider', $classes);
        if($divider_class_position !== false){
          $output .= "<li class=\"divider\"></li>\n";
          unset($classes[$divider_class_position]);
        }
        
        $classes[] = ($args->has_children) ? 'dropdown' : '';
        $classes[] = ($item->current || $item->current_item_ancestor) ? 'active' : '';
        $classes[] = 'nav-item menu-item-' . $item->ID;
        if($depth && $args->has_children){
          $classes[] = 'dropdown-submenu';
        }
        $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-menu" aria-labelledby="dropdownMenu1"' : ' class="nav-link"';
        $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 .= ($depth == 0 && $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 ) {
        //v($element);
        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);
      }
    }
    ?>    
                
  5. Add the following code to the functions.php after the last function which we created (and before closing ?> tag).
  6.         
    /**
     * Include external files
     */
    require_once('inc/mdb_bootstrap_navwalker.php');
                 
    /**
     * Setup Theme
     */
    function MDB_setup() {
      // Navigation Menus
      register_nav_menus(array(
        'navbar' => __( 'Navbar Menu')
        ));
      // Add featured image support
        add_theme_support('post-thumbnails');
        add_image_size('main-full', 1078, 516, false); // main post image in full width
      }
      add_action('after_setup_theme', 'MDB_setup');
                                         
                                                                                         
                  
  7. Now let's get back to header.php and replace the following code:
  8.         
    <ul class="navbar-nav mr-auto">
        <li class="nav-item active">
            <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="#">Features</a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="#">Pricing</a>
        </li>
        <li class="nav-item btn-group">
            <a class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown 
            </a>
            <div class="dropdown-menu dropdown-primary" aria-labelledby="navbarDropdownMenuLink">
                <a class="dropdown-item" href="#">Action</a>
                <a class="dropdown-item" href="#">Another action</a>
                <a class="dropdown-item" href="#">Something else here</a>
            </div>
        </li>
    </ul>
                  

    with this one:

            
    <ul class="navbar-nav mr-auto">
      <?php
      if ( has_nav_menu( 'navbar' ) ) {
        wp_nav_menu( array(
        'menu'              => 'navbar',
        'theme_location'    => 'navbar',
        'depth'             => 2,
        'menu_class'        => 'navbar-nav mr-auto',
        'fallback_cb'       => 'wp_bootstrap_navwalker::fallback',
        'container'         => false,
        'walker'            => new MDBBootstrapNavMenuWalker())
        );
      } else
      echo "Please assign Navbar Menu in Wordpress Admin -> Appearance -> Menus -> Manage Locations";
      ?> 
    </ul>
  9. Refresh the page, you will notice that links which were there before have disappeared, instead, you can see now ugly text stating:
  10. Please assign Navbar Menu in Wordpress Admin -> Appearance -> Menus -> Manage Locations

  11. Let's do it. Open admin panel and navigate to Appearance -> Menus. Create a new menu, call it Navbar and add three items (posts/pages/custom links) to it. WordPress menu editing options Save menu and switch to Manage Locations tab. Assign our Navbar menu to Navbar Menu location.
WordPress Menu Locations manager

Now when you come back to your blog, you will notice that links which you have added, are visible in our navbar.

MDB Navbar

We've done quite a lot steps, let's analyze them now (don't be afraid that you do not understand what certain functions are doing. For now, you don't have to. We will learn that along tutorial. Information below is just a hint to give you brief idea on what we are doing):

New functions

mdb_bootstrap_navwalker.php - this is PHP function is responsible for building our output HTML of navbar depending on items which we choose from the admin menu. This code is using quite advanced PHP functions, we not gonna explain them now - we will back to them in next tutorials once we will get more familiar with PHP.

require_once('inc/mdb_bootstrap_navwalker.php'); - this PHP function includes given files and put it content in a place from where we call it. This allows us to split our functions.php file into multiple smaller files. That enhance our code readability. You don't have to split it and keep everything inside functions.php file instead, however, you will end up with a single file containing thousands line of code.

MDB_setup() - this is our function which we have created in order to register menu within WP and add featured image support to our theme.

register_nav_menus() - WP function which register place for our menu. As you noticed, in one of the last steps we assigned our menu to Menu location. This is how we created this location.

add_theme_support() - WP function which tells WP that our theme supports certain feature. In our case, we are adding feature image for posts. From now on when you edit a post you will see Feature image option, and you will be able to add a picture to each of the posts.

add_image_size() - WP function which defines size of our feature image. We will use it in next lessons.

wp_nav_menu() - WP function which informs WP that this is the place where we want to display. In this particular case, we are stating that we want to display Navbar menu inside our header.php file.

That's it! Our navbar is ready. Now we will take part of main part of our webpage.


If something doesn’t work as expected, you can download a final code for this lesson here:

Previous lesson Download Live preview Next lesson

Do you want to share?

Facebook Twitter Google +

About author


Dawid Adach

For more than 5 years Dawid was working as an IT Consultant specializing in SOA/EAI/ESB for banking domain. He was gaining experience working in countries like Netherlands, Belgium, Poland and India developing enterprise-class systems for the biggest companies within a domain. Since 2 years as a co-founder of mdbootstrap.com & brandflow.net is using and teaching others technologies like Angular, TypeScript, PHP, AJAX, Mongo, SQL, Hadoop Stack, Virtualization, Automation and many others...

Comments 45

  • perole

    Had problems with submenus not showing. Used the WP Boostrap Navwalker from wp-bootstrap (https://github.com/wp-bootstrap/wp-bootstrap-navwalker), seems to work nicely.

  • Douglas Sampaio (@dougsampaio)

    Hey Dawid, thanks for the tutorial! I was having trouble trying the step 6. My menu links weren't showing. On the 4th step, i changed ('fallback_cb' => 'wp_bootstrap_navwalker::fallback',) for ('fallback_cb' => 'mdb_bootstrap_navwalker::fallback',). And it worked.

  • it1

    In MDB JQuery 4.5.0 something wrong with the bootstrap.min.js file. It drop the following error: Uncaught TypeError: Cannot read property 'fn' of undefined

  • pr-olga

    Hi Dawid! Ich have the latest version of Wrodpress and of mdb. If I install the navigation, I get the following error by logging in into the back-end. So actually I have the white page: Warning: Cannot modify header information - headers already sent by (output started at .../wp-content/themes/karriere-auf-wp/inc/mdb_bootstrap_navwalker.php:1) in.../wp-includes/pluggable.php on line 1216 So could you please help me? Thank you in advance!

  • Jaxymbetov

    Hello Dawid, thanks for reply, I found some solution for submenu and it works, but now I need to create 3rd level submenu and it doesn't work. Now I don't know what to do with this, i got limited time. I know you are busy person, if you can find litle time for this problem we will be thankful to you. Thanks

      • Jaxymbetov

        Hello, I tried figure out Joels solution, but I didn't understand. I found another solution I use Max Mega Menu plugin, it has simular design with bootstrap and works great. I recomend it if someone needs to find fast solution for this problem. Thanks

      • Dawid Adach

        Dear Jaxymbetov , I am happy that you have solved your puzzle, however, I strongly discourage you from using Mega Menus! They break fundamental UX guidelines, and are very hard to use on mobile devices. I suggest thinking of alternative ways.

  • Joel Miguel Valente

    For those who have problems with the bootstrap menu 4 when creating submenus, well this is the method I have done in my own way so that it works correctly, you can visit my repository: https://github.com/joelmiguelvalente/wp_bootstrap_navwalker-2018

  • Jaxymbetov

    hello Dawid, your tutorials are great, but I couldn't create dropdown menu, when you plan to make tutorial about dropdown menus, thanks. Sorry for my english.

  • Dawid Adach

    Dear @zpzyyzp, This tutorial doesn't include dropdown feature. I will create tutorial about that soon.

  • zpzyyzp

    I have try the mdb_bootstrap_navwalker.php but it did not march the dropdown list in the bootstrap 4……

  • Dawid Adach

    Dear Liran, I will create a tutorial about that soon. Please follow us to get notification once it will be ready.

  • Liran Atli

    how can i include to my navbar collapse button or search form with wordpress functions?

  • Alan Mroczek

    Please remove the line `/*# sourceMappingURL=bootstrap.css.map */` from bootstrap.css

  • middll

    Hey Alan. Beings how the files are simply downloaded from this lesson and placed into the theme directory the origin for css/bootstrap.min.css.map must be coming from the files provided. It is also puzzling that the console in Safari displays the error (http://imgur.com/a/5xUPg) but Chrome does not (http://imgur.com/a/ylkXL).

  • Alan Mroczek

    Hi again Middll. This issue is very strange, because I haven't seen in your code including file that console displays as missing. This error means that file is included by some part of your code, but is not where it should or doesn't exist at all. It's hard to tell when it appears, you have to check every possible case. However file bootstrap.min.css.map shouldn't be included in your webpage code. You should search for that file in your code (probably next to some wp_enqueue_script function), and remove it.

  • middll

    Update: I went ahead and downloaded the final code for this lesson, moved the files into my theme directory after clearing it of any of my files, and loaded the webpage. The navbar is being displayed now; however, I'm still getting the following console error message: http://imgur.com/a/CcIap. I still do not know what was causing the issue with the code I copied and pasted, but alas. Does anyone know why this console error persists?

Leave a reply

Join MDB Affiliate Program

Get 30% profit from each sale

You earn 30% commission on affiliate sales, when a product is bought by a customer you referred, you will receive a 30% share.

Join us