Tutoriel WordPress : la sidebar à la loupe, comprendre les widgets et déclarer une « WAR »

A l’installation de WordPress 2.2, le thème par défaut propose une barre latérale contenant le champs de recherche, les catégories, les pages ou encore la blogoliste. Le tout, affichés via une liste non ordonnée contenant elle-même d’autres listes. C’est pratique en plus d’avoir du sens. Mais si je voulais séparer ces éléments pour respecter une charte graphique allant au-delà de la présentation habituelle, je devrais modifier le code HTML en plus de modifier la feuille de style CSS. Dans ce tutoriel, j’aborde la transformation de cette liste globale en plusieurs blocs transpositionnables, en enfilant des gants pour commencer, puis avec les Widgets qui ont fait leur apparition. Je termine en ajoutant une deuxième zone widgétisable à un thème qui n’en comportait qu’une au départ. J’en ai profité pour rendre le code du Widget Texte 1 plus sémantique en remplaçant une div par un p (c’est élégant, tiens…) 😉

Note : bien qu’écrit lors de la sortie de la version 2.2, cet article est toujours d’actualité 😉

Les mains dans le cambouis…

L’affichage des fonctionnalités est réalisé de plusieurs manières. Il s’agit parfois d’inclure un fichier qui fournit tout le code HTML nécessaire ou d’utiliser une fonction précédée ou non de balises li. Tout au long de ce tutoriel, j’ai choisi d’expliciter le parti-pris du thème par défaut concernant le balisage HTML de la sidebar en particulier, sachant que la zone de contenu principal ne présente pas de difficultés particulières.

L’affichage du champ de recherche

Le champs de recherche est appelé via la commande PHP include. Pour l’insérer dans la liste non ordonnée, le concepteur du thème default a simplement ajouté des balises li puisque la balise parente ul est présente dès le début de sidebar.php.

 <li><?php include (TEMPLATEPATH . '/searchform.php'); ?> </li>

Cette balise li est une des rares balises HTML de deuxième niveau avec dd (mise à part le body évidemment) qui accepte tout type de balises en son sein. Il est même possible d’y placer du texte directement sans perdre en conformité. Ce comportement associé au fait qu’on peut justifier l’utilisation d’une liste à partir de deux ou trois élements faisant partie d’une même unité logico-sémantique, explique le succès des listes ul ou ol auprès des intégrateurs HTML.

ll est intéressant de noter l’usage de la contante TEMPLATEPATH qui donne le chemin absolu vers le dossier du thème activé depuis l’interface d’administration. Il s’agit d’ailleurs de la méthode recommandée pour inclure des fichiers dans vos templates.

L’affichage des Pages, de la Blogoliste et des Catégories

Par défaut, ces fonctions génèrent des éléments de liste li qui sont habillées par la balise ul présente au début de sidebar.php. A noter que le titre h2 est précisé en tant qu’option :

 <?php wp_list_pages('title_li=<h2>Pages</h2>'); ?>
 <?php wp_list_bookmarks(); ?>
 <?php wp_list_categories('show_count=1&title_li=<h2>Catégories</h2>'); ?>

Pour info, voici le marquage HTML des Catégories de l’exemple ci-dessus :

<li class="categories">
    <h2>Catégories</h2>
    <ul>
        <li><a href="#">contines</a></li>
        <li><a href="#">nouvelles</a></li>
        <li><a href="#">pensées</a></li>
    </ul>
</li>

L’affichage des Archives

Les Archives nécessitent plus d’attention car la fonction ne produit qu’une suite de li, qu’il faut bien évidemment encadrer par une balise parente ul. Mais ça ne suffit pas : comme elle ne possède pas l’option pour afficher le titre, il faut le rajouter dans le code HTML. Ce qui demande d’ajouter une balise li au-dessus afin de respecter la structure du HTML qui n’autorise pas l’élément ul à être directement suivi d’un élément h2 ^^

<li>
    <h2>Archives</h2>
    <ul>
        <?php wp_get_archives('type=monthly'); ?>
    </ul>
