Show menu item description with line breaks

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