web-dev-qa-db-fra.com

Comment générer un système de menu / sous-menu personnalisé à l'aide de wp_get_nav_menu_items dans WordPress?

J'ai une structure html qui nécessite une personnalisation du wp_nav_menu code.

Voici le code HTML dont j'ai besoin pour générer:

<ul class="main-nav">
    <li class="item">
        <a href="http://example.com/?p=123" class="title">Title</a>
        <a href="http://example.com/?p=123" class="desc">Description</a>
        <ul class="sub-menu">
            <li class="item">
                <a href="http://example.com/?p=123" class="title">Title</a>
                <a href="http://example.com/?p=123" class="desc">Description</a>
            </li>
        </ul>
    </li>
     <li class="item">
        <a href="http://example.com/?p=123" class="title">Title</a>
        <a href="http://example.com/?p=123" class="desc">Description</a>
    </li>
</ul>

J'utilise actuellement wp_get_nav_menu_items pour obtenir tous les éléments de mon menu sous forme de tableau.

En ce moment, je suis capable de générer le HTML ci-dessus sans les sous-menus en utilisant le code suivant:

<?php

$menu_name = 'main-nav';
$locations = get_nav_menu_locations()
$menu = wp_get_nav_menu_object( $locations[ $menu_name ] );
$menuitems = wp_get_nav_menu_items( $menu->term_id, array( 'order' => 'DESC' ) );

foreach ( $menuitems as $item ):

    $id = get_post_meta( $item->ID, '_menu_item_object_id', true );
    $page = get_page( $id );
    $link = get_page_link( $id ); ?>

    <li class="item">
        <a href="<?php echo $link; ?>" class="title">
            <?php echo $page->post_title; ?>
        </a>
        <a href="<?php echo $link; ?>" class="desc">
            <?php echo $page->post_excerpt; ?>
        </a>
    </li>

<?php endforeach; ?>

J'aurais généré le menu en utilisant le wp_nav_menu mais j'ai toujours besoin de la description affichée à l'aide de $page->post_excerpt.

J'ai constaté qu'il existe une propriété pour chaque élément appelée $item->menu_item_parent qui donne l'ID de l'élément de menu parent.

Comment générer le sous-menu dans ma boucle foreach? Ou existe-t-il un moyen très simple d'utiliser wp_nav_menu que Google a oublié de mentionner?

41
hitautodestruct

Pour toute personne qui s'attaque à quelque chose de similaire, voici ma solution:

Exemple de code rapide sur un Gist

Voici le code sur un Github Gist pour tous ceux qui veulent se lancer dans l'action copier-coller.

TL; DR

TL; DR Boucle sur la liste, explorez s'il y a un sous-menu, fermez si nous atteignons la fin du sous-menu et du menu.

Explication complète du code

Obtenez d'abord les éléments de menu sous forme de tableau plat:

<?php
$menu_name = 'main_nav';
$locations = get_nav_menu_locations();
$menu = wp_get_nav_menu_object( $locations[ $menu_name ] );
$menuitems = wp_get_nav_menu_items( $menu->term_id, array( 'order' => 'DESC' ) );
?>

Ensuite, parcourez le tableau des éléments de menu:

<nav>
<ul class="main-nav">
    <?php
    $count = 0;
    $submenu = false;

    foreach( $menuitems as $item ):
        // set up title and url
        $title = $item->title;
        $link = $item->url;

        // item does not have a parent so menu_item_parent equals 0 (false)
        if ( !$item->menu_item_parent ):

        // save this id for later comparison with sub-menu items
        $parent_id = $item->ID;
    ?>

Écrivez le premier élément parent <li>:

    <li class="item">
        <a href="<?php echo $link; ?>" class="title">
            <?php echo $title; ?>
        </a>
    <?php endif; ?>

Vérifiez que l'ID parent de cet élément correspond à l'ID parent stocké:

        <?php if ( $parent_id == $item->menu_item_parent ): ?>

