# CHAPITRE 22 — Créer ses propres gabarits de page

Lorsque votre client clique sur « + Nouvelle page » dans le Studio, il choisit un gabarit de départ. Ce chapitre vous explique comment créer vos propres gabarits adaptés à la charte de votre site.

### <span style="color: rgb(35, 111, 161);">À quoi sert un gabarit</span>

Un gabarit est un squelette de page qui comporte :

- Du HTML structuré (sections, classes CSS, balises sémantiques).
- Des slots pré-déclarés pour les zones éditables.
- Des valeurs par défaut, pour disposer d'une page complète dès la création.
- Des métadonnées (titre par défaut, slug, type de conteneur).

Lorsqu'un client crée une page depuis un gabarit, le module :

1. <span style="white-space: pre-wrap;">Crée une entrée dans la table </span>`<span class="editor-theme-code">llx_website_page</span>`.
2. <span style="white-space: pre-wrap;">Génère un fichier </span>`<span class="editor-theme-code">page<N>.tpl.php</span>`<span style="white-space: pre-wrap;"> à partir du squelette.</span>
3. <span style="white-space: pre-wrap;">Crée le wrapper Apache </span>`<span class="editor-theme-code"><slug>.php</span>`.
4. Lance un rescan des slots pour les détecter immédiatement.

### <span style="color: rgb(35, 111, 161);">Structure d'un gabarit</span>

<span style="white-space: pre-wrap;">Un gabarit est un dossier dans </span>`<span class="editor-theme-code">htdocs/custom/infrasstudio/templates/</span>`<span style="white-space: pre-wrap;"> :</span>

```
templates/mon-gabarit/
├── meta.php             # Métadonnées du gabarit
└── skeleton.tpl.php     # Le squelette HTML avec slots
```

### <span style="color: rgb(35, 111, 161);">Le fichier meta.php</span>

Il retourne un tableau de configuration :

```
<?php
return array(
    'code'           => 'mon-gabarit',                    // identifiant unique
    'label'          => 'Mon Gabarit',                    // affiché dans l'assistant
    'category'       => 'page',                           // page | landing | blog
    'description'    => "Description courte affichée sous le titre.",
    'icon'           => 'fa-file-lines',                  // icône FontAwesome
    'type_container' => 'page',                           // type Dolibarr Website
    'default_slug'   => 'nouvelle-page',                  // slug suggéré
);
```

<table id="bkmrk-champdescriptioncode" 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);">Champ

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

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

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Identifiant unique. Doit correspondre au nom du dossier.

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

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Texte affiché dans la grille de sélection de l'assistant.

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

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Permet le regroupement visuel (page, landing, blog).

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

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Classe FontAwesome de l'icône de la tuile.

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

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

`<span class="editor-theme-code">llx_website_page.type_container</span>`

<span style="white-space: pre-wrap;">. Valeurs standards : </span>

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

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

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

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

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

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

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

.

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

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Slug suggéré dans le formulaire. Le client peut le modifier.

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

### <span style="color: rgb(35, 111, 161);">Le fichier skeleton.tpl.php</span>

Il s'agit du squelette HTML, identique à un fichier tpl.php standard, à la différence qu'il contient des marqueurs qui seront remplacés au moment de la création.

##### **Marqueurs disponibles**

<table id="bkmrk-marqueurremplac%C3%A9-par" 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);">Marqueur

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

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

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">L'identifiant Dolibarr de la nouvelle page (par exemple 42).

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

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);"><span style="white-space: pre-wrap;">Le slug URL final (par exemple </span>

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

).

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

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Le code ISO2 de la langue principale (

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

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

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

).

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

### <span style="color: rgb(35, 111, 161);">Exemple complet — gabarit page-libre</span>

##### **meta.php**

```
<?php
return array(
    'code'           => 'page-libre',
    'label'          => 'Page libre',
    'category'       => 'page',
    'description'    => 'Une page simple avec un titre et un grand champ de texte riche.',
    'icon'           => 'fa-file-lines',
    'type_container' => 'page',
    'default_slug'   => 'nouvelle-page',
);
```

##### **skeleton.tpl.php**

```
<?php // BEGIN PHP
$websitekey = basename(__DIR__);
if (! defined('USEDOLIBARRSERVER') && ! defined('USEDOLIBARREDITOR')) {
    require_once __DIR__ . '/master.inc.php';
}
require_once DOL_DOCUMENT_ROOT . '/core/lib/website.lib.php';
require_once DOL_DOCUMENT_ROOT . '/core/website.inc.php';
ob_start();
try {
// END PHP ?>
<html lang="@@ISO2@@">
<head>
    <title>{{slot:page_title|type=text|default=Nouvelle page|label=Titre SEO|group=seo}}</title>
    <meta name="description" content="{{slot:page_meta_description|type=text|default=|label=Meta description|group=seo}}" />
    <link rel="canonical" href="<?php echo $website->virtualhost; ?>/@@PAGEURL@@.php" />
</head>
<body>
    <?php includeContainer('header'); ?>
    <main class="container">
        <h1>{{slot:page_h1|type=text|default=Titre principal|label=H1|group=hero}}</h1>
        <div class="content">
            {{slot:page_body|type=richtext|default=<p>Contenu de la page.</p>|label=Contenu}}
        </div>
    </main>
    <?php includeContainer('footer'); ?>
</body>
</html>
<?php // BEGIN PHP
} catch (Exception $e) { print $e->getMessage(); }
include dol_buildpath('/infrasstudio/core/tpl/website_output.tpl.php', 0);
// END PHP ?>
```

