1

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

9
  • 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? Apr 10, 2011 at 19:07
  • Are you talking about a front-end menu, or the back-end (i.e. Admin UI) menu? Apr 10, 2011 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()? Apr 10, 2011 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, 2011 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, 2011 at 19:57

2 Answers 2

7

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

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.

1
  • 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, 2011 at 19:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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