Pregunta

Tengo un menú definido en WP administrador, que es similar al siguiente:

text alt

Quiero ser capaz de mostrar todos los enlaces en la barra lateral del niño cada vez que estoy en una página principal. Por ejemplo, si el usuario está en mi página "Sobre Nosotros", yo quiero una lista de los 4 enlaces resaltado en verde para que aparezca en la barra lateral.

Me miró a la documentación de wp_nav_menu () y no parece tener ningún incorporado en forma de especificar un nodo particular de una lista dada a utilizar como punto de partida cuando se generan los enlaces.

I creó una solución para una situación similar que se basaba en las relaciones creadas por la página principal, pero estoy en busca de uno que utiliza el sistema de menús en concreto. Cualquier ayuda sería muy apreciada.

¿Fue útil?

Solución

Esto todavía estaba en mi mente por lo que volví a visitar y lo puse juntos esta solución, que no depende del contexto que gran parte:

add_filter( 'wp_nav_menu_objects', 'submenu_limit', 10, 2 );

function submenu_limit( $items, $args ) {

    if ( empty( $args->submenu ) ) {
        return $items;
    }

    $ids       = wp_filter_object_list( $items, array( 'title' => $args->submenu ), 'and', 'ID' );
    $parent_id = array_pop( $ids );
    $children  = submenu_get_children_ids( $parent_id, $items );

    foreach ( $items as $key => $item ) {

        if ( ! in_array( $item->ID, $children ) ) {
            unset( $items[$key] );
        }
    }

    return $items;
}

function submenu_get_children_ids( $id, $items ) {

    $ids = wp_filter_object_list( $items, array( 'menu_item_parent' => $id ), 'and', 'ID' );

    foreach ( $ids as $id ) {

        $ids = array_merge( $ids, submenu_get_children_ids( $id, $items ) );
    }

    return $ids;
}

Uso

$args = array(
    'theme_location' => 'slug-of-the-menu', // the one used on register_nav_menus
    'submenu' => 'About Us', // could be used __() for translations
);

wp_nav_menu( $args );

Otros consejos

@goldenapples: Su Clase Walker no funciona. Pero la idea es muy buena. He creado un andador basado en su idea:

class Selective_Walker extends Walker_Nav_Menu
{
    function walk( $elements, $max_depth) {

        $args = array_slice(func_get_args(), 2);
        $output = '';

        if ($max_depth < -1) //invalid parameter
            return $output;

        if (empty($elements)) //nothing to walk
            return $output;

        $id_field = $this->db_fields['id'];
        $parent_field = $this->db_fields['parent'];

        // flat display
        if ( -1 == $max_depth ) {
            $empty_array = array();
            foreach ( $elements as $e )
                $this->display_element( $e, $empty_array, 1, 0, $args, $output );
            return $output;
        }

        /*
         * need to display in hierarchical order
         * separate elements into two buckets: top level and children elements
         * children_elements is two dimensional array, eg.
         * children_elements[10][] contains all sub-elements whose parent is 10.
         */
        $top_level_elements = array();
        $children_elements  = array();
        foreach ( $elements as $e) {
            if ( 0 == $e->$parent_field )
                $top_level_elements[] = $e;
            else
                $children_elements[ $e->$parent_field ][] = $e;
        }

        /*
         * when none of the elements is top level
         * assume the first one must be root of the sub elements
         */
        if ( empty($top_level_elements) ) {

            $first = array_slice( $elements, 0, 1 );
            $root = $first[0];

            $top_level_elements = array();
            $children_elements  = array();
            foreach ( $elements as $e) {
                if ( $root->$parent_field == $e->$parent_field )
                    $top_level_elements[] = $e;
                else
                    $children_elements[ $e->$parent_field ][] = $e;
            }
        }

        $current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' );  //added by continent7
        foreach ( $top_level_elements as $e ){  //changed by continent7
            // descend only on current tree
            $descend_test = array_intersect( $current_element_markers, $e->classes );
            if ( !empty( $descend_test ) ) 
                $this->display_element( $e, $children_elements, 2, 0, $args, $output );
        }

        /*
         * if we are displaying all levels, and remaining children_elements is not empty,
         * then we got orphans, which should be displayed regardless
         */
         /* removed by continent7
        if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
            $empty_array = array();
            foreach ( $children_elements as $orphans )
                foreach( $orphans as $op )
                    $this->display_element( $op, $empty_array, 1, 0, $args, $output );
         }
        */
         return $output;
    }
}