**Le bloc final —**<span style="white-space: pre-wrap;"> N'oubliez pas la ligne </span>`<span class="editor-theme-code">include dol_buildpath('/infrasstudio/core/tpl/website_output.tpl.php', 0);</span>`. C'est elle qui déclenche la résolution des slots et shortcodes au moment du rendu.

### <span style="color: rgb(35, 111, 161);">Localiser vos gabarits hors du module</span>

Si vous souhaitez livrer des gabarits avec votre projet client sans modifier le module, définissez la constante :

```
// htdocs/conf/conf.php ou via dolibarr_set_const
$conf->global->INFRASSTUDIO_TEMPLATE_EXTRA_DIR = '/var/www/monsite/templates';
```

<span style="white-space: pre-wrap;">Le module scanne ce répertoire en complément de </span>`<span class="editor-theme-code">htdocs/custom/infrasstudio/templates/</span>`.

### <span style="color: rgb(35, 111, 161);">Gabarits livrés par défaut</span>

<table id="bkmrk-codedescriptionpage-" 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);">Code

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

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

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Page libre avec titre et un grand champ texte riche. Pour les pages ponctuelles.

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

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Article de blog générique avec hero, introduction, corps et appel à l'action.

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

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Article de blog au design moderne (hero CSS, accroche en italique, image secondaire, articles liés). Adaptable à votre charte.

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

</td><td style="padding: 0.5rem 1rem; border: 1px solid rgb(229, 231, 235);">Page de destination produit complète (environ 70 slots). Hero, problème, solution, fonctionnalités, contact, FAQ.

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

<p class="callout info">**Conseil —**<span style="white-space: pre-wrap;"> Inspirez-vous de </span>`<span class="editor-theme-code">example-landing</span>`<span style="white-space: pre-wrap;"> pour comprendre comment structurer un gabarit complexe avec environ 70 slots organisés en sections.</span></p>

### <span style="color: rgb(35, 111, 161);">Bonnes pratiques pour vos gabarits</span>

- <span style="white-space: pre-wrap;">Préfixez tous les slots du gabarit par un identifiant commun (par exemple </span>`<span class="editor-theme-code">landing_</span>`) pour éviter les collisions entre gabarits.
- <span style="white-space: pre-wrap;">Regroupez les slots avec </span>`<span class="editor-theme-code">group=</span>`<span style="white-space: pre-wrap;"> par section logique (hero, fonctionnalités, contact, etc.).</span>
- Donnez des valeurs par défaut représentatives. Le rédacteur dispose ainsi d'un exemple à modifier plutôt que d'une page vide intimidante.
- Incluez les slots SEO (`<span class="editor-theme-code">page_title</span>`<span style="white-space: pre-wrap;">, </span>`<span class="editor-theme-code">page_meta_description</span>`) dans tout gabarit de type page.
- Incluez les balises Open Graph dans l'en-tête HTML pour le partage social.
- Incluez le helper hreflang si le site est multilingue.
- Testez le gabarit en créant une page réelle depuis l'assistant et vérifiez le rendu public.

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

**Vous savez désormais :**

- Comprendre l'utilité d'un gabarit (squelette, slots, valeurs par défaut).
- <span style="white-space: pre-wrap;">Créer un dossier </span>`<span class="editor-theme-code">templates//</span>`<span style="white-space: pre-wrap;"> avec </span>`<span class="editor-theme-code">meta.php</span>`<span style="white-space: pre-wrap;"> et </span>`<span class="editor-theme-code">skeleton.tpl.php</span>`.
- Renseigner les métadonnées (code, label, category, icon, type\_container, default\_slug).
- <span style="white-space: pre-wrap;">Utiliser les marqueurs </span>`<span class="editor-theme-code">@@PAGEID@@</span>`<span style="white-space: pre-wrap;">, </span>`<span class="editor-theme-code">@@PAGEURL@@</span>`<span style="white-space: pre-wrap;"> et </span>`<span class="editor-theme-code">@@ISO2@@</span>`.
- <span style="white-space: pre-wrap;">Localiser vos gabarits en dehors du module via </span>`<span class="editor-theme-code">INFRASSTUDIO_TEMPLATE_EXTRA_DIR</span>`.
- Suivre les bonnes pratiques (préfixe, regroupement, valeurs par défaut, SEO, multilingue).

Le dernier chapitre de la Partie IV détaille le catalogue produit dynamique en profondeur.

</body></html>