</li>

Pour styler ces éléments de liste, il est essentiel de garder à l’esprit l’imbrication des ul li ul li ou ul ul li…

Transportabiliser ces éléments

Si je voulais déplacer certains éléments de cette sidebar pour mettre le champs de recherche dans le header et transformer les Catégories en menu horizontal placé juste au-dessus des billets, je devrais placer chaque appel de fonction dans une balise div « transportable » ou « positionnable » si vous préférez. Pour celà, il suffirait de remplacer les balises li des deux exemples précédents par des div et le tour est joué.

…ou avec les Widgets ?

Je dois dire qu’au début, l’arrivée des Widgets ne m’a fait ni chaud ni froid : ils existaient déjà en tant que plugin. Par ailleurs, je préfère placer le code moi-même. Toutefois, dans une optique blog d’entreprise, ces modules sont une bénédiction pour donner aux clients qui veulent « prendre la main » sur leur outil de blog, la possibilité de le faire sans trop de casse.

Pour paraphraser une publicité bien connue : si c’est bon pour le confort de mon client, alors c’est bon pour mon confort ! Je me suis donc penché sur la question : on peut vraiment se simplifier la vie – et le code – en utilisant les Widgets. Le principe est simple : le sous-menu Widgets dans le menu Thèmes de l’administration permet de faire glisser les équivalents Widgets des fonctionnalités abordées plus haut (plus quelques autres qui étaient disponibles auparavant sous forme de plugin, comme : Commentaires récents, Articles récents et le très pratique module Texte) sur l’emplacement réservé Colonne latérale 1.

Comment ça marche ?

Par défaut, les fonctionnalités de la barre latérale sont gérées « en dur » dans le fichier sidebar.php qui attend que l’on glisse un Widget dans l’emplacement prévu pour passer en mode Dynamic Sidebar. Ce qui explique la présence de functions.php dans le dossier themes. Ce fichier est automatiquement reconnu par le moteur de WordPress dès sa création (au cas où je voudrais widgétiser un thème plus ancien) : il est destiné à contenir toutes mes fonctions PHP en plus des lignes suivantes :

<?php if (function_exists('register_sidebar') )
    register_sidebar(array(
        'before_widget' => '<li id="%1$s" class="widget %2$s">',
        'after_widget' => '</li>',
        'before_title' => '<h2 class="widgettitle">',
        'after_title' => '</h2>',
    ));
?>

Grosso modo : si la fonction register_sidebar() existe, tous les Widgets activés se verront chapeautés par un élément de liste li et le titre sera encadré par un h2 (l’élément ul est à ajouter dans le code, comme c’est le cas dans le thème par défaut).

Dans le fichier sidebar.php, je trouve, juste après l’ouverture de la balise ul, le code qui affiche ou non les fonctionnalités par défaut si le thème n’est pas Widget-Ready ou s’ils n’ont pas été activés. Autrement, ce sont les Widgets activés dans le panneau d’administration qui s’affichent.

<div id="sidebar">
    <ul>
        <?php   /* Widgetized sidebar, if you have the plugin installed. */
            if ( !function_exists('dynamic_sidebar') || !dynamic_sidebar() ) : ?>
                [ le code pour afficher votre sidebar si votre thème n'est pas
                widget ready ou si les widgets ne sont pas activés ]
            <?php endif; ?>
    </ul>
</div>

Pour remplacer les éléments de liste de premier niveau, je supprime les balises ul situées après l’ouverture de <div id= »sidebar »> et juste avant la dernière balise fermante </div> dans sidebar.php, puis j’utilise l’élément div à la place du li dans le passage suivant du fichier functions.php vu précédemment :

'before_widget' => '<div id="%1$s" class="widget %2$s">', 'after_widget' => '</div>',

Désormais, chaque appel de Widget sera encadré par une jolie div avec le nom du module comme identifiant, accompagné de la classe générique pour les Widgets et d’une classe spécifique pour le module en question.

