Pour ceux qui ont suivi mes derniers articles, j’étais conférencier lors du dernier WordCamp Paris. Lors des ateliers du samedi, nous avons discuté des solutions de mise en cache des données sur WordPress, et notamment des transients. Cette fonctionnalité est relativement puissante, mais il s’avère que je ne les utilisais pas forcément à bon escient, tout comme vous d’ailleurs…

Tête dans le sable
Le meilleur système de cache du monde : le transient sablé…

Qu’est ce qu’un transient ?

Sous ce terme barbare se cache une fonctionnalité intéressante de WordPress qui permet de mettre en cache temporairement une information, et cela directement en base de données. Elle permet notamment d’éviter de recalculer certains éléments récurrents de vos pages, vous permettant ainsi d’accélérer le temps de chargement. Cela peut être par exemple :

  • la liste des articles les plus commentés
  • le contenu de votre blogroll
  • vos derniers tweets

Le transient se stocke en base de données dans la table options. Libre à vous de créer ou de récupérer la valeur d’un transient pour l’utiliser, que ce soit dans un thème ou un de vos plugin.

Cela fonctionne comment ?

Le concept

Vous pouvez mettre ce que vous voulez dans un transient. Cela peut se résumer à un chiffre ou à un mot tout comme à un long contenu html. Voici comment en créer un :

set_transient( $nom, $valeur, $expiration );
  • $nom est le nom unique du transient (45 caractères maximum).
  • $valeur est le contenu de celui-ci.
  • $expiration est la durée en secondes au bout de laquelle le transient n’est plus valide (mais existe toujours en base de données).

Pour récupérer la valeur d’un transient dans WordPress, il faut alors utiliser la fonction suivante :

get_transient($nom);

Pour tester proprement si un transient existe et s’il est toujours valide, utiliser le code ci-dessous. La partie du code XX ne s’exécutera que si le transient n’existe pas ou s’il est expiré :

if ( false === ( $valeur = get_transient($nom) ) ) {
     // XXX
}

Un exemple pratique

Maintenant que l’on connait les fonctions de base, voici un exemple pratique.

Imaginons que vous ayez une fonction toto() qui récupère les 5 derniers commentaires de votre site et que vous voulez afficher cette liste sur toutes les pages. Vous pourriez utiliser la fonction suivante dans le fichier functions.php de votre thème WordPress :

function seomix_transient(){   
	// Quel est le nom du transient
	$nomtransient = 'tototransient';

	// Le transient est-il inexistant ou expiré ?
	if ( false === ( $transient = get_transient( $nomtransient ) ) ) {

		// Si oui, je fais appelle à n'importe quelle fonction pour donner une valeur au futur transient.
		// Dans mon exemple, ce sera ma fonction toto.
		$value = toto();

		// Je met à jour la valeur du transient avec $value, et j'indique à WordPress une durée d'expiration de 60 secondes
		set_transient($nomtransient, $value, 60);

		// Je met à jour la valeur de ma variable $transient
		$transient = get_transient( $nomtransient )
	}

	//Nous renvoyons la valeur du transient mis à jour
	return $transient; 
}

Ensuite, il suffira d’utiliser le code suivant dans votre thème à l’endroit désiré :

<?php echo seomix_transient(); ?>

Le concept est simple :

  • Au premier chargement d’une page contenant cette fonction, WordPress va vérifier si le transient existe.
    • S’il n’existe pas, il va lui donner la bonne valeur puis l’afficher.
    • S’il existe, il va directement afficher la bonne valeur
  • Dans les quelques secondes qui suivent, si une nouvelle page est chargée avec cette fonction à l’intérieur, WordPress va vérifier son existence puis afficher sa valeur sans la recalculer.
  • Si plus de 60 secondes se sont écoulées, le transient sera vérifié, recalculé, mis à jour puis affiché.

La fonction donnée en exemple ne sera calculée que toutes les 60 secondes maximum, peu importe le  nombre de pages et de visiteurs de votre site Internet pendant cette durée. Sur des fonctions très simples, le gain sera faible car WordPress doit toujours faire au moins deux requête pour vérifier si le transient existe. En d’autres termes :

  • plus le contenu du transient est complexe à générer, plus le gain de performance sera élevé pour votre site (car les ressources allouées pour vérifier l’existence du transient seront « amorties »).
  • plus un même transient est présent sur vos différentes pages, plus le gain sera là aussi élevé (un seul calcul nécessaire pour plusieurs pages).

WordPress MU

Si vous gérez un WordPress Multisite, sachez que vous pouvez également utiliser les fonctions transversales ci-dessous pour cacher la même donnée sur tous les sites en même temps. Elles fonctionnent exactement de la même manière que les transients basiques :

set_site_transient()
get_site_transient()

Quand utiliser un transient ?

Nous venons de comprendre le concept de base. Maintenant, posons-nous la seule et bonne question à se poser :

Dois-je utiliser les transients de WordPress ?

