1

I just updated a menu on a site of mine to utilize wp_nav_menu. Setting this up with WP was fairly straight forward however I've run into one small snag with the the way wordpress is outputting its parent/ancestor classes for use in highlighting the current page that the content belongs to, particularly with single post pages...

Highlighting the current page with .current_page_item a and .current_page_parent a works perfect as long as its just on a normal page with children, however as soon as you visit a post from events or media, the blog link in the menu is highlighted instead which is incorrect obviously.

*One thing noticeably wrong when looking at Wordpress' output is that the current page classes are not even being generated on the correct li tag that the post belongs to which seems to be the root of the problem.

For future reference, the Events, Media, & Blog pages all use a special query I've written to only grab the respective category for that page, ie.

$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
query_posts("category_name=media&paged=$paged");

if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<div class="post">
</div>
<?php
endwhile;
else:
endif;

Hope thats enough info, if not let me know. Best, SB


EDIT - August 3, 2011


Below is a screen shot of what Im referring to when I say that wp_nav_menu is generating the current classes on the wrong li tag. Highlighted in Blue is the menu item that the post actually belongs to. Hightlighted in Grey is the incorrect li tag that wordpress has decided to add the current classes to instead.

Example http://img688.imageshack.us/img688/4180/picture2zo.png



EDIT - August 4, 2011


Maybe this will help demonstrate how I have the menu setup thus far a little better w/ Hadvig's assistance?

In my functions.php template I have -

<?php
// Add Custom Menu Support
if ( function_exists( 'register_nav_menu' ) ) {
    register_nav_menu( 'epr_menu', 'EPR Main Menu' );
}

function my_menu_items_hook($items, $menu, $args) {

  if ( 'epr_menu' == $menu->slug ) { // check if it is process your top menu
    if ( is_single() ) { // check if single post loaded

      if ( in_category('events') || in_category('media') ) {
        foreach ( $items as $key => $value ) {
          if ( 'blog' == $value->ID ) {
            $items[$key]->classes[] = array(); //unset classes for blog item
          }

          // add class if post from event category
          if ( in_category('events') && 'events' == $value->ID ) {
            $items[$key]->classes[] = 'current-menu-item';
          }

          // add class if post from media category
          if ( in_category('media') && 'media' == $value->ID ) {
            $items[$key]->classes[] = 'current-menu-item';
          }
        }
      }
    }
  }

  return $items;
}

add_action('wp_get_nav_menu_items', 'my_menu_items_hook', 10, 3);
?>

In my header.php template I'm calling the menu like so -

<div id="nav_wrapper">
    <ul id="nav">
        <?php wp_nav_menu( array( 'container' => '', 'items_wrap' => '%3$s' ) ); ?>
    </ul>
</div>

Mr.Brown
  • 179
  • 3
  • 11
  • Do you have Events, Media and Blog categories? – hadvig Aug 03 '11 at 23:37
  • Yes, each page shows 1 category via a custom query exactly like the one displayed above...and in settings > reading > I have front page set to Events, and posts page set to Blog. Everything works as expected except wp_nav_menu is incorrectly generating current classes on the wrong li tags when visiting a single post from either media or events. Ill upload a screenshot from firebug to demonstrate what I mean and place it in my original post. – Mr.Brown Aug 04 '11 at 02:02

1 Answers1

0

I suppose problem because you set post page as Blog and wordpress set it as parent(in your menu) for all post. You can try to change this behaviour with wp_get_nav_menu_items hook. Example:

function my_menu_items_hook($items, $menu, $args) {

  if ( 'my-menu-slug' == $menu->slug ) { // check if it is process your top menu
    if ( is_single() ) { // check if single post loaded

      if ( in_category(EVENT_CATEGORY_ID) || in_category(MEDIA_CATEGORY_ID) ) {
        foreach ( $items as $key => $value ) {
          if ( BLOG_PAGE_ID == $value->object_id ) {
            $items[$key]->classes[] = array(); //unset classes for blog item
          }

          // add class if post from event category
          if ( in_category(EVENT_CATEGORY_ID) && EVENT_PAGE_ID == $value->object_id ) {
            $items[$key]->classes[] = 'current-menu-item';
          }

          // add class if post from media category
          if ( in_category(MEDIA_CATEGORY_ID) && MEDIA_PAGE_ID == $value->object_id ) {
            $items[$key]->classes[] = 'current-menu-item';
          }
        }
      }
    }
  }

  return $items;
}

