Aprenda a escribir caminantes de menú para menús de WordPress
WordPress permite el uso de las llamadas clases Walker para recorrer y mostrar elementos en una estructura jerárquica. En esta publicación, aprenderemos cómo crear, implementar y personalizar nuestra propia clase de caminante para personalizar la salida de nuestro menú.
El uso más conocido de la personalización con las clases de Walker en WordPress es para los menús, pero en realidad WordPress usa las clases de Walker para un montón de casos, por ejemplo, generar jerarquías de taxonomía, jerarquías de comentarios [wp_list_pages](https://developer.wordpress.org/reference/functions/wp_list_pages/)()y archivos [wp_list_categories](https://developer.wordpress.org/reference/functions/wp_list_categories/)(). Todos extienden una Walkerclase general. Ampliaremos el Walker_Nav_Menuque se usa para los menús en WordPress.
Debido a que extendemos otra clase, solo necesitamos agregar las funciones que deseamos anular. Si una función no existe en nuestra clase, WordPress ejecutará la función de la clase principal (la clase que extendemos) en su lugar.
Preparación
Puede agregar su clase de caminante en sus archivos de complemento, temas function.phpo cualquier archivo PHP incluido por functions.php(para un código más limpio). Comienza definiendo tu clase con un nombre de tu elección (¡asegúrate de que el nombre de la clase sea único, y esto incluye posibles nombres de clase en el núcleo de WordPress!) extendiendo Walker_Nav_Menu:
class AWP_Menu_Walker extends Walker_Nav_Menu {
}
Para decirle a WordPress que use nuestro andador, lo definimos en nuestras [wp_nav_menu](https://developer.wordpress.org/reference/functions/wp_nav_menu/)()llamadas. Esta función es responsable de generar un menú y probablemente tenga al menos uno en su tema para el menú principal.
En la matriz de argumentos wp_nav_menu(), agregue un nuevo elemento con la clave ‘walker’ y cree una nueva instancia de su clase walker de la siguiente manera:
wp_nav_menu([
'theme_location' => 'primary',
'menu_class' => 'main-menu',
'container' => 'nav',
'container_class' => 'header__main-nav',
'walker' => new AWP_Menu_Walker()
]);
Si actualiza su sitio, no debería ver ningún cambio. Esto se debe a que nuestra clase no anula ninguna de las funciones de los padres y, por lo tanto, WordPress simplemente ejecuta las funciones normales del caminante del menú cuando genera el menú, tal como antes le dijimos que usara nuestro caminante.
Las siguientes son funciones que puede agregar a su clase de caminante personalizada para anular las funciones de la clase de crianza Walker_Nav_Menu:
Las primeras cuatro son funciones que son simplemente responsables de la salida, y todas requieren que agregue una cadena: la primera variable de parámetro. Es importante saber que no haces echonada aquí, se supone que todo debe construirse como una cadena.
inicio_lvl
La función start_lvles responsable de generar el HTML para el inicio de un nuevo nivel. En resumen, debería dar salida al archivo de inicio <ul>.
function start_lvl(&$output, $depth=0, $args=null) { }
El primer parámetro, $outputpasado por referencia, es la cadena a la que agregará su salida. $depthes un número entero que indica en qué nivel se encuentra; 0 para el nivel superior, 1 para el hijo directo del nivel superior, y así sucesivamente. $argses un objeto de todos los argumentos proporcionados en wp_nav_menu().
fin_lvl
La end_lvlfunción es responsable de generar el HTML para el final de un nivel. Esto suele ser sólo el cierre </ul>.
function end_lvl(&$output, $depth=0, $args=null) { }
Los parámetros son exactamente los mismos que los start_lvlanteriores.
start_el
Esta función es responsable de generar el HTML de cada elemento. En resumen, debería generar el inicio <li>y la <a>etiqueta con el título del enlace dentro.
function start_el(&$output, $item, $depth=0, $args=null, $id=0) { }
El primer argumento, $output, es como de costumbre la cadena a la que agregará la salida. El segundo argumento, $item, es el objeto del elemento del menú, y aquí es donde obtendrá la mayoría de los datos para generar el elemento del menú. Si el enlace del menú es un elemento del menú de publicación, obtendrá el objeto de publicación aquí. Independientemente del tipo de menú, también obtendrá algunos elementos útiles adicionales; como classes, url, titley description.
El tercer argumento, $depth, es un número entero que le dice en qué nivel estamos. El nivel 0 es el nivel superior, el 1 es hijo directo del nivel superior, y así sucesivamente. El cuarto argumento, $args, es un objeto de todos los argumentos proporcionados a wp_nav_menu(). El quinto parámetro, $id, es el ID del elemento de menú actual.
end_el
La end_elfunción es responsable de dar salida al cierre de un elemento. Por lo general, solo generaría la </li>etiqueta.
function end_el(&$output, $item, $depth=0, $args=null) { }
Los argumentos para end_elson los mismos que start_ellos anteriores, excepto que la función no tiene el quinto parámetro, $id.
mostrar_elemento
La función display_elementes una función heredada de la Walkerclase general y es la función responsable de atravesar. Esta es la función que llama a todas las funciones anteriores a su vez.
Incluyo esto aquí porque en algunos casos, por ejemplo, si desea evitar atravesar una rama completa, usaría esta función para eso.
function display_element($element, &$children_elements, $max_depth, $depth, $args, &$output) { }
El primer argumento, $element, es el objeto del elemento de menú: esto es lo que se transmite como $itemen las funciones anteriores. El segundo argumento, $children_elementspasado por referencia, contiene todos los elementos secundarios que atravesará esta función. $max_depth, el tercer argumento, es un número entero que indica qué tan profundo debemos atravesar, y el cuarto argumento $depth, es la profundidad a la que nos encontramos actualmente. El quinto argumento, $args, son los argumentos pasados a la función que llamó al caminante (para los menús serían los argumentos proporcionados a wp_nav_menu()), y el argumento final, $outputpasado por referencia, es la salida que se pasa como primer argumento en todos de las funciones anteriores.
Modificar la salida de cada elemento
En la descripción general anterior, debería ver que la función start_el()es la responsable de generar el HTML para un solo elemento de menú. Comencemos reemplazando esta función en nuestra clase walker con un ejemplo simple.
Ejemplo: evitar agregar enlaces para elementos ‘#’
Asegurémonos de que cualquier #enlace ‘ ‘ obtenga un <span>elemento en lugar de una etiqueta de enlace, para evitar actualizar la página.
class AWP_Menu_Walker extends Walker_Nav_Menu {
function start_el(&$output, $item, $depth=0, $args=[], $id=0) {
$output .= "<li class='". implode(" ", $item->classes). "'>";
if ($item->url && $item->url != '#') {
$output .= '<a href="'. $item->url. '">';
} else {
$output .= '<span>';
}
$output .= $item->title;
if ($item->url && $item->url != '#') {
$output .= '</a>';
} else {
$output .= '</span>';
}
}
}
Comenzaremos el elemento agregando una <li>etiqueta a $output. Queremos asegurarnos de que las clases predeterminadas de WordPress (por ejemplo, ‘menu-item’, ‘menu-item-has-child’, etc.), así como las clases ingresadas manualmente en el editor de menú, se agreguen a nuestro elemento de lista. Pegamos las clases proporcionadas como una matriz $item->classesusando la función PHP [implode](https://www.php.net/manual/en/function.implode.php)()separando cada elemento con un espacio.
En las líneas #5-9 y #13-17 manejamos la salida condicional del elemento envolvente. Enviamos una <a>etiqueta, a menos que la URL del elemento sea ‘ #‘, en cuyo caso proporcionamos una <span>etiqueta en su lugar. En la línea #11 simplemente mostramos el texto del enlace, que reside en $item->title.
¡Esto es todo lo que necesitamos para asegurarnos de que #no se pueda hacer clic en todos los elementos del menú que tienen ‘ ‘ como URL!
Si está haciendo esto en un tema con estilo, tenga en cuenta que podría perder algo de estilo si el tema ha aplicado estilo a la <a>etiqueta directamente. Puede resolver esto cambiando el estilo y posiblemente agregando una clase al elemento span.
Como ejemplo, otra cosa que puede hacer aquí es mostrar la descripción del menú. Esto existe, pero no está activado por defecto. En el editor de menú de WordPress, debe hacer clic en "Opciones de pantalla" en la parte superior derecha y marcar para mostrar "Descripción":
Esto permite al usuario ingresar una descripción para cada elemento. Puede generar esta descripción en su clase de caminante. Supongamos que solo desea mostrar la descripción de los elementos de nivel superior, ya que esto es parte del diseño de su tema. Simplemente puede verificar si $itemtiene una descripción y si $depthes 0, así:
...
$output .= $item->title;
if ($depth == 0 && !empty($item->description)) {
$output .= '<span class="description">'. $item->description. '</span>';
}
...
Ejemplo: Adición de símbolos de intercalación desplegables
Un ejemplo más común y útil es agregar un "signo de intercalación", un ícono que indica que este elemento del menú tiene un menú desplegable (tiene elementos secundarios).
Ejemplo de signos de intercalación en acción: detrás de "Blog" y "Noticias"
Deberá averiguar su salida HTML de intercalación. En mi caso, estoy generando un <i>elemento con clases específicas para una buena flecha hacia abajo disponible en la biblioteca Fontawesome que proporciona miles de íconos. También desea asegurarse de que este signo de intercalación solo se muestre en elementos que tienen elementos secundarios. La mejor manera que he encontrado para averiguar si el elemento actual tiene hijos es haciendo referencia al objeto walker (sí, que es nuestro walker en sí mismo, ¡pero también las clases que extiende!) en $args, y verificando el boolean has_children. La salida de un signo de intercalación es tan simple como:
if ($args->walker->has_children) {
$output .= '<i class="caret fa fa-angle-down"></i>';
}
La clase de caminante completa se vería así:
class AWP_Menu_Walker extends Walker_Nav_Menu {
function start_el(&$output, $item, $depth=0, $args=[], $id=0) {
$output .= "<li class='". implode(" ", $item->classes). "'>";
if ($item->url && $item->url != '#') {
$output .= '<a href="'. $item->url. '">';
} else {
$output .= '<span>';
}
$output .= $item->title;
if ($item->url && $item->url != '#') {
$output .= '</a>';
} else {
$output .= '</span>';
}
if ($args->walker->has_children) {
$output .= '<i class="caret fa fa-angle-down"></i>';
}
}
}
Y eso es todo lo que necesita para asegurarse de que su menú tenga bonitos iconos de intercalación en los elementos principales y que #no se pueda hacer clic en los enlaces ‘ ‘.
Si desea que el ícono de intercalación cambie, por ejemplo, a una flecha hacia arriba cuando el menú desplegable esté activo, deberá agregar esto con Javascript a su tema.
Como sugieren los ejemplos anteriores, puede manipular la salida como desee, en función de cualquier condicional. Puede, por ejemplo, modificar la salida en función de si una determinada clase está presente (por ejemplo, una clase ingresada manualmente en el editor de menús) buscando la clase en $item->classes, o puede manipular (por ejemplo, poner en mayúsculas) el texto del elemento de salida proporcionado en $item->title.
Me gustaría mencionar otra cosa útil. Recuerde que $args contiene todos los argumentos proporcionados a wp_nav_menu(). Esto incluye, por ejemplo theme_location, y otros, por lo que si puede modificar la salida solo para ubicaciones de temas específicos, por ejemplo, el menú principal. ¡Pero en realidad puede proporcionar cualquier argumento personalizado!
Digamos que está mostrando el mismo menú varias veces, por ejemplo, una para escritorio y otra para móvil. ¿O desea que su caminante manipule los elementos solo cuando se generan wp_nav_menu()en su tema, y no cuando el menú se agrega a través de un widget? ¿Quizás desea que su andador maneje la salida de manera diferente en estos casos?
Puede proporcionar cualquier argumento personalizado a wp_nav_menu(). Como un ejemplo simple, show_caretsagregaré un booleano ‘ ‘ a los argumentos para garantizar que los símbolos de intercalación se agreguen solo en los casos en que los quiero, en lugar de que mi clase de caminante agregue símbolos de intercalación a todos los menús.
wp_nav_menu([
'theme_location' => 'primary',
'menu_class' => 'main-menu',
'container' => 'nav',
'container_class' => 'header__main-nav',
'walker' => new AWP_Menu_Walker(),
'show_carets' => true
]);
Luego, simplemente puedo cambiar mi código de intercalación anterior (línea n. ° 19-21) para verificar si show_caretsestá presente o no y es verdadero en $args, así:
if ($args->show_carets && $args->walker->has_children) {
$output .= '<i class="caret fa fa-angle-down"></i>';
}
Puede agregar cualquier argumento que desee para asegurarse de que su andador solo personalice los menús que desee. Por ejemplo, booleanos simples para diferentes casos, por ejemplo is_mobile_menu, o cualquier otra cosa que necesite.
Y eso es todo. ¡Siéntase libre de experimentar y avíseme si tiene alguna pregunta o sugerencia a continuación!