La réponse est oui et non, car tout dépendra de ce que vous voulez faire avec. Tout d’abord, je vais partir du fait que vous avez un autre système de cache déjà mis en place. Et celui-ci peut-être de deux types :

  • Si celui-ci est géré du côté serveur, les transients seront très peu utiles. Par exemple, si vous avez installé correctement Nginx, Varnish ou encore MemCached, tous les autres système de mise en cache n’apporteront pas grand chose à vos visiteurs puisque le contenu aura déjà été mis en cache par votre serveur (je simplifie mais c’est l’idée de base).
  • Si le cache est généré par l’utilisateur, par exemple avec des plugins comme WP-Super Cache ou W3 Total Cache, les transients seront plus utiles.
Cache serveur
Le cache serveur, il n’y a que ça de vrai…

Quel que soit le système de cache de votre site, les transients ne peuvent les remplacer. Ils viendront le compléter.  Il existe en réalité deux cas de figure où il est fortement conseillé de les utiliser :

  • un même contenu est présent sur plusieurs pages (derniers commentaires, une sélection d’articles, une blogoliste, une galerie d’image, …). On limite ainsi le calcul d’une donnée identique.
  • vous utilisez du contenu issu d’un site externe. Vous limitez ainsi les requêtes DNS et la consommation de bande passante et d’API (celle de Twitter, de Facebook, …).

Pour le dernier point, c’est là où les transients seront vraiment efficaces. Dans le cas où vous faites appel à des données externes comme par exemple Twitter, les transients vont vraiment apporter un gain de performance en évitant de nombreuses requêtes superflues. Par exemple, le transient peut stocker pendant 10 minutes les derniers tweets. Ainsi, votre site Internet ne fera que 6 requêtes maximum par heure aux serveurs de Twitter, tout en laissant votre site dynamique et réactif.

Bien utiliser les transients de WordPress

Je connaissais déjà les points que j’ai cité juste avant, mais c’est au WordCamp Paris que j’ai réalisé deux choses :

  • Un transient ne doit pas avoir obligatoirement un délai d’expiration.
  • Un transient expiré reste en base de données.

Commencez donc pas ne pas mettre du délai d’expiration si vous savez que la donnée calculée ne changera plus jamais.

L’autre cas de figure est de se demander à partir de quand vous n’utiliserez plus un transient. Si vous en avez créé un et que vous ne l’utilisez plus, celui-ci restera dans votre base de données inutilement. En effet, WordPress ne le supprimera que si vous essayez d’y accéder. En fonction de nombre de plugins installés puis désinstallés, ou du changement de vos thèmes, il est possible que vous ayez des dizaines de transients inutiles dans la table option de WordPress. Il est donc nécessaire de faire un peu le ménage. Pour vous donner un ordre d’idée, j’ai supprimé 1,4Mo de données inutiles après avoir appliquer l’astuce qui va suivre.

Le code initial est tiré du très bon plugin « Artiss Transient Cleaner« , et a été ensuite optimisé par mes soins. Le plugin est excellent mais il supprime tous les transients (ceux expirés et ceux qui ne le sont pas) lors de la mise à jour de la base de données WordPress. Comme je ne juge pas cela pertinent comme comportement par défaut, le code a été simplifié.

Tout d’abord, il faut définir la durée au bout de laquelle les différentes corbeilles de WordPress vont se vider (articles, commentaires, …). Le code et le plugin se greffent en effet sur cette fonction pour supprimer tous les transients expirés. Cela se définit avec la ligne suivante à placer dans le fichier wp-config.php situé à la racine de votre site :

define('EMPTY_TRASH_DAYS', 3 );

Dans la ligne, définissez la durée en jours (ici 3) au bout de laquelle WordPress doit faire le ménage. Ensuite, copiez/collez le code suivant dans le fichier functions.php de votre thème :

// Création de l'action qui va déclencher la suppression des transients    
function seomix_content_transients_opti() {
	seomix_action_delete_transient();}

// Activation de l'action en même temps que wp_scheduled_delete
//La variable EMPTY_TRASH_DAYS doit être définie dans le fichier WP-Config
//exemple : define('EMPTY_TRASH_DAYS', 3 );
add_action( 'wp_scheduled_delete', 'seomix_content_transients_opti' );

// Fonction de suppression des transients  
function seomix_action_delete_transient() {
	// Si WordPress ne fait pas appel à un cache externe
	global $_wp_using_ext_object_cache;
	if ( !$_wp_using_ext_object_cache ) {
		//On récupère la globale du site
        	global $wpdb;
        	// On récupère l'heure actuelle
        	$time = time();
        	// On récupère tous les transients
        	$sql = "SELECT option_name FROM $wpdb->options WHERE option_name LIKE '_transient_timeout%' AND option_value < $time";
        	// On les récupère proprement
        	$mestransients = $wpdb->get_col( $sql );
        	// Pour chacun d'entre eux, on les supprime
        	foreach( $mestransients as $transient ) {
          		$deletion = delete_transient( str_replace( '_transient_timeout_', '', $transient ) );
        	}
        	// On optimise la base de données après les suppressions
        	$wpdb->query('OPTIMIZE TABLE ' . $wpdb->options);
      	}
}

Vous pouvez également forcer la suppression immédiate des transient inutiles en remplaçant wp_scheduled_delete par init. Attention cependant, le code s’exécutera alors à chaque chargement de page de votre site : vous ne devez donc laisser init que le temps de recharger une de vos pages pour nettoyer les transients actuels, puis remettre la valeur wp_scheduled_delete à la place.

Et vous, comment utilisez-vous les transients ?