Le blog de Nukleo

Afficher les articles en colonne avec WordPress

18 avril 2011 dans WordPress | 6 commentaires

Traditionnellement la liste des articles d’un blog sont affichés les uns à la suite des autres, de haut en bas (comme sur ce blog). Pour diverses raisons (design, optimisation de l’espace, utilisation spécifique de WordPress etc…) on pourrait souhaiter les afficher en colonne. Voici une méthode simple pour y arriver.

Voici ce que l’on veut obtenir : afficher sur la page d’accueil la liste des articles (ou les extraits) dans 2 colonnes, avec les plus récents en haut. Pour y parvenir nous utiliserons l’opérateur modulo de PHP et de la fonction rewind_posts() de WordPress.

Afficher les articles de WordPress en colonne

Le problème

On pourrait tout simplement utiliser la propriété float de CSS pour arriver à nos fins et ça fonctionnerai parfaitement dans le cas de figure où tous les blocs contenant les articles ont la même hauteur (comme dans l’image précédente).

Mais il est très probable que ça ne soit pas le cas : la hauteur de chaque bloc va varier en fonction de son contenu (l’extrait ou l’article). Dans ce cas de figure il y aura 2 problèmes : l’espacement aléatoire entre les blocs (en hauteur) et le non respect de l’ordre chronologique :

Espacement aléatoire et ordre non respecté avec float
Ce n’est pas un bug mais seulement la manière dont fonctionnent les éléments « floatants ».

Pour résoudre le problème d’espacement on pourrait utiliser 2 div pour créer les colonnes et y insérer nos articles, mais dans ce cas l’ordre chronologique des articles se fera de haut en bas, colonne par colonne (voir l’image ci-dessous). Hors nous voulons que les 2 derniers articles soient en haut de la page.

Espacement corrigé mais l'ordre n'est pas celui attendu

La solution

Nous utiliserons tout de même les 2 div pour créer nos colonnes, c’est au niveau de la boucle de WordPress que nous agirons pour respecter la chronologie de nos articles.

Voici la structure HTML de base que nous utiliserons:

<div id="page">
	
	<div id="header"></div>
	
	<div id="contenu" class="clearfix">
		<div class="colonne"></div>
		<div class="colonne"></div>
	</div>
	
	<div id="sidebar" class="clearfix"></div>
	
	<div id="footer"></div>
	
</div>

Les règles CSS qui vont avec :

#page { width: 960px; margin: 0 auto }
#header { padding: 10px; margin: 20px 0 }
#contenu { width: 660px; float: left }
.colonne { width: 300px; margin-right: 30px; float: left }
#sidebar { width: 300px; float: right }
#footer { padding: 10px; margin: 20px 0 }
.clearfix:after { visibility: hidden; display: block; font-size: 0; content: " "; clear: both; height: 0; }

J’ai mis la structure complète mais ce qui nous intéresse ici c’est surtout le contenu de la div #contenu

Le template WordPress

Dans le cas d’un blog classique il n’y a qu’une seule boucle pour afficher les articles. Pour ce que nous souhaitons réaliser on pourrait utiliser 2 boucles sur mesure, mais ce n’est pas nécessaire et utiliserai inutilement plus de ressources (2 requêtes MySql au lieu d’une seule, plus de mémoire) et de temps.
Nous utiliserons la fonction rewind_posts() qui permet de revenir au début de la boucle pour ensuiter la parcourir à nouveau. L’astuce réside dans la manière dont nous allons la traiter : grâce à l’opérateur modulo nous filtrerons l’affichage (ou non) des articles…

Dans le template de la page d’accueil :