Ahora se puede usar:

<?php wp_nav_menu( 
   array(
       'theme_location'=>'test', 
       'walker'=>new Selective_Walker() ) 
   ); ?>

La salida es una lista que contiene el elemento raíz actual y de los niños (no son sus hijos). Def: Elemento Raíz: = El elemento de menú de nivel superior que corresponde a la página actual o es padre de un página actual o un padre de un padre ...

Esto no responde exactamente a la pregunta original, pero casi, ya que sigue siendo el elemento del nivel superior. Esto está bien para mí, porque quiero que el elemento de nivel superior como un titular de la barra lateral. Si desea deshacerse de este, puede que tenga que reemplazar display_element o utilizar un analizador HTML.

Hola @jessegavin

Menús de navegación se almacenan en una combinación de tipos de envíos personalizados y taxonomías personalizadas. Cada menú se almacena como un término (es decir, "Acerca del menú" , que se encuentra en wp_terms) de una taxonomía personalizada (es decir nav_menu, que se encuentra en wp_term_taxonomy.)

Cada Nav elemento de menú se almacena como un puesto de post_type=='nav_menu_item' (es decir, "Acerca de la Firma" , que se encuentra en wp_posts) con sus atributos almacenados como meta post (en wp_postmeta) utilizando un prefijo meta_key de _menu_item_* donde _menu_item_menu_item_parent es el ID de matriz de navegación posterior elemento de menú de su elemento de menú.

La relación entre los menús y elementos de menú se almacena en wp_term_relationships donde object_id se refiere a la $post->ID para el elemento de menú Nav y la $term_relationships->term_taxonomy_id refiere al menú definido colectivamente en wp_term_taxonomy wp_termsand.

Estoy bastante seguro de que sería posible gancho tanto 'wp_update_nav_menu' y 'wp_update_nav_menu_item' para crear menús reales en wp_terms y un conjunto paralelo de las relaciones en wp_term_taxonomy y wp_term_relationships donde cada elemento del menú de navegación que tiene sub- Los elementos del menú de navegación también se convierte en su propio menú de navegación.

También querría gancho 'wp_get_nav_menus' (que me sugirió que añadir a WP 3.0 basada en algún trabajo similar que estaba haciendo hace unos meses) para asegurarse de que tu generada Nav los menús no se muestran para la manipulación por el usuario en el administrador, de lo contrario tendrían que salir de sincronización muy rápido y entonces tendría una pesadilla datos en su mano.

suena como un proyecto divertido y útil, pero es un poco más de código y pruebas de lo que puede permitirse el lujo de hacer frente en este momento, en parte, porque cualquier cosa que sincroniza los datos tiende a ser un PITA cuando se trata de limar todos los errores (y porque los clientes que pagan están presionándome para hacer las cosas:.). pero armado con la información anterior estoy bastante motivado un plugin de WordPress desarrollador podría codificar que si querían

Por supuesto que no se da cuenta ahora si lo hace el código que usted está obligado a publicar de nuevo aquí para que todos puedan beneficiarse de su generosidad! : -)

Esta es una extensión andador que debe hacer lo que usted está buscando:

class Selective_Walker extends Walker_Nav_Menu
{

