Nuage de tags en Php/Mysql

La manipulation pour créer et administrer des tags sur son site n'est pas des plus simple.

En effet, créer un simple liste de tags n'est pas bien compliqué mais rendre administrable cette liste (a savoir ajouter, retirer les tags d'un sujet) n'est pas forcément facile !

Je vous présente donc une technique assez pratique pour mettre en œuvre un nuage de tags en Php/Mysql.

Pour illustrer ce code je vais prendre l'exemple d'un blog, mais n'ayez crainte, c'est facilement adaptable à tout type de site.

Voici la structure des tables

+-----------+     +--------------+     +--------+
+  billets  +     + billets_tags +     +  tags  +
+-----------+     +--------------+     +--------+
| id_billet |     +    id_btag   +     + id_tag +
|   titre   |     +   id_billet  +     +   tag  +
|    ...    |     +    id_tag    +     +--------+
+-----------+     +--------------+

Explications
La table "billets" contient la liste des billets, la table "tags" la liste unique de tous les tags et la table "billets_tags" permet d'associer un tag à un billet.


Maintenant lorsque vous créez un billet sur votre blog, il vous suffit d'ajouter un nouveau champs Tags ou vous placerez la liste des tags associés au billet, séparés par une virgule.
Petite astuce, vous pouvez placer en dessous de ce champ la liste des tags que vous avez déjà utilisez en prenant tout les valeurs contenu dans la table "tags". (Avec du javascript pour ajouter le texte dans le champ)
Vous pouvez donc lister cette table et créer "une variable cache" comme ceci :

<?php
$cache_tags = array();
while($donnees_tags = mysql_fetch_assoc($votre_requete))
	$cache_tags[$donnees_tags['tag']] = $donnees_tags;

Pour le traitement des tags (et de l'ajout du billet) je vous propose ce morceau de code :

<?php
# Gestion des tags
$post_tags = array_map('trim', explode(',', $_POST['tags'])); // Mon champ s'appelle "tags"
$post_tags = array_map('strtolower', $post_tags); // Minuscules
 
foreach($post_tags as $tag)
{
	if(empty($tag)) // Si le tag est vide on passe au suivant
		continue;
 
	# Recherche tag
	foreach($cache_tags AS $cache_key => $cache_tag)
	{
		if($cache_tag['tag'] == $tag) # Le tag existe
		{
			$id_tag = $cache_key;
			continue;
		}
	}
 
	/* Le tag existe pas */
	if(!isset($id_tag))
	{
		db_query('INSERT INTO '.$db_prefix.'tags(tag) VALUES(\''.escape($tag).'\') ');
		$id_tag = mysql_insert_id();
	}
 
	mysql_query('INSERT INTO billets_tags(id_tag, id_billet) VALUES(\''.$id_tag.'\', \''.$id_billet.'\') ');
}

Maintenant pour modifier un billet et donc ses tags c'est plus ou moins compliqué : comment savoir quels tags on été enlevés ou retirés du billet ? Il existe plusieurs solutions plus ou moins simple. La plus simple consiste à supprimer tous les tags du billet puis d'ajouter lors du traitement de la modification les tags voulus.

Je partage donc un petit bout de code permettant de faire la différence entre les tags utilisés avant et les tags utilisés après. A grand coup de tableau !

<?php
# Gestion des tags
$post_tags = array_map('trim', explode(',', $_POST['tags']));
$post_tags = array_map('strtolower', $post_tags);
$post_tags = array_unique($post_tags);
 
# Tags ajoutés
$tags_ajoutes = array_diff($post_tags, $liste_tags);
/*
$liste_tags est un tableau contenant les tags actuellement
utilisés pour le billet sous la forme : 'id_tag' => 'tag'
*/
if(count($tags_ajoutes) > 0)
{
		foreach($tags_ajoutes as $tag)
	{
		if(empty($tag))
			continue;
 
		/* Le tag existe pas */
		if(!in_array($tag, $cache_tags))
		{
			mysql_query('INSERT INTO tags(tag) VALUES(\''.addslashes($tag).'\') ');
			$id_tag = mysql_insert_id();
		}
		else
			$id_tag = array_keys($liste_tags, $tag);
 
		mysql_query('INSERT INTO billets_tags(id_tag, id_billet) VALUES(\''.$id_tag.'\', \''.$billet.'\') ');
	}
}
# Tags retirés
$tags_retires = array_diff($liste_tags, $post_tags);
if(count($tags_retires) > 0)
{
	foreach($tags_retires as $id_tag => $tag)
		mysql_query('DELETE FROM billets_tags WHERE `id_tag`=\''.$id_tag.'\' && `id_billet`=\''.$billet.'\' ');
}

Voilà les étapes les plus importante pour la création de votre nuage de tag. Il ne reste plus qu'a parler de l'affichage des tags sur une des page de votre site.

Voici le code qui gère l'affichage des tags

<?php
// Taille minimum et maximum en pixels
$min_size = 9;
$max_size = 36;
$nuage_tags = array();
 
$req_nuage = mysql_query('SELECT t.tag, t.id_tag, count(bt.id_btag) as number FROM tags AS t,
 billets_tags AS bt WHERE bt.id_tag=t.id_tag GROUP BY t.tag ORDER BY t.tag');
 
$min = MAX_INT;
$max = -MAX_INT;
 
while ($tag = mysql_fetch_assoc($req_nuage)) {
	if ($tag['number'] < $min)
		$min = $tag['number'];
	if ($tag['number'] > $max)
		$max = $tag['number'];
	$nuage_tags[$tag['id_tag']] = $tag;
}
 
foreach ($nuage_tags as $tag_id => $tag) {
	$tag['size'] = intval($min_size + (($tag['number'] - $min) * (($max_size - $min_size) / ($max - $min))));
	$tags_extended[$tag_id] = $tag;
}
 
foreach($tags_extended as $tag_id => $tag)
	echo ' <span style="font-size: '.$tag['size'].'px;">'.$tag['tag'].'</span> ';

Vous voilà prêt à créer un nuage de tags administrable !

Billets relatifs

2 Commentaire(s)

  1. Commenté par lidaa le lundi 28 février à 10:50

    Tres bon article. Merci

  2. Commenté par Loïc le mardi 22 novembre à 14:59

    Superbe article,

    Cependant, je ne comprend pas comment vous récupérez l'id_tag.

    foreach($cache_tags AS $cache_key => $cache_tag)
    {
    }

    Est-ce que la requête du départ doit contenir l'id tag ?

    par avance merci.

  3. Réponse

    C'est exact, dans la première requête tu récupère tous les champs de la table. Si bien que la variable $cache_tag contient toutes les infos de cette même table.

Ajouter un commentaire





Les commentaires sont validés manuellement afin d'éviter le spam.