Le WordPress d'aujourd'hui, décodé pour les développeurs

Extensions

register_post_status : des statuts de workflow au-delà de publié

Un studio de design veut qu'un article reste invisible du public mais clairement identifiable par le client comme « en validation », avec son propre libellé et son propre compteur dans l'administration.

Par WordPress Développement • 30 septembre 2026 • 8 min de lecture • Aucun commentaire
register_post_status : des statuts de workflow au-delà de publié

Un studio de design produit des fiches de recommandations pour des clients externes, stockées comme un CPT recommandation dans WordPress. Le processus de travail comporte une étape intermédiaire cruciale : une fois rédigée par le designer, une fiche doit être visible par le client pour validation, sans être publique, et surtout sans se confondre visuellement avec un simple brouillon interne dans la liste d’administration. Le statut « Brouillon » natif ne porte pas cette nuance : il ne dit rien sur qui doit agir ensuite ni sur l’état réel du processus de validation.

La réponse à ce besoin ne passe pas par une métadonnée personnalisée affichée à côté du statut natif, une solution bancale qui demanderait de dupliquer la logique d’affichage un peu partout dans l’administration. La bonne réponse est de déclarer un véritable statut de publication personnalisé, avec register_post_status(), qui s’intègre alors nativement au même menu déroulant que « Publié » ou « Brouillon ».

Déclarer le statut

add_action( 'init', function() {
    register_post_status( 'en_validation_client', array(
        'label'                     => _x( 'En validation client', 'statut de publication', 'studio-design' ),
        'public'                    => false,
        'internal'                  => false,
        'protected'                 => true,
        'private'                   => false,
        'show_in_admin_status_list' => true,
        'show_in_admin_all_list'    => true,
        'label_count'               => _n_noop(
            'En validation client <span class="count">(%s)</span>',
            'En validation client <span class="count">(%s)</span>',
            'studio-design'
        ),
    ) );
} );

Chaque argument porte une nuance précise qu’il vaut la peine de détailler. public à false garantit que ce statut ne rend jamais la fiche accessible publiquement, même en connaissant son URL directe. protected à true indique que ce contenu nécessite une capacité d’édition pour être consulté dans l’administration, ce qui exclut un simple abonné du site mais permet à un client disposant d’un rôle adapté d’y accéder, à condition que ce rôle porte la capacité appropriée. show_in_admin_status_list et show_in_admin_all_list déterminent respectivement l’apparition du statut dans le menu déroulant d’édition d’une fiche, et son inclusion dans l’onglet « Tous » de la liste d’administration.

Ajouter le statut au menu déroulant de l’écran d’édition

L'essentiel à retenir : Un statut personnalisé s'affiche dans le menu déroulant d'état comme les statuts natifs ; Le compteur de l'onglet de filtre en haut de liste nécessite un argument dédié ; Les capacités de lecture doivent être pensées séparément pour un client externe

Déclarer le statut avec register_post_status() ne suffit pas à le faire apparaître automatiquement dans le menu déroulant visible lors de l’édition d’une fiche : WordPress affiche ce menu à partir d’une liste fixe de statuts natifs, et il faut explicitement y ajouter les statuts personnalisés via un script JavaScript injecté sur l’écran d’édition, une limitation connue de longue date dans le cœur de WordPress :

add_action( 'admin_footer-post.php', 'studio_design_statut_menu_classique' );
add_action( 'admin_footer-post-new.php', 'studio_design_statut_menu_classique' );

function studio_design_statut_menu_classique() {
	global $post;

	if ( ! $post || 'recommandation' !== $post->post_type ) {
		return;
	}

	$libelle = __( 'En validation client', 'studio-design' );
	$actif   = ( 'en_validation_client' === $post->post_status );
	?>
	<script>
	jQuery( function ( $ ) {
		$( '#post_status' ).append(
			$( '<option>', { value: 'en_validation_client', text: <?php echo wp_json_encode( $libelle ); ?> } )
		);
		<?php if ( $actif ) : ?>
		$( '#post_status' ).val( 'en_validation_client' );
		$( '#post-status-display' ).text( <?php echo wp_json_encode( $libelle ); ?> );
		<?php endif; ?>
	} );
	</script>
	<?php
}

Ce script ne vise que l’éditeur classique, où le bloc « Publier » contient un menu déroulant #post_status. Il ajoute l’option, la sélectionne si la fiche est déjà dans cet état et met à jour le libellé affiché. Les libellés passent par wp_json_encode() pour être injectés sans risque dans le JavaScript. Sur l’écran de l’éditeur de blocs, l’élément #post_status n’existe pas et le script n’a simplement aucun effet.

Dans l’éditeur de blocs

L’éditeur de blocs n’affiche pas le menu des états d’une fiche de la même façon : il expose un panneau « Résumé » avec des états natifs. Pour y proposer le statut personnalisé, on ajoute un champ dans ce panneau avec PluginPostStatusInfo, qui modifie l’attribut status de la fiche en cours d’édition :

const { registerPlugin } = wp.plugins;
const { PluginPostStatusInfo } = wp.editPost;
const { SelectControl } = wp.components;
const { useSelect, useDispatch } = wp.data;
const { createElement: el } = wp.element;
const { __ } = wp.i18n;

