Site icon WP Smith

How to Add Menu Descriptions & Featured Images to WordPress Menu Items

Recently I read an awesome post by Bill Erickson about customizing WordPress menus. However, there are two things I wanted this class to do that in its original form it doesn't do.

So since out of the box, WordPress doesn't intuitively allow you to add descriptions to the menu without requiring some custom code, rather the Walker class extended.

Since Bill has done an excellent job at this I will extend his code to add the options of having a featured image and/or descriptions applied based on depth.

Add this to your functions.php file.

<?php
class Menu_With_Description 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 ) . '"' : '';
// get user defined attributes for thumbnail images
$attr_defaults = array(
'class' => 'nav_thumb',
'alt' => esc_attr( $item->attr_title ),
'title' => esc_attr( $item->attr_title )
);
$attr = isset( $args->thumbnail_attr ) ? $args->thumbnail_attr : '';
$attr = wp_parse_args( $attr, $attr_defaults );
$item_output = $args->before;
// thumbnail image output
$item_output .= ( isset( $args->thumbnail_link ) && $args->thumbnail_link ) ? '<a' . $attributes . '>' : '';
$item_output .= apply_filters( 'menu_item_thumbnail', ( isset( $args->thumbnail ) && $args->thumbnail ) ? get_the_post_thumbnail( $item->object_id, ( isset( $args->thumbnail_size ) ) ? $args->thumbnail_size : 'thumbnail', $attr ) : '', $item, $args, $depth );
$item_output .= ( isset( $args->thumbnail_link ) && $args->thumbnail_link ) ? '</a>' : '';
// menu link output
$item_output .= '<a' . $attributes . '>';
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
// menu description output based on depth
$item_output .= ( $args->desc_depth >= $depth ) ? '<br /><span class="sub">' . $item->description . '</span>' : '';
// close menu link anchor
$item_output .= '</a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}

 

All Menus

To highjack ALL of your menus, enter this code in your functions.php.

<?php
add_filter( 'wp_nav_menu_args', 'my_add_menu_descriptions' );
function my_add_menu_descriptions( $args ) {
$args['walker'] = new Menu_With_Description;
$args['desc_depth'] = 0;
$args['thumbnail'] = true;
$args['thumbnail_link'] = false;
$args['thumbnail_size'] = 'nav_thumb';
$args['thumbnail_attr'] = array( 'class' => 'nav_thumb my_thumb', 'alt' => 'test', 'title' => 'test' );
return $args;
}

Menus Based on Location

To highjack a menu based on registered and assigned location, then use this code in your functions.php.

<?php
add_filter( 'wp_nav_menu_args', 'my_add_menu_descriptions' );
function my_add_menu_descriptions( $args ) {
if ( $args['theme_location'] == 'primary' ) {
$args['walker'] = new Menu_With_Description;
$args['desc_depth'] = 0;
$args['thumbnail'] = true;
$args['thumbnail_link'] = false;
$args['thumbnail_size'] = 'nav_thumb';
$args['thumbnail_attr'] = array( 'class' => 'nav_thumb my_thumb', 'alt' => 'test', 'title' => 'test' );
}
return $args;
}

 

Menus via WordPress Custom Menu Widget

To highjack a custom menu based menu id that is called using the custom menu widget, or even a manual method (if the menu is being called by a location, you must use 'theme_location'), then use this code in your functions.php. This will highjack any menu called by the custom menu widget assuming you only have the standard registered theme locations. The example below assumes a standard theme custom menu registered locations for Genesis. Change 'primary' and/or 'secondary' to whatever your theme adds and add whatever more menus that your theme has to only target the custom menu widget.

<?php
add_filter( 'wp_nav_menu_args', 'my_add_menu_descriptions' );
function my_add_menu_descriptions( $args ) {
if ( $args['theme_location'] != 'primary' && $args['theme_location'] != 'secondary' ) {
$args['walker'] = new Menu_With_Description;
$args['desc_depth'] = 0;
$args['thumbnail'] = true;
$args['thumbnail_link'] = false;
$args['thumbnail_size'] = 'nav_thumb';
$args['thumbnail_attr'] = array( 'class' => 'nav_thumb my_thumb', 'alt' => 'test', 'title' => 'test' );
}
return $args;
}

There is a caveat though. There are certain menu items that may not have a featured image such as custom links, categories, etc. There is a possible work-around that I am trying to work out.

Here is the result of a sandbox description and featured images for all types (not just pages and posts), which I will be posting soon or writing up into a plugin...