Créer un formulaire front-end ACF multi-étapes

Dans cette preuve de concept, nous analysons la création d’un formulaire WordPress en front-end avec ACF, formulaire éclaté en plusieurs étapes.

Vous ne le savez peut-être pas, mais j’adore utiliser ACF pour me faciliter le développement de sites WordPress. En quelques minutes, cette extension me permet de créer des groupes de champs et de les remplir avec des champs complexes. Pratique !

Beaucoup de hooks bien pensés nous permettent — à nous, développeurs — d’interagir avec la logique par défaut d’ACF afin de créer des validations de champs sur-mesure, des modifications à la volée de configuration de champs, des événements faits maisons lors d’une sauvegarde d’un post, etc. Nous avons d’ailleurs précédemment parlé de ces hooks ici même !

Analysons ensemble comment créer un formulaire multi-étapes affiché en front-end de notre site WordPress grâce à ACF.

Créer/éditer du contenu via le front-end

Une fonctionnalité un peu moins connue d’Advanced Custom Fields est sa capacité à offrir des formulaires front-end via une simple fonction. Je l’utilise intensément sur les sites WordPress plus complexes de mes clients dès lors que nous avons besoin d’interactions utilisateurs côté front-end. Avec un peu de code, on gagne énormément de temps car c’est ACF qui gère le rendu des champs, la logique conditionnelle de ces derniers, la validation des valeurs de chaque champ, etc.

Mais proposer un formulaire particulièrement long, rempli de nombreux champs, n’est probablement pas une expérience utilisateur optimale. Dans cette preuve de concept, nous avons profiter de la flexibilité de acf_form() afin d’optimiser l’affichage de ce formulaire et l’éclater en plusieurs étapes plus petites.

Cet article est une traduction de mon article Create a multi-pages form with ACF publié sur mon site anglais.

Comment créer un formulaire front-end multi-étapes avec ACF

Code et démonstration

Le code complet de cette preuve de concept est disponible sur GitHub.

Nous allons créer un formulaire assez basique qui sera composé de 3 étapes distinctes, comme démontré ci-dessous. La soumission du formulaire créera un nouveau post de type estimate-request dans notre base de données WordPress ; les champs meta de ce post seront peuplés avec les valeurs des champs correspondants du formulaire (notez que cette logique de création d’un post et enregistrement d’une meta donnée est native à la fonction acf_form() proposée par ACF).

Pré-requis

Evidemment, nous avons besoin de l’extension Advanced Custom Fields !

Nous avons également besoin d’un type de contenu Estimate Request qui accueillera les données envoyées par le formulaire.

Conseil

Vous pouvez mettre en place rapidement ce type de contenu grâce à l’extension CPT UI et ce fichier de configuration JSON disponible ici.

Nous avons également besoin de groupes de champs (ou metaboxes) ACF associées à ce type de contenu. Dans notre example, nous utilisons ces quatre metaboxes.

Notez l’importance de séparer nos champs meta dans de multiples groupes de champs : une étape de notre formulaire affichera un ou plusieurs groupe(s) de champs.

Pour terminer, vous avez besoin d’inclure la fonction acf_form_head() tout en haut du fichier header.php de votre thème comme mentionné dans la documentation officielle d’ACF.

Concept général « d’éclatement » du formulaire en plusieurs sous-étapes

Nous allons tout d’abord créer un shortcode [acf_multiforms_example] qui sera en charge de présenter le formulaire ACF côté front-end.

public function output_shortcode() {
	ob_start();

	if ( ! function_exists( 'acf_form' ) ) {
		return ob_get_clean();
	}

	// User is currently filling the form, we display it.
	if ( ! $this->current_multiform_is_finished() ) {
		$this->output_acf_form( [
			'post_type' => $this->post_type,
		] );

	// Form has been filled entirely, we display a thanks message.
	} else {
		_e( 'Thanks for your submission, we will get back to you very soon!' );
	}

	return ob_get_clean();
}

Réflexion

Cette logique pourrait être incluse dans un thème ou un plugin via une alternative au shortcode : on pourrait utiliser un bloc Gutenberg, ou une fonction spécifique à inclure dans un template… Libre à vous !

Afficher un ensemble précis de champs

La chose importante à comprendre est que chaque étape du formulaire est composée d’une ou plusieurs metaboxes ACF.

Un ou plusieurs groupes de champs compose(nt) une étape de formulaire

Selon l’avancement de l’utilisateur dans notre formulaire, nous affichons uniquement les groupes de champs concernés par cette étape.