function SelecteurStatut() {
	const statut = useSelect(
		( select ) => select( 'core/editor' ).getEditedPostAttribute( 'status' ),
		[]
	);
	const { editPost } = useDispatch( 'core/editor' );

	if ( 'draft' !== statut && 'en_validation_client' !== statut ) {
		return null;
	}

	return el(
		PluginPostStatusInfo,
		{},
		el( SelectControl, {
			label: __( 'Validation', 'studio-design' ),
			value: statut,
			options: [
				{ label: __( 'Brouillon', 'studio-design' ), value: 'draft' },
				{ label: __( 'En validation client', 'studio-design' ), value: 'en_validation_client' },
			],
			onChange: ( valeur ) => editPost( { status: valeur } ),
		} )
	);
}

registerPlugin( 'studio-design-statut', { render: SelecteurStatut } );

Le champ ne s’affiche que pour une fiche en brouillon ou en validation : proposer ce choix à une fiche déjà publiée la ferait repasser dans un état non public par simple clic. Le script se charge uniquement pour le type de contenu concerné :

add_action( 'enqueue_block_editor_assets', function () {
	if ( 'recommandation' !== get_post_type() ) {
		return;
	}

	wp_enqueue_script(
		'studio-design-statut',
		plugins_url( 'statut.js', __FILE__ ),
		array( 'wp-plugins', 'wp-edit-post', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n' ),
		'1.0.0',
		true
	);
} );

Le type de contenu doit être exposé dans l’API REST (show_in_rest) pour être édité dans l’éditeur de blocs. Un statut déclaré avec internal à false est en principe accepté par cette API ; testez l’enregistrement dans votre version avant de le promettre au client.

Le compteur de l’onglet de filtre

La liste d’administration affiche en haut des onglets de filtre : « Tous (12) », « Publiés (4) », et désormais « En validation client (3) ». Le nombre vient de l’argument label_count, déjà présent dans la déclaration plus haut. Il attend un couple de chaînes singulier et pluriel, produit par _n_noop(), où %s marque l’emplacement du nombre. Sans ce marqueur, l’onglet s’affiche sans compteur ; c’est l’oubli le plus courant. Avec show_in_admin_status_list à true, l’onglet existe ; avec show_in_admin_all_list à true, les fiches restent visibles dans « Tous ».

Pour afficher aussi l’état dans la colonne du titre, le filtre display_post_states reçoit la liste des mentions et la fiche concernée, et permet d’ajouter une mention : utile quand l’onglet actif n’est pas celui du statut.

Prévenir le client à chaque changement d’état

Un statut de workflow n’a de valeur que si quelqu’un est averti. Le crochet transition_post_status reçoit le nouvel état, l’ancien et la fiche, ce qui suffit pour envoyer un message uniquement lors du passage en validation :

add_action( 'transition_post_status', 'studio_design_notifier_client', 10, 3 );

function studio_design_notifier_client( $nouveau, $ancien, $post ) {
	if ( 'recommandation' !== $post->post_type
		|| $nouveau === $ancien
		|| 'en_validation_client' !== $nouveau ) {
		return;
	}

	$adresse = get_post_meta( $post->ID, '_email_client', true );
	if ( ! is_email( $adresse ) ) {
		return;
	}

	wp_mail(
		$adresse,
		sprintf( __( 'Fiche à valider : %s', 'studio-design' ), $post->post_title ),
		sprintf(
			__( "Une fiche attend votre validation.\n\nOuvrir la fiche : %s", 'studio-design' ),
			get_edit_post_link( $post->ID, 'raw' )
		)
	);
}

Qui peut lire une fiche en validation ?

C’est le troisième point de l’encadré, et le plus souvent négligé. Un statut protected n’est pas public : sur l’adresse de la fiche, un visiteur anonyme reçoit une erreur 404, et un utilisateur connecté n’y accède que s’il possède la capacité d’édition correspondante. Un client qui a simplement le rôle « Abonné » verra donc, lui aussi, une page introuvable. Deux approches existent. La première donne au client un rôle dédié, avec les capacités d’un type de contenu à droits propres (capability_type personnalisé) limitées à ses propres fiches. La seconde construit une page de consultation qui vérifie elle-même le droit d’accès, sans ouvrir l’administration. Dans les deux cas, ne comptez pas sur le statut seul pour protéger ou pour ouvrir l’accès, et vérifiez dans votre version comment une requête qui cible explicitement ce statut se comporte pour un visiteur non connecté.

Pièges à connaître

  • Désactiver l’extension rend les fiches orphelines. Un statut qui n’est plus déclaré n’apparaît plus dans les onglets : les fiches existent toujours en base, mais deviennent difficiles à retrouver.
  • Un statut n’est pas une permission. Changer l’état d’une fiche ne change aucun droit de lecture ou d’écriture tant que vous n’avez pas écrit la règle correspondante.
  • Les identifiants de statut sont limités. La colonne post_status tient sur vingt caractères : en_validation_client en compte vingt, la limite exacte ; choisissez des identifiants courts.
  • Le libellé doit rester traduisible. Passez-le par _x() ou __() avec un domaine de traduction, comme dans la déclaration.
  • Le retour à un état précédent doit rester possible. Prévoyez le cas où le client refuse : quel statut reprend la fiche ?

Un état de workflow vaut ce que valent les règles qui l’accompagnent : qui le pose, qui le lit, qui est prévenu.

Conclusion

Déclarer le statut avec register_post_status() ne prend que quelques lignes ; la valeur se trouve dans ce qui l’entoure : le menu qui le propose dans chaque éditeur, le compteur que permet label_count, la notification au client et surtout la règle de lecture. Traitez ces quatre morceaux ensemble et votre studio obtiendra un vrai circuit de validation, visible dans l’administration comme n’importe quel état natif, sans métadonnée parallèle à maintenir.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi