Pour mon premier tutoriel, je vais vous expliquer comment réaliser le même menu que j’utilise sur screenfeed.fr, compatible avec WordPress 3.
Au programme: XHTML strict, php, css2 et 3, jQuery + easing, et bien sûr, des fonctions de WordPress.
Notre menu sera compatible à partir de WordPress 3, disposera d’une description pour chaque lien de premier niveau et d’un niveau de sous-menus (sans description cette fois), et sera bien sûr administrable.
Le menu original est tiré de cet article sur le site de Codrops, sauf qu’il n’est du tout prévu pour WordPress. C’est donc ce que nous allons faire aujourd’hui, il nous faudra modifier le code original et rajouter quelques lignes dans le fichier functions.php de notre thème. Je ne vais pas reprendre l’explication de la construction du menu puisque tout est déjà expliqué dans le tutoriel original (si vous n’êtes pas anglophobe ça devrait glisser tout seul ;) ). On va plutôt se concentrer sur les modifications et nouveautés à apporter.
Au début, il y avait…
Tout d’abord, si ce n’est déjà fait, il faut déterminer un emplacement pour notre menu dans notre thème, et on va appeler cet emplacement « Menu du haut » (c’est ce qui s’affichera dans la partie « Apparence » -> « Menus » de l’administration). Pour cela, on va éditer le fichier functions.php situé dans le dossier du thème:
01020304050607080910
add_action( 'init', 'slide_down_menus' );
if ( ! function_exists( 'slide_down_menus' ) ):
function slide_down_menus() {
register_nav_menus(
array(
'top-menu' => __( 'Menu du haut' )
)
);
}
endif;
A partir de là, on peut créer un menu classique en ajoutant des liens vers nos pages, catégories, etc. depuis l’administration. Maintenant il nous faut placer notre menu sur le site, et préciser que l’on veut faire apparaitre la description des liens.
Pour ma part, j’ai placé mon menu dans le fichier header.php de mon thème:
010203040506070809101112
wp_nav_menu( array(
'container' =>false,
'menu_class' => 'nav',
'echo' => true,
'before' => '',
'after' => '',
'link_before' => '',
'link_after' => '',
'depth' => 2,
'walker' => new description_walker(),
'theme_location' => 'top-menu')
);
Concernant les arguments: j’ai mis 'container' => false
car je ne souhaite pas englober ma balise ul dans une div ou autre (inutile dans mon thème, mais à vous d’adapter selon vos besoins), ‘depth’ correspond au nombre de sous-catégories dont vous aurez besoin, ‘walker’ est l’argument le plus important dans notre cas, c’est là qu’on indique une classe php qui nous est utile pour la description des liens et l’architecture du menu, et pour ‘theme_location’ on retrouve le ‘top-menu’ qu’on a indiqué précédemment dans le fichier functions.php.
Bien, maintenant on peut passer aux choses sérieuses: ajouter la description sous les liens de premier niveau (c’était ça l’idée à la base).
En même temps, il faudrait en profiter pour créer l’architecture html du menu.
Jetons déjà un coup d’œil à la structure du menu de Codrops.
010203040506070809101112131415161718
<ul id="sdt_menu" class="sdt_menu">
<li>
<a href="#">
<img src="images/1.jpg" alt=""/>
<span class="sdt_active"></span>
<span class="sdt_wrap">
<span class="sdt_link">Portfolio</span>
<span class="sdt_descr">My work</span>
</span>
</a>
<div class="sdt_box">
<a href="#">Websites</a>
<a href="#">Illustrations</a>
<a href="#">Photography</a>
</div>
</li>
...
</ul>
Dans le fond, ce n’est pas très différent d’un menu WordPress classique, on doit « juste » rajouter quelques balises.
Au final, on va arriver à ça:
0102030405060708091011121314151617
<ul id="menu-mainmenu">
...
<li id="..." class="...">
<a href="/ma-categorie/">
<img src="/wp-content/themes/mon-theme/images/tab_category13.jpg" alt="" />
<span class="tab_active"> </span>
<span class="tab_wrap">
<strong>Nom de ma catégorie</strong>
<span>Description de ma catégorie</span>
</span>
</a>
<ul class="sub-menu">
<li id="..." class="..."><a href="/ma-categorie/ma-sous-cat-1/">Sous-catégorie 1</a></li>
<li id="..." class="..."><a href="/ma-categorie/ma-sous-cat-2/">Sous-catégorie 2</a></li>
</ul>
</li>
</ul>
Quelques aménagements ont été faits afin d’être valide au niveau XHTML, se faciliter la vie pour le css, et pour ne pas se la compliquer avec WordPress (puisqu’il génère les balises ul et li automatiquement.
On ouvre le capot
Bien, pour construire cette structure, on va partir d’une fonction existante dans une classe php de WordPress. Pour les curieux, il s’agit de la fonction start_el de la classe Walker_Nav_Menu située dans le fichier /wp-includes/nav-menu-template.php, mais rassurez-vous, on ne va pas y toucher, on va la « réécrire » et la modifier dans notre fichier functions.php :
0102030405060708091011121314151617181920212223242526272829303132333435
class description_walker extends Walker_Nav_Menu {
function start_el(&$output, $item, $depth, $args) {
$indent = ( $depth ) ? str_repeat( "t", $depth ) : '';
$class_names = $value = '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
$class_names = ' class="'. esc_attr( $class_names ) . '"';
$output .= $indent . '<li id="menu-item-'. $item->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 ) .'"' : '';
$prepend = '<strong>';
$append = '</strong>';
$description = ! empty( $item->description ) ? '<span>'.esc_attr( $item->description ).'</span>' : ''; //Si la description du lien n'est pas vide on l'enregistre
if($depth != 0) { //Si ce n'est pas un lien de premier niveau, on écrase tout
$description = $append = $prepend = "";
}
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>'; //On ouvre notre lien avec son url et ses classes
if($item->menu_item_parent == 0) { //S'il s'agit d'un lien de premier niveau
$item_output .= '<img src="'.get_bloginfo('template_directory').'/images/tab_'.$item->object.$item->object_id.'.jpg" alt="" />'; //L'image du lien
$item_output .= '<span class="tab_active"> </span>'; //Le span nécessaire à l'animation
$item_output .= '<span class="tab_wrap">';
$item_output .= $args->link_before .$prepend.apply_filters( 'the_title', $item->title, $item->ID ).$append; //Le nom du lien (titre de la page)
$item_output .= $description.$args->link_after; //La description
$item_output .= '</span></a>'; //On referme le lien
} else { //Si ce n'est pas un lien de premier niveau
$item_output .= $args->link_before .$prepend.apply_filters( 'the_title', $item->title, $item->ID ).$append; //Le nom du lien
$item_output .= $args->link_after.'</a>'; //On referme le lien
}
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
Le début de la fonction est identique à l’originale, puis on indique qu’on va utiliser des balises strong pour entourer le nom des liens de premier niveau. Ensuite, si la description du lien est disponible on l’entoure de nos span et on la met dans une variable.
Si on est en train de générer un lien dans un sous-menu, on n’a pas besoin de la description ni de nos balises strong donc on met une chaine vide dans nos variables précédentes.
On commence maintenant à générer notre lien en ouvrant la balise a, puis avec une condition « if » on va créer le reste, suivant s’il s’agit d’un lien de premier niveau ou d’un lien de sous-menu: un item de premier niveau n’a pas d’item parent, donc la valeur de $item->menu_item_parent sera 0.
L’image, c’est là que ça devient intéressant :) On va utiliser une petite astuce, mais il faudra remplir 3 conditions:
– il faudra placer chaque image dans… le dossier « images » de votre thème ( /wp-content/themes/mon-theme/images/ ) donc vérifiez que votre dossier s’appelle bien « images », ou modifiez le script,
– chaque image devra s’appeler « tab_xxxxxx123.jpg »: vous pouvez modifier le « tab_ » s’il ne vous plait pas bien sûr, quant au « xxxxxx123 » cela va dépendre du type de page que vous voulez afficher avec votre lien et de l’ID de votre page. Par exemple si vous voulez afficher les posts de la catégorie dont l’ID est 145, votre image devra s’appeler « tab_category145.jpg ». Pour une page dont l’ID est 72, « tab_page72.jpg »…
Comment trouver cet ID et ce « xxxxxx » me direz-vous? C’est très simple: dans l’administration, rentrez par exemple dans la page ou le post que vous voulez afficher, comme si vous vouliez la (le) modifier et regardez la fin de l’URL dans la barre d’adresse de votre navigateur: « …post.php?post=11&action=edit… » là il s’agit d’un POST et son ID est 11: tab_post11.jpg.
– toutes les images doivent avoir la même extension: .jpg mais vous pouvez aussi le changer si vous avez des images en .png, il suffit juste qu’elles soient toutes au même format.
La suite du code est facile, on construit les span dont on a besoin avec le nom et description du lien puis on fini notre condition « if » pour ensuite créer nos lien de sous-menus avec le « else ».
On s’habille pour l’hiver
Le plus gros est fait, il faudrait mettre tout ça en forme avec du css maintenant. Là, vous allez certainement devoir faire des modifications pour adapter le menu à votre thème. Je vous livre quand même un morceau de celui employé ici. Dans mon thème, j’avais besoin d’un menu affichant seulement 4 liens, de largeur fixe 480px, de hauteur 50px, d’une bordure de 1px, et des images de 120px de côté. Je vous fait grâce des font-family et images de fond. Le tout est à inclure dans le fichier css de votre thème:
001002003004005006007008009010011012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061062063064065066067068069070071072073074075076077078079080081082083084085086087088089090091092093094095096097098099100101102103104105106107108109
a {
cursor: pointer;
}
#menu-mainmenu {
float: left;
position: relative;
top: 80px;
width: 480px;
height: 50px;
border-style: solid;
border-color: #ababab;
border-width: 1px 1px 0 1px;
list-style:none;
background-color: #191919;
}
#menu-mainmenu li {
float: left;
width: 120px;
height: 50px;
position: relative;
list-style-type: none;
}
#menu-mainmenu a {
display: block;
width: 120px;
height: 50px;
position: absolute;
left: 0;
top: 0;
z-index: 12;
text-align: center;
color: #ababab;
}
#header a:hover, #header a:active {
text-decoration: none;
}
#menu-mainmenu a img {
width: 0;
height: 0;
position: absolute;
left: 120px;
bottom: -1px;
z-index: 100;
-moz-box-shadow: 0 0 4px #000;
-webkit-box-shadow: 0 0 4px #000;
-khtml-box-shadow: 0 0 4px #000;
box-shadow: 0 0 4px #000;
}
#menu-mainmenu .current-menu-item a img,
#menu-mainmenu .current_page_parent a img,
#menu-mainmenu .current-menu-ancestor a img { /* On change la couleur et la taille de l'ombre des images pour l'onglet courant */
-moz-box-shadow: 0 0 6px #00f5f1;
-webkit-box-shadow: 0 0 6px #00f5f1;
-khtml-box-shadow: 0 0 6px #00f5f1;
box-shadow: 0 0 6px #00f5f1;
}
#menu-mainmenu .tab_active { /* L'onglet qui va descendre sous l'image */
width: 120px;
height: 0;
line-height: 0;
position: absolute;
left: -1px;
top: 50px;
z-index: 14;
border-style: solid;
border-width: 0 1px 1px 1px;
border-color: #ababab;
background-color: #110205; /* Couleur de fond des onglets */
}
#menu-mainmenu .tab_wrap { /* La span incluant nos liens et descriptions */
width: 120px;
height: 50px;
position: absolute;
left: 0;
top: 0;
z-index: 15;
}
#menu-mainmenu a strong {
display: block;
height: 24px;
padding-top: 7px;
font-size: 24px;
line-height: 24px;
}
#menu-mainmenu a span span { /* Description */
display: block;
font-size: 12px;
line-height: 18px;
font-weight: normal;
}
#menu-mainmenu .sub-menu {
display: none;
width: 120px;
height: 119px;
position: absolute;
left: 0;
top: 50px;
border: solid 1px #ababab;
background-color: #110205; /* Couleur de fond des sous-menus */
}
#menu-mainmenu .sub-menu li {
height: 59px; /* Hauteur prévue pour seulement 2 liens dans le sous-menu, à modifier selon vos besoins */
}
#menu-mainmenu .sub-menu a {
height: 59px; /* Hauteur prévue pour seulement 2 liens dans le sous-menu, à modifier selon vos besoins */
line-height: 59px; /* Hauteur prévue pour seulement 2 liens dans le sous-menu, à modifier selon vos besoins */
font-weight: normal;
font-size: 12px;
}
Un peu de mouvement
On passe enfin au javascript. Dans le dossier de votre thème, créez un dossier « js » où vous allez mettre vos scripts javascript, puis un fichier « main.js » puis collez-y ceci:
0102030405060708091011121314151617181920212223242526272829303132333435363738394041424344454647
jQuery(document).ready(function($){
//-------------------------------------------------------------------------- Menu principal --------------------
$(function() {
$('#menu-mainmenu > li').bind('mouseenter',function(){
var $elem = $(this);
$elem.find('img')
.stop(true)
.animate({
'width':'120px',
'height':'120px',
'left':'0px'
},400,'easeOutBack')
.andSelf()
.find('.tab_wrap')
.stop(true)
.animate({'top':'85px'},500,'easeOutBack')
.andSelf()
.find('.tab_active')
.stop(true)
.animate({'height':'120px'},300,function(){
var $sub_menu = $elem.find('.sub-menu');
if($sub_menu.length){
var left = '120px';
if($elem.parent().children().length == $elem.index()+1) left = '-120px';
$sub_menu.show().animate({'left':left},200,function(){$(this)});
}
});
}).bind('mouseleave',function(){
var $elem = $(this);
var $sub_menu = $elem.find('.sub-menu');
if($sub_menu.length) $sub_menu.hide().css('left','0px');
$elem.find('.tab_active')
.stop(true)
.animate({'height':'0px'},300)
.andSelf().find('img')
.stop(true)
.animate({
'width':'0px',
'height':'0px',
'left':'50px'},400)
.andSelf()
.find('.tab_wrap')
.stop(true)
.animate({'top':'0'},300);
});
});
});
Il ne reste lus qu’à inclure les fichiers javascript dans votre fichier footer.php, juste après wp_footer(); (bien sûr il faudra que jQuery soit présent):
12
<script type='text/javascript' src="<?php bloginfo('stylesheet_directory'); ?>/js/jquery.easing.1.3.js"></script>
<script type='text/javascript' src="<?php bloginfo('stylesheet_directory'); ?>/js/main.js"></script>
Vous trouverez jquery.easing.1.3 ici.
Pour ma part, j’ai directement inclus jquery.easing.1.3.js dans main.js afin d’avoir une requête http en moins, à vous de voir ;)
Enjoy
Notre menu est terminé! Vous n’avez plus qu’à ajouter les images dans votre dossier avec les noms indiqués et le tour est joué.
Commentaires
Commentaire de Yann.
Bonjour Greg,
Je viens de découvrir ton blog.
Je te félicite pour ces intégrations et ces tutoriaux…
Je suis épaté que tu aies réussi à adapter ce si joli menu de Codrops pour wordpress.
Un grand merci donc pour ton travail, le tout enrobé d’humour !!
Keep going ;)
Yann
Commentaire de Greg.
Merci Yann ;)
PS : désolé pour la réponse tardive, j’ai eu un soucis de commentaires fantômes >_<
Commentaire de Claymenia.
Bonsoir,
J’ai trouvé votre tuto génial, toutefois j’ai deux soucis :
– si j’active « container », il n’apparaît pas en div ou h1 mais juste <1 id=" et , ce qui évidemment n’inclut pas le menu dans un div.
– mon second soucis : comment intégrer un lien pour le « home » sous wordpress après l’ouverture de ?
Merci par avance de votre aide !!!
Commentaire de Greg.
Bonsoir.
Pour « container » il ne suffit pas de mettre « true » ou 1, il faut préciser quelle balise utiliser. Voir la fonction wp_nav_menu() sur le codex.
‘div’ étant la valeur par défaut, il suffit de supprimer la ligne « container » pour avoir une
<div>
, sinon il faut préciser :1
Pour le lien vers la home, est-ce que tu parles de la page d’accueil du site (front-page) ou de la page listant les articles (home-page)?
Commentaire de Claymenia.
Bonjour et merci de votre réponse si rapide et si claire :)
A vrai dire j’aimerai bien savoir pour les deux cas ^^
Sinon je ne suis pas très bon en code mais pour ceux qui débute comme moi, vous n’avez pas précisez dans votre tuto que le menu créé par l’admin doit se nommer « mainmenu » ou qu’il faut alors changer le nom dans la feuille de style :D
Commentaire de Claymenia.
Re bonjour,
Je profite également pour vous signaler un autre soucis que je rencontre : les 2
<a>
des sous-menu est décalé et dépasse par la droite (il n’est pas correctement centré dans l’onglet). J’ai tenté de modifier le main.js, mais cela ne modifie que la taille de l’onglet. J’ai tenté également de modifier cela par le css en ajoutant aux classes .sub-menu un text-align: center; mais cela ne marche pas, ni même pour les margin ou les padding…Merci de votre aide !
Commentaire de Greg.
A vrai dire j’aimerai bien savoir pour les deux cas ^^
J’ai envie de dire : une fois le menu crée dans l’administration, regarder le nom de l’image générée dans le front-end et créer une image avec ce nom ;)
Sinon je ne suis pas très bon en code mais pour ceux qui débute comme moi, vous n’avez pas précisez dans votre tuto que le menu créé par l’admin doit se nommer « mainmenu » ou qu’il faut alors changer le nom dans la feuille de style :D
Anéfé©
Commentaire de Greg.
le
text-align: center
est appliqué aux liens via#menu-mainmenu a
.Je suppose qu’une autre déclaration css venant de ton thème par exemple, doit interférer avec ceci. Si tu ne trouves pas d’où ça vient, transmets moi un lien vers la dite page que je puisse y jeter un œil.
Commentaire de Claymenia.
Bonsoir,
Je me suis mal exprimé, il s’agit des balises
<a>
des sous menus. Concernant mon code je n’ai que ça pour l’instant :01020304050607080910111213141516171819202122232425262728293031323334
donc je ne vois pas trop en quoi cela peu interférer… et j’en suis bien embêté !!!
Commentaire de Claymenia.
Je vais paraître très stupide, mais étant donné que je créé mon design, je ne vois pas quel image devrait être générée dans le front-end… :)
Commentaire de Claymenia.
J’ai résolu le problème en créant un page statique pour les news. J’ai également résolu le problème de décalage (plutôt rusé ;) ) en ajoutant un padding à #menu-mainmenu .sub-menu.
Merci beaucoup pour votre aide en tout cas, je veux bien toutefois connaître la manière de faire le lien vers la page des articles native (index.php) sans passer par une statique.
Commentaire de Greg.
Je me suis mal exprimé, il s’agit des balises
<a>
des sous menus.Tu t’es bien exprimé et j’avais compris ce dont tu voulais parler.
Le
text-align: center
appliqué aux liens via#menu-mainmenu a
s’applique également aux liens de sous-menu. Ce que je voulais dire c’est que : je suppose que le menu est intégré dans ton site, ton site a donc un thème, il suffit que dans ton thème il y ait une déclaration css genrea { padding-left: 20px; }
ou quelque chose de similaire pour que ce décalage non désiré apparaisse dans le menu.je ne vois pas quel image devrait être générée dans le front-end…
L’image du menu. Voir mon explication dans le tuto :
chaque image devra s’appeler « tab_xxxxxx123.jpg »
Le menu va vouloir afficher une image pour chaque lien de « haut niveau ». Si tu ne sais pas comment appeler cette image, il suffit de regarder son nom dans le code html crée sur ton site (bien sûr, si l’image n’existe pas elle ne sera pas visible, mais son code et donc son url seront là), tu pourra ainsi savoir comment nommer ton image.
je veux bien toutefois connaître la manière de faire le lien vers la page des articles native (index.php) sans passer par une statique.
Administration > Apparence > Menu :
Boîte « Liens personnalisés » :
– Adresse web : http://www.mon-site.com/
– Titre : Accueil
Cliquer sur « Ajouter au menu ».
Dans ce nouvel item Accueil (de type « lien » donc), rentrer la description (de là, tu pourras aussi ajouter les catégories dont tu parlais en sous-menu).
Enregistrer le menu.
Aller sur le site, regarder l’url de l’image de ce nouveau lien : le nom du fichier sera du type « tab_custom123.jpg » (tu auras un autre nombre que 123).
Créer une image nommée tab_custom123.jpg et la glisser dans le dossier.
Terminé :)
Commentaire de Claymenia.
Désolé pour mon erreur au dessus, il s’agit des 2 balises
<a>
.Sinon en revenant sur la question du home, serait-il possible d’après-vous d’afficher en sub-menu sous le Home les catégories des articles ?
Désolé de toutes ces questions, mais votre code m’ouvre de nouveaux horizons :)
Commentaire de Greg.
Oui, il suffit d’ajouter ces catégories depuis l’administration, mais attention, le design du menu n’est pas prévu pour mettre des sous-menus longs. En l’occurrence, le code fourni est prévu pour 2 lignes par sous-menu.
Commentaire de BKcine.
Bonsoir.
Merci pour ce super tuto.
Ma question de newbeee : pourquoi déclare-t-on le jquery dans le footer ?
Au passage, ton blog est vraiment de conception très originale, bravo !!
Commentaire de Greg.
Bonsoir.
C’est pour optimiser le temps de chargement des pages, pour qu’elles commencent à s’afficher au plus tôt.
En mettant les javascripts dans le footer, ils seront chargés seulement à la fin, le plus important étant le contenu de la page et sa mise en forme via css.
Merci! :)
Commentaire de BKcine.
Ah oui… c’est une très bonne idée, en effet… je la pique immédiatement :)
Par curiosité : combien de temps cela t’a pris pour intégrer un tel design dans ton wordpress ??
En effet, plus on se balade sur ton site, plus on découvre des fonctionnalités impensables il y a peu…
Encore bravo !
Et bonne continuation.
Amicalement,
BK.
Commentaire de karakzho.
Tuto super bien fait.En revanche j’ai un petit soucis dans la compréhension des élèments.
Je n’arrive pas à customiser le menu.Par exemple, que l’image s’affiche en haut du menu bar et que toutes les images prènnent la même place. en gros, qu’elle ne soit pas toute décallé avec les différents menus.
Je ne sais pas si je suis clair, mais voilà, auriez vous des trames de recherches? ou des idées sur cette personnalisation?
Merci