#about and #services are sections on home page. Because #about and #services URLs are pointing to the home page, wordpress adds .current-menu-item class to all 3 above URLs at the same time.
I was wondering how can I have that class added only when home or about or services is clicked? I use .current-menu-item class to style currently active menu item.
I tried the following solution but it didnât work
The problem is that since all your menu links point to the same URL (/ with different #fragment identifiers), WordPress sees them all as the same page and adds .current-menu-item to all of them. PHP canât really help here â it never sees the #about or #services parts, so this is a front-end problem.
Hereâs a small JavaScript snippet that will highlight only the item you click:
Try this on your site and let me know if it comes close to what you want. It wonât persist after reload or navigation, but it may be enough depending on what youâre after.
Also, is the page live anywhere? If so, itâs be great if you could post a link (or DM it to me).
http://test.prygara.com/
Iâve added the JS script that you suggested. It only appears to be working when you are on a home page and click âaboutâ or âservicesâ. In all other scenarios - all 3 menu items on home page are still highlighted (underlined). You can try click through menu items back and forth and see how it behaves.
:target can style the section itself, but it canât affect the menu item that links to it. So unfortunately it wonât help here for controlling .current-menu-item in the navigation.
Iâve adjusted the JavaScript to handle the fragment (#about, #services) on page load. It reads the URL and sets the correct menu item active based on that, removing the highlight from the others.
document.addEventListener("DOMContentLoaded", () => {
if (window.location.pathname === "/") {
const menuItems = document.querySelectorAll(".menu-item");
const currentHash = window.location.hash;
// Clean up all current-menu-item classes first
menuItems.forEach(item => item.classList.remove("current-menu-item"));
if (currentHash) {
// Look for a menu link that matches the hash
const match = document.querySelector(`.menu-item a[href$="${currentHash}"]`);
if (match) {
match.parentElement.classList.add("current-menu-item");
}
} else {
// No hash â assume it's the Home link (href="/")
const homeLink = document.querySelector('.menu-item a[href="/"]');
if (homeLink) {
homeLink.parentElement.classList.add("current-menu-item");
}
}
// Handle clicks
document.querySelectorAll(".menu-item a").forEach(link => {
link.addEventListener("click", () => {
menuItems.forEach(item => item.classList.remove("current-menu-item"));
link.parentElement.classList.add("current-menu-item");
});
});
}
});
squints
If you added the menu-item-# class to the sections, it could work for services and about? (Would still have to work something for the null case⌠eh.)
(Yeah, its a bit fragile, but it would work without javascriptâŚ)
Side note: Should probably use the empty fragment instead of no-fragment for the Home link, if youâre going to use fragment navigation like that. Saves a reload of the page when clicking home from services/about.
EDIT: I suppose the null case could be .page:not(:has(:target)) .menu-item-60 ? (No Marc, that doesnt work for the other pages⌠try again) .page:not(:has(:target)) .current_page_item.menu-item-60
Ah, I see what youâre going for now. If you add .menu-item-### classes to the corresponding sections, your :has(:target) selectors can map the active section back to the nav item without JavaScript.
Your revised fallback using .page:not(:has(:target)) .current_page_item.menu-item-60 is a better call â relying on WordPress to flag the actual page does help avoid highlighting Home on unrelated pages like /gallery.
The main drawback for me is that itâs tightly coupled to specific menu item IDs and assumes a strict structure â meaning your CSS selectors depend on exact .menu-item-### classes, and youâd need to manually mirror those classes on the corresponding sections.
yeah, thats what i meant by it being âfragileâ⌠if the menu items change (I assume Wordpress generates the IDs once, but maybe it ârefreshesâ at certain triggers? I dont know.) then the house of cards comes tumbling down unless you can specify a class to always be put on each individual element. Wordpress tries to do this with the â.menu-item-(pagename)â class, but it doesnt do it uniquely for the other anchors on the page, sadly.
Makes sense â and yes, the menu item IDs are persistent unless you delete/recreate them, but thereâs always that lingering possibility that someone edits the menu later without realizing what the CSS depends on.
Itâs a shame WordPress doesnât auto-generate semantic classes like .menu-item-about for custom anchor links. If that were possible, the whole approach would be much cleaner and easier to maintain.
Although, that said, something like this might work (untested):
It appears the following portion of the script is not working. When âhomeâ is clicked current-menu-item class is not added to that menu item. Rest of menu items work as expected.
else {
// No hash â assume it's the Home link (href="/")
const homeLink = document.querySelector('.menu-item a[href="/"]');
if (homeLink) {
homeLink.parentElement.classList.add("current-menu-item");
}
Iâve updated the test site link. Please take a look once you get a chance.
This filter also works but I am not sure how to target âhomeâ menu item when it is clicked so it gets highlighted. Basically each menu item should get highlighted separately on click.
It seems that when youâre already on the homepage (including if youâre at #about or #services) and you click âHome,â the browser reloads the page. That wipes out the highlight that JavaScript had just set.
And when youâre coming from another page, like Gallery or Contact, then the reload is legit. But JavaScript kicks in and clears the highlighting and then nothing gets re-highlighted, because thereâs no fragment.
Try updating the JavaScript like this:
document.addEventListener("DOMContentLoaded", () => {
const menuItems = document.querySelectorAll(".menu-item");
const menuLinks = document.querySelectorAll(".menu-item a");
const currentHash = window.location.hash;
const currentPath = window.location.pathname;
// Clean up all current-menu-item classes first
menuItems.forEach(item => item.classList.remove("current-menu-item"));
// Highlight based on hash or fallback to Home
if (currentHash) {
const match = document.querySelector(`.menu-item a[href$="${currentHash}"]`);
if (match) match.parentElement.classList.add("current-menu-item");
} else if (currentPath === "/") {
const homeLink = Array.from(menuLinks).find(link =>
link.href === window.location.origin + "/" || link.href === window.location.href
);
if (homeLink) homeLink.parentElement.classList.add("current-menu-item");
}
// Intercept clicks
menuLinks.forEach(link => {
link.addEventListener("click", event => {
// Prevent reload if already on homepage and clicking Home
if (
link.getAttribute("href") === "/" &&
window.location.pathname === "/" &&
!window.location.hash
) {
event.preventDefault();
}
// Set active state
menuItems.forEach(item => item.classList.remove("current-menu-item"));
link.parentElement.classList.add("current-menu-item");
});
});
});
Ah, itâs probably the case that the filter works for adding custom classes on fragment links, but it wonât apply anything to the Home menu item, since thatâs not a custom link with a fragment.
If you want to give the Home item a similar semantic class, you can extend the filter like this:
This version keeps home item highlighted persistently so when next item is clicked I have 2 items highlighted. Also I didnât figure out how to highlight gallery and contact menu items with this version of filter.
Sorry, I know that must be quite frustrating, especially when itâs close to working but still behaving weirdly. At this point, Iâm shooting in the dark a bit because there might be something else in play (theme CSS, JS, or how WordPress is outputting the menu).
Give me a couple of days and Iâll spin up a WordPress install on my end and try to replicate exactly what youâre seeing. That way I can test everything properly and stop guessing.
.page:not(:has(#about:target)):not(:has(#services:target)) .current_page_item.menu-item-home:nth-of-type(1) a:after
?
(Still quasi-fragile, and a helluva mouthful, but assuming you always keep âHomeâ first in the navâŚ)
EDIT: Also Marc, think shorter. Youâre targetting the lack of a target entirely. .page:not(:has(:target)) .current_page_item.menu-item-home:nth-of-type(1) a:after
If there is no targeted element (the hashtag is missing, empty, or doesnât have a matching element), And the current page is the Home page (because .current_page_item will only be set on Home, Services, and About at that point, this would select all 6 of them [because youâve got a nav at the top and bottom, so 6 elements inside 2 different parents]) But only the first element you selected inside each parent. Inside that element, find all links, and target their :after pseudoelements.