Revenons-en à nos moutons : générer un fil RSS grâce aux tags ou mots-clés. Je m'explique.

Outre les flux RSS par catégorie qui indexent les derniers billet d'une catégorie donnée, outre les flux de galeries d'images, je propose les flux par tags multiples. En effet, parmi tous les tags définis, le visiteur choisit ceux qui l'intéressent et génère le fil en fonction de ces-derniers. Ce fil liste donc les derniers billets contenant au moins un des tags choisis par le visiteur. L'intérêt est de permettre à chaque visiteur de préciser le choix du contenu duquel il souhaite être tenu au courant.

Pour être sûr de bien comprendre de quoi il s'agit, je vous invite à créer votre fil personnalisé en fonction de mes tags (cette page est accessible via la sidebar, par le lien Tous les tags).

0. Réalisation concrète

Parce que trêve de blabla, je vous l'accorde.

En clair, le but de la manoeuvre est de générer une adresse de flux RSS de la forme http://monsite/rss-meta.php?limite=x&key=tag?value=tag1,tag2,tag3 où x est le nombre de billets à afficher dans le fil. Ce qui suit ne constitue en rien un plugin. Ce sont des modifications manuelle qui offrent in fine une nouvelle fonctionnalité. Dans les prochaines semaines, un plugin sera réalisé (cf. dernier paragraphe).

I. Prélude : fichiers existants à modifier

Ainsi, abordons des considérations plus techniques afin de réaliser cette modeste modification.

Les plugins nécessaires à la réalisation de cette astuce et les fichiers à modifier sont :

  • Métadonnées de billets dit twMeta
    • functions.php (dans /ecrire/tools/twpostmeta)
    • rss-meta.php (dans /ecrire/tools/twpostmeta)
  • Tags dit twTags
    • functions.php (dans /ecrire/tools/twtags)
  • Related, pour créer la page du formulaire de création du fil

II. Greffons à insérer ou code à modifier

Avant toute manipulation, procédez à la sauvegarde des fichiers mentionnés, au cas où un problème surviendrait. On n'est jamais trop prudent !

II.1 Le fichier functions.php (dans /ecrire/tools/twpostmeta)

Remplacez le code suivant (à la fin du fichier)

# Récupère les $limit derniers billets dont le champ $key est défini et a la valeur $value
function getLastNews($key, $value, $limit = 20, $order = 'post_dt DESC', $lang='', $pub_mode = 1)
{
	global $blog, $con;
	$reqPlus = 'AND meta_key = "' . $con->escapeStr($key) . '" AND meta_value = "' . $con->escapeStr($value) . '" ';

	if ($pub_mode)
		$reqPlus .= 'AND post_pub = '.(integer) $pub_mode.' ';
	if ($lang != '')
		$reqPlus .= 'AND post_lang = "'.$con->escapeStr($lang).'" ';
			
	$strReq = 'SELECT P.post_id, post_chapo, post_chapo_wiki, post_content, '.
			'post_content_wiki, post_notes, post_titre, post_titre_url, '.
			'post_dt, post_upddt, post_creadt, post_pub, '.
			'post_open_comment, post_open_tb, nb_comment, nb_trackback, '.
			'post_lang, post_selected, U.user_id, U.user_nom, '.
			'U.user_prenom, U.user_pseudo, U.user_email, '.
			'DATE_FORMAT(post_dt,"%Y%m%d") AS postdate, '.
			'DATE_FORMAT(post_dt,"%H:%i") AS posthour, '.
			'DATE_FORMAT(post_dt,"%d") AS postday, '.
			'DATE_FORMAT(post_dt,"%m") AS postmonth, '.
			'DATE_FORMAT(post_dt,"%Y") AS postyear, '.
			'P.cat_id, C.cat_libelle, C.cat_libelle_url '.
			'FROM '.DB_PREFIX.'post P, '.DB_PREFIX.'categorie C, '.
			DB_PREFIX.'user U ,'.DB_PREFIX.'post_meta M '.
			'WHERE P.cat_id = C.cat_id AND U.user_id = P.user_id AND P.post_id = M.post_id '.
			$reqPlus.
			'ORDER BY '.$con->escapeStr($order).' ';
	
	if ($limit != '')
	{
		$limit = (preg_match('/^[0-9]+$/',$limit)) ? '0,'.$limit : $limit;
		$strReq .= 'LIMIT '.$limit.' ';
	}
	
	if (($rs = $con->select($strReq,$GLOBALS['blog']->rs_blogpost)) !== false) 
	{
		$rs->setBlog($GLOBALS['blog']);
		return $rs;
	}
	else
		exit($strReq);
		return false;
}

