Different Colors in Different Menu Items

I came across this idea while working on one of our themes that had to have different body colors for different pages, like a red body on the home page, a yellow one on the contact page, a blue one on the archives page and so on. Of course this would be easy to achieve if we were working on a website where we knew all the existing pages, their IDs or slugs and I’ll talk about this too, but today I’ll show you a different approach.

This post will teach you how to output the current menu item number (in the menu order) in the body element classes in your theme. We will then use the class to give a different background color to each page according to it’s position in the navigation menu. Note that this will work only with wp_nav_menu but can easily be modified to the fallback pages walker if a menu is not set.

The Problem

To give you a better idea of what we’re going to do, take a look at this navigation menu structure:

  • Home
  • Parent Page
    • Child Page 1
    • Child Page 2
  • Contacts Page

If the home page is selected, the background of the page will be yellow. If the parent page is selected you’ll see a purple background color, if any of the child pages is the selected one, you’ll get the purple background since they’re children of the ancestor page. And if the contacts page is the current one, we’ll see a blue background.

The concept can be modified of course to get different backgrounds on the children pages too, and that would actually be easier, but since I had to color my pages according to the top level menu items, I took this approach.

It may seem a little crazy, since you can easily output the current requested page slug in the body class and style the page according to it’s slug. But as I said in the beginning of this post, I’m working on a public theme, so I can’t guess what sort of menu items will be used, pages, posts, category archives and so on, and of course I’ve no idea of what kind of slugs users might be thinking of :)

Getting Started

With all due respect to plugins and functions.php hacks, I’ll be doing this as a child theme and of course I picked Twenty Eleven as my parent theme. I already wrote a couple of posts about Twenty Eleven and if you haven’t read them yet, you probably should:

So today we’ll create a new child theme for Twenty Eleven and use the navigation menu items to define the background color of each page. Ready? Code!

First thing’s first, create a new directory next to Twenty Eleven and call it whatever you like, insert a style.css file inside and make it our new child theme, like this:

/*
Theme Name:     Twenty Eleven Navigation Colors
Theme URI:      http: //example.org/
Description:    Child theme for the Twenty Eleven theme
Author:         Konstantin
Author URI:     http: //theme.fm
Template:       twentyeleven
Version:        1.0
*/

@import url("../twentyeleven/style.css");

The Template: part tells WordPress which parent theme to use and we’ve also imported the original Twenty Eleven stylesheet so that we don’t loose our structure. Next, in that very same directory create an empty functions.php file. We’ll write a few hooks there to give us a new body class.

Menu Items CSS Class

Our task here is to figure out the position of the currently selected menu item. We’ll hook to the nav_menu_css_class filter that is used on each item in every navigation menu and we’ll tell it to work only on the primary one as well as when the depth is set to 1 and when echo is set to false. This may sound strange at first but I’ll explain very soon. So in your functions.php file, add this:

add_filter( 'nav_menu_css_class', 'my_menu_class', 10, 3 );
function my_menu_class( $classes, $menu_item, $args ) {

    if ( $args->theme_location == 'primary' && $args->depth == 1 && $args->echo == false ) {
        global $current_menu_item_counter;
        $current_menu_item_counter++;

        if ( $menu_item->current == 1 || $menu_item->current_item_ancestor == 1 || $menu_item->current_item_parent == 1 ) {
            global $current_menu_item_number;
            $current_menu_item_number = $current_menu_item_counter;
        }
    }
    return $classes;
}

Okay so let me try to explain what’s happening here, what the globals are and why we’re limiting the depth and making sure the menu is not being output. You see, the wp_nav_menu function in the Twenty Eleven theme is called after the body tag, meaning the body_class fill work out before we even get a chance to look at our menu.

For this reason I’ll call an extra wp_nav_menu with the same theme_location during the body class filter, and this will trigger the my_menu_class filter, which is what we need. The difference between the wp_nav_menu call in the body class and the real one in Twenty Eleven’s header.php is that in the body class I’ll set the depth to 1 so it walks through top-level items only, and set the echo to false so that it doesn’t output anything. I will also set the global counter to 0 before calling it as you’ll see in a bit.

