Minor css-change based on topmenu – how?

The question:

I want to make minor css-changes based on the choice of the top (root) menu.

What’s the proper way to handle this in WP?

//edit//
It’s a website (pages), no blog, and basically, the colors of some links and some images should depend of the choosen top-menu-item.

Example, page-structure:

* Start
* Products
  * Prod.categ.
    * A product
* Services
  * List of services
    * Nested
* Contact
  * Main office
    * List of staff
  * Abroad
    * Another list

Top level is in a topmenu, one-level, and level2&3 in nested left-menu.
Now minor coloured items in sidemenu changes depending on selected top-menu item.

//end edit//

regards,
/t

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

My answer adds a class to the <body> element via the body_class filter. This is probably the easiest way to apply extra formatting to any element on the page. The added classes are wpse14430_products, wpse14430_services or wpse14430_contact (based on the slugs of the top pages in your example).

Using wp_nav_menu()

If you use wp_nav_menu() to display the menu, WordPress builds a tree of the menu items. We can use this information to get the top page of the current item. Only problem: we need it in the <body> tag, thus before the menu is rendered. The solution is to save the menu in an variable which we later echo ourselves.

Taking the Twenty Ten theme as an example, I move the wp_nav_menu() call up to the first <?php block:

$wpse14430_menu = wp_nav_menu( array(
    'container_class' => 'menu-header',
    'theme_location' => 'primary',
    'echo' => false,
) );

And where we used to call it, we now echo our saved output:

echo $wpse14430_menu;

wp_nav_menu() has an interesting filter, called after the menu items are ordered and have their classes. The classes already contain ancestor information. We hook into this filter and find the first item that is the current item or an ancestor of it:

add_filter( 'wp_nav_menu_objects', 'wpse14430_wp_nav_menu_objects' );
function wpse14430_wp_nav_menu_objects( $sorted_menu_items )
{
    // The items are in menu order, so the first match is the top item
    foreach ( $sorted_menu_items as $menu_item ) {
        if ( $menu_item->current || $menu_item->current_item_ancestor ) {
            $GLOBALS['wpse14430_top_page'] = get_post( $menu_item->object_id );
            break;
        }
    }
    return $sorted_menu_items;
}

Now we got the top page, and only need to add this to the body class:

add_filter( 'body_class', 'wpse14430_body_class_menu' );
function wpse14430_body_class_menu( $body_class )
{
    if ( isset( $GLOBALS['wpse14430_top_page'] ) ) {
        $body_class[] = 'wpse14430_' . $GLOBALS['wpse14430_top_page']->post_name;
    }
    return $body_class;
}

Using pages as the menu structure

If you don’t use wp_nav_menu() but instead use the direct ordering of the pages, you can also check for ancestors. Remember that if don’t define a menu using the new menu system but still display the page list via wp_nav_menu() (the fallback functionality), the above system will work for you.

add_filter( 'body_class', 'wpse14430_body_class_pages' );
function wpse14430_body_class_pages( $body_class )
{
    if ( is_page() ) {
        $null = null;
        $top_page = get_post( $null );
        $ancestors = get_post_ancestors( $top_page );
        if ( $ancestors ) {
            $top_page = get_post( array_pop( $ancestors ) );
        }
        $body_class[] = 'wpse14430_' . $top_page->post_name;
    }
    return $body_class;
}

Method 2

If you are outputting the menu using wp_list_pages / categories or the built in menu builder, then each page or category link is given a class that you can style. This means the current page or cat that a user is on will have a class that you can then style to look “active.”

Parent page links will display:

current_page_item or current-menu-item (when top level active)
current_page_ancestor or current-menu-ancestor (when first child active)

Categories links will display:

current-cat (when top level active)
current-cat-parent (when first child active)

There are other classes that WP will auto insert into the li tag of menu items, depending on the depth.

I’m assuming this is what you were looking to do, so I hope it helps.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment