Reputation: 63
I'm having difficulty implementing a dropdown menu with Bootstrap and WordPress. I've used filters to add the 'dropdown-toggle-split' class to the link elements of menu items that have submenus. However, after configuring this, the dropdown menu doesn't behave as expected. When I click the first dropdown toggle menu item, all submenus appear, instead of only the submenus of the related menu item. Maybe you can look at this gif:
Explanation:
WordPress Filter Usage: I'm using the nav_menu_link_attributes and nav_menu_item_title filters to modify the attributes and content of link elements on menu items that have submenus. My goal is to add the dropdown-toggle-split class to the link elements and change the HTML structure of these menu elements to fit Bootstrap's requirements. Here is the code:
add_filter( 'nav_menu_link_attributes', function( $atts, $item, $args, $depth ) {
// Cek jika menu item memiliki submenu
if ( in_array( 'menu-item-has-children', $item->classes ) ) {
$args->before = '<div class="btn-group" style="flex-direction: row-reverse;">';
// $args->before .= '<a href="'.$item->url.'" class="nav-link">'.$item->title.'</a>';
$atts['class'] .= ' dropdown-toggle dropdown-toggle-split';
// Tambahkan data-toggle dan aria-haspopup ke atribut
$atts['data-toggle'] = 'dropdown';
$atts['aria-haspopup'] = 'true';
}
// Kembalikan array $atts yang telah dimodifikasi
return $atts;
}, 10, 4 );
add_filter( 'nav_menu_item_title', function( $title, $item, $args, $depth ) {
// Cek jika menu item memiliki submenu
if ( in_array( 'menu-item-has-children', $item->classes ) ) {
// Bungkus judul dengan elemen <span> yang memiliki class visually-hidden
$title = '<span class="visually-hidden">' . esc_html__( 'Toggle Dropdown', 'your-text-domain' ) . '</span>';
// Tambahkan elemen <a> untuk tautan menu
$title .= '<a href="' . esc_url( $item->url ) . '" class="nav-link">' . esc_html( $item->title ) . '</a>';
// Tambahkan div penutup untuk btn-group
$args->after = '</div>';
}
// Kembalikan judul yang telah dimodifikasi
return $title;
}, 10, 4 );
Because of this code, I get duplicate 'ul dropdown-menu show' with same aria-labelledby="menu-item-dropdown-179".
here is the html elements:
<li id="menu-item-179" class="menu-item menu-item-type-post_type menu-item-object-page current-menu-item page_item page-item-2 current_page_item menu-item-has-children dropdown active menu-item-179 nav-item">
<div class="btn-group" style="flex-direction: row-reverse;">
<a href="#" data-toggle="dropdown" aria-expanded="false" class="dropdown-toggle nav-link dropdown-toggle dropdown-toggle-split" id="menu-item-dropdown-179" aria-current="page" aria-haspopup="true">
<span itemprop="name"><span class="visually-hidden">Toggle Dropdown</span></span>
</a>
<a href="http://localhost/wc_course/sample-page/" class="nav-link">Sample Page</a>
</div>
<ul class="dropdown-menu show" aria-labelledby="menu-item-dropdown-179">
<li id="menu-item-187" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children dropdown menu-item-187 nav-item">
<div class="btn-group" style="flex-direction: row-reverse;">
<a itemprop="url" href="http://localhost/wc_course/sample-page-2/" class="dropdown-item dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true">
<span itemprop="name"><span class="visually-hidden">Toggle Dropdown</span></span>
</a>
<a href="http://localhost/wc_course/sample-page-2/" class="nav-link">Sample Page 2</a>
</div>
<ul class="dropdown-menu show" aria-labelledby="menu-item-dropdown-179">
<li id="menu-item-188" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-188 nav-item">
<div class="btn-group" style="flex-direction: row-reverse;">
<a itemprop="url" href="http://localhost/wc_course/winter-warm-up-sale/" class="dropdown-item"><span itemprop="name">Winter Warm-up Sale</span></a>
</div>
</li>
</ul>
</li>
</ul>
</li>
And this is my javascript file:
import $ from 'jquery';
class scriptNavbar {
constructor() {
this.events();
}
events() {
$(document).ready(() => {
$('.main-menu .dropdown-toggle').on('click', function (e) {
e.preventDefault();
// Close other dropdown-menus within the same level
$(this).closest('.menu-item-has-children').siblings('.menu-item-has-children').find('.dropdown-menu').removeClass('show');
// Toggle class for the clicked dropdown-menu
$(this).closest('.menu-item-has-children').find('.dropdown-menu').toggleClass('show');
});
// Close dropdown-menus when clicking outside of them
$(document).on('click', function (e) {
if (!$(e.target).closest('.main-menu .dropdown').length) {
$('.main-menu .dropdown .dropdown-menu').removeClass('show');
}
});
// Prevent closing the dropdown-menu when clicking inside it
$('.main-menu .dropdown-menu').on('click', function (e) {
e.stopPropagation();
});
});
}
}
export default scriptNavbar;
I suspect the issue stems from the duplicate 'dropdown-menu show' elements, but I'm unable to find a solution since WordPress Bootstrap NavWalker automatically generates these elements with incremental numbers. Any assistance in resolving this would be greatly appreciated. Thank you in advance for your help!
I expected that upon clicking the dropdown toggle menu item, only the submenus associated with that specific menu item would appear. In other words, I anticipated that the dropdown functionality would behave as expected, displaying the relevant submenus in response to user interaction. However, despite implementing the modifications, the dropdown menu displayed all submenus simultaneously, regardless of which dropdown toggle menu item was clicked.
Upvotes: 1
Views: 57
Reputation: 545
i try to replicate something similar to your code
$(document).ready(() => {
$('.main-menu .dropdown-toggle').on('click', function (e) {
e.preventDefault();
//#######################################################################
//##i cannot check this because your html does not have enough elements##
//#######################################################################
// Close other dropdown-menus within the same level
$(this).closest('.menu-item-has-children').
siblings('.menu-item-has-children').
find('.dropdown-menu').removeClass('show');
//######################################################################
//if you want to use $.toggle() you need to remember that toggle() and toggleClass()
// are not the same function:
// $.toggle() use css style
//$.toggleClass() add / remove class
// so if you use $.toggle() you need to check css display and "reset" content on "display=none"
//=========================================================================================
var heroBros=$(this).closest('.menu-item-has-children').find('.dropdown-menu');
var hero=heroBros.first();
// Toggle class for the clicked dropdown-menu
hero.toggle('show',function(){
//hide child when hide main=======================
if($(this).css("display")=='none')heroBros.hide();
//================================================
});
});
// Close dropdown-menus when clicking outside of them
$(document).on('click', function (e) {
/*
if (!$(e.target).closest('.main-menu .dropdown').length) {
$('.main-menu .dropdown .dropdown-menu').removeClass('show');
}
*/
});
// Prevent closing the dropdown-menu when clicking inside it
$('.main-menu .dropdown-menu').on('click', function (e) {
e.stopPropagation();
});
});
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<ul class="main-menu">
<li id="menu-item-179" class="menu-item menu-item-type-post_type menu-item-object-page current-menu-item page_item page-item-2 current_page_item menu-item-has-children dropdown active menu-item-179 nav-item">
<div class="btn-group" style="flex-direction: row-reverse;">
<a href="#" data-toggle="dropdown" aria-expanded="false" class="dropdown-toggle nav-link dropdown-toggle dropdown-toggle-split" id="menu-item-dropdown-179" aria-current="page" aria-haspopup="true">
<span itemprop="name"><span class="visually-hidden">Toggle Dropdown</span></span>
</a>
<a href="#" class="nav-link">Sample Page</a>
</div>
<ul class="dropdown-menu " aria-labelledby="menu-item-dropdown-179">
<li id="menu-item-187" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children dropdown menu-item-187 nav-item">
<div class="btn-group" style="flex-direction: row-reverse;">
<a itemprop="url" href="#" class="dropdown-item dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true">
<span itemprop="name"><span class="visually-hidden">Toggle Dropdown</span></span>
</a>
<a href="#" class="nav-link">Sample Page 2</a>
</div>
<ul class="dropdown-menu" aria-labelledby="menu-item-dropdown-188">
<li id="menu-item-188" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-188 nav-item">
<div class="btn-group" style="flex-direction: row-reverse;">
<a itemprop="url" href="" class="dropdown-item"><span itemprop="name">Winter Warm-up Sale</span></a>
</div>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
Upvotes: 2