# CHAPITRE 24 — Les formulaires publics

InfraSStudio embarque un moteur de formulaires publics conçu pour transformer la moindre saisie web en lead qualifié dans Dolibarr. Un formulaire de contact rempli sur un site géré par le module ne déclenche pas un simple envoi d'email : il alimente automatiquement le CRM, ouvre un ticket, prévient les équipes commerciales et déclenche, au besoin, un rappel en agenda. Ce chapitre détaille la mécanique interne, la configuration côté administrateur et l'intégration dans un site Dolibarr Website.

### <span style="color: rgb(35, 111, 161);">Architecture du moteur</span>

L'architecture repose sur trois pièces : un descripteur JSON par formulaire, un point d'entrée unique côté serveur, et une chaîne d'adapters exécutés à chaque soumission. Aucun code PHP n'est nécessaire pour ajouter ou modifier un formulaire : il suffit d'éditer le descripteur depuis l'interface d'administration ou directement depuis l'éditeur Studio.

<table id="bkmrk-pi%C3%A8cer%C3%B4leendpoint-un" style="width: 100%; border-collapse: collapse; margin: 1rem 0px; font-size: 0.95em;"><colgroup><col></col><col></col></colgroup><tbody><tr style="background: rgb(25, 5, 45); color: rgb(254, 252, 232);"><th class="align-left" style="padding: 0.6rem 1rem; text-align: left; border: 1px solid rgb(25, 5, 45);">Pièce

</th><th class="align-left" style="padding: 0.6rem 1rem; text-align: left; border: 1px solid rgb(25, 5, 45);">Rôle

</th></tr><tr><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">**Endpoint unique**

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">`<span class="editor-theme-code">public/forms/submit.php</span>`<span style="white-space: pre-wrap;"> reçoit toutes les soumissions. Le formulaire est identifié par son nom inséré en champ caché </span>`<span class="editor-theme-code">form_name</span>`.

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">**Descripteur JSON**

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);"><span style="white-space: pre-wrap;">Une ligne dans </span>`<span class="editor-theme-code">llx_infrasstudio_form_config</span>`<span style="white-space: pre-wrap;"> par formulaire. Décrit les champs, les règles de validation, les paramètres anti-spam et les adapters à exécuter.</span>

</td></tr><tr><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">**Pipeline d'adapters**

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Six étapes activables à la carte : validation, anti-spam, tiers, contact, ticket, notification, agenda.

</td></tr></tbody></table>

##### **Le pipeline étape par étape**

Chaque soumission acceptée traverse la chaîne ci-dessous. Chaque étape s'active indépendamment dans le descripteur, ce qui permet de couvrir aussi bien un formulaire de newsletter minimaliste qu'une demande de démonstration commerciale complète.

<table id="bkmrk-adaptereffet-sur-la-" style="width: 100%; border-collapse: collapse; margin: 1rem 0px; font-size: 0.95em;"><colgroup><col></col><col></col></colgroup><tbody><tr style="background: rgb(25, 5, 45); color: rgb(254, 252, 232);"><th class="align-left" style="padding: 0.6rem 1rem; text-align: left; border: 1px solid rgb(25, 5, 45);">Adapter

</th><th class="align-left" style="padding: 0.6rem 1rem; text-align: left; border: 1px solid rgb(25, 5, 45);">Effet sur la soumission

</th></tr><tr><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">**antispam**

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Honeypot, délai minimum de remplissage, rate-limit par adresse IP, captcha délégué au gestionnaire Dolibarr actif.

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">**tiers**

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);"><span style="white-space: pre-wrap;">Recherche ou création d'une société dans </span>`<span class="editor-theme-code">llx_societe</span>`. Application d'une catégorie et d'une origine.

</td></tr><tr><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">**contact**

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);"><span style="white-space: pre-wrap;">Recherche ou création d'un contact dans </span>`<span class="editor-theme-code">llx_socpeople</span>`, libre ou rattaché au tiers.

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">**ticket**

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Ouverture d'un ticket Dolibarr avec sujet, message, catégorie et sévérité.

</td></tr><tr><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">**notification**

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Envoi d'un email interne à l'équipe commerciale et d'un accusé de réception au visiteur.

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">**agenda**

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Création d'un événement de rappel lié au tiers et au ticket.

</td></tr></tbody></table>

### <span style="color: rgb(35, 111, 161);">Configurer un formulaire</span>

<span style="white-space: pre-wrap;">Deux interfaces complémentaires sont disponibles. </span>**L'administration avancée**<span style="white-space: pre-wrap;"> se trouve dans </span>**Outils → InfraS → Formulaires**<span style="white-space: pre-wrap;"> : grille des configurations, statistiques de soumission, accès au descripteur JSON brut. </span>**L'éditeur Studio**<span style="white-space: pre-wrap;"> propose désormais un onglet </span>**Formulaires**<span style="white-space: pre-wrap;"> avec un inspector inline qui couvre la majorité des réglages courants sans repasser par l'administration Dolibarr.</span>

