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'm new to Wordpress and I've tried wp_nav_menu function. If i get it right it is a standard way to show you navigation menu created with help of the Menu Manager.

What is bothering me is the fact that it internally creates a bunch of CSS classes I probably don't need. I have control over the container div(delete it, change its class and so on) and the ul element itself, it is also possible to add extra elements before and after an anchor element. What i couldn't find out is how to remove those bizillion classes attached to list elements(li).

Is there any way to achieve this? And another question would be: could it harm? I have noticed that there are some classes, which could be used by another built in Wordpress functions. If there is a way to remove those, which should definitely stay?

share|improve this question

3 Answers 3

up vote 0 down vote accepted

Using wp_nav_menu() and a Walker is a great thing and I really appreciate the other answers with this solution, but I think it's a really hard way to go for a simple menu. So I found myself quite often doing it via wp_get_nav_menu_items()

So let's focus on the idea: I just get all the menu items from one of the WordPress navigation menus to completely re-build the menu myself.

What I get is a strip naked menu as we've once seen it as we learned HTML. The output will look like this:

<ul>
    <li></li>
    <li></li>
    <li></li>
    (...)
</ul>

First and last of all we need the name of the menu registered in the menu manager. You'll probably find this in your functions.php. This is for example what it looks like in the Twenty Thirteen-Theme:

register_nav_menu( 'primary', __( 'Navigation Menu', 'twentythirteen' ) );

Besides this we'll not need to insert any more information manually because we'll be able to get the details (e.g. location, id,...) of the registered menu:

<?php
    $menu_name = 'primary'; // this is the registered menu name

    if ( ( $locations = get_nav_menu_locations() ) && isset( $locations[ $menu_name ] ) ) :
        $menu = wp_get_nav_menu_object( $locations[ $menu_name ] );
        $menu_items = wp_get_nav_menu_items($menu->term_id);
        echo '<ul>';
            foreach ( (array) $menu_items as $key => $menu_item ) :
                $title = $menu_item->title;
                    echo '<li>' . $title . '</li>';
            endforeach;
        echo '</ul>';
    else :  
        echo '<p>Menu "' . $menu_name . '" not defined.</p>';
    endif;
?>

So this will echo a simple menu structure completely without classes and with the menu items form your navigations menus manager; or it will fail smoothly if the menu name or the location is not (yet) defined.

With all this in mind you should have no trouble to add your own sorting or whatever... just take a look at the wp_get_nav_menu_items() default parameters (as provided in the Codex):

<?php 
    $args = array(
        'order'                  => 'ASC',
        'orderby'                => 'menu_order',
        'post_type'              => 'nav_menu_item',
        'post_status'            => 'publish',
        'output'                 => ARRAY_A,
        'output_key'             => 'menu_order',
        'nopaging'               => true,
        'update_post_term_cache' => false 
    ); 
?>

UPDATE: To summarize my answer and to focus on the last part of your question: this will not harm you (it's only about the styling), but it will also not provide any kind of extra functionality (like extra classes for current pages or things like that). You'll have to build all extra functions by yourself.

So you'll have a good go to use wp_nav_menu(); simply ignore all these id and class names within the source code of your page if you do not need them, but they will be there if you'll need them in the future :)

share|improve this answer

There are various ways to customize the navigation menus in Wordpress, even you can override totally the output.

First, the wp_nav_menu() accepts some arguments to customize near every element of the menu. There are more arguments but those needed to customize the output are those (please, go to wp_nav_menu() docu for the description of each one):

 wp_nav_menu(array(
     'container'       => 'div',
     'container_class' => '',
     'container_id'    => '',
     'menu_class'      => 'menu',
     'menu_id'         => '',
 'before'          => '',
 'after'           => '',
 'link_before'     => '',
 'link_after'      => '',
 'items_wrap'      => '<ul id="%1$s" class="%2$s">%3$s</ul>',
));

If the above it is not enough. There are some filters you can also apply, like nav_menu_css_class. And if you need still more control you override completely the default menu output in the walker parameter of the wp_nav_menu() function. The walker value must be set to a new PHPClass that extend the Wordpress Walker_Nav_Menu class:

 wp_nav_menu(array(
 'walker'      => new MyCustomNavWalker,
));

And here the MyCustomNavWalker class (just copied the deault) that you can completely customize:

class MyCustomNavWalker extends Walker_Nav_Menu {
/**
 * @see Walker::$tree_type
 * @since 3.0.0
 * @var string
 */
var $tree_type = array( 'post_type', 'taxonomy', 'custom' );

/**
 * @see Walker::$db_fields
 * @since 3.0.0
 * @todo Decouple this.
 * @var array
 */
var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );

/**
 * @see Walker::start_lvl()
 * @since 3.0.0
 *
 * @param string $output Passed by reference. Used to append additional content.
 * @param int $depth Depth of page. Used for padding.
 */
function start_lvl( &$output, $depth = 0, $args = array() ) {
    $indent = str_repeat("\t", $depth);
    $output .= "\n$indent<ul class=\"sub-menu\">\n";
}

/**
 * @see Walker::end_lvl()
 * @since 3.0.0
 *
 * @param string $output Passed by reference. Used to append additional content.
 * @param int $depth Depth of page. Used for padding.
 */
function end_lvl( &$output, $depth = 0, $args = array() ) {
    $indent = str_repeat("\t", $depth);
    $output .= "$indent</ul>\n";
}

/**
 * @see Walker::start_el()
 * @since 3.0.0
 *
 * @param string $output Passed by reference. Used to append additional content.
 * @param object $item Menu item data object.
 * @param int $depth Depth of menu item. Used for padding.
 * @param int $current_page Menu item ID.
 * @param object $args
 */
function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
    $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 );
    $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';

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

    $atts = array();
    $atts['title']  = ! empty( $item->attr_title ) ? $item->attr_title : '';
    $atts['target'] = ! empty( $item->target )     ? $item->target     : '';
    $atts['rel']    = ! empty( $item->xfn )        ? $item->xfn        : '';
    $atts['href']   = ! empty( $item->url )        ? $item->url        : '';

    $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args );

    $attributes = '';
    foreach ( $atts as $attr => $value ) {
        if ( ! empty( $value ) ) {
            $value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
            $attributes .= ' ' . $attr . '="' . $value . '"';
        }
    }

    $item_output  = $args->before;
    $item_output .= '<a'. $attributes .'>';
    $item_output .= $args->link_before;
            // HERE are your <span> tags
            $item_output .= '<span data-hover="'.esc_attr($item->title).'">';
            $item_output .= apply_filters( 'the_title', $item->title, $item->ID );
            $item_output .= '</span>';
            $item_output .= $args->link_after;
    $item_output .= '</a>';
    $item_output .= $args->after;

    $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}

/**
 * @see Walker::end_el()
 * @since 3.0.0
 *
 * @param string $output Passed by reference. Used to append additional content.
 * @param object $item Page data object. Not used.
 * @param int $depth Depth of page. Not Used.
 */
function end_el( &$output, $item, $depth = 0, $args = array() ) {
    $output .= "</li>\n";
}
}
share|improve this answer

Yes it's possible.
You have to write your own custom nav Walker for that. Here is an one which does exactly what you want : https://snipt.net/huskie/wordpress-custom-walker-class-to-remove-unnecessary-classes-and-ids-from-menu-items/ . I hope it helps. And there will be no harm done if you remove those auto generated classes.

share|improve this answer
1  
The external links may result 404 in the future. So, please try to summarize how it is done, in your own words. –  Pothi Sep 22 '13 at 6:14

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.