1

How do I mix HTML element types for a two-menu navbar?

I am building a WordPress theme with Bootstrap 4.

WordPress' menu contents should be sourced from the Menus options, output in to a Bootstrap 4 navbar. I am using this Bootstrap 4-specific wp_nav_menu navwalker ...

require_once get_template_directory() . '/inc/bs4navwalker.php';

... to output the primary menu of nav text links as an unordered list, just as God intended...

 <!-- Navbar https://getbootstrap.com/docs/4.1/components/navbar/ -->
 <nav class="navbar navbar-expand-md navbar-light"><!-- collapse at stated breakpoint -->
     <a class="navbar-brand" href="<?php echo esc_url( home_url( '/' ) ); ?>">
       <img src="https://www.example.com/logo.gif" height="30" class="d-inline-block align-top mr-1">
       <?php bloginfo( 'name' ); ?>
     </a>
     <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#bs4navbar" aria-controls="bs4navbar" aria-expanded="false" aria-label="Toggle navigation">
       <span class="navbar-toggler-icon"></span>
     </button>
     <?php
     wp_nav_menu([ // bs4navwalker menu generator
       'menu'            => 'primary', // name of wordpress menu
       'theme_location'  => 'primary',
       'depth'           => 2,
       // <nav>:
       // 'container'       => 'false',
       'container_id'    => 'bs4navbar',
       'container_class' => 'collapse navbar-collapse',
       // <ul>:
       'menu_id'         => false,
       'menu_class'      => 'navbar-nav ml-auto',
       // other:
       'fallback_cb'     => 'bs4navwalker::fallback',
       'walker'          => new bs4navwalker()
     ]);
     ?>
     <button class="btn btn-outline-primary mx-3" type="submit">Button</button>
     <button class="btn btn-primary ml-3" type="submit">Sign up</button>
 </nav>

That works fine. Output is...

enter image description here

<nav class="navbar navbar-expand-md navbar-light"><!-- collapse at stated breakpoint -->
     <a class="navbar-brand" href="http://www.example.com/">
       <img src="https://www.example.com/logo.gif" height="30" class="d-inline-block align-top mr-1">
              Sandbox     </a>
     <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#bs4navbar" aria-controls="bs4navbar" aria-expanded="false" aria-label="Toggle navigation">
       <span class="navbar-toggler-icon"></span>
     </button>
     <div id="bs4navbar" class="collapse navbar-collapse">
       <ul id="menu-my-menu" class="navbar-nav ml-auto">
         <li id="menu-item-3" class="menu-item menu-item-type-custom menu-item-object-custom current-menu-item current_page_item menu-item-home menu-item-3 nav-item mx-3 active"><a title="Home Page" href="http://sandbox.contexthq.com/" class="nav-link active" aria-expanded="false"><i class="icon-speedometer"></i>Home</a></li>
         <li id="menu-item-4" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-4 nav-item mx-3"><a title="Example Page" href="http://example.com/" class="nav-link" aria-expanded="false"><i class="ti-layout-grid2"></i>Trends</a></li>
         <li id="menu-item-5" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-5 nav-item mx-3"><a title="Custom Page" href="http://example.com/custom/" class="nav-link" aria-expanded="false"><i class="ti-palette"></i>Custom</a></li>
         <li id="menu-item-14" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-14 nav-item mx-3"><a href="#" class="nav-link" aria-expanded="false">Strategy</a></li>
       </ul>
     </div>
     <button class="btn btn-outline-primary mx-3" type="submit">Button</button>
     <button class="btn btn-primary ml-3" type="submit">Sign up</button>
 </nav>

However, you'll see the portion in which I have manually inserted two <button> elements. Instead of hard-coding, I want these to be dynamically generated from a WordPress menu, just like the primary menu.

I have made a second WordPress menu, buttons. This is where I am breaking down...

I can insert a second wp_nav_menu call for buttons, right after the first one for primary...

 <?php
 wp_nav_menu([ // bs4navwalker menu generator
   'menu'            => 'buttons', // name of wordpress menu
   'theme_location'  => 'buttons',
   'depth'           => 2,
   // <nav>:
   // 'container'       => 'false',
   'container_id'    => 'bs4navbar',
   'container_class' => 'collapse navbar-collapse',
   // <ul>:
   'menu_id'         => false,
   'menu_class'      => 'navbar-nav ml-auto',
   // other:
   'fallback_cb'     => 'bs4navwalker::fallback',
   'walker'          => new bs4navwalker()
 ]);
 ?>

... and the menu items will get inserted in the right place.

The problem is, those items are <li>s inside a <ul>, just like the primary menu...

enter image description here

I assume bs4navwalker is set up to output all wp_nav_menu items as list items, or maybe that's WordPress' doing.

How can I see to it that the items from the second menu, buttons, get output using different HTML construction, as <button> elements instead?

  • What are these buttons supposed to do? The whole WordPress menu system is for adding links, but <button> elements are inappropriate for links, so there isn't really anything you could add to a menu that would make sense for a button element. – Jacob Peattie Aug 20 '18 at 12:20
  • Yes, I'm trying to bend WordPress to do something which is acceptable in modern UI terms but which it does not instinctively support. – Robert Andrews Aug 20 '18 at 13:13
  • Using button elements for links is not acceptable in 'modern UI' terms, which is why I asked what you want to use them for. If you are only using a <button> element for styling reasons then you're doing this all wrong. – Jacob Peattie Aug 20 '18 at 14:22
0

The following is a solution, though uses extra PHP processing...

 <?php

 $options =  array(
     'echo'              => false,
     'theme_location'    => 'buttons',
     'items_wrap'        => '%3$s',
     'menu_class'        => false,
     'menu_id'           => false,
     'container'         => 'false',
     'container_class'   => false,
     'container_id'      => false,
     'before'            => '<button class="btn btn-primary mx-3 d-none d-md-block" type="submit">',
     'after'             => '</button>'
 );

 $menu = wp_nav_menu($options);

 $output = strip_tags($menu, '<button>');

 echo preg_replace('/btn-primary/', 'btn-outline-primary', $output, 1);

 ?>

This involves:

  • Removing <ul>
  • Not setting any containers
  • Wrapping each item in a <button> tag
  • Suppressing echo
  • Stripping all tags (ie. <li>) except <button>)
  • In the last part, replacing the first instance of the btn-primary class with btn-outline-primary, in order to retain buttons of two colours.

Here is the output...

enter image description here

<button class="btn btn-outline-primary mx-3 d-none d-md-block" type="submit">Button</button>
<button class="btn btn-primary mx-3 d-none d-md-block" type="submit">Learn More</button>

I would have preferred to set the button colour classes using WordPress' own functionality for setting Menu item classes, rather than hard-code them here.

Is there a way to get those classes appearing in the nav item, instead of using preg_replace, or would this method not support it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.