##### **Créer un nouveau formulaire**

<span style="white-space: pre-wrap;">Le bouton </span>**« + Nouveau formulaire »**<span style="white-space: pre-wrap;"> de l'onglet Formulaires de l'éditeur Studio ouvre une modale en quatre champs :</span>

- <span style="white-space: pre-wrap;">le </span>**libellé affiché en administration**<span style="white-space: pre-wrap;"> (facultatif) ;</span>
- l'**identifiant technique**<span style="white-space: pre-wrap;"> (a-z, 0-9, tiret, underscore — utilisé dans le HTML, unique par entité) ;</span>
- <span style="white-space: pre-wrap;">le </span>**type**<span style="white-space: pre-wrap;"> (</span>**contact**<span style="white-space: pre-wrap;">, </span>**newsletter**<span style="white-space: pre-wrap;">, </span>**demo**<span style="white-space: pre-wrap;"> ou </span>**generic**) — le type définit les champs par défaut et le pipeline par défaut ;
- <span style="white-space: pre-wrap;">un </span>**modèle de design**<span style="white-space: pre-wrap;"> (facultatif) — voir la section </span>**Les starter design templates**<span style="white-space: pre-wrap;"> ci-dessous.</span>

Le formulaire fraîchement créé est immédiatement sélectionné dans l'inspector et prêt à recevoir d'éventuels ajustements (champs, anti-spam, design, pipeline). L'identifiant technique sert d'ancrage tout au long du cycle de vie : il est référencé dans le HTML, dans le viewer de soumissions et dans les journaux.

##### **Gérer les champs depuis l'éditeur**

<span style="white-space: pre-wrap;">Dans l'onglet </span>**Formulaires**<span style="white-space: pre-wrap;"> de l'éditeur Studio, la section </span>**Champs**<span style="white-space: pre-wrap;"> permet d'</span>**ajouter**<span style="white-space: pre-wrap;">, de </span>**réordonner**<span style="white-space: pre-wrap;"> (boutons monter / descendre) et de </span>**supprimer**<span style="white-space: pre-wrap;"> un champ sans toucher au JSON. L'ordre défini ici est exactement l'ordre d'affichage du formulaire public. Chaque champ porte un interrupteur </span>**Obligatoire**<span style="white-space: pre-wrap;"> : lorsqu'il est activé, un astérisque </span>`<span class="editor-theme-code">*</span>`<span style="white-space: pre-wrap;"> est ajouté automatiquement à côté du libellé sur le formulaire rendu. Les saisies en cours (libellé, type, placeholder) sont préservées lors d'un déplacement, d'un ajout ou d'une suppression.</span>

##### **Supprimer un formulaire**

<span style="white-space: pre-wrap;">La section </span>**« Zone dangereuse »**<span style="white-space: pre-wrap;"> en bas de l'inspector expose un bouton </span>**Supprimer ce formulaire**<span style="white-space: pre-wrap;">. La suppression efface uniquement la configuration : les soumissions déjà enregistrées dans </span>`<span class="editor-theme-code">llx_infrasstudio_form_submission</span>`<span style="white-space: pre-wrap;"> sont conservées (traçabilité RGPD préservée). Une modale de confirmation Studio garde le doigt sur le bouton — la fenêtre </span>`<span class="editor-theme-code">confirm()</span>`<span style="white-space: pre-wrap;"> native du navigateur n'est jamais utilisée. Le même contrôle est disponible depuis </span>**Outils → InfraS → Formulaires**<span style="white-space: pre-wrap;"> via le bouton </span>**Supprimer**<span style="white-space: pre-wrap;"> de chaque ligne.</span>

##### **Le descripteur JSON**

Le cœur de la configuration est un descripteur JSON qui décrit le formulaire sous une forme structurée. L'éditeur d'administration valide la syntaxe à l'enregistrement et propose une référence dépliable de toutes les clés supportées pour éviter d'avoir à mémoriser la grammaire.

```
{
    "antispam": { "honeypot": true, "min_fill_seconds": 3, "rate_limit_per_hour": 5, "captcha": true },
    "consent":  { "required": true, "field_name": "consent", "text": "..." },
    "fields":   {
        "name":    { "required": true, "type": "text",  "maxlength": 100 },
        "email":   { "required": true, "type": "email", "maxlength": 200 },
        "message": { "required": true, "type": "text",  "maxlength": 5000 }
    },
    "tiers":        { "enabled": true,  "lookup_by_email": true, "category_label": "Lead web" },
    "ticket":       { "enabled": true,  "category_code":   "COMMERCIAL" },
    "notification": { "autoreply_enabled": true, "autoreply_template_label": "Accusé de réception" },
    "template_override": "site:contact.tpl.php"
}
```