    function walk( $elements, $max_depth) {

        $args = array_slice(func_get_args(), 2);
        $output = '';

        if ($max_depth < -1) //invalid parameter
            return $output;

        if (empty($elements)) //nothing to walk
            return $output;

        $id_field = $this->db_fields['id'];
        $parent_field = $this->db_fields['parent'];

        // flat display
        if ( -1 == $max_depth ) {
            $empty_array = array();
            foreach ( $elements as $e )
                $this->display_element( $e, $empty_array, 1, 0, $args, $output );
            return $output;
        }

        /*
         * need to display in hierarchical order
         * separate elements into two buckets: top level and children elements
         * children_elements is two dimensional array, eg.
         * children_elements[10][] contains all sub-elements whose parent is 10.
         */
        $top_level_elements = array();
        $children_elements  = array();
        foreach ( $elements as $e) {
            if ( 0 == $e->$parent_field )
                $top_level_elements[] = $e;
            else
                $children_elements[ $e->$parent_field ][] = $e;
        }

        /*
         * when none of the elements is top level
         * assume the first one must be root of the sub elements
         */
        if ( empty($top_level_elements) ) {

            $first = array_slice( $elements, 0, 1 );
            $root = $first[0];

            $top_level_elements = array();
            $children_elements  = array();
            foreach ( $elements as $e) {
                if ( $root->$parent_field == $e->$parent_field )
                    $top_level_elements[] = $e;
                else
                    $children_elements[ $e->$parent_field ][] = $e;
            }
        }

        $current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' );

        foreach ( $top_level_elements as $e ) {

            // descend only on current tree
            $descend_test = array_intersect( $current_element_markers, $e->classes );
            if ( empty( $descend_test ) )  unset ( $children_elements );

            $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
        }

        /*
         * if we are displaying all levels, and remaining children_elements is not empty,
         * then we got orphans, which should be displayed regardless
         */
        if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
            $empty_array = array();
            foreach ( $children_elements as $orphans )
                foreach( $orphans as $op )
                    $this->display_element( $op, $empty_array, 1, 0, $args, $output );
         }

         return $output;
    }

}

Basado libremente en código que mfields' hace referencia en mi anterior comentario. Todo lo que hace es comprobar al caminar el menú para ver si el elemento actual es (1) el elemento de menú actual, o (2) un antepasado del elemento de menú actual, y se expande el subárbol debajo de ella sólo si ninguna de esas condiciones es verdadera . Espero que esto funcione para usted.

Para usarlo, basta con añadir un argumento "walker" cuando se llama al menú, es decir:

<?php wp_nav_menu( 
   array(
       'theme_location'=>'test', 
       'walker'=>new Selective_Walker() ) 
   ); ?>

Actualización: Me hizo esto en un plugin. Descarga aquí .


que necesitaba para resolver esto mismo y, finalmente, terminó escribiendo un filtro a los resultados de las operaciones de búsqueda del menú. Se le permite utilizar wp_nav_menu como normal, pero elige una sub-sección del menú basado en el título del elemento padre. Añadir un parámetro submenu al menú de esta manera:

wp_nav_menu(array(
  'menu' => 'header',
  'submenu' => 'About Us',
));

Usted puede incluso ir a varios niveles de profundidad, poniendo barras en:

wp_nav_menu(array(
  'menu' => 'header',
  'submenu' => 'About Us/Board of Directors'
));

O, si lo prefiere, con una matriz:

wp_nav_menu(array(
  'menu' => 'header',
  'submenu' => array('About Us', 'Board of Directors')
));

Se utiliza una versión babosa del título, que debería hacer más cosas como que perdona de capitales y puntuacion.

Me armó la clase siguiente para mí. Se encontrará el padre superior de navegación de la página actual, o puede darle un navegador vía Identificación superior de destino en el constructor andador.

class Walker_SubNav_Menu extends Walker_Nav_Menu {
    var $target_id = false;

    function __construct($target_id = false) {
        $this->target_id = $target_id;
    }

