Question

J'ai un menu défini dans wp qui ressemble à ceci:

text alt

Je veux être en mesure d'afficher tous les liens de l'enfant sur la barre latérale chaque fois que je suis à une page parent. Par exemple, si l'utilisateur est sur mon « A propos de nous », je veux une liste des 4 liens en vert pour apparaître sur la barre latérale.

Je regarde la documentation wp_nav_menu () et il ne semble pas avoir de intégré de manière à spécifier un noeud particulier d'un menu donné à utiliser comme point de départ lors de la génération des liens.

Je créé une solution pour une situation similaire qui reposait sur les relations créées par le parent de la page, mais je suis à la recherche d'un qui utilise spécifiquement le système de menus. Toute aide serait appréciée.

Était-ce utile?

La solution

C'était encore dans mon esprit si je revisité et mis en place cette solution, qui ne repose sur le contexte que beaucoup:

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;
}

Utilisation

$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 );

Autres conseils

@goldenapples: Votre classe Walker ne fonctionne pas. Mais l'idée est vraiment bon. J'ai créé un marcheur basé sur votre idée:

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;
    }
}

vous pouvez utiliser:

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

La sortie est une liste contenant l'élément racine en cours et pour les enfants (pas leurs enfants). Def: Elément racine: = L'élément de menu de niveau supérieur qui correspond à la page actuelle ou est parent d'une page ou d'un parent d'un parent ...

Cela ne répond pas exactement à la question initiale, mais presque, car il y a encore l'élément de niveau supérieur. Ceci est bien pour moi, parce que je veux l'élément de niveau supérieur comme un titre de la barre latérale. Si vous voulez vous débarrasser de cela, vous pourriez avoir à remplacer display_element ou utiliser un HTML-Parser.

Salut @jessegavin :

Nav menus sont stockés dans une combinaison de types de postes personnalisés et taxonomies personnalisées. Chaque menu est enregistré comme un terme (à savoir "A propos du menu" , a trouvé dans wp_terms) d'une taxonomie personnalisée (à savoir nav_menu, trouvé dans wp_term_taxonomy.)

Chaque menu Nav élément est stocké en tant que poste de post_type=='nav_menu_item' (ie "A propos de l'entreprise" , a trouvé dans wp_posts) avec les attributs de it stockés sous forme de méta post (en wp_postmeta) en utilisant un préfixe meta_key de _menu_item_*_menu_item_menu_item_parent est l'ID de votre parent de l'élément de menu Nav poste point de menu.

La relation entre les menus et les éléments de menu sont mémorisées dans wp_term_relationshipsobject_id concerne la $post->ID pour le menu de navigation et l'article $term_relationships->term_taxonomy_id concerne le menu défini collectivement dans wp_term_taxonomyand wp_terms.

Je suis sûr qu'il serait possible de crochet à la fois 'wp_update_nav_menu' et 'wp_update_nav_menu_item' pour créer des menus réels dans wp_terms et un ensemble parallèle de relations dans wp_term_taxonomy et wp_term_relationships où chaque menu Nav élément qui a sous nav les éléments de menu devient également son propre menu de navigation.

Vous voulez aussi voulez crochet 'wp_get_nav_menus' (que je suggère d'ajouter à WP il y a 3.0 basé sur un travail similaire, je faisais quelques mois) pour veiller à ce que vos menus de navigation générés ne sont pas affichés pour la manipulation par l'utilisateur dans l'admin, sinon ils seraient sortir de synchronisation très rapide et vous auriez un cauchemar de données sur votre main.

Sons comme un projet amusant et utile, mais il est un peu plus de code et les tests que je ne peux me permettre d'aborder ce moment en partie parce que tout ce qui synchronise les données ont tendance à être un PITA quand il vient à repasser tous les bugs (et parce que les clients payants me pressant de faire avancer les choses.). Mais armé avec les informations ci-dessus, je suis un développeur WordPress plugin motivé pourrait coder s'ils voulaient

Bien sûr, vous vous rendez compte si vous le code, il vous êtes obligé de le publier de nouveau ici afin que nous puissions tous bénéficier de votre largesse! : -)

Ceci est une extension marcheur qui devrait faire ce que vous cherchez:

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;
    }

}

Basé lâchement sur le code de mfields Í référencé dans mon commentaire précédent. Tout ce qu'il fait est de vérifier lors de la marche dans le menu pour voir si l'élément courant est (1) l'élément de menu en cours, ou (2) un ancêtre de l'élément de menu en cours, et développe la sous-arborescence ci-dessous que si l'une de ces conditions est vraie . Espérons que cela fonctionne pour vous.

Pour l'utiliser, il suffit d'ajouter un argument « marcheur » lorsque vous appelez le menu, par exemple:

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

Mise à jour: J'ai fait cela dans un plug-in. Télécharger ici .


Je avais besoin pour résoudre moi-même et finalement liquidée à écrire un filtre sur les résultats de la recherche de menu. Il vous permet d'utiliser wp_nav_menu comme d'habitude, mais choisissez une sous-section du menu basé sur le titre de l'élément parent. Ajouter un paramètre submenu au menu comme ceci:

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

Vous pouvez même aller sur plusieurs niveaux en mettant des barres obliques dans:

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

Ou si vous préférez avec un tableau:

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

Il utilise une version limace du titre, qui devrait faire pardonner des choses comme capitales et la ponctuation.

Je mis en place la classe suivante pour moi-même. Il trouvera le parent de navigation haut de la page en cours, ou vous pouvez lui donner un haut cible ID de navigation dans le constructeur Walker.

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;
    }
}

Appel Nav:

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

@davidn @hakre Salut, j'ai une solution laide sans HTML-Parser ou display_element remplaçant.

 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 sortie du menu de navigation comprend beaucoup de classes pour l'élément actuel, ancêtre de l'élément en cours, etc. Dans certaines situations, j'ai été en mesure de faire ce que vous voulez faire en laissant toute la sortie de l'arbre de navigation, puis en utilisant css pour pare vers le bas pour que les enfants de la page en cours, etc.

J'ai fait un déambulateur modifié qui devrait aider! Pas parfait - il laisse quelques éléments vides, mais le tour est joué. La modification est essentiellement ces bits de current_branch de $. Il aide quelqu'un l'espoir!

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;
}

}

Vérifiez le code dans mon plug-in ou l'utiliser pour votre fin;)

Ce plugin ajoute un widget amélioré "Menu de navigation". Il offre de nombreuses options qui pourraient être définies pour personnaliser la sortie du menu personnalisé dans le widget.

Les caractéristiques comprennent:

  • hiérarchie personnalisée - « sous-éléments uniquement liés » ou « Seulement strictement liée sous-éléments ».
  • Démarrage et profondeur niveau maximum écran + écran plat.
  • Afficher tous les articles de menu en commençant par celui sélectionné.
  • Affichage seule voie directe à l'élément courant ou seuls les enfants de
    élément sélectionné (option d'inclure l'élément parent).
  • classe personnalisée pour un bloc widget.
  • Et presque tous les paramètres de la fonction wp_nav_menu.

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à wordpress.stackexchange
scroll top