So I'm adding descriptions to my site's main menus. Checked the box, added the text. Dropped in a custom walker in functions.php. Dropped in a wp_nav_menu call in header.php to call the custom walker. Added text to the descriptions.

All good... but then I decided I wanted to add breaks via HTML... Dammit they're being stripped out. Oh, right, I need to turn off that filter. So I do, via the correct line in functions.php. ONly, it doesn't work. The HTML is still being stripped.

Before I go on, here's the walker I'm using with the filter removal line after it:

#new walker to enable description text under menu items. 
    class description_walker extends Walker_Nav_Menu
      function start_el(&$output, $item, $depth, $args)
           global $wp_query;
           $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

           $class_names = $value = '';

           $classes = empty( $item->classes ) ? array() : (array) $item->classes;

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

           $output .= $indent . '<li id="menu-item-'. $item->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        ) .'"' : '';

           $description  = ! empty( $item->description ) ? '<p class="menu_description">'.esc_attr( $item->description ).'</p>' : '';

           if($depth != 0)
                     $description = $append = $prepend = "";

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

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

## Function to stop HTML removal from menu descriptions
    remove_filter('nav_menu_description', 'strip_tags');

More info: The HTML is recorded in the database, so it's present there... just not on output. This is in Wordpress 3.3. For clarity, here's the code that calls the menu in header.php:

            wp_nav_menu( array(
                'theme_location' => 'primary',
                'depth' => 0,
                'walker' => new description_walker())

I have that sinking feeling I'm missing something basic and just need a new pair of eyes on this... any ideas?

  • You're resetting the description variable inside the $depth != 0 conditional block.
    – t31os
    Dec 13, 2011 at 21:51
  • Hmmm except that depth was set to zero. Removed that code anyway and no luck. I'll add the wp_nav_menu call above for clarity. Dec 13, 2011 at 22:32
  • So what do you get in the output, everything minus the HTML, or are you still seeing content from inside HTML tags? Can you provide some sample data, ie. a sample of something in the DB and a sample of what you're getting on output.
    – t31os
    Dec 13, 2011 at 23:25
  • Sure. IN the database the description text is just a test so it looks like this: <p>Line 1</p> <p>Line 2</p> <p>Line3</p> in the generated code I get: Line 1 Line 2 Line3 just as you'd expect if the strip_tags filter was active. Since I added a remove_filter call in function.php, it shouldn't be. Same thing happens with <br /> tags. Dec 14, 2011 at 0:03
  • Removed my last 2 comments, see answer.
    – t31os
    Dec 14, 2011 at 0:42

2 Answers 2


in a new wordpress version, the remove_filter isn't enough, cause the desc is stripped hardcoded from post_content ...

this will do the trick:

remove_filter('nav_menu_description', 'strip_tags');
add_filter( 'wp_setup_nav_menu_item', 'cus_wp_setup_nav_menu_item' );
function cus_wp_setup_nav_menu_item($menu_item) {
                $menu_item->description = apply_filters( 'nav_menu_description',  $menu_item->post_content );
                return $menu_item;
  • For me this returns the content of the page, any way to fix this?
    – dingo_d
    Oct 3, 2014 at 11:54

The problem is not the DB doesn't contain the HTML, the filter seems to work at getting the information saved, the issue is that the menu administration page strips HTML, it's written into the walker that displays that page.

Take a look at line 167 here.

HTML is escaped when it's displayed, because naturally it's not suppose to support HTML, i'm not sure where that occurs exactly when displaying the nav menu frontside, but doing a little debugging and dumping of the $item variable lead to a discovery.

$item->post_content will hold the description, but with the HTML!!... use that in place of $item->description and you should get the result you're after.. ;)

Hope that helps.. :)

  • Ah nice... It's now outputting the html tags as text, but I can solve that I think. Thanks! Oddly, this still feels broken to me. The description call SHOULD work. It's referenced in several places on the WP support site and the codex entry for custom walkers points to a walker like my original one (wordpress.stackexchange.com/questions/14037/…). However, your way gets me what I want, so again, THANKS. Dec 14, 2011 at 0:55
  • Yeah i wasn't in the mood to keep digging(i understand what you're saying), there must be another function or method the data passes through before it reaches the walker(or something), but the workaround does work just fine and i've already had my share of digging through menu code today, lol..
    – t31os
    Dec 14, 2011 at 1:07

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.