Hope that explained all the depth and echo voodoo, you’ll get a better idea when you see the body class filter. Now, the $current_menu_item_counter is a global variable that I’ll reset before calling my fake wp_nav_menu so in my menu class filter it’ll initially be set to 0 and then incremented with every item.

I then fire a check to see if the current item is selected or is a parent/ancestor of a selected one and if it is, set the $current_menu_item_number global to the counter. We could have used the $menu_item object from the passed in arguments here, but we’re counting the top level ones only, while $menu_item->menu_order will count the children as well, thus giving a 5 on the contacts page instead of 3.

You can call this voodoo but it’s really simple once you understand how it works, there really is no magic inside ;) Let’s take a look at the body classes now.

The Body Classes

In that very same functions.php file, we’ll create a filter on the body_class tag and assign it the my_body_class function, like this:

add_filter( 'body_class', 'my_body_class' );
function my_body_class( $classes ) {
    global $current_menu_item_counter;
    $current_menu_item_counter = 0;
    wp_nav_menu( array( 'theme_location' => 'primary', 'depth' => 1, 'echo' => false ) );

    global $current_menu_item_number;
    $classes[] = 'current-menu-item-number-' . $current_menu_item_number;
    return $classes;
}

The body class filter will run when printing the set of classes used for the body tag in Twenty Eleven’s header.php file, so we’re going to add our new class there. First thing you want to do is reset that global counter as shown in the first two lines of the function. Next we fire our fake wp_nav_menu call, that’s where we set the depth to 1 and echo to false. At this point, it will walk through the navigation menu items and trigger the function that we wrote before on each and every item, incrementing the global counter and updating our $current_menu_item_number global, and after that’s done, we can use it.

As seen in the second part of the function we grab our global and add a new class to the passed in $classes array and finally return the array. That’s really all there is to it.

Styling the Pages

Now the fun part. If you inspect the body tag while switching to different pages in your navigation menu, you’ll notice the new current-menu-item-number-x class, where x is the order number of each item. Let’s make use of that in our child theme’s stylesheet, like this:

body.current-menu-item-number-1 { background: #FFCF00; }
body.current-menu-item-number-2 { background: #8805A8; }
body.current-menu-item-number-3 { background: #3415B0; }

I output three for brevity, you can have more, much more. In fact, you can go back to the body class and output the remainder of the $current_menu_item_number divided by the number of colors you have defined, that way it’ll repeat itself on the fourth, fifth and sixth items, like this:

$classes[] = 'current-menu-item-number-' . ( $current_menu_item_number % 3 );

And set the third item to 0 in your stylesheet, since 3 % 3 and 6 % 3 will give you 0. Like this:

body.current-menu-item-number-0 { background: #3415B0; }

Voila! And how about some screenshots to illustrate all the madness that we’ve been through?

Twenty Eleven Child Theme Yellow

Here's how the first page looks, a yellow background!

Twenty Eleven Purple Background Color

This is my second page and it's got a purple background color

Twenty Eleven Blue

This is my third page and it is of course blue :)

And if you were wondering, the authors page has a yellow background while “Sample Page” is purple, that’s the division magic I’ve shown above.

Conclusion

This might not be the best or cleanest approach, but it certainly is one that works. The last bit can break the semantics a little bit but you can fix that on your own by leaving the current menu item number as it was and introducing a color-index-x class where you’ll do the division magic, that’ll obviously read better :)

I don’t know whether this is at all useful and whether my case is just a special one but with this trick you’ll be able to do different things on different pages depending on their menu order and not knowing the page IDs or slugs, thus possible to use in public free or premium themes. So let me know your thoughts and please ask if you want me to clarify any part of that code or perhaps you’ve got a suggestion on how to make it easier.

Use the comments section below to leave your thoughts and don’t forget to subscribe to our RSS feed. Thank you all for reading and enjoy your day!