par la fonction suivante :

# Récupère les $limit derniers billets dont le champ $key est défini et a la valeur $value
function getLastNews($key, $value, $limit = 20, $order = 'post_dt DESC', $lang='', $pub_mode = 1)
{
	global $blog, $con;
		
	$arrayvalue = explode(',',$value); // On sépare les tags présents dans l'url du fil
		
	if (count($arrayvalue) == 1) {
		$reqPlus = 'AND meta_key = "' . $con->escapeStr($key) . '" AND meta_value = "' . $con->escapeStr($arrayvalue[0]) . '" '; // S'il n'y a qu'un seul tag, la fonction est la même que l'originale
	}
	else {
		$reqPlus = 'AND meta_key = "' . $con->escapeStr($key) . '" AND (meta_value = "' . $con->escapeStr($arrayvalue[0]) . '" ';
		for ($i=1; $i < count( $arrayvalue ); $i++) {
			$reqPlusPlus .= 'OR meta_value = "' .trim($con->escapeStr($arrayvalue[$i])). '" '; // Sinon, on sélectionne tous les billets contenant au moins un des tags choisis
		}
		$reqPlusPlus .= ') ';
	}
		if ($pub_mode)
			$reqPlus2 = 'AND post_pub = '.(integer) $pub_mode.' ';
		if ($lang != '')
			$reqPlus2 .= 'AND post_lang = "'.$con->escapeStr($lang).'" ';
			
		$strReq = 'SELECT DISTINCT P.post_id, post_chapo, post_chapo_wiki, post_content, '. /* Notez que la requête est ''SELECT DISTINCT'' et non ''SELECT''. On évite ainsi les doublons dans les résultats (car un même tag peut être attribué à des billets différents) */
				'post_content_wiki, post_notes, post_titre, post_titre_url, '.
				'post_dt, post_upddt, post_creadt, post_pub, '.
				'post_open_comment, post_open_tb, nb_comment, nb_trackback, '.
				'post_lang, post_selected, U.user_id, U.user_nom, '.
				'U.user_prenom, U.user_pseudo, U.user_email, '.
				'DATE_FORMAT(post_dt,"%Y%m%d") AS postdate, '.
				'DATE_FORMAT(post_dt,"%H:%i") AS posthour, '.
				'DATE_FORMAT(post_dt,"%d") AS postday, '.
				'DATE_FORMAT(post_dt,"%m") AS postmonth, '.
				'DATE_FORMAT(post_dt,"%Y") AS postyear, '.
				'P.cat_id, C.cat_libelle, C.cat_libelle_url '.
				'FROM '.DB_PREFIX.'post P, '.DB_PREFIX.'categorie C, '.
					DB_PREFIX.'user U ,'.DB_PREFIX.'post_meta M '.
				'WHERE P.cat_id = C.cat_id AND U.user_id = P.user_id AND P.post_id = M.post_id '.
				$reqPlus.$reqPlusPlus.$reqPlus2. // On a ajouté nos requêtes supplémentaires
				'ORDER BY '.$con->escapeStr($order).' ';
		if ($limit != '')
		{
			$limit = (preg_match('/^[0-9]+$/',$limit)) ? '0,'.$limit : $limit;
			$strReq .= 'LIMIT '.$limit.' ';
		}
		
		if (($rs = $con->select($strReq,$GLOBALS['blog']->rs_blogpost)) !== false) 
		{
			$rs->setBlog($GLOBALS['blog']);
			return $rs;
		}
		else
			exit($strReq);
			return false;
	}

