1

I'm trying to add a class to the body tag based on whether current menu items either have children, or are children. The custom menu was added via wp_nav_menu.

I have hooked into wp_nav_menu_objects via a filter, and am successfully detecting whether the current active menu item is a ancestor or child:

function has_submenu( $menu_items ) {

    $current_id = 0;

    foreach( $menu_items as $menu_item ) {

        // Get the id of the current menu item
        if( $menu_item->current ) {
            $current_id = $menu_item->ID;
        }
        // if the current item has a child
        if( $menu_item->menu_item_parent != 0 && $menu_item->menu_item_parent == $current_id ) {
            $body_class = 'has-submenu';
            break;
        }
        // if the current item has an ancestor
        if( $menu_item->current_item_ancestor ) {
            $body_class = 'is-submenu';
            break;
        }
    }
    return $menu_items;
}
add_filter( 'wp_nav_menu_objects', 'has_submenu', 10, 2 );

Now the issue i'm having is how to I then filter body_class to add the class?? I created the variable called $body_class, however i'm not sure hot to pass it to the body_class hook function. Make it a global variable? Create a class for all this?

Thanks in advance!

4
  • When you print the menu, the body class was already outputted. Is not possible with php modify something already printed to browser. You have to use javascript.
    – gmazzap
    Commented Sep 13, 2013 at 23:24
  • Perhaps if you tell us why you want to add 'is-submenu' or 'has-submenu' to the body class, we can help you find a different solution. Commented Sep 13, 2013 at 23:31
  • @G.M. you're totally right, I need to hook into the menu before the body tag is called.
    – plankguy
    Commented Sep 13, 2013 at 23:59
  • @CharlesClarkson The menu is fixed/sticky at the top of the page. On pages where there is either a child menu, or is a child page, the sub menu (level 2) is visible. So i need/want to add a class to the body, so I can move the content down via CSS so the fixed menu doesn't overlap. I was hoping to find a non-js solution.
    – plankguy
    Commented Sep 14, 2013 at 0:01

1 Answer 1

1

As @CharlesClarkson has already explained, you cannot modify the page output with PHP after the output has been sent to the browser. Your menu certainly runs after body_class since the menu must run inside the <body> tag.

The only PHP solution I see would involve editing your theme templates in addition to the code above (with changes).

If you run wp_nav_menu before the <body> tag but use output buffering to capture the content instead of print it, what you are trying to do might work.

You would need to run your menu before the <body> tag, like this:

ob_start();
wp_nav_menu();
$my_captured_menu = ob_get_contents();
ob_end_clean();

In your function callback, instead of lines like this:

$body_class = 'has-submenu';

You would need this:

add_filter(
  'body_class',
  function($classes) {
    $classes[] = 'has-submenu'; // or 'is-submenu'
    return $classes;
  }
);

And of course, use echo $my_captured_menu wherever it needs to be printed.

Your Answer

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

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