Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

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

share|improve this question
    
Can you be more specific in what is the change you are trying to achieve...change to the navigation menu, change to the displayed page, etc? –  Ray Mitchell Apr 10 '11 at 19:07
    
Are you talking about a front-end menu, or the back-end (i.e. Admin UI) menu? –  Chip Bennett Apr 10 '11 at 19:10
    
And how are you building your menu, are you using wp_nav_menu() (i.e. core Custom Nav Menus feature), or something else like wp_list_pages() or wp_page_menu()? –  Chip Bennett Apr 10 '11 at 19:41
    
@chip, thanks for your help. Haven't used WP for several years so have some catching up to do. Advices are welcome. –  user4569 Apr 10 '11 at 19:54
    
@chip, to answer your question, I'm evaluating to use either the new core-menu features or just use one tree and try to hide other menus (shortcut-menus not described in original Q), hiding with custom-fields. I'll probably sort it out, but it's even better if it's in line with WP-guru way of doing it. –  user4569 Apr 10 '11 at 19:57

2 Answers 2

up vote 6 down vote accepted

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;
}
share|improve this answer
    
Hats off for a very well laid out answer. Will look into it further later. Big thanks. –  user4569 Apr 11 '11 at 13:00

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.

share|improve this answer
    
Thanks mark, I can't style based on ID, it has to be related to the top-menu parent. As new content is added (by client), the coloring has to be correct. –  user4569 Apr 10 '11 at 19:59

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.