¿Por qué wp_get_nav_menu_items() no funciona con el slug?
Según la documentación, el primer parámetro de wp_get_nav_menu_items()
acepta:
(string) (Obligatorio) Nombre del menú, ID o slug.
Así es como estoy registrando mis menús:
register_nav_menus(
array(
'primary' => 'Navegación principal',
'secondary' => 'Navegación secundaria',
)
);
Así es como he intentado cargar uno:
var_dump( wp_get_nav_menu_items('primary') ); // bool(false)
var_dump( wp_get_nav_menu_items('navegacion-principal') ); // bool(false)
var_dump( wp_get_nav_menu_items('Navegación principal') ); // bool(false)
var_dump( wp_get_nav_menu_items(51) ); // array([...]) (correcto)
La función solo devuelve el menú cuando uso el ID. Preferiría usar el slug ya que mi sitio es multilingüe y no quiero tener que usar diferentes IDs según el idioma.
¿Estoy haciendo algo mal o es un error del núcleo de WordPress? He probado esto en el tema TwentySixteen con mi plugin multilingüe desactivado (Polylang).

Dado que nadie ha explicado realmente por qué la función no funciona como pensabas, intentaré explicarlo en detalle ya que acabo de caer en la misma trampa que tú.
Aquí es donde la documentación no es muy clara sobre a qué se refiere con el "slug". La mayoría asumiría que es el slug del menú registrado, pero eso no es correcto. En realidad se refiere al slug del término para la taxonomía nav_menu.
Profundicemos en el código fuente para ver cómo el núcleo de WordPress interpreta el slug del menú.
function wp_get_nav_menu_items( $menu, $args = array() ) {
$menu = wp_get_nav_menu_object( $menu );
....
La primera línea muestra que usa una función llamada wp_get_nav_menu_object() para recuperar el menú. Pasa el $menu
como primer parámetro a esta función. Ya que esto es lo que usamos para nuestro slug, tendremos que ver el código fuente de wp_get_nav_menu_object()
.
function wp_get_nav_menu_object( $menu ) {
$menu_obj = false;
if ( is_object( $menu ) ) {
$menu_obj = $menu;
}
if ( $menu && ! $menu_obj ) {
$menu_obj = get_term( $menu, 'nav_menu' );
if ( ! $menu_obj ) {
$menu_obj = get_term_by( 'slug', $menu, 'nav_menu' );
}
if ( ! $menu_obj ) {
$menu_obj = get_term_by( 'name', $menu, 'nav_menu' );
}
}
....
Podemos ver que esta función usa get_term_by
para recuperar el $menu_obj
. Aquí es donde obtenemos nuestro menú.
Cuando creas un menú en el área de administración de WordPress, crea un nuevo término. Los términos tienen slugs basados en su nombre. Así que si tienes un menú llamado "Mi Menú Increíble", WordPress generará un slug llamado "mi-menu-increible". Puedes haber registrado el menú como "primary" pero ese no es el slug al que se refieren estas funciones. En realidad es el slug del término del menú.
Para aclarar, digamos que registraste un menú así:
register_nav_menu('primary', 'mi navegación principal');
primary
no es el slug. mi-navegacion-principal
tampoco es el slug.
Ya que creamos un menú llamado "Mi Menú Increíble" (como ejemplo), y el slug es 'mi-menu-increible', puedes recuperarlo así:
$menu_increible = wp_get_nav_menu_items( 'mi-menu-increible' );
Puedes ver tú mismo cuál es el slug revisando la base de datos en la tabla wp_terms (o cualquiera que sea tu prefijo) y buscar el nombre de tu menú allí.
Como estás usando un sitio multilingüe o incluso multisitio, este método no será el mejor. Ya que el nombre y el slug podrían ser diferentes.
Así que el mejor método es obtener todas las ubicaciones de menú con get_nav_menu_locations()
que devolverá un array asociativo donde la clave es el slug del menú registrado y el valor es el id del término de menú seleccionado para su ubicación.
Con el id del término, podemos obtener la información de ese término y luego devolver el slug correcto que requiere la función.
A continuación hay una función que utiliza wp_get_nav_items()
pero pasarías el slug del menú registrado. En tu caso sería 'primary'.
Solución de Código
// un nombre de función algo largo pero bueno
function get_menu_items_by_registered_slug($menu_slug) {
$menu_items = array();
if ( ( $locations = get_nav_menu_locations() ) && isset( $locations[ $menu_slug ] ) ) {
$menu = get_term( $locations[ $menu_slug ] );
$menu_items = wp_get_nav_menu_items($menu->term_id);
}
return $menu_items;
}

Pequeña modificación a la respuesta aceptada
Después de eliminar un menú de su ubicación, $locations[ $menu_slug ]
retorna 0
, por lo que es bueno agregar esta verificación:
function get_menu_items_by_registered_slug($menu_slug) {
$menu_items = array();
if ( ($locations = get_nav_menu_locations()) && isset($locations[$menu_slug]) && $locations[$menu_slug] != 0 ) {
$menu = get_term( $locations[ $menu_slug ] );
$menu_items = wp_get_nav_menu_items($menu->term_id);
}
return $menu_items;
}

No parece funcionar para mí. get_nav_menu_locations()
devuelve un array con un solo elemento ('primary' => 51
), pero wp_get_nav_menu_items()
devuelve false cuando se usa un slug.

custom_menu('primary');
function custom_menu( $theme_location ) {
if ( ($theme_location) && ($locations = get_nav_menu_locations()) && isset($locations[$theme_location]) ) {
$menu = get_term( $locations[$theme_location], 'nav_menu' );
$menu_items = wp_get_nav_menu_items($menu->term_id);
//tu código del menú.
}