<span style="white-space: pre-wrap;">La clé </span>`<span class="editor-theme-code">template_override</span>`<span style="white-space: pre-wrap;"> est facultative — sans elle, le moteur utilise le template par défaut du type. Voir la section </span>**Intégrer le formulaire dans un site**<span style="white-space: pre-wrap;"> pour les trois modes de résolution.</span>

##### **Tester un formulaire avant mise en ligne**

La fiche admin de chaque formulaire (**Outils → InfraS → Formulaires**<span style="white-space: pre-wrap;"> → ouvrir un formulaire) expose un bouton </span>**« Tester ce formulaire »**<span style="white-space: pre-wrap;"> qui simule une soumission de bout en bout sans passer par le site public. Le tester forge un payload factice à partir des champs déclarés dans la configuration, traverse le pipeline complet (tiers, contact, ticket, notification, agenda) et restitue un rapport détaillé étape par étape.</span>

Les entités créées en mode test (Société, Contact, Ticket, événement d'agenda) sont :

- **marquées explicitement**<span style="white-space: pre-wrap;"> : leur libellé est préfixé </span>`<span class="editor-theme-code">[TEST]</span>`<span style="white-space: pre-wrap;"> pour être reconnaissables au premier coup d'œil dans Dolibarr ;</span>
- **flaguées en base**<span style="white-space: pre-wrap;"> : la soumission correspondante porte </span>`<span class="editor-theme-code">is_test=1</span>`<span style="white-space: pre-wrap;"> dans </span>`<span class="editor-theme-code">llx_infrasstudio_form_submission</span>`<span style="white-space: pre-wrap;"> ;</span>
- **purgeables en un clic**<span style="white-space: pre-wrap;"> : le bouton </span>**Purger les données de test**<span style="white-space: pre-wrap;"> supprime en cascade tous les enregistrements de test (événement → ticket → contact → société → soumission), avec un filet de sécurité qui empêche d'effacer une société qui aurait reçu des soumissions de production entre-temps.</span>

<span style="white-space: pre-wrap;">En mode test, le captcha est </span>**volontairement bypassé**<span style="white-space: pre-wrap;"> par le moteur — l'administrateur est déjà authentifié dans Dolibarr, exiger un code image en plus n'aurait pas de sens. Les autres contrôles antispam (honeypot, délai minimum de remplissage, rate-limit) restent actifs et sont exercés avec des valeurs forgées correctement par le tester, ce qui permet de valider la chaîne complète.</span>

<span style="white-space: pre-wrap;">L'usage typique : après chaque modification importante d'un formulaire (ajout d'un champ, changement de catégorie ticket, nouveau template d'accusé), cliquer une fois sur </span>**Tester ce formulaire**, vérifier dans le rapport que chaque adapter s'est exécuté avec succès, puis purger. Cinq secondes de validation qui évitent de découvrir un bug en production via un vrai client.

### <span style="color: rgb(35, 111, 161);">Connecter le formulaire à votre CRM</span>

L'intérêt principal du moteur réside dans la chaîne de traitement qu'il déclenche au moment de la soumission. Chaque adapter peut être activé indépendamment selon les besoins.

##### **Tiers et contact**

<span style="white-space: pre-wrap;">Lorsque l'adapter tiers est actif, le moteur recherche d'abord une société existante dont l'adresse email correspond à celle saisie ; à défaut, il regarde si l'email appartient à un contact rattaché à une société, puis tente une correspondance par nom d'entreprise. Si aucune correspondance n'est trouvée, un nouveau tiers est créé, catégorisé automatiquement et associé à un canal d'origine (extrafield </span>`<span class="editor-theme-code">origine</span>`<span style="white-space: pre-wrap;"> renseigné depuis le dictionnaire </span>`<span class="editor-theme-code">c_input_reason</span>`). La même logique existe pour les contacts, utile notamment pour les inscriptions à la newsletter qui ne nécessitent pas la création d'une société.

##### **Ouverture d'un ticket**

L'adapter ticket ouvre un ticket Dolibarr rattaché au tiers résolu. Le sujet et le message sont construits soit à partir des champs du formulaire, soit à partir de gabarits permettant d'injecter dynamiquement le nom du visiteur, sa demande, l'adresse IP d'origine ou tout autre élément du contexte. Catégorie et sévérité sont déterminées par les codes du dictionnaire Dolibarr (`<span class="editor-theme-code">llx_c_ticket_category</span>`<span style="white-space: pre-wrap;">, </span>`<span class="editor-theme-code">llx_c_ticket_severity</span>`).

##### **Notification et accusé de réception**

<span style="white-space: pre-wrap;">Deux emails partent automatiquement à chaque soumission acceptée : une </span>**notification interne**<span style="white-space: pre-wrap;"> adressée à l'équipe pour traiter la demande, et un </span>**accusé de réception**<span style="white-space: pre-wrap;"> destiné au visiteur pour le rassurer. Les deux sont indépendants — il est possible d'envoyer uniquement la notification interne, uniquement l'accusé de réception, ou les deux. Tous les paramètres sont accessibles depuis l'éditeur Studio, onglet </span>**Pipeline**<span style="white-space: pre-wrap;">, section </span>**Notifications email**, sans avoir à manipuler le JSON brut.

###### **Les champs disponibles dans le wizard**

Chaque champ porte une tooltip d'aide affichée en gris sous l'input. Le tableau ci-dessous récapitule leur rôle.

<table id="bkmrk-champeffetemail-dest" style="width: 100%; border-collapse: collapse; margin: 1rem 0px; font-size: 0.93em;"><colgroup><col></col><col></col></colgroup><tbody><tr style="background: rgb(25, 5, 45); color: rgb(254, 252, 232);"><th class="align-left" style="padding: 0.5rem; text-align: left; border: 1px solid rgb(25, 5, 45);">Champ

</th><th class="align-left" style="padding: 0.5rem; text-align: left; border: 1px solid rgb(25, 5, 45);">Effet

</th></tr><tr><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">**Email destinataire admin**

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">Adresse(s) qui reçoivent l'alerte interne. Plusieurs destinataires séparés par une virgule. Laisser vide pour désactiver la notification interne.

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">**Modèle du sujet admin**

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);"><span style="white-space: pre-wrap;">Objet du mail interne. Accepte les variables </span>