    function walk($items, $depth) {
        $args = array_slice(func_get_args(), 2);
        $args = $args[0];
        $parent_field = $this->db_fields['parent'];
        $target_id = $this->target_id;
        $filtered_items = array();

        // if the parent is not set, set it based on the post
        if (!$target_id) {
            global $post;
            foreach ($items as $item) {
                if ($item->object_id == $post->ID) {
                    $target_id = $item->ID;
                }
            }
        }

        // if there isn't a parent, do a regular menu
        if (!$target_id) return parent::walk($items, $depth, $args);

        // get the top nav item
        $target_id = $this->top_level_id($items, $target_id);

        // only include items under the parent
        foreach ($items as $item) {
            if (!$item->$parent_field) continue;

            $item_id = $this->top_level_id($items, $item->ID);

            if ($item_id == $target_id) {
                $filtered_items[] = $item;
            }
        }

        return parent::walk($filtered_items, $depth, $args);
    }

    // gets the top level ID for an item ID
    function top_level_id($items, $item_id) {
        $parent_field = $this->db_fields['parent'];

        $parents = array();
        foreach ($items as $item) {
            if ($item->$parent_field) {
                $parents[$item->ID] = $item->$parent_field;
            }
        }

        // find the top level item
        while (array_key_exists($item_id, $parents)) {
            $item_id = $parents[$item_id];
        }

        return $item_id;
    }
}

Nav llamada:

wp_nav_menu(array(
    'theme_location' => 'main_menu',
    'walker' => new Walker_SubNav_Menu(22), // with ID
));

@davidn @hakre Hola, tengo una solución fea sin un analizador HTML o anulando display_element.

 class Selective_Walker extends Walker_Nav_Menu
    {
        function walk( $elements, $max_depth) {

            $args = array_slice(func_get_args(), 2);
            $output = '';

            if ($max_depth < -1) //invalid parameter
                return $output;

            if (empty($elements)) //nothing to walk
                return $output;

            $id_field = $this->db_fields['id'];
            $parent_field = $this->db_fields['parent'];

            // flat display
            if ( -1 == $max_depth ) {
                $empty_array = array();
                foreach ( $elements as $e )
                    $this->display_element( $e, $empty_array, 1, 0, $args, $output );
                return $output;
            }

            /*
             * need to display in hierarchical order
             * separate elements into two buckets: top level and children elements
             * children_elements is two dimensional array, eg.
             * children_elements[10][] contains all sub-elements whose parent is 10.
             */
            $top_level_elements = array();
            $children_elements  = array();
            foreach ( $elements as $e) {
                if ( 0 == $e->$parent_field )
                    $top_level_elements[] = $e;
                else
                    $children_elements[ $e->$parent_field ][] = $e;
            }

            /*
             * when none of the elements is top level
             * assume the first one must be root of the sub elements
             */
            if ( empty($top_level_elements) ) {

                $first = array_slice( $elements, 0, 1 );
                $root = $first[0];

                $top_level_elements = array();
                $children_elements  = array();
                foreach ( $elements as $e) {
                    if ( $root->$parent_field == $e->$parent_field )
                        $top_level_elements[] = $e;
                    else
                        $children_elements[ $e->$parent_field ][] = $e;
                }
            }

            $current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' );  //added by continent7
            foreach ( $top_level_elements as $e ){  //changed by continent7
                // descend only on current tree
                $descend_test = array_intersect( $current_element_markers, $e->classes );
                if ( !empty( $descend_test ) ) 
                    $this->display_element( $e, $children_elements, 2, 0, $args, $output );
            }

            /*
             * if we are displaying all levels, and remaining children_elements is not empty,
             * then we got orphans, which should be displayed regardless
             */
             /* removed by continent7
            if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
                $empty_array = array();
                foreach ( $children_elements as $orphans )
                    foreach( $orphans as $op )
                        $this->display_element( $op, $empty_array, 1, 0, $args, $output );
             }
            */

/*added by alpguneysel  */
                $pos = strpos($output, '<a');
            $pos2 = strpos($output, 'a>');
            $topper= substr($output, 0, $pos).substr($output, $pos2+2);
            $pos3 = strpos($topper, '>');
            $lasst=substr($topper, $pos3+1);
            $submenu= substr($lasst, 0, -6);

        return $submenu;
        }
    }