II.2 Le fichier rss-meta.php (dans /ecrire/tools/twpostmeta)

Remplacez les deux lignes suivantes :

# Dernières nouvelles
$news = twPostMeta::getLastNews($key, $value, 10,'post_dt DESC',$lang);

par les quelques lignes :

# Dernières nouvelles
if (is_numeric($_GET['limit']) === TRUE) { // On vérifie que la limite présente dans l'URL du fil est bien un nombre
$value = str_replace(',',', ',$value); // Pour des raisons cosmétiques...
$news = twPostMeta::getLastNews($key, $value, $_GET['limit'],'post_dt DESC',$lang); // On fait appelle à la nouvelle fonction getLastNews(), permettant les tags multiples
} else { exit("<pre>Erreur : la limite soumise n'est pas numérique.<pre>"); } // Si la variable ''limit'' passée par l'URL n'est pas un nombre, on arrête le script

II.3 Le fichier functions.php (dans /ecrire/tools/twtags)

Nous allons créer deux fonctions par analogie à deux fonctions existantes. Ces fonctions génèrent le nuage de tags dans lequel chaque tag est associé à une case à cocher. Ce nuage permet de sélectionner les mots-clés d'intérêt, ceux-là même qui définissent notre fameux flux RSS.

Pour ce faire, ajouter, en fin de fichier, le code suivant.

// tagListPolyRss() et tagCloudPolyRss(), sur le modèle de tagList() et tagCloud()
function tagListPolyRss($block = '<ul>%s</ul>', $item = '<li>%s</li>', $levels = 5)
{
	global $blog, $tag_id;
		
	$rec = twTags::_recordset();
		
	if ($rec)
	{
		$max = 0;
			
		while ($rec->fetch())
		{
			if ($rec->f('cnt') > $max) 
				$max = $rec->f('cnt');
		}
		$rec->moveStart();

		$res = '';
		$i=0;
		while ($rec->fetch())
		{
			$tag = $rec->f('meta_value');
			$tagclean = $tag;
			$link = '<input type="checkbox" id="'.$tagclean.'" name="tag'.$i.'" value="'.$tagclean.'"/> <label for="'.$tagclean.'">' . htmlspecialchars($tag) . '</label>'; // Les fameuses cases à cocher sont définies ici
			if ($tag_id == $tag)
				$link = $link;
					
			$level = ceil($levels * $rec->f('cnt') / $max);
			$res .= sprintf($item, $link.' ', $level);
			$i++;
		}
		printf($block, $res);
	}
}
	
function tagCloudPolyRss($levels = 5, $block='<ul>%s</ul>', $item='<li class="level-%2$d">%1$s</li>')
{	
	twTags::tagListPolyRss($block, $item, $levels);
}

III. Création de la page annexe : le formulaire de création du fil

Si les modifications ont bien été faites, il convient maintenant de les exploiter. Pour ce faire, nous allons créer une page annexe grâce au plugin Related, dit "Pages connexes" (notons que le terme connexe n'est pas très approprié car le plugin permet d'accéder à n'importe quelle page créée par le webmaster, ces pages n'ayant riene de "connexe" au blog ; bref).

Le code suivant étant le mien et comporte certains éléments propres à mes pages, il convient de l'adapter pour l'inclure parfaitement à votre gabarit.

