Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save prayas-sapkota/8e78f9e43a806dc7d8d06a42f4afa768 to your computer and use it in GitHub Desktop.
Save prayas-sapkota/8e78f9e43a806dc7d8d06a42f4afa768 to your computer and use it in GitHub Desktop.
Allow adding custom classes to WordPress menu ul, li, a and at different depths. Perfect for TailwindCSS and AlpineJS usage.
<?php
/**
* WordPress filters to allow custom arguments to wp_nav_menu to,
* in turn, allow custom classes to every element of a menu.
*
* You can apply a class only to certain depth of your menu as well.
*
* The filters use the depth argument given by WordPress
* which is an index, thus starts with level 0 (zero).
*
* Custom Arguments supported :
* link_atts or link_atts_$depth -> Add any attribute to <a> elements
* a_class or a_class_$depth -> Add classes to <a> elements
* li_class or li_class_$depth -> Add classes to <li> elements
* submenu_class or submenu_class_$depth -> Add classes to submenu <ul> elements
*
* Ex.: add a "text-black" class to all links and "text-blue" class only to 3rd level links
* wp_nav_menu([
* 'theme_location' => 'primary_navigation',
* 'a_class' => 'text-black',
* 'a_class_2'
* ...
* ])
*
* Ex.: More complete example with some TailwindCSS classes and AlpineJS sugar
* wp_nav_menu([
* 'theme_location' => 'primary_navigation',
* 'menu_class' => 'relative w-full z-10 pl-0 list-none flex',
* 'link_atts_0' => [
* ":class" => "{ 'active': tab === 'foo' }",
* "@click" => "tab = 'foo'"
* ],
* 'li_class' => 'w-full',
* 'li_class_0' => 'mb-12',
* 'a_class' => 'text-sm xl:text-xl text-white border-b hover:border-white',
* 'a_class_0' => 'text-3xl xl:text-5xl relative dash-left js-stagger a-mask after:bg-primary',
* 'li_class_1' => 'js-stagger a-mask after:bg-primary hidden lg:block',
* 'a_class_1' => 'flex h-full items-center uppercase py-2 relative border-white border-opacity-40 hover:border-opacity-100',
* 'submenu_class' => 'list-none pl-0 grid grid-cols-1 lg:grid-cols-2 lg:gap-x-12 xl:gap-x-24 xxl:gap-x-32',
* 'container'=>false
* ])
*
* @author davidwebca
* @link https://gist.github.com/davidwebca/a7b278bbb0c0ce1d1ec5620126e863bb
*/
/**
* Add custom attributes or classes to links in wp_nav_menu
*/
add_filter( 'nav_menu_link_attributes', function ( $atts, $item, $args, $depth ) {
if (property_exists($args, 'link_atts')) {
$atts = array_merge($atts, $args->link_atts);
}
if (property_exists($args, "link_atts_$depth")) {
$atts = array_merge($atts, $args->{"link_atts_$depth"});
}
if(empty($atts['class'])) {
$atts['class'] = '';
}
$classes = explode(' ', $atts['class']);
/**
* Fix for tailwindcss classes that include ":" (colon)
* Enter triple underscore hover___text-primary instaed of hover:text-primary
*
* Some filters provided so that you can customize your own replacements,
* passed directly to preg_replace so supports array replacements as well.
*
* WordPress trac following the issue of escaping CSS classes:
* @link https://core.trac.wordpress.org/ticket/33924
*/
$patterns = apply_filters( 'nav_menu_css_class_unescape_patterns', '/___/');
$replacements = apply_filters( 'nav_menu_css_class_unescape_replacements', ':' );
$classes = array_map(function($cssclass) use( $patterns, $replacements) {
return preg_replace($patterns, $replacements, $cssclass);
}, $classes);
if (property_exists($args, 'a_class')) {
$arr_classes = explode(' ', $args->a_class);
$classes = array_merge($classes, $arr_classes);
}
if (property_exists($args, "a_class_$depth")) {
$arr_classes = explode(' ', $args->{"a_class_$depth"});
$classes = array_merge($classes, $arr_classes);
}
$atts['class'] = implode(' ', $classes);
return $atts;
}, 1, 4 );
/**
* Add custom classes to lis in wp_nav_menu
*/
add_filter( 'nav_menu_css_class', function ( $classes, $item, $args, $depth ) {
if (property_exists($args, 'li_class')) {
$arr_classes = explode(' ', $args->li_class);
$classes = array_merge($classes, $arr_classes);
}
if (property_exists($args, "li_class_$depth")) {
$arr_classes = explode(' ', $args->{"li_class_$depth"});
$classes = array_merge($classes, $arr_classes);
}
return $classes;
}, 1, 4 );
/**
* Add custom classes to ul.sub-menu in wp_nav_menu
*/
add_filter('nav_menu_submenu_css_class', function( $classes, $args, $depth ) {
if (property_exists($args, 'submenu_class')) {
$arr_classes = explode(' ', $args->submenu_class);
$classes = array_merge($classes, $arr_classes);
}
if (property_exists($args, "submenu_class_$depth")) {
$arr_classes = explode(' ', $args->{"submenu_class_$depth"});
$classes = array_merge($classes, $arr_classes);
}
return $classes;
}, 1, 3);
/**
* Apply our new custom attributes to widgetized wp_nav_menus
*/
add_filter('widget_nav_menu_args', function($nav_menu_args, $nav_menu, $args, $instance) {
// if($args['id'] == 'sidebar-footer') {
// $nav_menu_args['menu_class'] = 'mt-5 font-alt text-sm font-normal leading-7 opacity-60';
// $nav_menu_args['a_class'] = 'text-gray-300 opacity-60 hover:opacity-100';
// }
return $nav_menu_args;
}, 10, 4);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment