Show menu item description with line breaks

I have a problem with my theme…

I use Agama, and i’ve checkmarked “description” in the menu settings, but it won’t display it on the frontend, since the theme doesn’t allow it.

But then I found this function:

function prefix_nav_description( $item_output, $item, $depth, $args ) {
if ( !empty( $item->description ) ) {
    $item_output = str_replace( $args->link_after . '</a>', '<span class="menu-item-description">' . $item->description . '</span>' . $args->link_after . '</a>', $item_output );
}
return $item_output;
}
add_filter( 'walker_nav_menu_start_el', 'prefix_nav_description', 10, 4 );

That helped me get the description to be shown.
But i can’t make line-breaks in my description. Everytime I just make a line-break or inserts
and save the changes, it removes the changes again.

So can anyone help me with a function that both makes the description be showned and also makes it possible for me to add
in the description.

Thanks 😀

1 Answer
1

OK, it took me a little while to debug this behaviour, but… Everything is clear for me right now… I’m not sure if this is fully intentional…

Why is it so?

So… The line breaks are stored in DB correctly. Then in wp_setup_nav_menu_item the description field is filled based on post_content column of given menu item post.

On line 845 (https://core.trac.wordpress.org/browser/tags/4.9/src/wp-includes/nav-menu.php#L845) it is shortened and filtered:

if ( ! isset( $menu_item->description ) ) {
    /**
     * Filters a navigation menu item's description.
     *
     * @since 3.0.0
     *
     * @param string $description The menu item description.
    */
    $menu_item->description = apply_filters( 'nav_menu_description', wp_trim_words( $menu_item->post_content, 200 ) );
}

And the wp_trim_words function trims text to a certain number of words, but it doesn’t preserve line breaks – so any line break is replaced with space.

So what can we do about it?

There are no filters in wp_trim_words that will allow us to modify its behaviour. There is also no filters that will allow us to skip wp_trim_words call, but…

You can replace the \n with some placeholder and then use nav_menu_description filter to replace it back. There even is no need that users put this placeholder himself – we can replace them with a placeholder with save_post filter:

function replace_nl_placeholder_nav_menu_description( $description ) {
    return str_replace('%NL% ', "\n", $description);
}
add_filter('nav_menu_description', 'replace_nl_placeholder_nav_menu_description');

function replace_nl_with_placeholder_nav_menu_description( $post_id ) {
    if ( 'nav_menu_item' !== get_post_type($post_id) ) return;

    remove_action( 'save_post', 'replace_nl_with_placeholder_nav_menu_description' );

    wp_update_post( array(
        'ID' => $post_id,
        'post_content' => str_replace("\n", '%NL% ', get_post_field('post_content', $post_id, 'raw'))
    ) );

    add_action( 'save_post', 'replace_nl_with_placeholder_nav_menu_description' );
}
add_action( 'save_post', 'replace_nl_with_placeholder_nav_menu_description' );

And that’s all. You only have to remember to properly display such line breaks in your theme (nl2br and so on).

Leave a Comment