This is the start of what will be a long intensive treatment of using Bootstrap with the WordPress Navigation Menu System (found in Dashboard -> Appearance -> Menus) if in fact you have called the wp_nav_menu() function correctly. We will also be using a custom WP_Nav_Walker object so we can add our Bootstrap classes to the system neatly & easily… strap in.
// This is my bootstrap-overrides.scss file, only calls particular .scss files...
$primary: #0000ff; // your custom primary color
$secondary: #ff9c00; // your custom primary color
@import "bootstrap/functions";
@import "bootstrap/variables";
@import "bootstrap/mixins";
@import "bootstrap/nav";
@import "bootstrap/navbar";
collapse
functions. Download the Bootstrap source code and in the “js/src” directory you will find the collapse.js plugin.The “collapse” classes can be found in _transitions.scss
// from transitions.scss
.fade {
transition: opacity 0.15s linear; }
@media screen and (prefers-reduced-motion: reduce) {
.fade {
transition: none; } }
.fade:not(.show) {
opacity: 0; }
.collapse:not(.show) {
display: none; }
.collapsing {
position: relative;
height: 0;
overflow: hidden;
transition: height 0.35s ease; }
@media screen and (prefers-reduced-motion: reduce) {
.collapsing {
transition: none; } }
// This is the actual CSS generated from the SASS processor...
// I had button selectors but removed that for the sake of brevity
/*!
* Bootstrap v4.2.1 (https://getbootstrap.com/)
* Copyright 2011-2018 The Bootstrap Authors
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
.nav {
display: flex;
flex-wrap: wrap;
padding-left: 0;
margin-bottom: 0;
list-style: none; }
.nav-link {
display: block;
padding: 0.5rem 1rem; }
.nav-link:hover, .nav-link:focus {
text-decoration: none; }
.nav-link.disabled {
color: #6c757d;
pointer-events: none;
cursor: default; }
.nav-tabs {
border-bottom: 1px solid #dee2e6; }
.nav-tabs .nav-item {
margin-bottom: -1px; }
.nav-tabs .nav-link {
border: 1px solid transparent;
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem; }
.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {
border-color: #e9ecef #e9ecef #dee2e6; }
.nav-tabs .nav-link.disabled {
color: #6c757d;
background-color: transparent;
border-color: transparent; }
.nav-tabs .nav-link.active,
.nav-tabs .nav-item.show .nav-link {
color: #495057;
background-color: #fff;
border-color: #dee2e6 #dee2e6 #fff; }
.nav-tabs .dropdown-menu {
margin-top: -1px;
border-top-left-radius: 0;
border-top-right-radius: 0; }
.nav-pills .nav-link {
border-radius: 0.25rem; }
.nav-pills .nav-link.active,
.nav-pills .show > .nav-link {
color: #fff;
background-color: #0000ff; }
.nav-fill .nav-item {
flex: 1 1 auto;
text-align: center; }
.nav-justified .nav-item {
flex-basis: 0;
flex-grow: 1;
text-align: center; }
.tab-content > .tab-pane {
display: none; }
.tab-content > .active {
display: block; }
.navbar {
position: relative;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
padding: 0.5rem 1rem; }
.navbar > .container,
.navbar > .container-fluid {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between; }
.navbar-brand {
display: inline-block;
padding-top: 0.3125rem;
padding-bottom: 0.3125rem;
margin-right: 1rem;
font-size: 1.25rem;
line-height: inherit;
white-space: nowrap; }
.navbar-brand:hover, .navbar-brand:focus {
text-decoration: none; }
.navbar-nav {
display: flex;
flex-direction: column;
padding-left: 0;
margin-bottom: 0;
list-style: none; }
.navbar-nav .nav-link {
padding-right: 0;
padding-left: 0; }
.navbar-nav .dropdown-menu {
position: static;
float: none; }
.navbar-text {
display: inline-block;
padding-top: 0.5rem;
padding-bottom: 0.5rem; }
.navbar-collapse {
flex-basis: 100%;
flex-grow: 1;
align-items: center; }
.navbar-toggler {
padding: 0.25rem 0.75rem;
font-size: 1.25rem;
line-height: 1;
background-color: transparent;
border: 1px solid transparent;
border-radius: 0.25rem; }
.navbar-toggler:hover, .navbar-toggler:focus {
text-decoration: none; }
.navbar-toggler:not(:disabled):not(.disabled) {
cursor: pointer; }
.navbar-toggler-icon {
display: inline-block;
width: 1.5em;
height: 1.5em;
vertical-align: middle;
content: "";
background: no-repeat center center;
background-size: 100% 100%; }
@media (max-width: 575.98px) {
.navbar-expand-sm > .container,
.navbar-expand-sm > .container-fluid {
padding-right: 0;
padding-left: 0; } }
@media (min-width: 576px) {
.navbar-expand-sm {
flex-flow: row nowrap;
justify-content: flex-start; }
.navbar-expand-sm .navbar-nav {
flex-direction: row; }
.navbar-expand-sm .navbar-nav .dropdown-menu {
position: absolute; }
.navbar-expand-sm .navbar-nav .nav-link {
padding-right: 0.5rem;
padding-left: 0.5rem; }
.navbar-expand-sm > .container,
.navbar-expand-sm > .container-fluid {
flex-wrap: nowrap; }
.navbar-expand-sm .navbar-collapse {
display: flex !important;
flex-basis: auto; }
.navbar-expand-sm .navbar-toggler {
display: none; } }
@media (max-width: 767.98px) {
.navbar-expand-md > .container,
.navbar-expand-md > .container-fluid {
padding-right: 0;
padding-left: 0; } }
@media (min-width: 768px) {
.navbar-expand-md {
flex-flow: row nowrap;
justify-content: flex-start; }
.navbar-expand-md .navbar-nav {
flex-direction: row; }
.navbar-expand-md .navbar-nav .dropdown-menu {
position: absolute; }
.navbar-expand-md .navbar-nav .nav-link {
padding-right: 0.5rem;
padding-left: 0.5rem; }
.navbar-expand-md > .container,
.navbar-expand-md > .container-fluid {
flex-wrap: nowrap; }
.navbar-expand-md .navbar-collapse {
display: flex !important;
flex-basis: auto; }
.navbar-expand-md .navbar-toggler {
display: none; } }
@media (max-width: 991.98px) {
.navbar-expand-lg > .container,
.navbar-expand-lg > .container-fluid {
padding-right: 0;
padding-left: 0; } }
@media (min-width: 992px) {
.navbar-expand-lg {
flex-flow: row nowrap;
justify-content: flex-start; }
.navbar-expand-lg .navbar-nav {
flex-direction: row; }
.navbar-expand-lg .navbar-nav .dropdown-menu {
position: absolute; }
.navbar-expand-lg .navbar-nav .nav-link {
padding-right: 0.5rem;
padding-left: 0.5rem; }
.navbar-expand-lg > .container,
.navbar-expand-lg > .container-fluid {
flex-wrap: nowrap; }
.navbar-expand-lg .navbar-collapse {
display: flex !important;
flex-basis: auto; }
.navbar-expand-lg .navbar-toggler {
display: none; } }
@media (max-width: 1199.98px) {
.navbar-expand-xl > .container,
.navbar-expand-xl > .container-fluid {
padding-right: 0;
padding-left: 0; } }
@media (min-width: 1200px) {
.navbar-expand-xl {
flex-flow: row nowrap;
justify-content: flex-start; }
.navbar-expand-xl .navbar-nav {
flex-direction: row; }
.navbar-expand-xl .navbar-nav .dropdown-menu {
position: absolute; }
.navbar-expand-xl .navbar-nav .nav-link {
padding-right: 0.5rem;
padding-left: 0.5rem; }
.navbar-expand-xl > .container,
.navbar-expand-xl > .container-fluid {
flex-wrap: nowrap; }
.navbar-expand-xl .navbar-collapse {
display: flex !important;
flex-basis: auto; }
.navbar-expand-xl .navbar-toggler {
display: none; } }
.navbar-expand {
flex-flow: row nowrap;
justify-content: flex-start; }
.navbar-expand > .container,
.navbar-expand > .container-fluid {
padding-right: 0;
padding-left: 0; }
.navbar-expand .navbar-nav {
flex-direction: row; }
.navbar-expand .navbar-nav .dropdown-menu {
position: absolute; }
.navbar-expand .navbar-nav .nav-link {
padding-right: 0.5rem;
padding-left: 0.5rem; }
.navbar-expand > .container,
.navbar-expand > .container-fluid {
flex-wrap: nowrap; }
.navbar-expand .navbar-collapse {
display: flex !important;
flex-basis: auto; }
.navbar-expand .navbar-toggler {
display: none; }
.navbar-light .navbar-brand {
color: rgba(0, 0, 0, 0.9); }
.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus {
color: rgba(0, 0, 0, 0.9); }
.navbar-light .navbar-nav .nav-link {
color: rgba(0, 0, 0, 0.5); }
.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus {
color: rgba(0, 0, 0, 0.7); }
.navbar-light .navbar-nav .nav-link.disabled {
color: rgba(0, 0, 0, 0.3); }
.navbar-light .navbar-nav .show > .nav-link,
.navbar-light .navbar-nav .active > .nav-link,
.navbar-light .navbar-nav .nav-link.show,
.navbar-light .navbar-nav .nav-link.active {
color: rgba(0, 0, 0, 0.9); }
.navbar-light .navbar-toggler {
color: rgba(0, 0, 0, 0.5);
border-color: rgba(0, 0, 0, 0.1); }
.navbar-light .navbar-toggler-icon {
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); }
.navbar-light .navbar-text {
color: rgba(0, 0, 0, 0.5); }
.navbar-light .navbar-text a {
color: rgba(0, 0, 0, 0.9); }
.navbar-light .navbar-text a:hover, .navbar-light .navbar-text a:focus {
color: rgba(0, 0, 0, 0.9); }
.navbar-dark .navbar-brand {
color: #fff; }
.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus {
color: #fff; }
.navbar-dark .navbar-nav .nav-link {
color: rgba(255, 255, 255, 0.5); }
.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus {
color: rgba(255, 255, 255, 0.75); }
.navbar-dark .navbar-nav .nav-link.disabled {
color: rgba(255, 255, 255, 0.25); }
.navbar-dark .navbar-nav .show > .nav-link,
.navbar-dark .navbar-nav .active > .nav-link,
.navbar-dark .navbar-nav .nav-link.show,
.navbar-dark .navbar-nav .nav-link.active {
color: #fff; }
.navbar-dark .navbar-toggler {
color: rgba(255, 255, 255, 0.5);
border-color: rgba(255, 255, 255, 0.1); }
.navbar-dark .navbar-toggler-icon {
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); }
.navbar-dark .navbar-text {
color: rgba(255, 255, 255, 0.5); }
.navbar-dark .navbar-text a {
color: #fff; }
.navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus {
color: #fff; }
<?php
// This is version 3! (WP_Bootstrap_Navwalker) with some modification...
// https://stackoverflow.com/questions/28247321/bootstrap-nav-walker-add-class-to-child-ul-multi-level-menu
/* Check if Class Exists. */
if ( ! class_exists( 'WP_Bootstrap_Navwalker' ) ) {
class WP_Bootstrap_Navwalker extends Walker_Nav_Menu {
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat( "\t", $depth );
$output .= "\n$indent<ul role=\"menu\" class=\" dropdown-menu\" >\n";
}
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
if ( 0 === strcasecmp( $item->attr_title, 'divider' ) && 1 === $depth ) {
$output .= $indent . '<li role="presentation" class="divider">';
} elseif ( 0 === strcasecmp( $item->title, 'divider' ) && 1 === $depth ) {
$output .= $indent . '<li role="presentation" class="divider">';
} elseif ( 0 === strcasecmp( $item->attr_title, 'dropdown-header' ) && 1 === $depth ) {
$output .= $indent . '<li role="presentation" class="dropdown-header">' . esc_attr( $item->title );
} elseif ( 0 === strcasecmp( $item->attr_title, 'disabled' ) ) {
$output .= $indent . '<li role="presentation" class="disabled"><a href="#">>' . esc_attr( $item->title ) . '</a>';
} else {
$value = '';
$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, $depth ) );
if ( isset( $args->has_children ) && $args->has_children ) {
$class_names .= ' dropdown';
}
if ( in_array( 'current-menu-item', $classes, true ) ) {
$class_names .= ' active';
}
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
$id = apply_filters( 'nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args );
$id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
$output .= $indent . '<li itemscope="itemscope" itemtype="https://www.schema.org/SiteNavigationElement"' . $id . $value . $class_names . '>';
$atts = array();
if ( empty( $item->attr_title ) ) {
$atts['title'] = ! empty( $item->title ) ? strip_tags( $item->title ) : '';
} else {
$atts['title'] = $item->attr_title;
}
$atts['target'] = ! empty( $item->target ) ? $item->target : '';
$atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';
// If item has_children add atts to a.
if ( isset( $args->has_children ) && $args->has_children /** && 0 === $depth **/ ) {
$atts['href'] = '#';
$atts['data-toggle'] = 'dropdown';
$atts['class'] = 'dropdown-toggle';
$atts['aria-haspopup'] = 'true';
} else {
$atts['href'] = ! empty( $item->url ) ? $item->url : '';
}
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
$icon_attributes = '';
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
// if item has icon, we want all except title attributes because we
// want to avoid link title to be icon class.
if ( 'title' != $attr ) {
$icon_attributes .= ' ' . $attr . '="' . $value . '"';
}
}
}
$item_output = isset( $args->before ) ? $args->before : '';
if ( ! empty( $item->attr_title ) ) {
$pos = strpos( esc_attr( $item->attr_title ), 'glyphicon' );
if ( false !== $pos ) {
$item_output .= '<a' . $icon_attributes . ' title="' . esc_attr( $item->title ) . '"><span class="glyphicon ' . esc_attr( $item->attr_title ) . '" aria-hidden="true"></span> ';
} else {
$item_output .= '<a' . $icon_attributes . ' title="' . esc_attr( $item->title ) . '"><i class="fa ' . esc_attr( $item->attr_title ) . '" aria-hidden="true"></i> ';
}
} else {
$item_output .= '<a' . $attributes . '>';
}
$item_output .= isset( $args->link_before ) ? $args->link_before : '';
$item_output .= apply_filters( 'the_title', $item->title, $item->ID );
$item_output .= isset( $args->link_after ) ? $args->link_after: '';
// REMOVED: <span class="caret"></span<
$item_output .= ( isset( $args->has_children ) && $args->has_children && 0 === $depth ) ? ' </a>' : '</a>';
$item_output .= isset( $args->after ) ? $args->after : '';
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
} // End if().
}
// WP_Bootstrap_Navwalker extends Walker_Nav_Menu
// Walker_Nav_Menu extends Walker
// https://developer.wordpress.org/reference/classes/walker/
public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
if ( ! $element ) {
return; }
$id_field = $this->db_fields['id'];
// Display this element.
if ( is_object( $args[0] ) ) {
$args[0]->has_children = ! empty( $children_elements[ $element->$id_field ] ); }
parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
}
}
} // End if(). ?>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapseOne" aria-controls="collapseOne" aria-expanded="false" aria-label="<?php esc_attr_e( 'Toggle navigation', 'twentytwenty-child' ); ?>">
<span class="navbar-toggler-icon"></span>
</button>
<?php
// This will go in header.php for example and allows it to appear in Dashboard -> Appearance -> Menus
<nav class="navbar navbar-expand-lg navbar-light bg-light">
wp_nav_menu(
array(
'theme_location' => 'main_menu',
'container_class' => 'collapse show',
'container_id' => 'collapseOne',
'menu_class' => 'navbar-nav ml-auto',
'menu_id' => 'main_menu',
'depth' => 0,
'walker' => new WP_Bootstrap_Navwalker(),
)
);
</nav><!-- .site-navigation -->
?>
(function($) {
$( document ).ready(function() {
console.log( "document loaded" );
$('ul.dropdown-menu [data-toggle=dropdown]').on('click', function(event) {
event.preventDefault();
event.stopPropagation();
// change parent sibling A's aria-expanded attribute to "false"
$(this).parent().siblings().attr( "aria-expanded", "false" );
// change this A aria-expanded attribute to "true"
$(this).attr( "aria-expanded", "true" );
// show ul
$(this).parent().children("ul.dropdown-menu").toggleClass('show');
});
});
})( jQuery );