# transition_post_status : éviter de dupliquer une alerte à chaque sauvegarde

> save_post se déclenche à chaque enregistrement, même sans changement de statut réel. transition_post_status ne réagit qu'aux vraies bascules d'état.

- Auteur : WordPress Développement
- Publié le : 2023-09-06
- Mis à jour le : 2023-09-06
- Catégorie : Astuces
- URL : https://www.wpmoderne.fr/tips/transition-post-status-eviter-doublon-alerte/

## L’essentiel

- save_post se déclenche à chaque sauvegarde, y compris les révisions automatiques
- transition_post_status ne réagit qu'à un vrai changement de statut
- Il fournit directement l'ancien et le nouveau statut en paramètres

Une alerte e-mail part trois fois pour la publication d'un seul article. Ce symptôme, un développeur WordPress finit toujours par le croiser, généralement en branchant une notification sur le hook `save_post`, qui semble pourtant le candidat naturel pour ce genre de besoin.

Le problème vient du fonctionnement même de `save_post` : ce hook se déclenche à chaque enregistrement d'un contenu, y compris lors des sauvegardes automatiques de brouillon, des révisions créées en arrière-plan, et de tout enregistrement qui ne correspond pas nécessairement à une bascule réelle de statut éditorial.

## Ce que save_post ne distingue pas

Rien dans les arguments transmis à `save_post` n'indique directement si le statut du contenu vient de changer. Le développeur doit alors comparer manuellement l'ancien et le nouveau statut, en gérant lui-même les cas de révisions automatiques, de type de contenu à exclure, et de sauvegardes répétées liées à l'éditeur de blocs qui enregistre régulièrement en arrière-plan pendant la rédaction.

Cette logique de comparaison, réécrite à la main dans chaque fonction accrochée à `save_post`, devient vite source d'erreurs, avec des conditions oubliées qui déclenchent des doublons ou, à l'inverse, ratent une vraie transition.

## transition_post_status : un hook dédié à la comparaison

> L'essentiel à retenir : save_post se déclenche à chaque sauvegarde, y compris les révisions automatiques ; transition_post_status ne réagit qu'à un vrai changement de statut ; Il fournit directement l'ancien et le nouveau statut en paramètres

WordPress propose un hook spécifiquement conçu pour ce besoin : `transition_post_status`. Il se déclenche à chaque changement d'état d'un contenu, avec trois arguments directement exploitables : le nouveau statut, l'ancien statut, et l'objet `WP_Post` concerné.

```
add_action( 'transition_post_status', function ( $nouveau_statut, $ancien_statut, $post ) {
    if ( 'article' !== $post->post_type ) {
        return;
    }

    if ( 'publish' === $nouveau_statut && 'publish' !== $ancien_statut ) {
        wp_mail(
            'redaction@example.com',
            'Nouvel article publié',
            sprintf( "L'article « %s » vient de passer en ligne.", $post->post_title )
        );
    }
}, 10, 3 );
```

La condition `'publish' !== $ancien_statut` est ici essentielle : elle garantit que l'alerte ne part qu'au moment précis où l'article bascule vers l'état publié, pas à chaque enregistrement ultérieur d'un article déjà en ligne.

## Pourquoi trois arguments changent tout

La grande force de ce hook tient à ce qu'il fournit à la fois l'ancien et le nouveau statut dans un seul appel, sans avoir à interroger la base de données pour retrouver l'état précédent. Cela permet de couvrir des transitions bien plus fines qu'un simple passage en « publié » :

- D'un statut `draft` vers `pending`, pour notifier un relecteur qu'un contenu attend sa validation.
- D'un statut `publish` vers `trash`, pour tracer la mise à la corbeille d'un contenu sensible.
- D'un statut personnalisé vers un autre, sur un flux éditorial qui définit ses propres statuts via `register_post_status()`.

## Un exemple avec des statuts personnalisés

Sur un projet qui gère un flux de relecture à plusieurs niveaux, un statut personnalisé `en_relecture` peut être déclaré, puis surveillé exactement de la même façon :

```
register_post_status( 'en_relecture', array(
    'label'                     => 'En relecture',
    'public'                    => false,
    'internal'                  => true,
    'exclude_from_search'       => true,
    'show_in_admin_all_list'    => true,
    'show_in_admin_status_list' => true,
) );

add_action( 'transition_post_status', function ( $nouveau, $ancien, $post ) {
    if ( 'en_relecture' === $nouveau && 'en_relecture' !== $ancien ) {
        // Notifier l'équipe de relecture désignée.
    }
}, 10, 3 );
```

## La différence avec wp_after_insert_post

Un hook plus récent, `wp_after_insert_post`, couvre un besoin voisin mais distinct : il se déclenche une fois qu'un contenu et toutes ses métadonnées associées ont fini d'être enregistrés, ce qui le rend plus adapté quand la logique dépend de champs personnalisés déjà à jour. `transition_post_status`, lui, reste focalisé sur la seule question du changement d'état, sans attendre la fin complète du processus d'enregistrement.

> Sur toute notification liée à un changement d'état éditorial, comparer explicitement l'ancien et le nouveau statut évite de renvoyer la même alerte à chaque clic sur « Mettre à jour », un piège que beaucoup découvrent seulement après plusieurs plaintes de la rédaction.

## En résumé

Le bon réflexe consiste à se poser la question : ce déclenchement dépend-il réellement d'un changement de statut ? Si la réponse est oui, `transition_post_status` évite d'écrire à la main une comparaison qui existe déjà nativement, et referme du même coup la porte aux doublons de notification qui agacent tant les équipes éditoriales.