Pour info et pour comparer avec le premier exemple, voici le marquage HTML des Catégories:

<div id="categories" class="widget widget_categories">
    <h2 class="widgettitle">Catégories</h2>
    <ul>
        <li><a href="#">contines</a></li>
        <li><a href="#">nouvelles</a></li>
        <li><a href="#">pensées</a></li>
    </ul>
</div>

Voici maintenant le marquage HTML affichant le contenu du Widget Texte 1 :

<div id="text-1" class="widget widget_text">
    <h2 class="widgettitle">Introduction</h2>
    <div class="textwidget">
        Bla bla bla...
    </div>
</div>

Arrgh ! Mais que vois-je ? Et la sémantique, alors, elle est où ? Lorsqu’on ne saisie que du texte, il faut se contenter d’une pauvre div sans signification pour encadrer notre prose ? Pas très sémantique tout ça. Je vais réparer tout celà efficacement à défaut de le faire proprement… Je vais modifier le fichier /wp-includes/widgets.php à la ligne 502 pour remplaçer les éléments div de la fonction wp_widget_text($args, $number = 1) par des éléments p plus parlant !

Il existe certainement un moyen pour arriver au même résultat en ne modifiant que le fichier functions.php du dossier themes, ce qui serait bien plus propre. Mais bon, la modif est minime et le résultat en vaut la peine 😉 Et puis, je garde une trace des modifications apportées à mon code (enfin, je crois 😉 ).

Heureusement, il est possible de saisir du code HTML dans le widget Texte qui accepte toutes les balises, de sorte que si l’on saisit le texte entre deux balises p, le « problème » est résolu 😉 Mais bon, quand ce texte tient sur un seul paragraphe (ce qui est souvent le cas dans les présentations de blogs ou d’auteurs) ou que l’administrateur du blog ne connait pas le HTML (ce qui arrive lorsqu’on livre un blog clés en main), ce petit détour vers widget.php peut présenter un intérêt.

MàJ : La solution de burningHat pour modifier les widgets originaux proprement

La modification du moteur de WordPress n’est jamais une bonne idée : les concepteurs ont fait moult effort pour qu’on l’évite. Encore faut-il s’y connaitre un peu. C’est le cas de burningHat qui s’est creusé la tête pour trouver une solution dans l’esprit WordPress : élégance et efficacité.

L’idée est de redéfinir les fonctions des widgets dans le fichiers functions.php qui est attaché au thème et non au moteur. Voici un extrait de l’article original : WordPress 2.2 – Modifier les widgets originaux que je vous invite à lire sans tarder :

Nous allons utiliser cette méthode afin de faire en sorte que le widget “pages” exclu certaines des pages de notre blog de son listing.

Je voulais exclure les liens vers “Archives”, “Liens” et “Nuage de tags” afin de de les séparer dans une rubrique à part. Ces pages sont identifiées respectivement par les n°131, 132 et 133.

Le code dans une sidebar classique serait donc :

 <?php wp_list_pages('exclude=131,132,133&title_li='); ?>

Je vous renvoie à la page du codex pour détails de la fonction “wp_list_pages“. Nous allons donc définir un widget pour notre thème qui renverra le même affichage. Pour cela ouvrons le fichier “functions.php” situé à la racine de notre thème et ajoutons une fonction “widget_montheme_pages” :

function widget_newburn_pages() {
  wp_list_pages('exclude=131,132,133&title_li=<h2>Et encore...</h2>');
}

Et pour que WordPress en tienne compte en lieu et place du widget “Pages” normal, ajoutons également la condition suivante :

 if ( function_exists('register_sidebar_widget') ){   register_sidebar_widget('pages', 'widget_newburn_pages'); }

Cette dernière va simplement dire à WordPress que le widget “pages” à utiliser n’est pas celui d’origine mais celui que nous venons de définir avec la fonction “widget_newburn_pages“.

Widgets Area Ready ou comment gérer plusieurs « barres latérales » avec les Widgets