<div class="post"> 
  <h2 class="post-title" id="generer">G&eacute;n&eacute;rer un fil (b&eacute;t&acirc;)</h2> 
  <p>Vous pouvez, aussi, g&eacute;n&eacute;rer un fil RSS filtrant les billets lib&eacute;l&eacute;s comme vous le souhaitez. Choisissez une combinaison de tags afin de cr&eacute;er un fil permettant de lister les billets contenant tous les tags choisis.</p> 
  <form action="#generer" method="post">
  <div class="tags com"> 
  <?php twTags::tagCloudPolyRss($levels = 8, $block = '<p class="commentaire">%s</p>', $item = '<span class="level-%2$d">%1$s</span> '); ?> 
  </div><fieldset> 
  <p><label for="limite" class="bold">Longueur du fil RSS (limite) :</label></p> 
  <select id="limite" name="limit"> 
  <option value="1">1</option> 
  <option value="5">5</option> 
  <option value="10" selected="selected">10</option> 
  <option value="15">15</option> 
  <option value="20">20</option> 
  <option value="25">25</option> 
  <option value="30">30</option> 
  </select> <p><input type="submit" value="G&eacute;n&eacute;rer le fil" name="generer" /></p></fieldset> 
  </form> 
  <?php  
  if ($_POST['generer']) { // Si l'on demande de générer l'URL (<=> si le bouton ''Génerer'' est cliqué) 
  $i=0; 
  for ($i=0;$i<=100;$i++) { // 100 est une marge arbitraire, nécessairement supérieure au nombre de tags définis pour le blog. Il s'agit en fait d'une boucle censée balayée l'ensemble des tags, d'où l'intérêt d'un nombre bien supérieur au nombre de tag (je n'ai pas de fonction donnant le nombre total de tags définis) 
  $tagnum = 'tag'.$i; 
  if ($_POST[$tagnum] != '') {  
  $str .= $_POST[$tagnum].','; 
  $strclean = substr($str,0,strlen($str)-1); 
  } 
  else { } 
  }  
  $urlgeneree = $_SERVER['HTTP_HOST'].'/blog/rss-meta.php?limit='.$_POST['limit'].'&amp;key=tag&amp;value='.$strclean; 
  ?> 
  <?php // On reconstruit une chaine énumérant les tags choisit (ceci est accessoire et en rien nécessaire au fonctionnement du script, c'est vraiment "pour faire joli") 
  $arraytags = explode(',',$strclean);  
  for ($x=0;$x<count($arraytags);$x++) { // Cette boucle permet  
  if ($x == count($arraytags)-2) { 
  $chn .= '<strong>'.$arraytags[$x].'</strong> et '; 
  } 
  else { $chn .= '<strong>'.$arraytags[$x].'</strong>, '; } 
  } 
  $chnclean = substr($chn,0,strlen($chn)-2);
?> 
  <div> 
  <p>Tags choisis : <?php echo $chnclean; ?></p><!--> cette phrase peut être enlevée (elle suit la partie en PHP juste au dessus, elle-même accessoire)<--> 
  <p><br /><a href="http://<?php echo $urlgeneree; ?>" hreflang="rss">Abonnez-vous directement</a> ou copiez <label for="urlgeneree" class="bold">l'adresse suivante</label> dans votre agr&eacute;gateur favoris :</p> 
  <p><br /><input id="urlgeneree" style="padding:3px;" onclick="select(this)" type="text" size="70" value="<?php echo 'http://'.$urlgeneree; ?>" /></p></div> 
  <?php 
  } 
  ?> 
  </div>

IV. Activation, conclusion et perspective

Après avoir placé la page que vous venez de créer dans le dossier /share/related, allez activer son accès via le panneau d'administration du plugin.

Par souci de commodité, je vous conseille de placer votre fichier rss-meta.php dans le même dossier que votre fichier rss.php (souvent à la racine du blog). Le code que je vous propose ne fonctionne que dans le cas où rss-meta.php est placé à la racine du blog.

En vous rendant sur cette page, vous devriez voir un nuage de tags à côté desquels se trouve une case à cocher. Vous n'avez plus qu'à générer le fil et y souscrire. Pour le visiteur intéressé, ce système offre donc une plus grande marge de liberté au niveau de la gestion de l'information, et c'est tant mieux !

On notera cependant un inconvéniant inhérent au fait que l'URL soit variable : l'impossibilité de gérer ces nouveaux fils par des services tiers tel que FeedBurner.

Cette modification est quelque peu barbare, je le conçois. Malheureusement, elle reflète assez bien le type de modifications que j'apporte ici ou là dans mon blog. Néanmoins, je réaliserai un plugin intègre, évitant toutes ces manipulations fastidieuses. Créez un flux à partir des tags ''développement web'' et ''DotClear'', abonnez-vous y et comme ça vous serez tenu au courant de la sortie du plugin ! Quel meilleur destin pour cette fonction de flux RSS que de servir à sa propre fin ?