La salida del menú de navegación incluye un montón de clases de elemento actual, actual ancestro artículo, etc. En algunas situaciones, he sido capaz de hacer lo que quiere hacer al permitir que toda la producción del árbol de navegación y, a continuación, utilizando css para recortar abajo a sólo los niños de la página actual, etc.

Me hizo un andador modificado que debería ayudar! No es perfecto - se deja un par de elementos vacíos, pero no el truco. La modificación es básicamente esos bits current_branch $. Espero que ayude a alguien!

class Kanec_Walker_Nav_Menu extends Walker {
/**
 * @see Walker::$tree_type
 * @since 3.0.0
 * @var string
 */
var $tree_type = array( 'post_type', 'taxonomy', 'custom' );

/**
 * @see Walker::$db_fields
 * @since 3.0.0
 * @todo Decouple this.
 * @var array
 */
var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );

/**
 * @see Walker::start_lvl()
 * @since 3.0.0
 *
 * @param string $output Passed by reference. Used to append additional content.
 * @param int $depth Depth of page. Used for padding.
 */
function start_lvl(&$output, $depth) {
    $indent = str_repeat("\t", $depth);
    $output .= "\n$indent<ul class=\"sub-menu\">\n";
}

/**
 * @see Walker::end_lvl()
 * @since 3.0.0
 *
 * @param string $output Passed by reference. Used to append additional content.
 * @param int $depth Depth of page. Used for padding.
 */
function end_lvl(&$output, $depth) {
    global $current_branch;
    if ($depth == 0) $current_branch = false;
    $indent = str_repeat("\t", $depth);
    $output .= "$indent</ul>\n";
}

/**
 * @see Walker::start_el()
 * @since 3.0.0
 *
 * @param string $output Passed by reference. Used to append additional content.
 * @param object $item Menu item data object.
 * @param int $depth Depth of menu item. Used for padding.
 * @param int $current_page Menu item ID.
 * @param object $args
 */
function start_el(&$output, $item, $depth, $args) {
    global $wp_query;
    global $current_branch;

    // Is this menu item in the current branch?
    if(in_array('current-menu-ancestor',$item->classes) ||
    in_array('current-menu-parent',$item->classes) ||
    in_array('current-menu-item',$item->classes)) {
        $current_branch = true; 
    }

    if($current_branch && $depth > 0) {
        $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

        $class_names = $value = '';

        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
        $classes[] = 'menu-item-' . $item->ID;

        $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
        $class_names = ' class="' . esc_attr( $class_names ) . '"';

        $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
        $id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';

        $output .= $indent . '<li' . $id . $value . $class_names .'>';

        $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
        $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
        $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
        $attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';

        $item_output = $args->before;
        $item_output .= '<a'. $attributes .'>';
        $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;

        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }

}

/**
 * @see Walker::end_el()
 * @since 3.0.0
 *
 * @param string $output Passed by reference. Used to append additional content.
 * @param object $item Page data object. Not used.
 * @param int $depth Depth of page. Not Used.
 */
function end_el(&$output, $item, $depth) {
    global $current_branch;
    if($current_branch && $depth > 0) $output .= "</li>\n";
    if($depth == 0) $current_branch = 0;
}

}

Salida del código en mi plugin o utilizarlo para su propósito;)

Este plugin añade mejorada "Menús de navegación" de widgets. Ofrece muchas opciones que se podrían configurar para personalizar la salida del menú personalizado a través del widget.

Las características incluyen:

  • jerarquía personalizada - "solo acerca subtemas" o "Sólo estrictamente relacionada subtemas".
  • A partir profundidad y el nivel máximo a la pantalla de visualización plana +.
  • Mostrar todos los artículos del menú que comienzan con el seleccionado.
  • Pantalla único camino directo al elemento actual o sólo a los niños de
    elemento seleccionado (opción de incluir el elemento padre).
  • clase personalizada para un bloque de widgets.
  • Y casi todos los parámetros de la función wp_nav_menu.

http://wordpress.org/extend/plugins/advanced-menu-widget /

Licenciado bajo: CC-BY-SA con atribución
scroll top