`<span class="editor-theme-code">{{payload.X}}</span>`

<span style="white-space: pre-wrap;">, </span>

`<span class="editor-theme-code">{{form_name}}</span>`

<span style="white-space: pre-wrap;">, </span>

`<span class="editor-theme-code">{{submission_id}}</span>`

.

</td></tr><tr><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">**Corps de la notification admin**

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">Corps du mail interne. Laisser vide pour générer automatiquement un récapitulatif de tous les champs saisis. Permet de mettre en forme une notification riche (tableau, branding, lien vers la fiche soumission).

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">**Le corps admin est du HTML**

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">Interrupteur (toggle). Si activé, le corps est interprété comme du HTML ; sinon il part en texte brut et les balises apparaissent telles quelles.

</td></tr><tr><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">**Champ payload utilisé comme Reply-To**

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);"><span style="white-space: pre-wrap;">Nom du champ contenant l'email du visiteur (défaut : </span>

`<span class="editor-theme-code">email</span>`

<span style="white-space: pre-wrap;">). Un clic sur </span>

**Répondre**

<span style="white-space: pre-wrap;"> dans la messagerie répondra directement au visiteur, pas à l'expéditeur technique.</span>

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">**Activer l'accusé de réception**

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">Interrupteur. Si activé, le visiteur reçoit un mail de confirmation à l'adresse qu'il a saisie.

</td></tr><tr><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">**Champ payload de l'adresse visiteur**

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);"><span style="white-space: pre-wrap;">Nom du champ du formulaire contenant l'adresse du visiteur. Par défaut </span>

`<span class="editor-theme-code">email</span>`

.

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">**Sujet de l'accusé de réception**

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);"><span style="white-space: pre-wrap;">Objet du mail reçu par le visiteur. </span>

**Ignoré**

<span style="white-space: pre-wrap;"> si un modèle est sélectionné ci-dessous.</span>

</td></tr><tr><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">**Corps de l'accusé de réception**

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);"><span style="white-space: pre-wrap;">Corps du mail reçu par le visiteur. </span>

**Ignoré**

<span style="white-space: pre-wrap;"> si un modèle est sélectionné. Laisser vide pour un texte générique de remerciement.</span>

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">**Le corps de l'accusé est du HTML**

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">Interrupteur (toggle) équivalent côté visiteur.

</td></tr><tr><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">**Modèle d'accusé de réception**

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);"><span style="white-space: pre-wrap;">Liste déroulante des modèles d'email Dolibarr de type </span>

`<span class="editor-theme-code">infrasstudio_form</span>`

<span style="white-space: pre-wrap;">. Quand un modèle est sélectionné, il prend la main sur les champs </span>

**Sujet**

<span style="white-space: pre-wrap;"> et </span>

**Corps**

<span style="white-space: pre-wrap;"> ci-dessus. Avantage : le texte est centralisé dans </span>

**Configuration → Emails → Modèles d'e-mails**

, partagé entre tous les formulaires qui pointent dessus.

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">**Adresse expéditeur (From) / Nom expéditeur (From)**

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);"><span style="white-space: pre-wrap;">Surcharge per-formulaire de l'adresse et du nom apparaissant comme expéditeur des deux mails. Vides : utilise </span>

