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.

1 Answer 1


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, 2017 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, 2017 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, 2017 at 12:49
  • btw, i'm putting together some code you could drop into functions.php
    – danbrellis
    Mar 14, 2017 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, 2017 at 13:47

This site is temporarily in read-only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .