Information exchange is vital for making the world a better place.
The Internet must grow and I'm here to help.

Add a class to wp_nav_menu() items with URLs included in the current URL

Meta data: posted by Rares on 23 November 2010. Categories: Articles, User Interface, WordPress. 24 comments.

The Problem

We’re all enjoying the benefits and features of WordPress 3.0. Custom menus are awesome and custom post types shatter all capability and imagination limits. A small problem arises when these two features are used in conjunction: the classes applied to navigation menu items only reflect direct inheritance, and entities that have their URLs included in the current URL can’t get highlighted.

Let me illustrate through a simple example:

Suppose you defined a ‘Services’ page that lives at this URL: http://example.com/services/.
This page has an entry in the main menu of your website. To further emphasize your services, you also defined a ‘services’ custom post type with the slug services. The URL of a ‘service’ post can be http://example.com/services/branding/.

When you browse the ‘Branding’ post, however, no special class is applied to the menu entry of your ‘Services’ page, and it’s impossible to style it as the current section of your website, even though the proposed URL structure is semantic.

The Solution

The solution is based on the nav_menu_css_class WordPress hook. This is a filter hook that allows us to alter an array containing CSS classes that will be applied to a menu item.

We also need a way to find the current URL, or the URL being browsed.

The Code

add_filter( 'nav_menu_css_class', 'add_parent_url_menu_class', 10, 2 );

function add_parent_url_menu_class( $classes = array(), $item = false ) {
	// Get current URL
	$current_url = current_url();
	
	// Get homepage URL
	$homepage_url = trailingslashit( get_bloginfo( 'url' ) );
		
	// Exclude 404 and homepage
	if( is_404() or $item->url == $homepage_url ) return $classes;
	
	if ( strstr( $current_url, $item->url) ) {
		// Add the 'parent_url' class
		$classes[] = 'parent_url';
	}
	
	return $classes;
}

function current_url() {
	// Protocol
	$url = ( 'on' == $_SERVER['HTTPS'] ) ? 'https://' : 'http://';
	
	$url .= $_SERVER['SERVER_NAME'];
	
	// Port
	$url .= ( '80' == $_SERVER['SERVER_PORT'] ) ? '' : ':' . $_SERVER['SERVER_PORT'];
	
	$url .= $_SERVER['REQUEST_URI'];
	
	return trailingslashit( $url );
}

In the hooked function, a check is first made to see if we’re on a 404 page. When an invalid URL is accessed, we don’t want to highlight anything.

The same holds if the menu item points to the domain root URL: all other URLs on the website include it.

The rest is pretty straightforward: add the class if the menu item URL is included in the current URL and return the $classes array.

Thank you for [retweet-anywhere].

Comments

  • [...] This post was mentioned on Twitter by Sabin Sanislav, Rares Cosma. Rares Cosma said: New #wordpress article: Add a class to wp_nav_menu() items with URLs included in the current URL. http://bit.ly/ekjMrs Please RT! [...]

  • Chris Blunt
    wrote on December 16, 2010, 11:28

    Incredibly useful post. I’ve been going round in circles trying to figure out how to highlight the entry for a custom taxonomy page in wp_nav_menu. Your code worked perfectly – Thanks!

    • Rares
      wrote on December 16, 2010, 11:36

      You’re welcome! :-)

  • BandonRandon
    wrote on December 29, 2010, 00:42

    Wow! Thank you thank you thank you. I was trying to figure out how to do this and so glad I found this post.

    • Rares
      wrote on December 29, 2010, 08:20

      You’re welcome! :)

  • Shaun Dobson
    wrote on March 5, 2011, 14:01

    Just wanted to let you know that I found this code very helpful and have just used it on a page to highlight the parent menu items for custom post type pages. Thanks for sharing!

    • Rares
      wrote on March 6, 2011, 12:17

      You’re welcome!

  • David
    wrote on April 7, 2011, 06:05

    Thank you, thank you, thank you!!

    Everyone using CPT in wordpress 3 are finally getting around all these little nuances with work-arounds like these.

    I hope they are all addressed in future versions.

    • Rares
      wrote on April 7, 2011, 14:27

      You’re welcome, David.

      This the beauty of FOSS: if there’s a missing feature, you can always build it yourself instead of waiting for future versions.

  • Ken
    wrote on November 8, 2011, 22:47

    nice work. This has been slow getting into the WP core, but your solution is the perfect fit until they do.

    saved a ton of time, thanks!

  • Adam
    wrote on June 26, 2012, 15:55

    Worked like a charm! Thanks so much!

    • Rares
      wrote on June 26, 2012, 16:11

      I’m glad someone still finds this useful. You’re welcome!

  • Robert Abramski
    wrote on August 19, 2012, 21:31

    These are the kind of things I would never figure out without a Codex and a community of blogs killing it on WordPress. Thanks for the post!

  • Joshua
    wrote on August 20, 2012, 06:15

    Thanks for this…after a couple hours of googling and copy/pasting non-working functions, this worked beautifully.

  • Joshua
    wrote on September 1, 2012, 15:09

    This worked while developing locally but once I moved it to the live server, it doesn’t – the classes are not being added at all.

    Could it possibly be the server port?

    Trying to get this solved…

    • Rares
      wrote on September 18, 2012, 09:37

      It might be the server port.
      I have tested the code on custom ports tho, and it works fine.
      Also, sorry for the belated reply. Have you figured it out?

  • Will
    wrote on September 27, 2012, 15:35

    Thank you very much, just what I needed!

  • Manu
    wrote on October 27, 2012, 13:05

    Hi, I’m a newbie with wordpress and I’ve the same problem. Where should I put your code?

    • Rares
      wrote on October 29, 2012, 19:42

      Hello, try to paste the code into your theme’s functions.php

  • Will
    wrote on January 3, 2013, 02:44

    Rares—thanks so much for this. I updated your function to additionally search for other paths, as I am using Tri.be’s The Events Calendar, and need my Calendar url to highlight for urls containing /calendar/, /venue/, /event/, etc.

    If anyone else can benefit from an example of adding additional bits to search for in the if statement, here’s a link:
    http://pastebin.com/U2ZNM4eQ

  • horacsio
    wrote on March 1, 2013, 12:09

    Thank you very much for your PRECIOUS help here.
    Although, to be EXTREME complete :) I would love to see some CSS aplication.
    I’ve managed to work with it, yet I think some things are missing.

  • Paul
    wrote on May 8, 2013, 02:05

    Great. Just what I was looking for, works great, saved some time for this pesky little issue.

  • Gabriel
    wrote on May 22, 2013, 03:34

    I added a line in the if statement to prevent highlithing anything else but the custom post type or the archive page:
    unset($classes[array_search('current_page_parent',$classes)]);

    This way, if you set the articles to show in a different blog menu item, your custom post types won’t highlight that blog menu item.

    I used this to answer my question on stackexchange
    http://wordpress.stackexchange.com/questions/100220/custom-post-type-current-menu-item-not-applying-on-custom-post-type-archive-pag

    btw, thanks alot for posting this solution, Rares :)

  • Chris
    wrote on January 10, 2014, 01:40

    EXACTLY what I needed, may thanks.