`<span class="editor-theme-code">MAIN_MAIL_EMAIL_FROM</span>`

<span style="white-space: pre-wrap;"> et le nom de la société configurée dans Dolibarr.</span>

</td></tr></tbody></table>

###### **Variables disponibles dans les templates**

Les sujets et corps de mail (admin et accusé) acceptent une substitution simple. Aucune logique conditionnelle : les marqueurs inconnus sont laissés en clair, ce qui facilite le debug.

<table id="bkmrk-variablevaleur%7B%7Bpayl" style="width: 100%; border-collapse: collapse; margin: 1rem 0px; font-size: 0.93em;"><colgroup><col></col><col></col></colgroup><tbody><tr style="background: rgb(25, 5, 45); color: rgb(254, 252, 232);"><th class="align-left" style="padding: 0.5rem; text-align: left; border: 1px solid rgb(25, 5, 45);">Variable

</th><th class="align-left" style="padding: 0.5rem; text-align: left; border: 1px solid rgb(25, 5, 45);">Valeur

</th></tr><tr><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">`<span class="editor-theme-code">{{payload.X}}</span>`

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);"><span style="white-space: pre-wrap;">Valeur du champ </span>

`<span class="editor-theme-code">X</span>`

<span style="white-space: pre-wrap;"> saisi par le visiteur. Raccourci : </span>

`<span class="editor-theme-code">{{X}}</span>`

.

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">`<span class="editor-theme-code">{{form_name}}</span>`

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">Identifiant technique du formulaire actif.

</td></tr><tr><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">`<span class="editor-theme-code">{{submission_id}}</span>`

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">Numéro de la soumission, utile pour bâtir un lien admin direct.

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">`<span class="editor-theme-code">{{ip}}</span>`

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">IP du visiteur.

</td></tr><tr><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">`<span class="editor-theme-code">{{mysoc.name}}</span>`

<span style="white-space: pre-wrap;">, </span>

`<span class="editor-theme-code">{{mysoc.email}}</span>`

<span style="white-space: pre-wrap;">, </span>

`<span class="editor-theme-code">{{mysoc.phone}}</span>`

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">Coordonnées de la société configurée dans Dolibarr.

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">`<span class="editor-theme-code">{{config.X}}</span>`

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">Clé de premier niveau du JSON config courant.

</td></tr></tbody></table>

###### **Exemple — notification interne mise en forme**

Sujet :

```
[{{form_name}}] Nouvelle demande de {{payload.name}} ({{payload.company}})
```

<span style="white-space: pre-wrap;">Corps HTML (interrupteur </span>**Le corps admin est du HTML**<span style="white-space: pre-wrap;"> activé) :</span>

```
<div style="font-family:Arial,sans-serif;max-width:600px;color:#333">
  <div style="background:#0f172a;color:#fff;padding:16px 20px;border-radius:6px 6px 0 0">
    <h2 style="margin:0;font-size:18px">Nouvelle demande de contact</h2>
    <div style="font-size:12px;opacity:.8;margin-top:4px">
      Formulaire : {{form_name}} · Soumission #{{submission_id}}
    </div>
  </div>
  <div style="border:1px solid #e2e8f0;border-top:0;padding:20px;border-radius:0 0 6px 6px">
    <table style="width:100%;border-collapse:collapse;font-size:14px">
      <tr><td style="color:#64748b;width:140px">Nom</td><td><strong>{{payload.name}}</strong></td></tr>
      <tr><td style="color:#64748b">Société</td><td>{{payload.company}}</td></tr>
      <tr><td style="color:#64748b">Email</td><td><a href="mailto:{{payload.email}}">{{payload.email}}</a></td></tr>
    </table>
    <p style="color:#64748b;font-size:13px;margin:20px 0 6px">Message</p>
    <div style="background:#f8fafc;border-left:3px solid #6366f1;padding:12px 14px;white-space:pre-wrap">{{payload.message}}</div>
    <div style="margin-top:24px;padding-top:14px;border-top:1px solid #e2e8f0;font-size:12px;color:#94a3b8">
      IP : {{ip}} · Reçu via {{mysoc.name}}
    </div>
  </div>
</div>
```

Côté boîte mail, l'équipe reçoit un message présenté en tableau avec une bande de couleur, le nom et l'email cliquables, le contenu du message dans un encadré, et un pied technique discret avec l'IP.

##### **Cohabitation avec le module Gestionnaire de tickets**

<span style="white-space: pre-wrap;">Quand l'adapter ticket d'InfraSStudio crée un ticket Dolibarr à la suite d'une soumission, le module Gestionnaire de tickets enverrait normalement son propre mail natif </span>`<span class="editor-theme-code">TICKET_CREATE</span>`<span style="white-space: pre-wrap;"> au tiers et sa propre alerte interne. Pour éviter les doublons, InfraSStudio positionne deux drapeaux dans le contexte de création :</span>

