Fixing Menu Issue on WordPress Single-Page Themes
Among WordPress themes out there, there are so called single- or one-page themes. Most of the content of the page is located on one page. Menu links are route to different sections of the page via anchors tags. The menu is created using custom anchor links like so:
The corresponding part of an anchor tag looks like this <a name=”#resume”></a>
This anchor link only works if you are jumping to a specific spot on the same page. For instance, if you have a blog page different from your home page unless you put the full URL of the home page like so http://www.mywebsite.com#resume. So, not a big deal, let’s replace Custom Link URL on the menu page with the full URL of the home page. Right? Well, this solution works but it makes all the menu links on home page to be highlighted, because each of them “think” they are on the correct page. It does not look good.
My solution to the problem is to dynamically prefix an anchor link with “http://www.mywebsite.com” when it is not on the homepage. The piece of code below does exactly that.
add_filter( 'wp_nav_menu_objects', 'em_links');
function em_links ( $sorted_menu_items, $args ) {
if(!is_front_page()){
foreach ($sorted_menu_items as $menu_item) {
$menuLink = $menu_item->url;
if(!preg_match("~^(?:f|ht)tps?://~i", $menuLink)){
$menu_item->url = get_bloginfo('url') . $menuLink;
}
}
}
return $sorted_menu_items;
}
We change nav_menu code by hooking into wp_nav_menu_objects filter. $sorted_menu_items and $args are passed from the filter. $args are arguments created by the user, but we not gonna touch them. We will work with $sorted_menu_items. It is an array of objects. First we make sure, we are not on front page. Then we start looping through all the objects and checking if link starts with a ‘#’ sign. Actually, in the code above I am checking if the link does not start with ‘http’ or https’ because I felt like playing with regular expressions. For a simple check if a string starts with ‘#’ character substr( $menuLink, 0,1 ) === “#” should do. If the link starts with ‘#’ character, we need to append website’s url to it. In the end, do not forget to return $sorted_menu_items. This is the difference of filter hook from action hook. In filter hook you are passed an argument. You do something to it and then return it.