WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a menu, that I need to insert an image that have it's path saved in a meta key (_menu_item_img) and associated with a post ID, every menu entry has it's own image, and I need to grab it dynamically.

The approach I tried, and I can't find anything on google that could help me out.

wp_nav_menu( array( 'container' =>false, 'theme_location' => 'main_menu', 'menu_id' => 'main_menu', 'link_before' => get_post_meta($item->object_id, '_menu_item_img'))));

This is the class I'm using for adding a custom entry into the menu page:

add_action( 'init', array( 'XTeam_Nav_Menu_Item_Custom_Fields', 'setup' ) );

class XTeam_Nav_Menu_Item_Custom_Fields {
    static $options = array(
        'item_tpl' => '
            <p class="additional-menu-field-{name} description description-thin">
                <label for="edit-menu-item-{name}-{id}">
                        class="widefat code edit-menu-item-{name}"

    static function setup() {
        // @todo we can do some merging of provided options from WP options for from config
        self::$options['fields'] = array(
            'color' => array(
                'name' => 'img',
                'label' => __('Link para Imagem', 'xteam'),
                'container_class' => 'link-img',
                'input_type' => 'text',

        add_filter( 'wp_edit_nav_menu_walker', function () {
            return 'XTeam_Walker_Nav_Menu_Edit';
        add_filter( 'xteam_nav_menu_item_additional_fields', array( __CLASS__, '_add_fields' ), 10, 5 );
        add_action( 'save_post', array( __CLASS__, '_save_post' ) );

    static function get_fields_schema() {
        $schema = array();
        foreach(self::$options['fields'] as $name => $field) {
            if (empty($field['name'])) {
                $field['name'] = $name;
            $schema[] = $field;
        return $schema;

    static function get_menu_item_postmeta_key($name) {
        return '_menu_item_' . $name;

     * Inject the 
     * @hook {action} save_post
    static function _add_fields($new_fields, $item_output, $item, $depth, $args) {
        $schema = self::get_fields_schema($item->ID);
        foreach($schema as $field) {
            $field['value'] = get_post_meta($item->ID, self::get_menu_item_postmeta_key($field['name']), true);
            $field['id'] = $item->ID;
            $new_fields .= str_replace(
                array_map(function($key){ return '{' . $key . '}'; }, array_keys($field)),
                array_values(array_map('esc_attr', $field)),
        return $new_fields;

     * Save the newly submitted fields
     * @hook {action} save_post
    static function _save_post($post_id) {
        if (get_post_type($post_id) !== 'nav_menu_item') {
        $fields_schema = self::get_fields_schema($post_id);
        foreach($fields_schema as $field_schema) {
            $form_field_name = 'menu-item-' . $field_schema['name'];
            if (isset($_POST[$form_field_name][$post_id])) {
                $key = self::get_menu_item_postmeta_key($field_schema['name']);
                $value = stripslashes($_POST[$form_field_name][$post_id]);
                update_post_meta($post_id, $key, $value);


require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
class XTeam_Walker_Nav_Menu_Edit extends Walker_Nav_Menu_Edit {
    function start_el(&$output, $item, $depth, $args) {
        $item_output = '';
        parent::start_el($item_output, $item, $depth, $args);
        $new_fields = apply_filters( 'xteam_nav_menu_item_additional_fields', '', $item_output, $item, $depth, $args );
        // Inject $new_fields before: <div class="menu-item-actions description-wide submitbox">
        if ($new_fields) {
            $item_output = preg_replace('/(?=<div[^>]+class="[^"]*submitbox)/', $new_fields, $item_output);
        $output .= $item_output;

Can someone point me out where I am missing the point?

share|improve this question

This code:

wp_nav_menu( array( 'container' =>false, 'theme_location' => 'main_menu', 'menu_id' => 'main_menu', 'link_before' => get_post_meta($item->object_id, '_menu_item_img'))));

Makes me think that the problem in on the front end when you try to display the values. For readability (and without the extra )):

    'container' =>false, 
    'theme_location' => 'main_menu', 
    'menu_id' => 'main_menu', 
    'link_before' => get_post_meta($item->object_id, '_menu_item_img')

Essentially, the problem is pure PHP. If you had debugging enabled you'd notice that there is a Notice on the line where that code runs. That is because $item is not defined at that point. $item is defined as the walker callback actually executes but PHP doesn't notice your variable and wait until later to try to make sense of it. It is processed right there, when it is used.

You will need to create a custom walker for the front end display (something like this).

A filter on the_title might also do it:

function pre_title_wpse_134186($title) {
  return 'test'.$title;
    'container' =>false, 
    'theme_location' => 'main_menu', 
    'menu_id' => 'main_menu',
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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