{"id":2769,"date":"2021-06-18T18:06:18","date_gmt":"2021-06-18T22:06:18","guid":{"rendered":"https:\/\/thewpgeek.com\/?p=2769"},"modified":"2021-06-22T08:21:26","modified_gmt":"2021-06-22T12:21:26","slug":"add-a-responsive-menu-in-sage","status":"publish","type":"post","link":"https:\/\/thewpgeek.com\/add-a-responsive-menu-in-sage\/","title":{"rendered":"Add a responsive menu in Sage"},"content":{"rendered":"\n

You should have added all the test data to the theme in the last step,<\/a> to begin working on our menu go to “Appearance > Menu” and choose the testing menu from the drop-down : <\/p>\n\n\n\n

\"WordPress<\/figure>\n\n\n\n

Then, set this as your primary navigation : <\/p>\n\n\n\n

\"Save<\/figure>\n\n\n\n

Now, visit your main page to see the visually stunning result, which will likely look a lot like mine : <\/p>\n\n\n\n

\"Default
Default Sage Menu Layout – Ready for styling<\/figcaption><\/figure><\/div>\n\n\n\n

So we have a structure, and we could manually work on the CSS for this menu. We would need to make sure it supports multiple levels, collapsed on small screens into a hamburger menu, and supported a wide variety of screen sizes and devices. It also needs to tab correctly and support screen readers. This is a lot of work. Let’s instead, use the bootstrap library. To do this, we need to format the menu with the classes bootstrap is looking for. We need a navwalker to do this task for us. <\/p>\n\n\n\n

I tried a few versions designed for sage – however, I had issues with all of them with the latest bootstrap and Sage theme. This is my solution, based entirely on this navwalker <\/a> (released under GPL) <\/p>\n\n\n\n

Copy all of the code in this file<\/a> (visit the external site link to get the very latest version in case any changes have been made, or use the code below). We first need to create a new file to paste this into, this will live here: app\/walker.php<\/p>\n\n\n\n

\"Add<\/figure><\/div>\n\n\n\n

Add this code and save :<\/p>\n\n\n\n

<?php\n\/**\n * WP Bootstrap Navwalker\n *\n * @package WP-Bootstrap-Navwalker\n *\n * @wordpress-plugin\n * Plugin Name: WP Bootstrap Navwalker\n * Plugin URI:  https:\/\/github.com\/wp-bootstrap\/wp-bootstrap-navwalker\n * Description: A custom WordPress nav walker class to implement the Bootstrap 4 navigation style in a custom theme using the WordPress built in menu manager.\n * Author: Edward McIntyre - @twittem, WP Bootstrap, William Patton - @pattonwebz\n * Version: 4.3.0\n * Author URI: https:\/\/github.com\/wp-bootstrap\n * GitHub Plugin URI: https:\/\/github.com\/wp-bootstrap\/wp-bootstrap-navwalker\n * GitHub Branch: master\n * License: GPL-3.0+\n * License URI: http:\/\/www.gnu.org\/licenses\/gpl-3.0.txt\n *\/\n\n\/\/ Check if Class Exists.\nif ( ! class_exists( 'WP_Bootstrap_Navwalker' ) ) :\n\t\/**\n\t * WP_Bootstrap_Navwalker class.\n\t *\/\n\tclass WP_Bootstrap_Navwalker extends Walker_Nav_Menu {\n\n\t\t\/**\n\t\t * Whether the items_wrap contains schema microdata or not.\n\t\t *\n\t\t * @since 4.2.0\n\t\t * @var boolean\n\t\t *\/\n\t\tprivate $has_schema = false;\n\n\t\t\/**\n\t\t * Ensure the items_wrap argument contains microdata.\n\t\t *\n\t\t * @since 4.2.0\n\t\t *\/\n\t\tpublic function __construct() {\n\t\t\tif ( ! has_filter( 'wp_nav_menu_args', array( $this, 'add_schema_to_navbar_ul' ) ) ) {\n\t\t\t\tadd_filter( 'wp_nav_menu_args', array( $this, 'add_schema_to_navbar_ul' ) );\n\t\t\t}\n\t\t}\n\n\t\t\/**\n\t\t * Starts the list before the elements are added.\n\t\t *\n\t\t * @since WP 3.0.0\n\t\t *\n\t\t * @see Walker_Nav_Menu::start_lvl()\n\t\t *\n\t\t * @param string           $output Used to append additional content (passed by reference).\n\t\t * @param int              $depth  Depth of menu item. Used for padding.\n\t\t * @param WP_Nav_Menu_Args $args   An object of wp_nav_menu() arguments.\n\t\t *\/\n\t\tpublic function start_lvl( &$output, $depth = 0, $args = null ) {\n\t\t\tif ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {\n\t\t\t\t$t = '';\n\t\t\t\t$n = '';\n\t\t\t} else {\n\t\t\t\t$t = \"\\t\";\n\t\t\t\t$n = \"\\n\";\n\t\t\t}\n\t\t\t$indent = str_repeat( $t, $depth );\n\t\t\t\/\/ Default class to add to the file.\n\t\t\t$classes = array( 'dropdown-menu' );\n\t\t\t\/**\n\t\t\t * Filters the CSS class(es) applied to a menu list element.\n\t\t\t *\n\t\t\t * @since WP 4.8.0\n\t\t\t *\n\t\t\t * @param array    $classes The CSS classes that are applied to the menu `<ul>` element.\n\t\t\t * @param stdClass $args    An object of `wp_nav_menu()` arguments.\n\t\t\t * @param int      $depth   Depth of menu item. Used for padding.\n\t\t\t *\/\n\t\t\t$class_names = join( ' ', apply_filters( 'nav_menu_submenu_css_class', $classes, $args, $depth ) );\n\t\t\t$class_names = $class_names ? ' class=\"' . esc_attr( $class_names ) . '\"' : '';\n\n\t\t\t\/*\n\t\t\t * The `.dropdown-menu` container needs to have a labelledby\n\t\t\t * attribute which points to it's trigger link.\n\t\t\t *\n\t\t\t * Form a string for the labelledby attribute from the the latest\n\t\t\t * link with an id that was added to the $output.\n\t\t\t *\/\n\t\t\t$labelledby = '';\n\t\t\t\/\/ Find all links with an id in the output.\n\t\t\tpreg_match_all( '\/(<a.*?id=\\\"|\\')(.*?)\\\"|\\'.*?>\/im', $output, $matches );\n\t\t\t\/\/ With pointer at end of array check if we got an ID match.\n\t\t\tif ( end( $matches[2] ) ) {\n\t\t\t\t\/\/ Build a string to use as aria-labelledby.\n\t\t\t\t$labelledby = 'aria-labelledby=\"' . esc_attr( end( $matches[2] ) ) . '\"';\n\t\t\t}\n\t\t\t$output .= \"{$n}{$indent}<ul$class_names $labelledby>{$n}\";\n\t\t}\n\n\t\t\/**\n\t\t * Starts the element output.\n\t\t *\n\t\t * @since WP 3.0.0\n\t\t * @since WP 4.4.0 The {@see 'nav_menu_item_args'} filter was added.\n\t\t *\n\t\t * @see Walker_Nav_Menu::start_el()\n\t\t *\n\t\t * @param string           $output Used to append additional content (passed by reference).\n\t\t * @param WP_Nav_Menu_Item $item   Menu item data object.\n\t\t * @param int              $depth  Depth of menu item. Used for padding.\n\t\t * @param WP_Nav_Menu_Args $args   An object of wp_nav_menu() arguments.\n\t\t * @param int              $id     Current item ID.\n\t\t *\/\n\t\tpublic function start_el( &$output, $item, $depth = 0, $args = null, $id = 0 ) {\n\t\t\tif ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {\n\t\t\t\t$t = '';\n\t\t\t\t$n = '';\n\t\t\t} else {\n\t\t\t\t$t = \"\\t\";\n\t\t\t\t$n = \"\\n\";\n\t\t\t}\n\t\t\t$indent = ( $depth ) ? str_repeat( $t, $depth ) : '';\n\n\t\t\tif ( false !== strpos( $args->items_wrap, 'itemscope' ) && false === $this->has_schema ) {\n\t\t\t\t$this->has_schema  = true;\n\t\t\t\t$args->link_before = '<span itemprop=\"name\">' . $args->link_before;\n\t\t\t\t$args->link_after .= '<\/span>';\n\t\t\t}\n\n\t\t\t$classes = empty( $item->classes ) ? array() : (array) $item->classes;\n\n\t\t\t\/\/ Updating the CSS classes of a menu item in the WordPress Customizer preview results in all classes defined\n\t\t\t\/\/ in that particular input box to come in as one big class string.\n\t\t\t$split_on_spaces = function ( $class ) {\n\t\t\t\treturn preg_split( '\/\\s+\/', $class );\n\t\t\t};\n\t\t\t$classes         = $this->flatten( array_map( $split_on_spaces, $classes ) );\n\n\t\t\t\/*\n\t\t\t * Initialize some holder variables to store specially handled item\n\t\t\t * wrappers and icons.\n\t\t\t *\/\n\t\t\t$linkmod_classes = array();\n\t\t\t$icon_classes    = array();\n\n\t\t\t\/*\n\t\t\t * Get an updated $classes array without linkmod or icon classes.\n\t\t\t *\n\t\t\t * NOTE: linkmod and icon class arrays are passed by reference and\n\t\t\t * are maybe modified before being used later in this function.\n\t\t\t *\/\n\t\t\t$classes = self::separate_linkmods_and_icons_from_classes( $classes, $linkmod_classes, $icon_classes, $depth );\n\n\t\t\t\/\/ Join any icon classes plucked from $classes into a string.\n\t\t\t$icon_class_string = join( ' ', $icon_classes );\n\n\t\t\t\/**\n\t\t\t * Filters the arguments for a single nav menu item.\n\t\t\t *\n\t\t\t * @since WP 4.4.0\n\t\t\t *\n\t\t\t * @param WP_Nav_Menu_Args $args  An object of wp_nav_menu() arguments.\n\t\t\t * @param WP_Nav_Menu_Item $item  Menu item data object.\n\t\t\t * @param int              $depth Depth of menu item. Used for padding.\n\t\t\t *\n\t\t\t * @var WP_Nav_Menu_Args\n\t\t\t *\/\n\t\t\t$args = apply_filters( 'nav_menu_item_args', $args, $item, $depth );\n\n\t\t\t\/\/ Add .dropdown or .active classes where they are needed.\n\t\t\tif ( $this->has_children ) {\n\t\t\t\t$classes[] = 'dropdown';\n\t\t\t}\n\t\t\tif ( in_array( 'current-menu-item', $classes, true ) || in_array( 'current-menu-parent', $classes, true ) ) {\n\t\t\t\t$classes[] = 'active';\n\t\t\t}\n\n\t\t\t\/\/ Add some additional default classes to the item.\n\t\t\t$classes[] = 'menu-item-' . $item->ID;\n\t\t\t$classes[] = 'nav-item';\n\n\t\t\t\/\/ Allow filtering the classes.\n\t\t\t$classes = apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth );\n\n\t\t\t\/\/ Form a string of classes in format: class=\"class_names\".\n\t\t\t$class_names = join( ' ', $classes );\n\t\t\t$class_names = $class_names ? ' class=\"' . esc_attr( $class_names ) . '\"' : '';\n\n\t\t\t\/**\n\t\t\t * Filters the ID applied to a menu item's list item element.\n\t\t\t *\n\t\t\t * @since WP 3.0.1\n\t\t\t * @since WP 4.1.0 The `$depth` parameter was added.\n\t\t\t *\n\t\t\t * @param string           $menu_id The ID that is applied to the menu item's `<li>` element.\n\t\t\t * @param WP_Nav_Menu_Item $item    The current menu item.\n\t\t\t * @param WP_Nav_Menu_Args $args    An object of wp_nav_menu() arguments.\n\t\t\t * @param int              $depth   Depth of menu item. Used for padding.\n\t\t\t *\/\n\t\t\t$id = apply_filters( 'nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args, $depth );\n\t\t\t$id = $id ? ' id=\"' . esc_attr( $id ) . '\"' : '';\n\n\t\t\t$output .= $indent . '<li ' . $id . $class_names . '>';\n\n\t\t\t\/\/ Initialize array for holding the $atts for the link item.\n\t\t\t$atts           = array();\n\t\t\t$atts['title']  = ! empty( $item->attr_title ) ? $item->attr_title : '';\n\t\t\t$atts['target'] = ! empty( $item->target ) ? $item->target : '';\n\t\t\tif ( '_blank' === $item->target && empty( $item->xfn ) ) {\n\t\t\t\t$atts['rel'] = 'noopener noreferrer';\n\t\t\t} else {\n\t\t\t\t$atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';\n\t\t\t}\n\n\t\t\t\/\/ If the item has_children add atts to <a>.\n\t\t\tif ( $this->has_children && 0 === $depth ) {\n\t\t\t\t$atts['href']          = '#';\n\t\t\t\t$atts['data-toggle']   = 'dropdown';\n\t\t\t\t$atts['aria-haspopup'] = 'true';\n\t\t\t\t$atts['aria-expanded'] = 'false';\n\t\t\t\t$atts['class']         = 'dropdown-toggle nav-link';\n\t\t\t\t$atts['id']            = 'menu-item-dropdown-' . $item->ID;\n\t\t\t} else {\n\t\t\t\tif ( true === $this->has_schema ) {\n\t\t\t\t\t$atts['itemprop'] = 'url';\n\t\t\t\t}\n\n\t\t\t\t$atts['href'] = ! empty( $item->url ) ? $item->url : '#';\n\t\t\t\t\/\/ For items in dropdowns use .dropdown-item instead of .nav-link.\n\t\t\t\tif ( $depth > 0 ) {\n\t\t\t\t\t$atts['class'] = 'dropdown-item';\n\t\t\t\t} else {\n\t\t\t\t\t$atts['class'] = 'nav-link';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t$atts['aria-current'] = $item->current ? 'page' : '';\n\n\t\t\t\/\/ Update atts of this item based on any custom linkmod classes.\n\t\t\t$atts = self::update_atts_for_linkmod_type( $atts, $linkmod_classes );\n\n\t\t\t\/\/ Allow filtering of the $atts array before using it.\n\t\t\t$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );\n\n\t\t\t\/\/ Build a string of html containing all the atts for the item.\n\t\t\t$attributes = '';\n\t\t\tforeach ( $atts as $attr => $value ) {\n\t\t\t\tif ( ! empty( $value ) ) {\n\t\t\t\t\t$value       = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );\n\t\t\t\t\t$attributes .= ' ' . $attr . '=\"' . $value . '\"';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t\/\/ Set a typeflag to easily test if this is a linkmod or not.\n\t\t\t$linkmod_type = self::get_linkmod_type( $linkmod_classes );\n\n\t\t\t\/\/ START appending the internal item contents to the output.\n\t\t\t$item_output = isset( $args->before ) ? $args->before : '';\n\n\t\t\t\/*\n\t\t\t * This is the start of the internal nav item. Depending on what\n\t\t\t * kind of linkmod we have we may need different wrapper elements.\n\t\t\t *\/\n\t\t\tif ( '' !== $linkmod_type ) {\n\t\t\t\t\/\/ Is linkmod, output the required element opener.\n\t\t\t\t$item_output .= self::linkmod_element_open( $linkmod_type, $attributes );\n\t\t\t} else {\n\t\t\t\t\/\/ With no link mod type set this must be a standard <a> tag.\n\t\t\t\t$item_output .= '<a' . $attributes . '>';\n\t\t\t}\n\n\t\t\t\/*\n\t\t\t * Initiate empty icon var, then if we have a string containing any\n\t\t\t * icon classes form the icon markup with an <i> element. This is\n\t\t\t * output inside of the item before the $title (the link text).\n\t\t\t *\/\n\t\t\t$icon_html = '';\n\t\t\tif ( ! empty( $icon_class_string ) ) {\n\t\t\t\t\/\/ Append an <i> with the icon classes to what is output before links.\n\t\t\t\t$icon_html = '<i class=\"' . esc_attr( $icon_class_string ) . '\" aria-hidden=\"true\"><\/i> ';\n\t\t\t}\n\n\t\t\t\/** This filter is documented in wp-includes\/post-template.php *\/\n\t\t\t$title = apply_filters( 'the_title', $item->title, $item->ID );\n\n\t\t\t\/**\n\t\t\t * Filters a menu item's title.\n\t\t\t *\n\t\t\t * @since WP 4.4.0\n\t\t\t *\n\t\t\t * @param string           $title The menu item's title.\n\t\t\t * @param WP_Nav_Menu_Item $item  The current menu item.\n\t\t\t * @param WP_Nav_Menu_Args $args  An object of wp_nav_menu() arguments.\n\t\t\t * @param int              $depth Depth of menu item. Used for padding.\n\t\t\t *\/\n\t\t\t$title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth );\n\n\t\t\t\/\/ If the .sr-only class was set apply to the nav items text only.\n\t\t\tif ( in_array( 'sr-only', $linkmod_classes, true ) ) {\n\t\t\t\t$title         = self::wrap_for_screen_reader( $title );\n\t\t\t\t$keys_to_unset = array_keys( $linkmod_classes, 'sr-only', true );\n\t\t\t\tforeach ( $keys_to_unset as $k ) {\n\t\t\t\t\tunset( $linkmod_classes[ $k ] );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t\/\/ Put the item contents into $output.\n\t\t\t$item_output .= isset( $args->link_before ) ? $args->link_before . $icon_html . $title . $args->link_after : '';\n\n\t\t\t\/*\n\t\t\t * This is the end of the internal nav item. We need to close the\n\t\t\t * correct element depending on the type of link or link mod.\n\t\t\t *\/\n\t\t\tif ( '' !== $linkmod_type ) {\n\t\t\t\t\/\/ Is linkmod, output the required closing element.\n\t\t\t\t$item_output .= self::linkmod_element_close( $linkmod_type );\n\t\t\t} else {\n\t\t\t\t\/\/ With no link mod type set this must be a standard <a> tag.\n\t\t\t\t$item_output .= '<\/a>';\n\t\t\t}\n\n\t\t\t$item_output .= isset( $args->after ) ? $args->after : '';\n\n\t\t\t\/\/ END appending the internal item contents to the output.\n\t\t\t$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );\n\t\t}\n\n\t\t\/**\n\t\t * Menu fallback.\n\t\t *\n\t\t * If this function is assigned to the wp_nav_menu's fallback_cb variable\n\t\t * and a menu has not been assigned to the theme location in the WordPress\n\t\t * menu manager the function will display nothing to a non-logged in user,\n\t\t * and will add a link to the WordPress menu manager if logged in as an admin.\n\t\t *\n\t\t * @param array $args passed from the wp_nav_menu function.\n\t\t * @return string|void String when echo is false.\n\t\t *\/\n\t\tpublic static function fallback( $args ) {\n\t\t\tif ( ! current_user_can( 'edit_theme_options' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t\/\/ Initialize var to store fallback html.\n\t\t\t$fallback_output = '';\n\n\t\t\t\/\/ Menu container opening tag.\n\t\t\t$show_container = false;\n\t\t\tif ( $args['container'] ) {\n\t\t\t\t\/**\n\t\t\t\t * Filters the list of HTML tags that are valid for use as menu containers.\n\t\t\t\t *\n\t\t\t\t * @since WP 3.0.0\n\t\t\t\t *\n\t\t\t\t * @param array $tags The acceptable HTML tags for use as menu containers.\n\t\t\t\t *                    Default is array containing 'div' and 'nav'.\n\t\t\t\t *\/\n\t\t\t\t$allowed_tags = apply_filters( 'wp_nav_menu_container_allowedtags', array( 'div', 'nav' ) );\n\t\t\t\tif ( is_string( $args['container'] ) && in_array( $args['container'], $allowed_tags, true ) ) {\n\t\t\t\t\t$show_container   = true;\n\t\t\t\t\t$class            = $args['container_class'] ? ' class=\"menu-fallback-container ' . esc_attr( $args['container_class'] ) . '\"' : ' class=\"menu-fallback-container\"';\n\t\t\t\t\t$id               = $args['container_id'] ? ' id=\"' . esc_attr( $args['container_id'] ) . '\"' : '';\n\t\t\t\t\t$fallback_output .= '<' . $args['container'] . $id . $class . '>';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t\/\/ The fallback menu.\n\t\t\t$class            = $args['menu_class'] ? ' class=\"menu-fallback-menu ' . esc_attr( $args['menu_class'] ) . '\"' : ' class=\"menu-fallback-menu\"';\n\t\t\t$id               = $args['menu_id'] ? ' id=\"' . esc_attr( $args['menu_id'] ) . '\"' : '';\n\t\t\t$fallback_output .= '<ul' . $id . $class . '>';\n\t\t\t$fallback_output .= '<li class=\"nav-item\"><a href=\"' . esc_url( admin_url( 'nav-menus.php' ) ) . '\" class=\"nav-link\" title=\"' . esc_attr__( 'Add a menu', 'wp-bootstrap-navwalker' ) . '\">' . esc_html__( 'Add a menu', 'wp-bootstrap-navwalker' ) . '<\/a><\/li>';\n\t\t\t$fallback_output .= '<\/ul>';\n\n\t\t\t\/\/ Menu container closing tag.\n\t\t\tif ( $show_container ) {\n\t\t\t\t$fallback_output .= '<\/' . $args['container'] . '>';\n\t\t\t}\n\n\t\t\t\/\/ if $args has 'echo' key and it's true echo, otherwise return.\n\t\t\tif ( array_key_exists( 'echo', $args ) && $args['echo'] ) {\n\t\t\t\t\/\/ phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped\n\t\t\t\techo $fallback_output;\n\t\t\t} else {\n\t\t\t\treturn $fallback_output;\n\t\t\t}\n\t\t}\n\n\t\t\/**\n\t\t * Filter to ensure the items_Wrap argument contains microdata.\n\t\t *\n\t\t * @since 4.2.0\n\t\t *\n\t\t * @param  array $args The nav instance arguments.\n\t\t * @return array $args The altered nav instance arguments.\n\t\t *\/\n\t\tpublic function add_schema_to_navbar_ul( $args ) {\n\t\t\t$wrap = $args['items_wrap'];\n\t\t\tif ( strpos( $wrap, 'SiteNavigationElement' ) === false ) {\n\t\t\t\t$args['items_wrap'] = preg_replace( '\/(>).*>?\\%3\\$s\/', ' itemscope itemtype=\"http:\/\/www.schema.org\/SiteNavigationElement\"$0', $wrap );\n\t\t\t}\n\n\t\t\treturn $args;\n\t\t}\n\n\t\t\/**\n\t\t * Find any custom linkmod or icon classes and store in their holder\n\t\t * arrays then remove them from the main classes array.\n\t\t *\n\t\t * Supported linkmods: .disabled, .dropdown-header, .dropdown-divider, .sr-only\n\t\t * Supported iconsets: Font Awesome 4\/5, Glypicons\n\t\t *\n\t\t * NOTE: This accepts the linkmod and icon arrays by reference.\n\t\t *\n\t\t * @since 4.0.0\n\t\t *\n\t\t * @param array   $classes         an array of classes currently assigned to the item.\n\t\t * @param array   $linkmod_classes an array to hold linkmod classes.\n\t\t * @param array   $icon_classes    an array to hold icon classes.\n\t\t * @param integer $depth           an integer holding current depth level.\n\t\t *\n\t\t * @return array  $classes         a maybe modified array of classnames.\n\t\t *\/\n\t\tprivate function separate_linkmods_and_icons_from_classes( $classes, &$linkmod_classes, &$icon_classes, $depth ) {\n\t\t\t\/\/ Loop through $classes array to find linkmod or icon classes.\n\t\t\tforeach ( $classes as $key => $class ) {\n\t\t\t\t\/*\n\t\t\t\t * If any special classes are found, store the class in it's\n\t\t\t\t * holder array and and unset the item from $classes.\n\t\t\t\t *\/\n\t\t\t\tif ( preg_match( '\/^disabled|^sr-only\/i', $class ) ) {\n\t\t\t\t\t\/\/ Test for .disabled or .sr-only classes.\n\t\t\t\t\t$linkmod_classes[] = $class;\n\t\t\t\t\tunset( $classes[ $key ] );\n\t\t\t\t} elseif ( preg_match( '\/^dropdown-header|^dropdown-divider|^dropdown-item-text\/i', $class ) && $depth > 0 ) {\n\t\t\t\t\t\/*\n\t\t\t\t\t * Test for .dropdown-header or .dropdown-divider and a\n\t\t\t\t\t * depth greater than 0 - IE inside a dropdown.\n\t\t\t\t\t *\/\n\t\t\t\t\t$linkmod_classes[] = $class;\n\t\t\t\t\tunset( $classes[ $key ] );\n\t\t\t\t} elseif ( preg_match( '\/^fa-(\\S*)?|^fa(s|r|l|b)?(\\s?)?$\/i', $class ) ) {\n\t\t\t\t\t\/\/ Font Awesome.\n\t\t\t\t\t$icon_classes[] = $class;\n\t\t\t\t\tunset( $classes[ $key ] );\n\t\t\t\t} elseif ( preg_match( '\/^glyphicon-(\\S*)?|^glyphicon(\\s?)$\/i', $class ) ) {\n\t\t\t\t\t\/\/ Glyphicons.\n\t\t\t\t\t$icon_classes[] = $class;\n\t\t\t\t\tunset( $classes[ $key ] );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn $classes;\n\t\t}\n\n\t\t\/**\n\t\t * Return a string containing a linkmod type and update $atts array\n\t\t * accordingly depending on the decided.\n\t\t *\n\t\t * @since 4.0.0\n\t\t *\n\t\t * @param array $linkmod_classes array of any link modifier classes.\n\t\t *\n\t\t * @return string                empty for default, a linkmod type string otherwise.\n\t\t *\/\n\t\tprivate function get_linkmod_type( $linkmod_classes = array() ) {\n\t\t\t$linkmod_type = '';\n\t\t\t\/\/ Loop through array of linkmod classes to handle their $atts.\n\t\t\tif ( ! empty( $linkmod_classes ) ) {\n\t\t\t\tforeach ( $linkmod_classes as $link_class ) {\n\t\t\t\t\tif ( ! empty( $link_class ) ) {\n\n\t\t\t\t\t\t\/\/ Check for special class types and set a flag for them.\n\t\t\t\t\t\tif ( 'dropdown-header' === $link_class ) {\n\t\t\t\t\t\t\t$linkmod_type = 'dropdown-header';\n\t\t\t\t\t\t} elseif ( 'dropdown-divider' === $link_class ) {\n\t\t\t\t\t\t\t$linkmod_type = 'dropdown-divider';\n\t\t\t\t\t\t} elseif ( 'dropdown-item-text' === $link_class ) {\n\t\t\t\t\t\t\t$linkmod_type = 'dropdown-item-text';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn $linkmod_type;\n\t\t}\n\n\t\t\/**\n\t\t * Update the attributes of a nav item depending on the limkmod classes.\n\t\t *\n\t\t * @since 4.0.0\n\t\t *\n\t\t * @param array $atts            array of atts for the current link in nav item.\n\t\t * @param array $linkmod_classes an array of classes that modify link or nav item behaviors or displays.\n\t\t *\n\t\t * @return array                 maybe updated array of attributes for item.\n\t\t *\/\n\t\tprivate function update_atts_for_linkmod_type( $atts = array(), $linkmod_classes = array() ) {\n\t\t\tif ( ! empty( $linkmod_classes ) ) {\n\t\t\t\tforeach ( $linkmod_classes as $link_class ) {\n\t\t\t\t\tif ( ! empty( $link_class ) ) {\n\t\t\t\t\t\t\/*\n\t\t\t\t\t\t * Update $atts with a space and the extra classname\n\t\t\t\t\t\t * so long as it's not a sr-only class.\n\t\t\t\t\t\t *\/\n\t\t\t\t\t\tif ( 'sr-only' !== $link_class ) {\n\t\t\t\t\t\t\t$atts['class'] .= ' ' . esc_attr( $link_class );\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\/\/ Check for special class types we need additional handling for.\n\t\t\t\t\t\tif ( 'disabled' === $link_class ) {\n\t\t\t\t\t\t\t\/\/ Convert link to '#' and unset open targets.\n\t\t\t\t\t\t\t$atts['href'] = '#';\n\t\t\t\t\t\t\tunset( $atts['target'] );\n\t\t\t\t\t\t} elseif ( 'dropdown-header' === $link_class || 'dropdown-divider' === $link_class || 'dropdown-item-text' === $link_class ) {\n\t\t\t\t\t\t\t\/\/ Store a type flag and unset href and target.\n\t\t\t\t\t\t\tunset( $atts['href'] );\n\t\t\t\t\t\t\tunset( $atts['target'] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn $atts;\n\t\t}\n\n\t\t\/**\n\t\t * Wraps the passed text in a screen reader only class.\n\t\t *\n\t\t * @since 4.0.0\n\t\t *\n\t\t * @param string $text the string of text to be wrapped in a screen reader class.\n\t\t * @return string      the string wrapped in a span with the class.\n\t\t *\/\n\t\tprivate function wrap_for_screen_reader( $text = '' ) {\n\t\t\tif ( $text ) {\n\t\t\t\t$text = '<span class=\"sr-only\">' . $text . '<\/span>';\n\t\t\t}\n\t\t\treturn $text;\n\t\t}\n\n\t\t\/**\n\t\t * Returns the correct opening element and attributes for a linkmod.\n\t\t *\n\t\t * @since 4.0.0\n\t\t *\n\t\t * @param string $linkmod_type a sting containing a linkmod type flag.\n\t\t * @param string $attributes   a string of attributes to add to the element.\n\t\t *\n\t\t * @return string              a string with the openign tag for the element with attribibutes added.\n\t\t *\/\n\t\tprivate function linkmod_element_open( $linkmod_type, $attributes = '' ) {\n\t\t\t$output = '';\n\t\t\tif ( 'dropdown-item-text' === $linkmod_type ) {\n\t\t\t\t$output .= '<span class=\"dropdown-item-text\"' . $attributes . '>';\n\t\t\t} elseif ( 'dropdown-header' === $linkmod_type ) {\n\t\t\t\t\/*\n\t\t\t\t * For a header use a span with the .h6 class instead of a real\n\t\t\t\t * header tag so that it doesn't confuse screen readers.\n\t\t\t\t *\/\n\t\t\t\t$output .= '<span class=\"dropdown-header h6\"' . $attributes . '>';\n\t\t\t} elseif ( 'dropdown-divider' === $linkmod_type ) {\n\t\t\t\t\/\/ This is a divider.\n\t\t\t\t$output .= '<div class=\"dropdown-divider\"' . $attributes . '>';\n\t\t\t}\n\t\t\treturn $output;\n\t\t}\n\n\t\t\/**\n\t\t * Return the correct closing tag for the linkmod element.\n\t\t *\n\t\t * @since 4.0.0\n\t\t *\n\t\t * @param string $linkmod_type a string containing a special linkmod type.\n\t\t *\n\t\t * @return string              a string with the closing tag for this linkmod type.\n\t\t *\/\n\t\tprivate function linkmod_element_close( $linkmod_type ) {\n\t\t\t$output = '';\n\t\t\tif ( 'dropdown-header' === $linkmod_type || 'dropdown-item-text' === $linkmod_type ) {\n\t\t\t\t\/*\n\t\t\t\t * For a header use a span with the .h6 class instead of a real\n\t\t\t\t * header tag so that it doesn't confuse screen readers.\n\t\t\t\t *\/\n\t\t\t\t$output .= '<\/span>';\n\t\t\t} elseif ( 'dropdown-divider' === $linkmod_type ) {\n\t\t\t\t\/\/ This is a divider.\n\t\t\t\t$output .= '<\/div>';\n\t\t\t}\n\t\t\treturn $output;\n\t\t}\n\n\t\t\/**\n\t\t * Flattens a multidimensional array to a simple array.\n\t\t *\n\t\t * @param array $array a multidimensional array.\n\t\t *\n\t\t * @return array a simple array\n\t\t *\/\n\t\tpublic function flatten( $array ) {\n\t\t\t$result = array();\n\t\t\tforeach ( $array as $element ) {\n\t\t\t\tif ( is_array( $element ) ) {\n\t\t\t\t\tarray_push( $result, ...$this->flatten( $element ) );\n\t\t\t\t} else {\n\t\t\t\t\t$result[] = $element;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn $result;\n\t\t}\n\n\t}\n\nendif;<\/code><\/pre>\n\n\n\n

in resources\/functions.php we need to add “walker<\/strong>” to the array around line 60<\/p>\n\n\n\n

\/*\n * Sage required files\n *\n * The mapped array determines the code library included in your theme.\n * Add or remove files to the array as needed. Supports child theme overrides.\n *\/\narray_map(function ($file) use ($sage_error) {\n    $file = \"..\/app\/{$file}.php\";\n    if (!locate_template($file, true, true)) {\n        $sage_error(sprintf(__('Error locating <code>%s<\/code> for inclusion.', 'sage'), $file), 'File not found');\n    }\n}, ['helpers', 'setup', 'filters', 'admin', 'walker'<\/span><\/strong>]);<\/code><\/pre>\n\n\n\n

in resources\/views\/partials\/header.blade.php remove everything and use this code: <\/p>\n\n\n\n

<nav class=\"navbar navbar-expand-md navbar-light bg-light\" role=\"navigation\">\n  <div class=\"container\">\n    <!-- Brand and toggle get grouped for better mobile display -->\n    <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#bs-example-navbar-collapse-1\" aria-controls=\"bs-example-navbar-collapse-1\" aria-expanded=\"false\" aria-label=\"<?php esc_attr_e('Toggle navigation', 'your-theme-slug'); ?>\">\n        <span class=\"navbar-toggler-icon\"><\/span>\n    <\/button>\n   <a class=\"brand\" href=\"{{ home_url('\/') }}\">{{ get_bloginfo('name', 'display') }}<\/a>\n\n   @if (has_nav_menu('primary_navigation'))\n  {!! wp_nav_menu(['theme_location' => 'primary_navigation',\n    'depth'           => 2, \/\/ 1 = no dropdowns, 2 = with dropdowns.\n    'container'       => 'div',\n    'container_class' => 'collapse navbar-collapse',\n    'container_id'    => 'bs-example-navbar-collapse-1',\n    'menu_class'      => 'navbar-nav mr-auto',\n    'fallback_cb'     => 'WP_Bootstrap_Navwalker::fallback',\n    'walker'          => new WP_Bootstrap_Navwalker()]) !!}\n@endif\n    <\/div>\n<\/nav>\n<\/code><\/pre>\n\n\n\n

We will be making some style changes to the menu, so let’s make a new stylesheet to contain all of this. In resources\/assets\/styles\/main.scss <\/strong>at the very bottom of the file, add this extra import : <\/p>\n\n\n\n

@import \"components\/navbar\";<\/code><\/pre>\n\n\n\n

create a new file in : resources\/assets\/styles\/components\/ <\/strong>and name this new file : _navbar.scss<\/strong> for now just add this code: <\/p>\n\n\n\n

.brand {\n  margin-right: 2rem;\n  font-size: 1.2em;\n  text-decoration: none;\n  color:black;\n}\n\n<\/code><\/pre>\n\n\n\n

Save everything and we should now have a menu that looks like this : <\/p>\n\n\n\n

\"Our<\/figure><\/div>\n\n\n\n

It functions great on all screens, has a hamburger menu, tabs correctly “enter” opens dropdowns, and is accessible friendly. We also have a .scss style sheet to make display changes in and make it look a little nicer in our next installment!<\/p>\n\n\n\n

<\/p>\n","protected":false},"excerpt":{"rendered":"

You should have added all the test data to the theme in the last step, to begin working on our menu go to “Appearance > Menu” and choose the testing menu from the drop-down : Then, set this as your primary navigation : Now, visit your main page to see the visually stunning result, which […]<\/p>\n","protected":false},"author":1,"featured_media":2762,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_seopress_robots_primary_cat":"none","_seopress_titles_title":"","_seopress_titles_desc":"","_seopress_robots_index":"","_uag_custom_page_level_css":"","footnotes":""},"categories":[136,146],"tags":[160,159,161,158,149],"uagb_featured_image_src":{"full":["https:\/\/thewpgeek.com\/wp-content\/uploads\/2021\/06\/code-820275_1920.jpg",1920,1280,false],"thumbnail":["https:\/\/thewpgeek.com\/wp-content\/uploads\/2021\/06\/code-820275_1920-150x150.jpg",150,150,true],"medium":["https:\/\/thewpgeek.com\/wp-content\/uploads\/2021\/06\/code-820275_1920-300x200.jpg",300,200,true],"medium_large":["https:\/\/thewpgeek.com\/wp-content\/uploads\/2021\/06\/code-820275_1920-768x512.jpg",768,512,true],"large":["https:\/\/thewpgeek.com\/wp-content\/uploads\/2021\/06\/code-820275_1920-1024x683.jpg",1024,683,true],"1536x1536":["https:\/\/thewpgeek.com\/wp-content\/uploads\/2021\/06\/code-820275_1920-1536x1024.jpg",1536,1024,true],"2048x2048":["https:\/\/thewpgeek.com\/wp-content\/uploads\/2021\/06\/code-820275_1920.jpg",1920,1280,false],"rigtest-featured":["https:\/\/thewpgeek.com\/wp-content\/uploads\/2021\/06\/code-820275_1920-720x480.jpg",720,480,true],"mailpoet_newsletter_max":["https:\/\/thewpgeek.com\/wp-content\/uploads\/2021\/06\/code-820275_1920.jpg",1320,880,false]},"uagb_author_info":{"display_name":"wpgeek","author_link":"https:\/\/thewpgeek.com\/author\/wpgeek\/"},"uagb_comment_info":12,"uagb_excerpt":"You should have added all the test data to the theme in the last step, to begin working on our menu go to “Appearance > Menu” and choose the testing menu from the drop-down : Then, set this as your primary navigation : Now, visit your main page to see the visually stunning result, which…","_links":{"self":[{"href":"https:\/\/thewpgeek.com\/wp-json\/wp\/v2\/posts\/2769"}],"collection":[{"href":"https:\/\/thewpgeek.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thewpgeek.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thewpgeek.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/thewpgeek.com\/wp-json\/wp\/v2\/comments?post=2769"}],"version-history":[{"count":8,"href":"https:\/\/thewpgeek.com\/wp-json\/wp\/v2\/posts\/2769\/revisions"}],"predecessor-version":[{"id":2803,"href":"https:\/\/thewpgeek.com\/wp-json\/wp\/v2\/posts\/2769\/revisions\/2803"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/thewpgeek.com\/wp-json\/wp\/v2\/media\/2762"}],"wp:attachment":[{"href":"https:\/\/thewpgeek.com\/wp-json\/wp\/v2\/media?parent=2769"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thewpgeek.com\/wp-json\/wp\/v2\/categories?post=2769"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thewpgeek.com\/wp-json\/wp\/v2\/tags?post=2769"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}