Register menu locations
Register each menu with a location
(like a unique slug) and a description
. The description will be shown on Wp-Admin > Appearance > Menus > Manage Locations.
register_nav_menus(
array(
// 'location' => 'description',
'main_menu' => 'Main menu',
'sub_menu1' => 'Sub menu 1 (top left)',
'sub_menu2' => 'Sub menu 2 (top right)',
'sub_menu3' => 'Sub menu 3 (bottom left)',
'sub_menu4' => 'Sub menu 4 (bottom right)',
)
);
Display the menu in a theme
WordPress documentation: wp_nav_menu()
menu
can be the menu ID, slug, name, or object.
Display menu using the theme_location
from the above setup. That way the theme will not rely on a specific name of a menu existing, but it does rely on a menu being set for that location.
menu_class
is the css class that will be added to the ul
of the menu output. It can be more than one class, e.g. 'sub-menu position-2'
Setting container
to false
will remove the container element (default is a div
) that normally contains the ul
.
<?php
wp_nav_menu(
array(
'theme_location' => 'main_menu',
'menu_class' => 'main-menu',
'items_wrap' => '<ul class="%2$s">%3$s</ul>', // remove the id on the ul element
'container' => false
)
);
?>
Display a menu using a name (relies on this name being added through the WordPress admin).
<?php
wp_nav_menu(
array(
'menu' => 'Menu 1',
)
);
?>
Menu style
Assuming we use the menu class .main-menu
as per above, we can style the menu like so. This assumes a custom breakpoint has been added in Tailwind called menu
. See Tailwind Breakpoints
/*--------------------------------------------------------------
# Main Menu
--------------------------------------------------------------*/
.main-menu {
@apply hidden menu:flex space-x-12;
}
.main-menu > li > a {
@apply text-base md:text-xl transition-opacity duration-300 hover:opacity-70;
.dark-header & {
@apply text-white;
}
}
Sub Menu
If the menu has a second level sub-menu use the following css. This assumes a custom breakpoint has been added in Tailwind called menu
. See Tailwind Breakpoints
/*--------------------------------------------------------------
# Sub-menu
--------------------------------------------------------------*/
/* Desktop menu */
@media screen(menu) {
.sub-menu {
@apply absolute hidden opacity-0 w-max;
}
.main-menu li:hover > .sub-menu,
.main-menu li:focus-within > .sub-menu {
@apply visible block opacity-100;
}
.sub-menu > li > a {
@apply block px-2 font-semibold leading-10 tracking-wider uppercase transition-opacity duration-300 md:text-sm md:leading-10;
}
}
/* Mobile menu overlay */
.mobile-menu {
.sub-menu {
@apply pl-5;
}
a {
@apply block py-1 leading-10 tracking-wider;
}
.current_page_item {
@apply underline underline-offset-8;
}
}
Credit: Based on https://css-tricks.com/solved-with-css-dropdown-menus/
Overlay modal menu
Micromodal.js is a lightweight, configurable and a11y-enabled modal library written in pure JavaScript.
Save micromodal.min.js to /js
folder.
Enqueue in functions.php
.
wp_enqueue_script( 'projectX-micromodal', get_stylesheet_directory_uri() . '/js/micromodal.min.js' );
Add html to footer.php
. The micromodal code also changes the aria-expanded
attribute to the current state. Note the svg in the close button has the class pointer-events-none
to endure the entire button is clickable.
<!-- Modal Mobile Menu -->
<div id="menu-modal" aria-hidden="true">
<div
aria-label="menu"
aria-modal="true"
class="h-screen p-5 overflow-auto bg-white modal-overlay"
role="dialog"
tabindex="-1"
>
<header class="flex justify-between">
<a
href="<?php echo esc_url( home_url( '/' ) ); ?>"
rel="home"
title="Return to the homepage"
>
Logo
</a>
<button aria-label="Close modal" data-micromodal-close class="p-4">
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M249-193.434 193.434-249l231-231-231-231L249-766.566l231 231 231-231L766.566-711l-231 231 231 231L711-193.434l-231-231-231 231Z" class="fill-white pointer-events-none"/></svg>
</button>
</header>
<div id="menu-modal-content">
Menu items
</div>
</div>
</div>
<script>
MicroModal.init({
disableScroll: true,
awaitCloseAnimation: true,
onShow: modal => {
document.getElementById("hamburger").setAttribute('aria-expanded', true);
},
onClose: modal => {
document.getElementById("hamburger").setAttribute('aria-expanded', false);
}
});
</script>
Add the attribute to the hamburger button. menu-modal
below must match the id of the main <div>
above.
<button data-micromodal-trigger="menu-modal"></button>
Full hamburger html example. This assumes the custom Tailwind breakpoint menu
has been added to the Tailwind config. See Tailwind Breakpoints
<nav class="main-navigation" aria-labelledby="hamburger">
<button
id="hamburger"
class="leading-none rounded hamburger focus:outline-none focus-visible:ring-2 focus-visible:ring-black focus-visible:ring-offset-4 menu:hidden"
aria-controls="menu-modal"
aria-expanded="false"
aria-label="navigation menu"
data-micromodal-trigger="menu-modal"
>
<svg xmlns="http://www.w3.org/2000/svg" width="41" height="30" class="menu-desktop"><g fill="#ffffff"><path d="M7 0h34v6H7z"/><path d="M0 12h41v6H0z"/><path d="M12 24h29v6H12z"/></g></svg>
</button>
</nav>
Add the css for the modal.
/*--------------------------------------------------------------
# Menu Modal
--------------------------------------------------------------*/
#menu-modal.is-open {
z-index: 99999; /* This is the minimum to be above admin bar */
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
@keyframes mmfadeIn {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
@keyframes mmfadeOut {
from { opacity: 1; transform: scale(1); }
to { opacity: 0; transform: scale(0.95); }
}
#menu-modal {
display: none;
}
#menu-modal.is-open {
display: block;
}
#menu-modal[aria-hidden="false"] .modal-overlay {
animation: mmfadeIn .3s cubic-bezier(0.0, 0.0, 0.2, 1);
}
#menu-modal[aria-hidden="true"] .modal-overlay {
animation: mmfadeOut .3s cubic-bezier(0.0, 0.0, 0.2, 1);
}