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.

How might I have custom markup for my menus, like I want to give menu items something like id="menuitem-postname" how might I do that?

share|improve this question
    
How are you creating the menu? Does it use the new custom menus in the admin, wp_list_pages or something else? –  PNMG Apr 4 '11 at 20:57
    
I use wp_nav_menu() –  JM at Work Apr 5 '11 at 1:27
    
Just so I am clear on what you are trying to accomplish. wp_nav_menu() already gives you an id similar to menu-item-[id]. You want to change that id="menuitem-postname" correct? What do you mean by postname? It looks like you can only add pages, categories and custom links to the menu's. Do you want the slug of the page or the category? Also, the id is on the <li> tag. Are you wanting to update that id or add an id to the <a> tag? Also, you can check out wordpress.stackexchange.com/questions/12784/… to see if that is any help –  PNMG Apr 5 '11 at 14:44
    
@PNMG, I am trying to style my menu item. menu-item-[id] is not really readable as I wont know without looking at the dashboard whats id is refering to. So I am looking for something more intuitive like the slug (currently for a page). ID on the <li> is fine –  JM at Work Apr 6 '11 at 3:16

2 Answers 2

up vote 0 down vote accepted

The only way that I could think to do this would be to add a filter to wp_nav_menu_items. Here is the code that I got to work (just add it to your themes functions.php file):

add_filter('wp_nav_menu_items', 'my_id_name_nav', 10, 2);
function my_id_name_nav($items,$args) {
  if( $args->theme_location == 'primary' ) {
    preg_match_all('/<li id="menu-item-([0-9]+)"([^>]+)>\s*<a href="([^"]+)">([^<]+)<\/a><\/li>/i', $items, $matches);
    $newItems = array();
    for($i=0; $i<count($matches[0]); $i++){
      $short = explode('/', $matches[3][$i]);
      $short = $short[count($short) - 2]; // if there is no trailing slash, subtract 1 instead of 2
      array_push($newItems, '<li id="menu-item-'. $short .'"'. $matches[2][$i] .'><a href="'. $matches[3][$i] .'">'. $matches[4][$i] .'</a></li>');
    }
    return implode('', $newItems);
  } else {
    return $items;
  }
}

It uses the last part of the url to create the page name for the id. So menu-item-2 for http://yoursite.com/page1/page2/ would become menu-item-page2.

The if( $args->theme_location == 'primary' ) is for targeting a specific menu. If you want to do this for all menus just remove the if else statement.

share|improve this answer

Very Simple ... Use a Custom Walker ... All you need to do is attach something constant to the id element ... such as the actual post or page id ... That's in the menu_item->object_id ... I don't really see why your doing this though ... with a cursory knowledge of CSS you can easily utilize the cascade to address an items children ... All the menu_items are already assigned css classes ... @see the Codex

$args = array (

'theme_location'  => 'primary',
'menu'            => 'Menu Name',
'container'       => 'div',
'container_class' => 'nav',
'container_id'    => FALSE,
'menu_class'      => FALSE,
'menu_id'         => FALSE,
'echo'            => TRUE,
'fallback_cb'     => 'wp_page_menu',
'before'          => FALSE,
'after'           => FALSE,
'link_before'     => FALSE,
'link_after'      => FALSE,
'items_wrap'      => "\n\t" . '<ul>%3$s</ul>' . "\n",
'depth'           => 0,
'walker'          => new ID_Walker()
);

wp_nav_menu( $args );

class ID_Walker extends Walker_Nav_Menu {

function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
    global $wp_query;
    $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

    $class_names = $value = '';

    $classes = empty( $item->classes ) ? array() : (array) $item->classes;
    $classes[] = 'menu-item-' . $item->ID;

    $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
    $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

    $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );

            /** 
            * Add the object id as a reference
            * This will tie your menu_item id ref to your post page or cpt
            */  

    $oid = esc_attr( $item->object_id ); 

            /**
            * Append the object id to the element id  
            */

    $id = $id ? ' id="' . esc_attr( $id ) . '-' . $oid . '"' : '';

    $output .= $indent . '<li' . $id . $value . $class_names .'>';

    $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
    $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
    $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
    $attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';

    $item_output = $args->before;
    $item_output .= '<a' . $attributes .'>';
    $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
    $item_output .= '</a>';
    $item_output .= $args->after;

    $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }
}
share|improve this answer

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.