El andador de navegación personalizado muestra elementos de menú actuales secundarios, o hermanos en ningún elemento secundario

14

He estado jugando / buscando durante horas y todavía no puedo hacer que esto funcione, así que finalmente estoy cediendo y pidiendo ayuda.

Estoy tratando de escribir un andador personalizado que muestre solo las páginas actuales hijos, o si no hay niños, muestra las páginas hermanas.

Por ejemplo, tome el siguiente árbol de menús:

  • 1.0
    • 1.2.0
      • 1.3.0
      • 1.3.1
      • 1.3.2
    • 1.2.1
    • 1.2.2
  • 2,0

Supongamos que estoy en la página actual 1.2.0. En esta página quiero mostrar sus hijos (1.3.0, 1.3.1, 1.3.2)

sin embargo, si estoy en la página 1.2.2, dado que no tiene hijos, debería mostrar sus hermanos de nivel actual, por lo que debería mostrarme (1.2.0, 1.2.1, 1.2.2).

jchamb
fuente
44
Mueva su solución a una respuesta para que sea más clara para los demás y las preguntas no persigan al sitio como sin respuesta.
Rarst
¡Lo que dijo @Rarst! Casi echo de menos que hayas encontrado una solución.
Chris Krycho
Necro responde. Hice más o menos la misma pregunta sobre SO hace aproximadamente 2 años con una muy buena respuesta. stackoverflow.com/questions/5826609/…
Stoosh
Se movió la respuesta dentro de la pregunta para separar la respuesta. OP: Por favor, sigue allí.
Kaiser

Respuestas:

4

Este es el andador que solía mostrar solo los elementos secundarios del elemento del menú actual. O los elementos del menú hermanos si no tiene hijos propios.

Hay comentarios a lo largo de la clase que explican cada sección.

<?php

class SH_Child_Only_Walker extends Walker_Nav_Menu {

private $ID;
private $depth;
private $classes = array();
private $child_count = 0;
private $have_current = false;


// Don't start the top level
function start_lvl(&$output, $depth=0, $args=array()) {

    if( 0 == $depth || $this->depth != $depth )
        return;

    parent::start_lvl($output, $depth,$args);
}

// Don't end the top level
function end_lvl(&$output, $depth=0, $args=array()) {
    if( 0 == $depth || $this->depth != $depth )
        return;

    parent::end_lvl($output, $depth,$args);
}

// Don't print top-level elements
function start_el(&$output, $item, $depth=0, $args=array()) {

    $is_current = in_array('current-menu-item', $this->classes);

    if( 0 == $depth || ! $is_current )
        return;

    parent::start_el($output, $item, $depth, $args);
}

function end_el(&$output, $item, $depth=0, $args=array()) {
    if( 0 == $depth )
        return;

    parent::end_el($output, $item, $depth, $args);
}

// Only follow down one branch
function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {

    // Check if element is in the current tree to display
    $current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' );
    $this->classes = array_intersect( $current_element_markers, $element->classes );

    // If element has a 'current' class, it is an ancestor of the current element
    $ancestor_of_current = !empty($this->classes);

    // check if the element is the actual page element we are on.
    $is_current = in_array('current-menu-item', $this->classes);

    // if it is the current element
    if($is_current) {

        // set the count / ID / and depth to use in the other functions.
        $this->child_count = ( isset($children_elements[$element->ID]) ) ? count($children_elements[$element->ID]) : 0;
        $this->ID = $element->ID;
        $this->depth = $depth;
        $this->have_current = true;

        if($this->child_count > 0) {

            // if there are children loop through them and display the kids.
            foreach( $children_elements[$element->ID] as $child ) {
                parent::display_element( $child, $children_elements, $max_depth, $depth, $args, $output );
            }

        } else {
            // no children so loop through kids of parent item.
            foreach( $children_elements[$element->menu_item_parent] as $child ) {
                parent::display_element( $child, $children_elements, $max_depth, $depth, $args, $output );
            }

        }
    }

    // if depth is zero and not in current tree go to the next element
    if ( 0 == $depth && !$ancestor_of_current)
        return;

    // if we aren't on the current element proceed as normal
    if(! $this->have_current )
        parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
}
}

Adjúntelo como lo haría con cualquier otro andador personalizado en un wp_nav_menu

<?php
wp_nav_menu( array(
    'menu' => 'primary-menu'
    ,'container' => 'nav'
    ,'container_class' => 'subpages'
    ,'depth' => 0
    ,'walker' => new SH_Child_Only_Walker()
 ));
?>
jchamb
fuente
Quiero señalar el comentario de @ Stoosh apuntando aquí. stackoverflow.com/questions/5826609/… ya que esta es otra buena solución
jchamb
0

Yo tuve una experiencia similar. Es posible que desee pensar en sacar la lógica de las páginas del andador. Básicamente, compila la jerarquía de la página actual como un objeto. Luego use el parámetro 'excluir' en la función wp_nav_menu. Ahora las páginas excluidas dependerían de si la página actual tiene hijos. Si ningún niño muestra hermanos; si los niños y esos niños son el final de la línea, muestre hermanos y niños; si existen hijos y nietos, excluya a los hermanos y muéstreles hijos y nietos.

Steve Fischer
fuente
¿Cuál es este excludeparámetro al que te refieres? Estoy mirando la documentación y no veo ninguna referencia a ella.
Chris Krycho
1
Pido disculpas me equivoqué. Tiene razón en que no hay un parámetro 'excluir'. Quise usar la función "wp_list_pages".
Steve Fischer
Muy bien, y no te preocupes. Tenía curiosidad por saber si había algo indocumentado, pero en el fondo, he visto que eso sucedió antes. ¡Gracias por aclararme! No había pensado en usarlo wp_list_pages()en este contexto, así que es una idea interesante.
Chris Krycho