¿Cómo agregar un campo personalizado en las propiedades avanzadas del menú?
¿Es posible agregar un campo personalizado a los elementos del menú?
Lo que quiero hacer es poder agregar un campo para 'Etiqueta de Navegación en Francés' y un 'Atributo de Título en Francés' en la interfaz del menú de WordPress.

Esto agregará un campo personalizado a la edición del elemento del menú. Sin embargo, no verás el campo personalizado hasta que hayas guardado el menú para el nuevo elemento añadido. Cuando añadas un elemento por primera vez, solo verás los campos estándar. Después de guardar, el nuevo campo estará disponible también para edición. Si añades elementos adicionales al menú, tendrás que guardar nuevamente el menú para ver y editar el campo personalizado para los nuevos elementos añadidos. Espero que esta explicación tenga sentido.
Pude crear y usar un walker personalizado para crear los campos de edición de elementos del menú. Cuando añades un elemento al menú por primera vez, parece que se crea completamente con jQuery en lugar del walker, por eso no verás el campo personalizado hasta después de guardar.
He llamado creativamente al campo personalizado que añadí "custom". Así que puedes cambiarlo/editar/duplicar para cualquier valor que necesites. Hay comentarios en el walker para mostrar dónde añadí el nuevo campo.
Espero que esto sea útil.
<?php
/**
* @package nav-menu-custom-fields
* @version 0.1.0
*/
/*
Plugin Name: Campos Personalizados para Menús de Navegación
*/
/*
* Guarda el nuevo campo en postmeta para la navegación
*/
add_action('wp_update_nav_menu_item', 'custom_nav_update',10, 3);
function custom_nav_update($menu_id, $menu_item_db_id, $args ) {
if ( is_array($_REQUEST['menu-item-custom']) ) {
$custom_value = $_REQUEST['menu-item-custom'][$menu_item_db_id];
update_post_meta( $menu_item_db_id, '_menu_item_custom', $custom_value );
}
}
/*
* Añade el valor del nuevo campo al objeto $item que será pasado a Walker_Nav_Menu_Edit_Custom
*/
add_filter( 'wp_setup_nav_menu_item','custom_nav_item' );
function custom_nav_item($menu_item) {
$menu_item->custom = get_post_meta( $menu_item->ID, '_menu_item_custom', true );
return $menu_item;
}
add_filter( 'wp_edit_nav_menu_walker', 'custom_nav_edit_walker',10,2 );
function custom_nav_edit_walker($walker,$menu_id) {
return 'Walker_Nav_Menu_Edit_Custom';
}
/**
* Copiado de la clase Walker_Nav_Menu_Edit en el núcleo
*
* Crea una lista HTML de elementos de entrada del menú de navegación.
*
* @package WordPress
* @since 3.0.0
* @uses Walker_Nav_Menu
*/
class Walker_Nav_Menu_Edit_Custom extends Walker_Nav_Menu {
/**
* @see Walker_Nav_Menu::start_lvl()
* @since 3.0.0
*
* @param string $output Pasado por referencia.
*/
function start_lvl(&$output) {}
/**
* @see Walker_Nav_Menu::end_lvl()
* @since 3.0.0
*
* @param string $output Pasado por referencia.
*/
function end_lvl(&$output) {
}
/**
* @see Walker::start_el()
* @since 3.0.0
*
* @param string $output Pasado por referencia. Usado para añadir contenido adicional.
* @param object $item Objeto de datos del elemento del menú.
* @param int $depth Profundidad del elemento del menú. Usado para padding.
* @param object $args
*/
function start_el(&$output, $item, $depth, $args) {
global $_wp_nav_menu_max_depth;
$_wp_nav_menu_max_depth = $depth > $_wp_nav_menu_max_depth ? $depth : $_wp_nav_menu_max_depth;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
ob_start();
$item_id = esc_attr( $item->ID );
$removed_args = array(
'action',
'customlink-tab',
'edit-menu-item',
'menu-item',
'page-tab',
'_wpnonce',
);
$original_title = '';
if ( 'taxonomy' == $item->type ) {
$original_title = get_term_field( 'name', $item->object_id, $item->object, 'raw' );
if ( is_wp_error( $original_title ) )
$original_title = false;
} elseif ( 'post_type' == $item->type ) {
$original_object = get_post( $item->object_id );
$original_title = $original_object->post_title;
}
$classes = array(
'menu-item menu-item-depth-' . $depth,
'menu-item-' . esc_attr( $item->object ),
'menu-item-edit-' . ( ( isset( $_GET['edit-menu-item'] ) && $item_id == $_GET['edit-menu-item'] ) ? 'active' : 'inactive'),
);
$title = $item->title;
if ( ! empty( $item->_invalid ) ) {
$classes[] = 'menu-item-invalid';
/* traductores: %s: título del elemento del menú que es inválido */
$title = sprintf( __( '%s (Inválido)' ), $item->title );
} elseif ( isset( $item->post_status ) && 'draft' == $item->post_status ) {
$classes[] = 'pending';
/* traductores: %s: título del elemento del menú en estado de borrador */
$title = sprintf( __('%s (Pendiente)'), $item->title );
}
$title = empty( $item->label ) ? $title : $item->label;
?>
<li id="menu-item-<?php echo $item_id; ?>" class="<?php echo implode(' ', $classes ); ?>">
<dl class="menu-item-bar">
<dt class="menu-item-handle">
<span class="item-title"><?php echo esc_html( $title ); ?></span>
<span class="item-controls">
<span class="item-type"><?php echo esc_html( $item->type_label ); ?></span>
<span class="item-order hide-if-js">
<a href="<?php
echo wp_nonce_url(
add_query_arg(
array(
'action' => 'move-up-menu-item',
'menu-item' => $item_id,
),
remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
),
'move-menu_item'
);
?>" class="item-move-up"><abbr title="<?php esc_attr_e('Mover arriba'); ?>">↑</abbr></a>
|
<a href="<?php
echo wp_nonce_url(
add_query_arg(
array(
'action' => 'move-down-menu-item',
'menu-item' => $item_id,
),
remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
),
'move-menu_item'
);
?>" class="item-move-down"><abbr title="<?php esc_attr_e('Mover abajo'); ?>">↓</abbr></a>
</span>
<a class="item-edit" id="edit-<?php echo $item_id; ?>" title="<?php esc_attr_e('Editar Elemento del Menú'); ?>" href="<?php
echo ( isset( $_GET['edit-menu-item'] ) && $item_id == $_GET['edit-menu-item'] ) ? admin_url( 'nav-menus.php' ) : add_query_arg( 'edit-menu-item', $item_id, remove_query_arg( $removed_args, admin_url( 'nav-menus.php#menu-item-settings-' . $item_id ) ) );
?>"><?php _e( 'Editar Elemento del Menú' ); ?></a>
</span>
</dt>
</dl>
<div class="menu-item-settings" id="menu-item-settings-<?php echo $item_id; ?>">
<?php if( 'custom' == $item->type ) : ?>
<p class="field-url description description-wide">
<label for="edit-menu-item-url-<?php echo $item_id; ?>">
<?php _e( 'URL' ); ?><br />
<input type="text" id="edit-menu-item-url-<?php echo $item_id; ?>" class="widefat code edit-menu-item-url" name="menu-item-url[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->url ); ?>" />
</label>
</p>
<?php endif; ?>
<p class="description description-thin">
<label for="edit-menu-item-title-<?php echo $item_id; ?>">
<?php _e( 'Etiqueta de Navegación' ); ?><br />
<input type="text" id="edit-menu-item-title-<?php echo $item_id; ?>" class="widefat edit-menu-item-title" name="menu-item-title[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->title ); ?>" />
</label>
</p>
<p class="description description-thin">
<label for="edit-menu-item-attr-title-<?php echo $item_id; ?>">
<?php _e( 'Atributo Título' ); ?><br />
<input type="text" id="edit-menu-item-attr-title-<?php echo $item_id; ?>" class="widefat edit-menu-item-attr-title" name="menu-item-attr-title[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->post_excerpt ); ?>" />
</label>
</p>
<p class="field-link-target description">
<label for="edit-menu-item-target-<?php echo $item_id; ?>">
<input type="checkbox" id="edit-menu-item-target-<?php echo $item_id; ?>" value="_blank" name="menu-item-target[<?php echo $item_id; ?>]"<?php checked( $item->target, '_blank' ); ?> />
<?php _e( 'Abrir enlace en una nueva ventana/pestaña' ); ?>
</label>
</p>
<p class="field-css-classes description description-thin">
<label for="edit-menu-item-classes-<?php echo $item_id; ?>">
<?php _e( 'Clases CSS (opcional)' ); ?><br />
<input type="text" id="edit-menu-item-classes-<?php echo $item_id; ?>" class="widefat code edit-menu-item-classes" name="menu-item-classes[<?php echo $item_id; ?>]" value="<?php echo esc_attr( implode(' ', $item->classes ) ); ?>" />
</label>
</p>
<p class="field-xfn description description-thin">
<label for="edit-menu-item-xfn-<?php echo $item_id; ?>">
<?php _e( 'Relación de Enlace (XFN)' ); ?><br />
<input type="text" id="edit-menu-item-xfn-<?php echo $item_id; ?>" class="widefat code edit-menu-item-xfn" name="menu-item-xfn[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->xfn ); ?>" />
</label>
</p>
<p class="field-description description description-wide">
<label for="edit-menu-item-description-<?php echo $item_id; ?>">
<?php _e( 'Descripción' ); ?><br />
<textarea id="edit-menu-item-description-<?php echo $item_id; ?>" class="widefat edit-menu-item-description" rows="3" cols="20" name="menu-item-description[<?php echo $item_id; ?>]"><?php echo esc_html( $item->description ); // textarea_escaped ?></textarea>
<span class="description"><?php _e('La descripción se mostrará en el menú si el tema actual lo soporta.'); ?></span>
</label>
</p>
<?php
/*
* Este es el campo añadido
*/
?>
<p class="field-custom description description-wide">
<label for="edit-menu-item-custom-<?php echo $item_id; ?>">
<?php _e( 'Personalizado' ); ?><br />
<input type="text" id="edit-menu-item-custom-<?php echo $item_id; ?>" class="widefat code edit-menu-item-custom" name="menu-item-custom[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->custom ); ?>" />
</label>
</p>
<?php
/*
* fin del campo añadido
*/
?>
<div class="menu-item-actions description-wide submitbox">
<?php if( 'custom' != $item->type && $original_title !== false ) : ?>
<p class="link-to-original">
<?php printf( __('Original: %s'), '<a href="' . esc_attr( $item->url ) . '">' . esc_html( $original_title ) . '</a>' ); ?>
</p>
<?php endif; ?>
<a class="item-delete submitdelete deletion" id="delete-<?php echo $item_id; ?>" href="<?php
echo wp_nonce_url(
add_query_arg(
array(
'action' => 'delete-menu-item',
'menu-item' => $item_id,
),
remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
),
'delete-menu_item_' . $item_id
); ?>"><?php _e('Eliminar'); ?></a> <span class="meta-sep"> | </span> <a class="item-cancel submitcancel" id="cancel-<?php echo $item_id; ?>" href="<?php echo esc_url( add_query_arg( array('edit-menu-item' => $item_id, 'cancel' => time()), remove_query_arg( $removed_args, admin_url( 'nav-menus.php' ) ) );
?>#menu-item-settings-<?php echo $item_id; ?>"><?php _e('Cancelar'); ?></a>
</div>
<input class="menu-item-data-db-id" type="hidden" name="menu-item-db-id[<?php echo $item_id; ?>]" value="<?php echo $item_id; ?>" />
<input class="menu-item-data-object-id" type="hidden" name="menu-item-object-id[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->object_id ); ?>" />
<input class="menu-item-data-object" type="hidden" name="menu-item-object[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->object ); ?>" />
<input class="menu-item-data-parent-id" type="hidden" name="menu-item-parent-id[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->menu_item_parent ); ?>" />
<input class="menu-item-data-position" type="hidden" name="menu-item-position[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->menu_order ); ?>" />
<input class="menu-item-data-type" type="hidden" name="menu-item-type[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->type ); ?>" />
</div><!-- .menu-item-settings-->
<ul class="menu-item-transport"></ul>
<?php
$output .= ob_get_clean();
}
}
?>

Gracias @djrmom. Mejoré lo que me mostraste creando una clase que gestiona la creación de campos y los muestra en un bucle en el walker.

@cbaigorri ¿no tendrás esa Clase todavía por ahí en tu computadora? ¿Podrías compartirla?

Acabo de hacer un plugin de prueba de concepto que es muy similar a esto. Pero en lugar de sobrescribir todo el método start_el()
, usé phpQuery para "inyectar" campos adicionales en el html: http://changeset.hr/blog/code/wordpress-menu-item-meta-fields

¿Cómo se obtiene el valor personalizado? Intenté usar get_post_meta pero no veo nada.

¿Y cómo hacer que realmente funcione? Todo lo que veo es una definición de clase

WordPress tiene la capacidad de permitir a los autores de publicaciones asignar campos personalizados a una publicación.
http://codex.wordpress.org/Custom_Fields
Pero - modificar la funcionalidad de la interfaz de usuario del menú probablemente sea algo que tendrías que hacer con un plugin. No estoy seguro si WordPress soporta este tipo de modificaciones por defecto.
Podrías escribir un plugin que use Javascript y agregue esos campos de entrada donde se necesiten, luego los guarde, y agregue un filtro a los elementos del menú cuando se usen en el sitio.