<div id="contenu" class="clearfix" >

	<!-- 1ere colonne -->
	<div class="colonne">
		<?php
		// variable qui servira pour filtrer l'affichage des posts
		// et qui sera incrémentée à chaque itération
		$i = 1;
		if( have_posts() ) :
			while( have_posts() ) :
				the_post();

				// s'il ne s'agit pas du 1er article dans la série de 2
				// on passe à l'itération suivante sans rien afficher
				if( $i%2 != 1 ) :
					$i++; // incrémente le compteur
					continue; // on passe directement à l'itération suivante

				else : // pas nécessaire mais clarifie le fonctionnement ?>

					<div class="article">
						<h2><?php the_title(); ?></h2>
						<?php the_excerpt(); // le résumé de l'article ?>
					</div>

				<?php
				endif; // fin if $i%2
				$i++; // incrémente le compteur
			endwhile; // fin boucle while
		endif; // fin if have_posts() ?>

		<?php
		// on se remet au début de la boucle des articles 
		// pour pouvoir la traiter à nouveau
		rewind_posts();
		?>
	</div><!-- fin 1ere colonne -->

	<!-- 2eme colonne -->
	<div class="colonne">
		<?php
		$i = 1; // variable qui servira pour filtrer l'affichage des posts
		if( have_posts() ) :
			while( have_posts() ) :
				the_post();

				// s'il ne s'agit pas du 2eme article dans la série de 2
				// on passe à l'itération suivante sans rien afficher
				if( $i%2 != 0 ) :
					$i++; // incrémente le compteur
					continue; // on passe directement à l'itération suivante

				else : ?>

					<div class="article">
						<h2><?php the_title(); ?></h2>
						<?php the_excerpt(); // le résumé de l'article ?>
					</div>

				<?php
				endif; // fin if $i%2
				$i++; // incrémente le compteur
			endwhile; // fin boucle while
		endif; // fin if have_posts() ?>

	</div><!-- fin 2eme colonne -->

</div><!-- fin #contenu -->

Et voila, nous sommes arrivé à notre résultat ! Bien évidemment on pourrait vouloir 3 colonnes d’articles : l’opération est la même sauf que l’on utilisera $i % 3 au lieu de $i % 2 — Le diviseur servant à déterminer le nombre d’articles a ne pas afficher et sera égal au nombre de colonnes.
Il faudra également dupliquer tout le bloc de code pour ajouter la 3e colonne, sans oublier rewind_posts() à la fin de la 2e colonne ni de changer la valeur de test du modulo pour la 2e colonne ( if( $i%3 != 2 ) ).

A propos du modulo

Si vous ne savez pas ou ne vous souvenez pas du fonctionnement de modulo, voici l’explication :
On divise le chiffre de gauche par celui de droite et le résultat ne tient compte que du chiffre entier obtenu (donc sans chiffre après la virgule). Ce calcul retourne le reste de cette division (donc un entier également).
Par exemple 1 % 3 = 1 car 1 / 3 = 0 et il reste 1
Ceci est très pratique lorsque l’on doit faire quelque chose de particulier toutes les X itérations.

Conclusion

Nous avons pu obtenir la liste de nos articles sur 2 colonnes sans utiliser inutilement de ressources supplémentaires. Autre avantage de cette technique : elle respecte le réglage du nombre de posts à afficher dans le tableau de bord de WordPress.

Happy coding :)

Mots-clés : ,

Vous avez aimé l'article ? Partagez-le : 

Commentaires

  1. Ozh dit :

    Idée intéressante, par contre est-ce que cela ne double pas le nombre de queries pour afficher la page?

    (il manque un plugin « subscribe to comments » ici :)

    • Erik dit :

      Non ca n’augmente pas le nombre de queries puisqu’il ne s’agit que de remettre le pointeur de l’array au début :) C’est tout l’intérêt de la fonction !

      Pour le plugin « subscribe »… c’est vrai je vais m’en occuper. Encore merci pour l’excellent livre, c’est vraiment très bien fait.

  2. jessica dit :

    Bonjour,
    article tres intéréssant puisque je lutte depuis 2jours ladessus,
    cela dit pour une newbe ca reste flou, ou mettre exactement le code?!
    des petite phrase d’enfant genre « mettez ce code dans » serait
    bien util pour moi..

    en espérant de laide, Merci à vous,

    Jess

    • Erik dit :

      Bonjour Jess,
      le code en question se met dans le fichier template désiré et modifie la boucle de WordPress. Par exemple : en supposant que vous souhaitiez utiliser la technique sur la page d’accueil, le code ira dans index.php à l’endroit où vous affichez la liste des articles.

      J’espère que cela vous aidera :)

  3. Rtransat dit :

    Bonjour,

    Personnellement j’utilise une autre technique que 2 div, lorsque la boucle est un nombre paire (donc $i % 2 == 0) alors je met un div en clear:both

    Voici un exemple :

    <a href=" »>
    <a href=" »>

    <?php echo ($i % 2 == 0) ? '’ :  »; ?>

    Aucune actualités.

  4. yannick dit :

    Merci pour ton astuce :) par contre petit souci ! Si il n’y pas de posts as tu un pti bout de code stp.

    Merci d’avance.