La plupart des articles sur WPGraphQL se concentrent sur la lecture de contenu, parce que c’est l’usage le plus fréquent en headless. Mais un formulaire de contribution, un espace membre qui permet de modifier son profil, ou un système d’avis client nécessitent d’écrire dans WordPress depuis le front, pas seulement d’y lire. C’est le rôle des mutations GraphQL, l’équivalent des requêtes POST/PUT en REST.
Cet article couvre l’écriture de mutations avec WPGraphQL, l’authentification nécessaire pour qu’elles fonctionnent, et la gestion des erreurs de permission — sans aborder WPGraphQL for ACF, qui mérite un traitement séparé pour la gestion des champs personnalisés dans ces mêmes mutations.
Anatomie d’une mutation WPGraphQL
Chaque mutation native de WPGraphQL suit la même convention : un objet input contenant les données à écrire, et un objet payload en retour, qui inclut l’objet créé ou modifié. La mutation createPost illustre ce schéma :
mutation CreerArticle($titre: String!, $contenu: String!) {
createPost(
input: {
title: $titre
content: $contenu
status: DRAFT
}
) {
post {
id
databaseId
title
status
}
}
}
Le statut DRAFT plutôt que PUBLISH n’est pas anodin dans cet exemple : pour un contenu généré depuis un formulaire public (une candidature, un témoignage), il est presque toujours préférable de le créer en brouillon et de laisser un humain valider la publication, plutôt que de publier automatiquement du contenu non modéré.
Authentifier la requête
Sans authentification, une mutation comme createPost échoue avec une erreur de permission, WPGraphQL respectant les mêmes capacités WordPress qu’une action équivalente dans l’administration. L’authentification passe généralement par un jeton JWT, obtenu via l’extension WPGraphQL JWT Authentication, transmis dans l’en-tête Authorization :

const reponse = await fetch('https://exemple.fr/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${jetonJWT}`,
},
body: JSON.stringify({
query: MUTATION_CREER_ARTICLE,
variables: { titre: 'Mon titre', contenu: 'Le contenu de l\'article.' },
}),
});
const { data, errors } = await reponse.json();
Notez que la réponse GraphQL renvoie systématiquement un code HTTP 200, même en cas d’erreur applicative : c’est le tableau errors dans le corps de la réponse qui signale un échec, jamais le code de statut HTTP seul. C’est une différence importante avec l’API REST, où une erreur de permission renvoie un 401 ou 403 explicite.
Gérer les erreurs de permission
Une mutation qui échoue pour cause de permission insuffisante renvoie un message d’erreur dans le tableau errors, avec une catégorie identifiable dans les extensions de l’erreur :
{
"errors": [
{
"message": "Sorry, you are not allowed to create posts as this user.",
"extensions": { "category": "user" }
}
],
"data": { "createPost": null }
}
Côté front, il faut systématiquement vérifier la présence du tableau errors avant de considérer la mutation comme réussie, même si data contient une structure a priori valide :
if (errors && errors.length > 0) {
throw new Error(errors[0].message);
}
if (!data.createPost.post) {
throw new Error('La création a échoué sans message explicite.');
}
Modifier un contenu existant
La mutation updatePost suit le même principe, en ajoutant l’identifiant de l’objet à modifier dans l’input :
mutation ModifierArticle($id: ID!, $titre: String!) {
updatePost(input: { id: $id, title: $titre }) {
post {
id
title
modified
}
}
}
L’utilisateur authentifié doit disposer de la capacité edit_post sur l’article ciblé, exactement comme pour une modification via l’administration classique : WPGraphQL ne contourne jamais les capacités WordPress natives, il les applique simplement dans un contexte GraphQL.
Un cas concret : un formulaire de témoignage client
Sur un front dédié aux témoignages clients, j’ai mis en place un formulaire public qui crée un CPT temoignage en statut brouillon via une mutation personnalisée, enregistrée côté WordPress avec register_graphql_mutation() plutôt que d’utiliser createPost directement, pour appliquer une validation métier spécifique (longueur minimale, filtrage anti-spam) avant l’écriture.
register_graphql_mutation( 'creerTemoignage', array(
'inputFields' => array(
'nomClient' => array( 'type' => 'String' ),
'message' => array( 'type' => 'String' ),
),
'outputFields' => array(
'succes' => array( 'type' => 'Boolean' ),
),
'mutateAndGetPayload' => function ( $input ) {
if ( strlen( $input['message'] ) < 20 ) {
throw new \GraphQL\Error\UserError( 'Le message est trop court.' );
}
wp_insert_post( array(
'post_type' => 'temoignage',
'post_title' => sanitize_text_field( $input['nomClient'] ),
'post_content' => sanitize_textarea_field( $input['message'] ),
'post_status' => 'draft',
) );
return array( 'succes' => true );
},
) );
Une mutation personnalisée coûte plus cher à écrire qu’un appel direct à
createPost, mais elle permet d’appliquer une validation métier avant l’écriture plutôt qu’après, ce qui évite de publier puis de corriger a posteriori un contenu non conforme.
En résumé
Les mutations WPGraphQL permettent d’écrire dans WordPress depuis un front découplé, à condition de gérer l’authentification par jeton et de vérifier systématiquement le tableau errors plutôt que de se fier au seul code HTTP. Pour une logique métier au-delà d’une simple création ou modification, une mutation personnalisée via register_graphql_mutation() offre un contrôle bien plus fin que les mutations génériques.