I have created a custom menu which is usable from the wp-admin. I call it using wp_nav_menu and the menu is created in an ul as text-only links. I wonder if there is a way to change these text-links and add a different image (img src="pic.jpg")to each anchor tag somehow? I tried to mess around with the 'items_wrap' argument in the wp_nav_menu call but with no success.

I have another menu which is hardcoded with anchor links with different images to each link and I want to transfer this functionality to the custom menu I hav created.

UPDATE Do follow the below tip and read up on that article, I ended up with fiddling around with it til it worked. The steps there will add a extra input field in wp-admin which is hooked onto every list-item and then you can experiment with altering this output to suit your needs and I got it to work with an img src.


Menu items are saved as posts with the post_type "nav_menu_item". This means you can assign postmeta to them just like you can with posts and create custom fields in the menu edit screen to enter an img url or assign a media ID.

You can follow this tutorial about adding custom meta to menu items to suit your needs. If you need help, I can throw together some code bits to get you rolling.

UPDATE I put together this bit that allows you to drop into functions.php. Untested, but should work. It's a different approach then the link I originally shared but it's a method I've used in the past.

//Adds custom data field form
function wpse_259995_menu_custom_fields_fields( $id, $item, $depth, $args ) {

  $_key = 'img_url';
  $label = "Image URL";
  $key   = sprintf( 'menu-item-%s', $_key );
  $id    = sprintf( 'edit-%s-%s', $key, $item->ID );
  $name  = sprintf( '%s[%s]', $key, $item->ID );
  $value = get_post_meta( $item->ID, $key, true );
  $class = sprintf( 'field-%s', $_key );

    '<p class="%5$s"><label for="%1$s">%2$s<br />
    <input type="text" id="%1$s" class="%5$s" name="%3$s" value="%4$s" /></label></p>',
    esc_attr( $id ),
    esc_html( $label ),
    esc_attr( $name ),
    esc_url( $value ),
    esc_attr( $class )
add_action( 'wp_nav_menu_item_custom_fields', 'wpse_259995_menu_custom_fields_fields', 10, 4 );

//Save Custom Menu data
function wpse_259995_menu_custom_fields_save( $menu_id, $menu_item_db_id, $menu_item_args ) {
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {

  check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' );
  $_key = 'img_url';
  $label = "Image URL";

  $key = sprintf( 'menu-item-%s', $_key );

  // Sanitize
  if ( ! empty( $_POST[ $key ][ $menu_item_db_id ] ) ) {
    // Do some checks here...
    $value = $_POST[ $key ][ $menu_item_db_id ];
  else {
    $value = null;

  // Update
  if ( ! is_null( $value ) ) {
    update_post_meta( $menu_item_db_id, $key, $value );
  else {
    delete_post_meta( $menu_item_db_id, $key );
add_action( 'wp_update_nav_menu_item', 'wpse_259995_menu_custom_fields_save', 10, 3 );

//Adds toggle to show field in screen options
function wpse_259995_menu_custom_fields_columns( $columns ) {
  $fields = array('img_url' => "Imae URL");
  $columns = array_merge( $columns, $fields );
  return $columns;
add_filter( 'manage_nav-menus_columns', 'wpse_259995_menu_custom_fields_columns', 99 );

//Modify the element of the WP walker
function wpse_259995_walker_nav_menu_start_el_menu_with_images ($item_output, $item, $depth, $args ){
  $attr_title  = ! empty( $item->attr_title ) ? $item->attr_title : $item->title;

  $img_url = get_post_meta( $item->ID, 'menu-item-img_url', true );

  $item_output = $args->before;
  $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . '<img src="'.$img_url.'" />' . $args->link_after;
  $item_output .= $args->after;
  return $item_output;

Then, in your header.php (or wherever you are calling your menu):

add_filter( 'walker_nav_menu_start_el', 'wpse_259995_walker_nav_menu_start_el_menu_with_images', 10, 4 );
wp_nav_menu( /*Call your menu*/ );
remove_filter( 'walker_nav_menu_start_el', 'wpse_259995_walker_nav_menu_start_el_menu_with_images', 10, 4 );

UPDATE I forgot that when I used this solution a few years ago it was in conjunction with this plugin that provided the hook "wp_nav_menu_item_custom_fields" https://wordpress.org/plugins/menu-item-custom-fields/installation/

You'll need to install that plugin (or reuse the code) to get this to work.

  • Thank you, Im reading through the tutorial at the moment, but it seems a bit over my head but I will give it a try. I have also seen posts about adding a span in the 'before' and 'after' arguments when calling the wp_nav_menu - is this a good solution too and if so, which should I try to use? Also, I would love some sample if you dont mind! – emcolsson Mar 14 '17 at 12:24
  • Also, if I were to create a custom plugin with a new field to that menu for example - isnt it needed for all themes to activate this plugin too? I want to make a custom template that can be used by others without installing extra material. Can I add the plugin to my theme-root? Or is it possible to do it all tihout creating a "external" plugin and just add the corresponding code to functions.php for example? – emcolsson Mar 14 '17 at 12:34
  • You can absolutely just add the code into your functions.php which acts (somewhat) like a plugin. As for the <span> in the 'before' and 'after', I assume what you've seen only allows the same span to be added to each menu item. If I understand correctly, you want a unique bit of code (ie an img tag) in each menu item. – danbrellis Mar 14 '17 at 12:49
  • btw, i'm putting together some code you could drop into functions.php – danbrellis Mar 14 '17 at 12:56
  • I followed the steps and tried to use it in my functions. I got to the point where the new field is showing in wp-admin, but when I add the custom_walker.php my website goes blank and wp-admin is no longer working. Functions.php:[link]paste.ofcode.org/cDfbnm5ZQddufKLPaXJXr2 Ive also created the edit_custom_walker.php and custom_walker.php, pasted the code and changed whats needed. Custom walker.php: [link]paste.ofcode.org/uGBiC9EhMtDCsinQ9CJCJk and then where I want to call the menu; <?php wp_nav_menu( array('menu' => 'main','walker' => new walker)); ?> – emcolsson Mar 14 '17 at 13:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.