- `<span class="editor-theme-code">disableticketemail = 1</span>`<span style="white-space: pre-wrap;"> — supprime le mail natif Dolibarr au tiers (l'accusé de réception InfraSStudio prend le relais avec un message bien plus soigné) ;</span>
- `<span class="editor-theme-code">notify_tiers_at_create = 0</span>`<span style="white-space: pre-wrap;"> — désactive aussi la notification native du tiers (configurable via la clé </span>`<span class="editor-theme-code">ticket.notify_tiers_at_create</span>`<span style="white-space: pre-wrap;"> du JSON si besoin).</span>

La répartition est donc claire :

<table id="bkmrk-modulep%C3%A9rim%C3%A8treinfra" style="width: 100%; border-collapse: collapse; margin: 1rem 0px; font-size: 0.93em;"><colgroup><col></col><col></col></colgroup><tbody><tr style="background: rgb(25, 5, 45); color: rgb(254, 252, 232);"><th class="align-left" style="padding: 0.5rem; text-align: left; border: 1px solid rgb(25, 5, 45);">Module

</th><th class="align-left" style="padding: 0.5rem; text-align: left; border: 1px solid rgb(25, 5, 45);">Périmètre

</th></tr><tr><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">**InfraSStudio**

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);"><span style="white-space: pre-wrap;">Accusé de réception au visiteur + notification interne </span>

**à la création initiale**

<span style="white-space: pre-wrap;"> du ticket par soumission web.</span>

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">**Gestionnaire de tickets Dolibarr**

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);"><span style="white-space: pre-wrap;">Tout l'échange ultérieur sur le ticket : réponses manuelles d'un agent, mises à jour de statut, fermeture. Utilise ses propres adresses </span>

**From**

<span style="white-space: pre-wrap;">, </span>

**Reply-To**

<span style="white-space: pre-wrap;"> et </span>

**destinataire interne**

<span style="white-space: pre-wrap;"> configurées dans la page d'admin du module.</span>

</td></tr></tbody></table>

<span style="white-space: pre-wrap;">Concrètement : une soumission de formulaire web déclenche exactement deux mails (accusé visiteur + notification équipe, gérés par InfraSStudio), jamais quatre. Quand un agent répond ensuite au ticket depuis Dolibarr, c'est le module natif qui reprend la main — les emails configurés dans </span>**Accueil → Configuration → Modules → Gestionnaire de tickets**<span style="white-space: pre-wrap;"> s'appliquent à ce moment-là.</span>

##### **Rappel automatique en agenda**

Pour les formulaires à fort enjeu commercial (typiquement une demande de démonstration), un événement de rappel peut être créé dans l'agenda. Le délai est configurable, les week-ends peuvent être évités automatiquement, et l'événement est lié au ticket et au tiers pour garantir la traçabilité.

### <span style="color: rgb(35, 111, 161);">Intégrer le formulaire dans un site</span>

Une fois la configuration en place, il reste à exposer le formulaire dans le site. Trois approches sont possibles selon le degré de personnalisation souhaité.

##### **Le shortcode `<strong class="editor-theme-bold editor-theme-code">{{form:name=...}}</strong>`**

La voie la plus simple, surtout pour un rédacteur. Dans n'importe quelle page du site (slot richtext ou directement dans le tpl) :

```
{{form:name=contact-site}}
```