Sous-menu Démarrer <ul> Et mettre $submenu drapeau à true pour référence ultérieure:

            <?php if ( !$submenu ): $submenu = true; ?>
            <ul class="sub-menu">
            <?php endif; ?>

Écrivez l'élément de sous-menu:

                <li class="item">
                    <a href="<?php echo $link; ?>" class="title"><?php echo $title; ?></a>
                </li>

Si l'élément suivant n'a pas le même identifiant parent et que nous avons un sous-menu déclaré, fermez le sous-menu <ul>

            <?php if ( $menuitems[ $count + 1 ]->menu_item_parent != $parent_id && $submenu ): ?>
            </ul>
            <?php $submenu = false; endif; ?>

        <?php endif; ?>

Encore une fois, si l'élément suivant du tableau n'a pas le même identifiant parent, fermez le <li>

    <?php if ( $menuitems[ $count + 1 ]->menu_item_parent != $parent_id ): ?>
    </li>                           
    <?php $submenu = false; endif; ?>

<?php $count++; endforeach; ?>

  </ul>
</nav>
66
hitautodestruct

Votre meilleur pari est de créer votre propre classe Walker pour adapter la sortie à vos besoins. Quelque chose comme ça:

class Excerpt_Walker extends Walker_Nav_Menu
{
    function start_el(&$output, $item, $depth, $args)
    {
        global $wp_query;
        $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, $args ) );
        $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;

        /*GET THE EXCERPT*/
        $q = new WP_Query(array('post__in'=>$item->object_id));
        if($q->have_posts()) : while($q->have_posts()) : $q->the_post();
            $item_output .= '<span class="menu-excerpt">'.get_the_excerpt().'</span>';
        endwhile;endif;
        /*****************/

        $item_output .= '</a>';
        $item_output .= $args->after;

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

Et puis appelez-le comme ceci:

<?php
wp_nav_menu(array('walker' => new Excerpt_Walker()));
?>

Tout avant et après le marqueur GET THE EXCERPT dans mon exemple était une copie directe de la fonction start_el dans wp-includes/nav-menu-template.php. Mon exemple utilise WP_Query pour déterminer si le post/page a un extrait et place l'extrait entre les balises span après le titre du lien.

Une idée serait de faire apparaître les balises span uniquement lors du survol, ce qui peut être fait en utilisant CSS.

Plus d'informations sur les marcheurs ici:

Codex du menu WP Nav

tilisation de la classe Walker

n autre exemple décent utilisant la classe Walker

9
maiorano84
      //Just set your variable and apply.. for sub menu
     <ul>
     <?php

     $activeclass = '';
    $activeclass1='';
     $count=0;
    $submenu = FALSE;
    foreach ( $primaryNav as $navItem ) {
            $activeclass = '';  
         if($navItem->object_id == $getid){
            $activeclass = 'class="live-act"';
         }
         if (!$navItem->menu_item_parent ){
            $parent_id = $navItem->ID;
        echo '<li><a href="'.$navItem->url.'" '.$activeclass.'   title="'.$navItem->title.'">'.$navItem->title.'</a>';
         }
         ?>
        <?php if ( $parent_id == $navItem->menu_item_parent ) { ?>
      <?php if ( !$submenu ): $submenu = true; ?>
        <ul>
        <?php endif; ?>
             <li>
                <a href="<?php echo $navItem->url; ?>" class="title"><?php echo $navItem->title; ?></a>
            </li>
       <?php if ( $primaryNav[ $count + 1 ]->menu_item_parent != $parent_id && $submenu ){ ?>
        </ul>
        <?php $submenu = false; 
       }
        ?>
        <?php }
         if ( $primaryNav[ $count + 1 ]->menu_item_parent != $parent_id ){ ?>
        </li>                            
            <?php $submenu = false; } ?>

        <?php $count++;   ?>


        <?php } ?>
         </ul>
0
GAJENDRA patel