Certains thèmes sont prévus pour fonctionner avec deux « barres latérales », bien que ce terme est réducteur puisqu’il s’agit simplement d’une zone que l’on peut placer n’importe où avec les CSS du moment que la structure du code HTML le permet… C’est pourquoi je préfère parler de Widgets Area Ready ou WAR pour les intimes 🙂

Pour mettre en place plusieurs WAR, il faut apporter des modifications à functions.php :

<?php if ( function_exists('register_sidebar') )
    $widgetWrap = array(
        'before_widget' => '<div id="%1$s" class="widget %2$s">',
        'after_widget' => '</div>',
        'before_title' => '<h2 class="widgettitle">',
        'after_title' => '</h2>',
    );
    register_sidebars(2, $widgetWrap); ?>

Notez le « s » à register_sidebars(…) qui a son importance. Je me suis inspiré de ce qui existe dans le thème sandbox :

J’ajoute ensuite le numéro d’ordre dans la fonction dynamic_sidebar() : 1 puis 2 et ainsi de suite pour chaque déclaration de WAR dans les fichiers où j’ai prévu d’afficher des Widgets :

<div id="sidebar">
    <ul>
        <?php   /* Widgetized sidebar, if you have the plugin installed. */
            if ( !function_exists('dynamic_sidebar') || !dynamic_sidebar(1) ) : ?>
                [ Les widgets glissés dans "Colonne latérale 1" s'afficheront ici  ]
            <?php endif; ?>
    </ul> </div> <div id="header-bis">
    <ul>
        <?php   /* Widgetized sidebar, if you have the plugin installed. */
            if ( !function_exists('dynamic_sidebar') || !dynamic_sidebar(2) ) : ?>
                [ Les widgets glissés dans "Colonne latérale 2" s'afficheront là ]
            <?php endif; ?>
    </ul>
</div>

Si tout se passe bien, la page d’adminitration des Widgets devrait proposer « Colonnes latérales 1 » et « Colonnes latérales 2 » pour accueillir les modules.

Pour aller plus loin

Oups ! j’ai dit « Colonnes latérales » et non pas WAR ! Et pour cause : l’emplacement est désigné de cette manière dans la page d’administration. Qu’à celà ne tienne, il est possible de modifier l’intitulé des emplacements en suivant les explications données par automattic.

Sauf qu’après quelques essais, l’intitulé est bien modifié mais le %d s’affiche à la place des chiffres. J’ai pourtant essayé deux méthodes :

<?php if ( function_exists('register_sidebar') )
    $widgetWrap = array(
        'before_widget' => '<div id="%1$s" class="widget %2$s">',
        'after_widget' => '</div>',
        'before_title' => '<h2 class="widgettitle">',
        'after_title' => '</h2>',
        'name'=>'Foobar %d',
    );
    register_sidebars(2, $widgetWrap);
?>

Puis :

<?php if ( function_exists('register_sidebar') )
    $widgetWrap = array(
        'before_widget' => '<div id="%1$s" class="widget %2$s">',
        'after_widget' => '</div>',
        'before_title' => '<h2 class="widgettitle">',
        'after_title' => '</h2>',
    );
    register_sidebars(2, $widgetWrap, array('name'=>'Foobar %d'));
?>

Pour continuer dans les améliorations, je cherche comment obtenir un formatage différent selon la WAR utilisée. Pour l’instant, j’ai l’impression que seul un modèle peut s’appliquer. Si vous avez une idée sur la question, n’hésitez pas à vous manifester 🙂

En guise de conclusion express

Comme la peinture de Stupeflip, WordPress est un outil de blog aux possibilités stupéfiantes que je teste sur différents terrains de jeux que je dévoilerais en temps voulu…
Dotclear n’est pas en reste puisque j’ai un billet en cours de finalisation dans les cartons concernant la version 2 bêta 6 (tiens, manquerais plus qu’une version stable sorte avant que je publie mon billet. Pas taper, pas taper 😉 )

Stay tuned and mind the gap!