`<span class="editor-theme-code">{{form:name=…}}</span>`<span style="white-space: pre-wrap;"> est un </span>**shortcode**<span style="white-space: pre-wrap;"> résolu au rendu par le moteur de contenu d'InfraSStudio (</span>`<span class="editor-theme-code">StudioContentEngine::applyToPage</span>`<span style="white-space: pre-wrap;">, via le registre de shortcodes — provider </span>`<span class="editor-theme-code">shortcodes/form.shortcode.php</span>`<span style="white-space: pre-wrap;">), qui appelle </span>`<span class="editor-theme-code">infrasstudio_render_public_form</span>`<span style="white-space: pre-wrap;"> pour produire le HTML complet du formulaire — anti-spam et style scopé inclus. Aucune ligne de PHP à toucher côté site. </span>**(Il n'existe pas de hook** `<span class="editor-theme-code">completeHtmlOutput</span>` **; les hooks** `<span class="editor-theme-code">websitepage</span>` **/** `<span class="editor-theme-code">websitenav</span>` **sont déclarés mais ne servent pas à ce rendu.)**

##### **L'helper de rendu unifié**

Pour passer des options dynamiques (référence produit sur une landing, libellés sur mesure, etc.), appeler directement le helper depuis un tpl.php :

```
dol_include_once('/infrasstudio/core/lib/infrasstudio.lib.php');
infrasstudio_render_public_form('contact-site', array(
    'fk_website' => $website->id,
    'fk_page'    => $object->id,
    'extra'      => array('productRef' => 'monproduit'),
));
```

##### **Les starter design templates**

<span style="white-space: pre-wrap;">Quatre templates « clé en main » sont livrés dans </span>`<span class="editor-theme-code">templates/forms/_starter-*.tpl.php</span>`<span style="white-space: pre-wrap;">. Chacun est auto-suffisant (CSS inline scopé, rendu dynamique des champs déclarés dans </span>`<span class="editor-theme-code">config.fields</span>`) — idéal pour démarrer rapidement sur un nouveau site, avant d'éventuellement basculer sur du HTML maison.

<table id="bkmrk-starterstyle-_starte" style="width: 100%; border-collapse: collapse; margin: 1rem 0px; font-size: 0.92em;"><colgroup><col></col><col></col></colgroup><tbody><tr style="background: rgb(25, 5, 45); color: rgb(254, 252, 232);"><th class="align-left" style="padding: 0.5rem; text-align: left; border: 1px solid rgb(25, 5, 45);">Starter

</th><th class="align-left" style="padding: 0.5rem; text-align: left; border: 1px solid rgb(25, 5, 45);">Style

</th></tr><tr><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">`<span class="editor-theme-code">_starter-minimal.tpl.php</span>`

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">Sobre, labels au-dessus, focus indigo.

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">`<span class="editor-theme-code">_starter-card.tpl.php</span>`

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">Carte avec ombre douce et bouton en gradient.

</td></tr><tr><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">`<span class="editor-theme-code">_starter-inline.tpl.php</span>`

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">Inputs alignés horizontalement, compact, idéal newsletter/footer.

</td></tr><tr style="background: rgb(250, 245, 255);"><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">`<span class="editor-theme-code">_starter-modern.tpl.php</span>`

</td><td style="padding: 0.5rem; border: 1px solid rgb(229, 231, 235);">Coins arrondis, fond teinté, gradient bouton, labels uppercase.

</td></tr></tbody></table>

<span style="white-space: pre-wrap;">Le starter choisi dans la modale « + Nouveau formulaire » est automatiquement posé comme </span>`<span class="editor-theme-code">template_override</span>`<span style="white-space: pre-wrap;"> dans la configuration. Il peut être changé à tout moment via l'éditeur JSON avancé.</span>

##### **Conserver un design existant — préfixe `<strong class="editor-theme-bold editor-theme-code">site:</strong>`**

<span style="white-space: pre-wrap;">Pour intégrer le formulaire dans une charte graphique déjà existante (classes CSS du site, structure HTML spécifique), le mécanisme officiel consiste à livrer son propre template depuis le </span>**dossier source du site Dolibarr Website**<span style="white-space: pre-wrap;"> et à le référencer via le préfixe </span>`<span class="editor-theme-code">site:</span>`<span style="white-space: pre-wrap;"> dans la configuration :</span>

1. <span style="white-space: pre-wrap;">Créer un dossier </span>`<span class="editor-theme-code">forms/</span>`<span style="white-space: pre-wrap;"> dans le source du site, soit </span>`<span class="editor-theme-code">DOL_DATA_ROOT/<entity>/website/<ref>/forms/</span>`.
2. <span style="white-space: pre-wrap;">Y déposer un fichier </span>`<span class="editor-theme-code">contact.tpl.php</span>`<span style="white-space: pre-wrap;"> qui réutilise les classes CSS du site et appelle </span>`<span class="editor-theme-code">infrasstudio_render_form_fields()</span>`<span style="white-space: pre-wrap;"> pour générer ses champs (voir la section </span>**Le rendu des champs — helper unique**<span style="white-space: pre-wrap;"> ci-dessous).</span>
3. <span style="white-space: pre-wrap;">Dans le descripteur du formulaire, poser : </span>`<span class="editor-theme-code">"template_override": "site:contact.tpl.php"</span>`.

<span style="white-space: pre-wrap;">Au rendu, le moteur résout vers </span>`<span class="editor-theme-code">DOL_DATA_ROOT/<entity>/website/<ref>/forms/contact.tpl.php</span>`<span style="white-space: pre-wrap;"> en utilisant le </span>`<span class="editor-theme-code">fk_website</span>`<span style="white-space: pre-wrap;"> du contexte. Cette approche permet à chaque site de livrer ses propres templates sans déposer le moindre fichier dans le module générique — qui reste 100% indépendant du métier de chaque client.</span>

<span style="white-space: pre-wrap;">Alternative : si le design impose seulement quelques champs cachés à injecter dans un &lt;form&gt; déjà existant, le helper </span>`<span class="editor-theme-code">infrasstudio_render_form_security($formName, $fkWebsite, $fkPage, $_SERVER['PHP_SELF'])</span>`<span style="white-space: pre-wrap;"> émet d'un seul tenant le </span>`<span class="editor-theme-code">form_name</span>`, le timestamp anti-bot, le honeypot et le captcha conditionnel.

##### **Le rendu des champs — helper unique**

<span style="white-space: pre-wrap;">Quel que soit le template (générique, starter ou </span>`<span class="editor-theme-code">site:</span>`<span style="white-space: pre-wrap;">), le rendu des champs est centralisé dans le helper </span>`<span class="editor-theme-code">infrasstudio_render_form_fields($cfg, $opts)</span>`<span style="white-space: pre-wrap;"> : ordre de déclaration des champs, mapping type → input HTML, hint </span>`<span class="editor-theme-code">autocomplete</span>`, placeholder, et surtout l'**astérisque automatique des champs obligatoires**<span style="white-space: pre-wrap;">. </span>**Un template de formulaire — y compris un template `<strong class="editor-theme-bold editor-theme-code">site:</strong>` — doit appeler ce helper**<span style="white-space: pre-wrap;"> plutôt que coder ses </span>`<span class="editor-theme-code"><input></span>`<span style="white-space: pre-wrap;"> en dur : sinon l'ajout, le réordonnancement ou le passage en obligatoire d'un champ depuis l'éditeur ne se reflète pas côté site.</span>

<span style="white-space: pre-wrap;">Le markup reste entièrement paramétrable pour conserver la charte du site. Options principales : </span>`<span class="editor-theme-code">row_class</span>`<span style="white-space: pre-wrap;">, </span>`<span class="editor-theme-code">label_class</span>`<span style="white-space: pre-wrap;">, </span>`<span class="editor-theme-code">input_class</span>`<span style="white-space: pre-wrap;">, </span>`<span class="editor-theme-code">textarea_class</span>`<span style="white-space: pre-wrap;">, </span>`<span class="editor-theme-code">req_html</span>`<span style="white-space: pre-wrap;"> (markup de l'astérisque), </span>`<span class="editor-theme-code">id_prefix</span>`<span style="white-space: pre-wrap;">, </span>`<span class="editor-theme-code">label_wrap</span>`<span style="white-space: pre-wrap;"> (libellé englobant l'input), </span>`<span class="editor-theme-code">show_label</span>`<span style="white-space: pre-wrap;"> (libellés masqués pour les formulaires compacts), </span>`<span class="editor-theme-code">exclude</span>`<span style="white-space: pre-wrap;"> (champs cachés gérés à part, ex. </span>`<span class="editor-theme-code">product_ref</span>`<span style="white-space: pre-wrap;">), </span>`<span class="editor-theme-code">labels</span>`<span style="white-space: pre-wrap;"> (overrides i18n </span>`<span class="editor-theme-code">field_<clé></span>`<span style="white-space: pre-wrap;"> / </span>`<span class="editor-theme-code">placeholder_<clé></span>`).

<span style="white-space: pre-wrap;">Exemple dans un template </span>`<span class="editor-theme-code">site:</span>`<span style="white-space: pre-wrap;"> réutilisant les classes CSS du site :</span>

```
print infrasstudio_render_form_fields($cfg, array(
    'row_class'   => 'form-row',
    'label_class' => 'form-label',
    'input_class' => 'form-input',
    'req_html'    => ' <span class="req">*</span>',
    'id_prefix'   => '',
));
```

### <span style="color: rgb(35, 111, 161);">Suivre et auditer les soumissions</span>

<span style="white-space: pre-wrap;">Chaque soumission acceptée est persistée dans </span>`<span class="editor-theme-code">llx_infrasstudio_form_submission</span>`<span style="white-space: pre-wrap;"> avec son contenu sanitisé, l'adresse IP d'origine, l'agent utilisateur, la page de provenance et la trace du consentement RGPD. Le viewer d'administration (</span>**Outils → InfraS → Soumissions**) permet de filtrer par formulaire, statut ou plage de dates, d'ouvrir le détail complet d'une soumission et d'accéder en un clic au tiers, au contact, au ticket et à l'événement d'agenda qui en ont découlé. Cette traçabilité complète est précieuse à la fois pour le suivi commercial et pour répondre aux demandes RGPD des visiteurs.

### <span style="color: rgb(35, 111, 161);">Récapitulatif</span>

<span style="white-space: pre-wrap;">Le moteur de formulaires d'InfraSStudio transforme un simple formulaire web en véritable point d'entrée du CRM. Configurable sans code, sécurisé par défaut et entièrement intégré à l'écosystème Dolibarr, il évite la fragmentation des outils tout en gardant la souplesse nécessaire à chaque projet. Pour aller plus loin, voir le Chapitre 28 (constantes), le Chapitre 31 (modèle SQL des trois tables </span>`<span class="editor-theme-code">llx_infrasstudio_form_*</span>`) et l'Annexe B (FAQ) pour les questions opérationnelles courantes.