
Bootstrap Navigation
WordPress Menu – Navigation Utilizing Bootstrap
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.scssUsing a Javascript plugin, behavior is accessed via data attributes. Just add data-toggle=”collapse” and a data-target to the element to automatically assign control of one or more collapsible elements. The data-target attribute accepts a CSS selector to apply the collapse to. Be sure to add the class collapse to the collapsible element. If you’d like it to default open, add the additional class show. To add accordion-like group management to a collapsible area, add the data attribute data-parent=”#selector”. Refer to the demo to see this in action.
// 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 );