# Transients API : quand et comment mettre en cache dans une extension

> set_transient ressemble à une option avec expiration, mais son comportement change du tout au tout selon qu'un cache d'objets persistant tourne derrière ou non.

- Auteur : Clément Hadrot
- Publié le : 2020-09-09
- Mis à jour le : 2020-09-09
- Catégorie : Extensions
- URL : https://wpmoderne.dev.wordpress-developpement.fr/extensions/transients-api-quand-comment-mettre-en-cache/

## L’essentiel

- Un transient sans cache persistant vit dans wp_options, avec une clé d'expiration séparée
- Avec un cache d'objets persistant, il ne touche jamais la base de données
- La suppression manuelle reste indispensable, l'expiration seule ne suffit pas toujours

La Transients API est l'une de ces fonctionnalités que tout développeur WordPress croit connaître après avoir lu deux lignes de documentation, et qu'il redécouvre complètement le jour où un client active un cache d'objets Redis en production. Le comportement change alors du tout au tout, sans qu'une seule ligne de code de l'extension n'ait bougé.

Voici ce qu'il faut vraiment comprendre avant d'utiliser `set_transient` dans une extension destinée à tourner sur des hébergements variés.

## Le principe : une donnée temporaire avec expiration

Un transient se manipule avec trois fonctions symétriques à l'API des options : `set_transient()`, `get_transient()` et `delete_transient()`. La différence avec `update_option()` tient dans un quatrième argument, la durée de vie en secondes.

```
function kaolin_recuperer_taux_change() {
    $taux = get_transient( 'kaolin_taux_eur_usd' );

    if ( false === $taux ) {
        $reponse = wp_remote_get( 'https://api.exemple-taux.test/eur-usd' );

        if ( is_wp_error( $reponse ) ) {
            return false;
        }

        $taux = (float) wp_remote_retrieve_body( $reponse );
        set_transient( 'kaolin_taux_eur_usd', $taux, HOUR_IN_SECONDS );
    }

    return $taux;
}
```

Le point que beaucoup ratent : `get_transient()` peut retourner `false` pour deux raisons différentes, un transient expiré ou une valeur qui vaut réellement `false`. Si votre donnée peut légitimement être booléenne, préférez encapsuler la valeur dans un tableau plutôt que de tester directement le retour brut.

## Sans cache d'objets persistant : deux lignes dans wp_options

Sur la grande majorité des hébergements mutualisés, sans Redis ni Memcached configuré, chaque transient se traduit concrètement par deux lignes dans la table `wp_options` : une pour la valeur (`_transient_kaolin_taux_eur_usd`), une pour l'horodatage d'expiration (`_transient_timeout_kaolin_taux_eur_usd`).

> L'essentiel à retenir : Un transient sans cache persistant vit dans wp_options, avec une clé d'expiration séparée ; Avec un cache d'objets persistant, il ne touche jamais la base de données ; La suppression manuelle reste indispensable, l'expiration seule ne suffit pas toujours

C'est important à savoir pour deux raisons. D'abord, ces options sont chargées avec `autoload` désactivé par défaut sur les transients récents, ce qui évite qu'elles alourdissent chaque chargement de page comme le ferait une option classique. Ensuite, l'expiration n'est pas gérée par une tâche automatique : WordPress vérifie la date d'expiration au moment de la lecture, via `get_transient()`. Un transient jamais relu après son expiration reste donc physiquement présent en base, potentiellement pendant des mois.

- Sans cache persistant, un transient expiré mais jamais relu pollue durablement `wp_options`
- La commande `wp transient delete --expired` de WP-CLI permet un nettoyage périodique
- Un transient à durée de vie très courte sur un site à fort trafic peut générer un nombre élevé d'écritures en base

## Avec un cache d'objets persistant : tout change

Dès qu'un plugin de cache d'objets persistant est actif (Redis Object Cache, Memcached Object Cache, ou une solution propriétaire d'hébergeur), la Transients API bascule entièrement sur le cache d'objets. Les fonctions `set_transient`, `get_transient` et `delete_transient` ne touchent alors plus du tout `wp_options` : elles délèguent à `wp_cache_set` et consorts.

La conséquence la plus surprenante pour qui découvre ce comportement : un transient stocké de cette façon peut disparaître à tout moment, sans respecter la durée demandée, si le cache décide d'évincer cette clé faute de mémoire disponible. Ce n'est pas un bug, c'est le contrat même d'un cache d'objets. Une extension qui suppose qu'un transient survivra forcément jusqu'à son expiration programmée prend un risque.

> Ne stockez jamais dans un transient une donnée que votre extension ne sait pas reconstruire à la volée si elle disparaît prématurément. C'est un cache, pas un espace de stockage garanti.

## Choisir la bonne durée de vie

Le choix de la durée dépend directement de la fraîcheur nécessaire et du coût de régénération de la donnée. Pour l'appel de taux de change du projet évoqué plus haut, une heure suffisait largement. Pour un résultat de requête coûteuse peu sensible à la fraîcheur, une journée entière (`DAY_IN_SECONDS`) est souvent raisonnable.

- `MINUTE_IN_SECONDS`, `HOUR_IN_SECONDS`, `DAY_IN_SECONDS` et `WEEK_IN_SECONDS` sont des constantes natives, à préférer à des valeurs en dur
- Une durée de zéro équivaut à ne jamais expirer par le mécanisme de la Transients API elle-même
- Un transient sans expiration explicite reste soumis à l'éviction du cache d'objets, s'il est actif

## Invalider un transient au bon moment

L'expiration passive ne suffit pas toujours : si la donnée source change (un article est modifié, un tarif est mis à jour dans un CPT), mieux vaut supprimer explicitement le transient concerné plutôt qu'attendre son expiration naturelle.

```
add_action( 'save_post_tarif', function ( $post_id ) {
    delete_transient( 'kaolin_taux_eur_usd' );
} );
```

Cette invalidation ciblée, déclenchée sur le hook approprié, évite d'afficher une donnée obsolète pendant toute la durée de vie restante du transient, ce qui serait particulièrement gênant pour une information aussi sensible qu'un taux de change.

## En résumé

La Transients API n'est pas un simple raccourci vers `wp_options` : c'est une abstraction qui s'adapte automatiquement à l'infrastructure de cache disponible, du mutualisé le plus basique au cluster Redis le plus sophistiqué. Écrire une extension qui la respecte, c'est accepter qu'un transient puisse disparaître avant l'heure, et toujours prévoir la régénération de la donnée en conséquence.
