gform_after_submission : ce hook, déclenché par Gravity Forms juste après l’enregistrement réussi d’une entrée, est le point d’ancrage naturel pour faire cohabiter deux extensions qui, par défaut, ignorent complètement l’existence l’une de l’autre. Sur un projet client où un formulaire de candidature devait apparaître comme un champ consultable directement dans l’écran d’édition d’une fiche candidat gérée par ACF, la question s’est posée simplement : où stocker la soumission pour qu’elle soit à la fois exploitée par Gravity Forms et visible côté ACF sans duplication de logique.
Gravity Forms stocke nativement chaque soumission dans ses propres tables (wp_gf_entry et wp_gf_entry_meta), totalement indépendantes du système de métadonnées standard de WordPress. ACF, de son côté, lit et écrit dans wp_postmeta via ses propres conventions de sérialisation pour les champs de type repeater ou groupe. Faire apparaître une donnée de l’un dans l’écran de l’autre suppose donc une synchronisation explicite, pas une lecture croisée directe des tables.
Écrire la soumission vers un champ ACF au moment de l’envoi
La solution la plus fiable consiste à intercepter la soumission via gform_after_submission et à écrire immédiatement les valeurs pertinentes dans un champ ACF associé au post concerné, en utilisant la fonction update_field() plutôt qu’un accès direct à update_post_meta() :
add_action( 'gform_after_submission_12', function ( $entry, $form ) {
$candidat_id = absint( rgpost( 'candidat_post_id' ) );
if ( ! $candidat_id ) {
return;
}
update_field( 'candidature_message', rgar( $entry, '3' ), $candidat_id );
update_field( 'candidature_date', current_time( 'mysql' ), $candidat_id );
}, 10, 2 );
Le suffixe numérique dans gform_after_submission_12 restreint le hook au formulaire d’ID 12 uniquement, une pratique préférable à un hook générique suivi d’une vérification manuelle de l’ID de formulaire, car elle rend le code plus lisible et évite l’exécution inutile de la fonction sur des formulaires sans rapport.
Gérer les soumissions multiples avec un champ repeater

Quand un même candidat peut soumettre plusieurs candidatures dans le temps, un champ simple ne suffit plus : il faut empiler les soumissions. Le champ de type repeater d’ACF Pro convient bien à ce cas, à condition d’ajouter une ligne plutôt que d’écraser la valeur existante :
$lignes_existantes = get_field( 'historique_candidatures', $candidat_id ) ?: [];
$lignes_existantes[] = [
'message' => rgar( $entry, '3' ),
'date_soumission' => current_time( 'mysql' ),
];
update_field( 'historique_candidatures', $lignes_existantes, $candidat_id );
Cette approche lit systématiquement la valeur actuelle avant d’y ajouter la nouvelle ligne, ce qui évite l’écrasement silencieux de l’historique si deux soumissions arrivent à quelques secondes d’intervalle — un scénario qui reste rare, mais pas impossible sur un formulaire ouvert au public.
Identifier le post cible depuis le formulaire
Le champ caché candidat_post_id utilisé plus haut suppose que le formulaire est affiché sur une page où l’ID du post concerné est déjà connu (une fiche candidat consultée en front, par exemple). Pour un formulaire de création initiale, sans post existant, la logique s’inverse : c’est la soumission Gravity Forms qui doit d’abord déclencher la création du post via wp_insert_post(), avant que les champs ACF ne soient renseignés sur l’ID nouvellement créé.
Rendre la donnée visible et lisible dans l’admin
Une fois la valeur écrite dans un champ ACF, elle apparaît naturellement dans l’écran d’édition du post via le groupe de champs configuré dans l’interface ACF, sans code supplémentaire. C’est précisément l’intérêt de cette approche : l’équipe côté client, qui connaît déjà l’interface ACF, n’a pas besoin d’apprendre à naviguer dans l’écran des entrées Gravity Forms pour consulter une candidature.
- Le groupe de champs ACF doit être configuré avec une règle de localisation adaptée au type de post concerné.
- Le champ peut être passé en lecture seule côté ACF si la modification manuelle n’a pas de sens métier.
- Un lien retour vers l’entrée Gravity Forms d’origine, via son ID, facilite l’audit en cas de litige sur une soumission.
Ce que cette intégration ne couvre pas
Cette approche reste spécifique à Gravity Forms et à son système de hooks nommés par ID de formulaire. Elle ne s’applique pas telle quelle à WPForms, dont le système de hooks et de stockage diffère sensiblement, notamment sur la structure des entrées et les conventions de nommage des actions déclenchées après soumission.
La règle qu’on retient de ce type d’intégration : ne jamais dupliquer une logique de stockage entre deux extensions quand un simple hook de synchronisation suffit à faire cohabiter les deux écosystèmes sans copie redondante des données.
En résumé
Faire coexister Gravity Forms et ACF sur un même post ne demande pas de réécrire la logique de l’un ou de l’autre : un hook gform_after_submission ciblé, couplé à update_field(), suffit à synchroniser une soumission vers un champ consultable dans l’admin. Le champ repeater prend le relais dès que plusieurs soumissions doivent s’accumuler sur un même post, sans écraser l’historique existant.