Cette logique dynamique se fait grâce à 3 points cruciaux :

  1. une variable passée en paramètre $_GET (?step=2) va nous indiquer quelle étape du formulaire doit être présentée à l’utilisateur,
  2. le paramètre field_groups de la fonction acf_form() nous permet d’indiquer à ACF quels groupes de champs doivent être utilisés pour afficher les champs du formulaire selon l’étape en cours
  3. un « crochetage » sur le hook acf/save_post nous permet d’intercepter les envois de formulaire, d’analyser l’étape en cours et de rediriger l’utilisateur vers l’étape suivante.

Rappel

Le code complet de cette preuve de concept est disponible sur GitHub.

Avancer à petits pas

L’étape « en cours » de notre formulaire provient d’un paramètre $_GET. En passant ce paramètre ?step=X, on indique explicitement à notre logique que l’on veut afficher l’étape n°X de notre formulaire. Ou en d’autres termes : on veut afficher l’ensemble n°X de groupes de champs dans notre formulaire front-end.

Pour obtenir tout ça, on injecte une logique grâce au hook/action acf/save_post. Ce hook est parfait pour intercepter des données de formulaire envoyées/sauvegardées par ACF.

Nous avons déjà partagé quelques astuces utiles pour un développement optimal avec WordPress ACF ; nous y parlions du hook acf/save_post.

Sur ce hook, nous faisons les choses suivantes :

  1. on intercepte la soumission de notre formulaire (et ignorons les autres formulaires ACF qui ne nous intéressent pas dans ce cas précis)
  2. on récupère et analyse l’étape « en cours » du formulaire qui vient d’être envoyé et on décide :
    1. s’il faut rediriger l’utilisateur vers l’étape suivante (la même URL avec le paramètre ?step correctement incrémenté) si ce n’est pas l’étape finale
    2. ou, si c’est la dernière étape du formulaire, si l’on doit rediriger l’utilisateur vers une page de conclusion/remerciement. Dans ce cas, c’est la même URL avec un paramètre ?finished afin d’afficher un message « Merci de votre envoi » en lieu et place du formulaire.

Créer ou éditer un post via acf_form() ?

private function output_acf_form( $args = [] ) {
	$requested_post_id = $this->get_request_post_id();
	$requested_step    = $this->get_request_step();

	$args = wp_parse_args(
		$args,
		[
			'post_id'     => $requested_post_id,
			'step'        => 'new_post' === $requested_post_id ? 1 : $requested_step,
			'post_type'   => 'post',
			'post_status' => 'publish',
		]
	);

	$submit_label           = $args['step'] < count( $this->metabox_ids ) ? __( 'Next step' ) : __( 'Finish' );
	$current_step_metaboxes = ( $args['post_id'] !== 'new_post' && $args['step'] > 1 ) ? $this->metabox_ids[ (int) $args['step'] - 1 ] : $this->metabox_ids[0];

	acf_form(
		[
			'id' 				=> $this->id,
			'post_id'			=> $args['post_id'],
			'new_post'			=> [
				'post_type'		=> $args['post_type'],
				'post_status'	=> $args['post_status'],
			],
			'field_groups'      => $current_step_metaboxes,
			'submit_value'      => $submit_label,
			'html_after_fields' => $this->output_hidden_fields( $args ),
			'uploader'          => 'basic',
		]
	);
}

Une autre flexibilité de la fonction acf_form() (qui nous permet d’afficher le formulaire ACF en front-end) est son paramètre post_id qui accepte deux types de valeurs possibles :

  1. new_post si l’on souhaite créer un nouveau post lors de la soumission du formulaire (qui utilisera wp_insert_post() en interne)
  2. ou un nombre entier qui indiquera à ACF que l’on souhaite éditer un post existant précis (qui utilisera wp_update_post() en interne)

Cette flexibilité est très importante dans notre cas : lorsqu’un utilisateur visite la page du formulaire pour la première fois et qu’on lui présente la première étape du formulaire, on souhaite qu’ACF créée un nouveau post estimate_request pour nous.

Par contre, dès la deuxième étape du formulaire et ce jusqu’à la dernière, nous indiquons à ACF que nous souhaitons éditer un post précédemment créé. Nous ne souhaitons évidemment pas qu’ACF créée un nouveau post à chaque étape, mais qu’il continue l’édition du même post (créé en fin d’étape 1) à partir de la seconde étape.