add_action('wp_get_nav_menu_items', 'my_menu_items_hook', 10, 3);

You should replace EVENT_CATEGORY_ID and MEDIA_CATEGORY_ID with your category ids(or names). Also replace EVENT_PAGE_ID and MEDIA_PAGE_ID with your page ids. Replace 'my-menu-slug' with your menu slug.

Of course this would work only if you attach post to only one category from Events, Media or Blog.

Updated.

hadvig
  • 1,096
  • 10
  • 20
  • This looks promising, I'll try it out and report back. PS - I believe your right about setting Post Page to: Blog...however Ive also tried it in its default behavior and I still never get an active class for home unfortunately, only .home-menu-item or something like that. – Mr.Brown Aug 04 '11 at 16:50
  • Hadvig - thank you so much for the help. Unfortunately, its still rendering the same results. What would you recommend would be the best route to remedy this problem? – Mr.Brown Aug 04 '11 at 17:11
  • For future reference, each post only contains 1 category. – Mr.Brown Aug 04 '11 at 17:18
  • Would it be better/more appropriate to create custom post types for everything but the blog instead?...just figured that seemed excessive. – Mr.Brown Aug 04 '11 at 17:24
  • I fix problems just like yours with this solutions. Dig into that way. Try to var_dump($items, $menu) from filter and look output. I suppose you get error in your filter function: menu slug check, category check or somewhere else. Sorry cannot say more without code of filter and names/ids of categories and menus. – hadvig Aug 04 '11 at 17:30
  • Apologies, but I'm not extremely skilled at php thus far, still learning it via Wordpress, so not too sure how to do a var_dump :( I can tell you however that my category slugs are: events, media, & blog. – Mr.Brown Aug 04 '11 at 17:38
  • Did you replace "my-menu-slug" with your menu slug? if not or you didn't know your menu slug insert var_dump($menu); at the begining of filter function and look into $menu dump and find slug attribute then replace "my-menu-slug" with your slug (or you can use menu id insted slug comparison). – hadvig Aug 04 '11 at 18:10
  • Ok, ill try that. Was I expected to replace the ones like "EVENT_CATEGORY_ID" as well with my own slugs? – Mr.Brown Aug 04 '11 at 18:14
  • yes of cause, you should get warnings if you didn't disable it. Your should raplace EVENT_CATEGORY_ID and MEDIA_CATEGORY_ID with yours category ids and replace EVENT_PAGE_ID and MEDIA_PAGE_ID with yours page id – hadvig Aug 04 '11 at 18:17
  • I originally tried replacing EVENT_PAGE_ID, etc. with the resepective slugs though, does that still count as a accurate ID in that context? I hadn't replaced "my-menu-slug" with my own yet though so let me try that. Thanks again for the help! – Mr.Brown Aug 04 '11 at 18:22
  • if var_dump print null it is very strange. Sorry, cannot give you any other advice. – hadvig Aug 04 '11 at 22:45
  • Dang, did you see the additional items I added to my original question? Is that still not enough to help show how everything's setup on my end?....well, thanks for trying either way, much appreciated. – Mr.Brown Aug 04 '11 at 23:25
  • Sorry didn't see changes: 'events' == $value->ID this is wrong. you try to compare page slug?? and it id. Go to admin area and find page called 'events' that click to edit and look into url you can find id parameter which should be placed instead 'events' (assume your 'events' page has id = 146) you should get: if ( in_category('events') && 146 == $value->ID ) . Also replace 'media' page id in second construction. – hadvig Aug 04 '11 at 23:45
  • Im editing "locally" right now so that means the ID will most likely change once I try this on the real site, but when I got to edit the EVENTS page for example my URL appears like this: `http://localhost:8888/wordpress/wp-admin/post.php?post=810&action=edit` ....So is 810 my page ID? – Mr.Brown Aug 04 '11 at 23:59
  • Does it make a difference that Im using a custom permalink structure? this is what my site is set to: `/%category%/%postname%` – Mr.Brown Aug 05 '11 at 00:09
  • Permalinks didn't make any different for ID. You can check page name instead ID. In that case you shoul replace PAGE_ID == $value->ID with 'Events' == $value->title – hadvig Aug 05 '11 at 06:42
  • I'm half aware of what your trying to get at - would it be possible for you to edit your original answer example to reflect what your saying possibly? It would be a big help. – Mr.Brown Aug 05 '11 at 21:36