Cette référence au post créé par ACF est passée via ?post_id=X dans un paramètre $_GET de l’URL de la page.

Un mot concernant la sécurité de ce système

Je vous vois déjà vous affoler : référencer un post via un paramètre $_GET librement accessible… Quoi de plus dangereux ?

J’avoue qu’en l’état, n’importe qui pourrait changer ce paramètre et accéder au formulaire d’édition d’un post spécifique. Loin d’être idéal et sécurisé !

public function process_acf_form( $post_id ) {
	if ( is_admin() || ! isset( $_POST['ame-multiform-id'] ) || $_POST['ame-multiform-id'] !== $this->id ) {
		return;
	}

	$current_step = $this->get_request_step();

	if ( $current_step === 1 ) {
		$token = wp_generate_password( rand( 10, 20 ), false, false );
		update_post_meta( (int) $post_id, 'secret_token', $token );
	}

	...
}

Pour éviter cela, nous allons créer un token (code) aléatoire qui servira de vérificateur de sécurité :

  • à la fin de la première étape du formulaire, quand ACF créée le post, on génère un mot de passe aléatoire. Ce dernier est stocké en métadonnée du post créé.
  • lorsque notre système redirige l’utilisateur vers les URLs des étapes suivantes ou finale, ce token de sécurité est passé dans l’URL.
  • si ce token de sécurité n’est pas présent dans l’URL, ou ne correspond pas au token de sécurité du post concerné, l’édition est ignorée et on présente à l’utilisateur un formulaire vide « tout neuf » qui créera un nouveau post.
Modifying the token in URL

Conclusion

Les avantages d’utiliser ACF pour développer des formulaires WordPress en front-end sont nombreux :

  1. on ne réinvente pas la roue : pas besoin d’écrire des formulaires HTML complexes ou de gérer le code pour la création/édition du post ou l’enregistrement des métadonnées
  2. on profite de la validation validation JavaScript AJAX des champs qu’ACF propose nativement dans le back-office, côté front-end cette fois
  3. on permet à l’utilisateur de créer ou d’éditer des articles (ou autres types de contenu) via un formulaire front-end parfaitement intégré à notre site
  4. nous n’avons qu’à nous concentrer sur le développement de logiques métiers spécifiques à notre projet, en s’interfaçant sur l’action acf/save_post proposée par ACF

En d’autres termes : on gagne un temps fou !

Et après ?

Mon rêve serait un jour de proposer un add-on ACF qui permettra de simplifier la création de formulaires front-end. Via une interface visuelle simple, on pourrait choisir ses groupes de champs et les assigner à telle ou telle étape du formulaire.

Il est également possible d’aller plus loin en proposant une barre de progression pour indiquer à l’utilisateur son avancement dans le formulaire, un bouton précédent pour éditer une étape déjà remplie, la création d’un bloc Gutenberg pour intégrer un formulaire ACF en front-end, etc.

Si vous avez des idées de suggestions, n’hésitez pas à les partager en commentaire !


Vous avez aimé cet article ?

Partagez-le sur vos réseaux sociaux en guise de remerciement :)


8 commentaires

super article, par contre j’ai beau utiliser le shortcode, rien ne s’affiche. En front j’ai juste [acf_multiforms_example]

J’ai bien mis la fonction en début de fichier.
J’ai recopié ton code dans function.php, récupéré tes metaboxes

Y’a autre chose à faire ??

Effectivement ca semble pas mal , mais je n’arrice pas non plus à faire fonctionner tout ca

j ai bien cptui et acf
j’ai importé les champs et le CPT
j ai mis le acf_form_head() dans le header
J ai enregistré le dossier sur git dans plugin et activé le plugin
j ai mis le shortcode dans une page mais rien ne se passe

Bonjour à tout le monde,
Super pour ces explications bravo .J’ai testé ACF .
je suis nouveau sous wordpress, J’ai un peu de mal à le faire fonctionner je voudrais créer une page client sur la partie admin avec plusieurs champs.Puis je voudrais lier le champs “nom” dans une autre page pour qu’il m’affiche toutes les infos du client et sur la même page après avoir recuperer les infos je voudrai un autre formulaire pour saisir encore des données.

merci de votre aide passez une bonne journée

Bonjour, ca fonctionne comme un charme !
Saurez-vous nous dire comment passer des attributs de shortcode de type [acf_multiforms_example tag= »xyz »] ?

Bonjour,

Je ne comprends pas très bien, cela m’affiche tous mes groupes de champs pour ma part ..

Laisser un commentaire