Contenu éditable (JSON)

Système de gestion de contenu qui permet aux clients de modifier les textes, liens, images et listes sans toucher au HTML, en éditant un simple fichier JSON.

JSON est un format de fichier texte simple (comme un fichier .txt structuré). Il ressemble à une liste de « clé : valeur ». Votre client modifie les valeurs dans ce fichier, et le site se met à jour automatiquement — sans toucher au code HTML.

Principe

  1. Le HTML contient le texte par défaut (visible par les moteurs de recherche, fonctionne sans JS)
  2. Un fichier JSON contient les valeurs modifiables
  3. Au premier déploiement, le build génère automatiquement le JSON avec les textes par défaut
  4. Le client modifie le JSON sur GitHub → le site se met à jour

Le dev n'a rien d'autre à faire. Pas de JSON à écrire, pas de dossier à créer, pas de clé à inventer.

Mise en place

1. Écrire du HTML normal

Le build (build-content.py) ajoute automatiquement data-editable sur les balises <main> sans classe de chaque page. Vous n'avez rien à faire — tout le contenu dans <main> est éditable par défaut. Si votre <main> porte une classe (ex : <main class="docs-content">), il est ignoré par le build.

Pour exclure un élément spécifique, ajoutez data-content-skip. Pour exclure une page entière du système de contenu, ajoutez data-content-skip-page sur <main> :

<main>
  <h1>Bienvenue chez nous</h1>
  <p>Votre partenaire digital depuis 2015.</p>
  <a href="/contact">Nous contacter</a>
  <img src="/assets/images/hero.jpg" alt="Photo hero">
  <ul>
    <li>Design</li>
    <li>Développement</li>
  </ul>
  <p data-content-skip>Ce texte ne sera PAS éditable.</p>
</main>

2. Déployer

./deploy.sh prod

Au premier déploiement, le build ajoute automatiquement data-content sur chaque élément, crée le dossier content/ et génère le JSON.

Convention : pages/entreprise/equipe.htmlcontent/entreprise/equipe.json

3. C'est fait

Le JSON généré ressemble à ça :

{
  "bienvenue-chez-nous": "Bienvenue chez nous",
  "votre-partenaire-digital-depuis-2015": "Votre partenaire digital depuis 2015.",
  "nous-contacter": { "text": "Nous contacter", "href": "/contact" },
  "photo-hero": { "src": "/assets/images/hero.jpg", "alt": "Photo hero" },
  "design": "Design",
  "developpement": "Développement",
  "seo": "SEO"
}

Le client n'a plus qu'à modifier les valeurs entre guillemets sur GitHub.

Priorité : le JSON prime toujours sur le HTML. Le client a le dernier mot.

Fusion intelligente : si le dev ajoute un élément dans le HTML, la clé est ajoutée au JSON. Si le dev supprime un élément, la clé est retirée. Les valeurs du client ne sont jamais écrasées.

Mode explicite (optionnel)

Pour contrôler les clés vous-même, ajoutez data-content="ma-clé" directement :

<h1 data-content="hero_titre">Bienvenue chez nous</h1>

Types de contenu

TypeValeur JSONÉlément HTMLComportement
Texte"string"Tout élémentRemplace le contenu avec formatage inline
Lien{ "text": "...", "href": "..." }<a>Met à jour le texte ET le href
Image"/chemin/image.jpg"<img>Met à jour le src
Image objet{ "src": "...", "alt": "..." }<img>Met à jour src et alt
Image fond"/chemin/bg.jpg"Tout + data-content-bgMet à jour le background-image
Liste["item1", "item2"]<ul> ou <ol>Génère les <li>

Formatage inline

SyntaxeRendu
**gras**gras
*italique*italique
[texte](url)lien cliquable
\nsaut de ligne

Exemple :

{
  "description": "Nous sommes **experts** en *design web*.\nContactez-nous [ici](/contact)."
}

Guide de formatage pour le client

Ce que le client tape dans le JSONCe qui s'affiche sur le site
"Notre **expertise** à votre service"Notre expertise à votre service
"Des sites *modernes* et *performants*"Des sites modernes et performants
"Contactez-nous par [email](mailto:contact@monsite.fr)"Contactez‑nous par email
"Ligne 1\nLigne 2"Ligne 1
Ligne 2
"Prix : 50 €"Prix : 50 €

Règles importantes pour le client :

  • Modifier uniquement le texte entre les guillemets "..."
  • Ne jamais toucher aux {, }, : ni aux noms avant les :
  • Ne jamais supprimer de lignes entières
  • Si vous faites une erreur, cliquez History (en haut du fichier sur GitHub) pour revenir à la version précédente

Clés imbriquées

Notation pointée pour les objets imbriqués :

{
  "hero": {
    "titre": "Bienvenue",
    "texte": "Notre entreprise..."
  },
  "contact": {
    "tel": "01 23 45 67 89",
    "email": "contact@example.com"
  }
}
<h1 data-content="hero.titre">Bienvenue</h1>
<p data-content="hero.texte">Notre entreprise...</p>
<span data-content="contact.tel">01 23 45 67 89</span>

Éléments responsive dupliqués

Si un même texte apparaît à plusieurs endroits (version mobile et desktop par exemple), utilisez le même data-content sur tous les éléments. Ils seront tous mis à jour :

<!-- Version desktop -->
<h1 class="desktop-only" data-content="hero_titre">Titre</h1>

<!-- Version mobile -->
<h2 class="mobile-only" data-content="hero_titre">Titre</h2>

Les deux éléments afficheront la même valeur du JSON.

Image de fond

Pour les éléments avec un background-image en CSS, ajoutez data-content-bg :

<section data-content="hero_bg" data-content-bg style="background-image: url(default.jpg)">
{
  "hero_bg": "/assets/images/nouveau-fond.jpg"
}

Compilation au déploiement

Le contenu JSON est compilé directement dans le HTML au moment du déploiement. Le script build-content.py (appelé automatiquement par deploy.sh) remplace les éléments data-content par les valeurs du JSON avant le rsync.

Ce script Python s'exécute automatiquement avant chaque mise en ligne. Il lit vos fichiers JSON et écrit le contenu directement dans vos pages HTML — pour que les moteurs de recherche (Google) voient le vrai texte, pas des emplacements vides.

  • Le code source HTML (Ctrl+U) contient le bon texte
  • Pas de flash de contenu par défaut
  • SEO parfait — les moteurs de recherche voient le contenu réel
  • Pas de JS requis en production
  • Le build est idempotent — rejouable sans risque

En développement local, content.js reste utile pour la preview en temps réel. Si la page ne contient aucun élément data-content, le script se termine silencieusement sans afficher d'erreur.

Gardes-fous et alertes

3 niveaux de protection pour éviter qu'une erreur JSON ne casse le site :

1. Bandeau d'erreur (front-end, rouge)

Si le JSON est introuvable ou contient une erreur de syntaxe : bandeau rouge fixe avec le type d'erreur, la position exacte, et le nom du fichier. Le HTML par défaut reste affiché.

2. Bandeau d'avertissement (front-end, jaune)

Si le JSON est valide mais contient des incohérences (clés manquantes, valeurs vides, types incompatibles) : bandeau jaune informatif. Le contenu est quand même appliqué.

3. Validation pré-déploiement (deploy.sh)

deploy.sh valide tous les fichiers JSON de manière récursive (content/**/*.json, pas seulement content/*.json) avant le déploiement. Si un fichier est invalide, le déploiement est bloqué avec la ligne et colonne de l'erreur.

✗ JSON invalide : content/accueil.json
  Ligne 12, colonne 5 : Expecting property name enclosed in double quotes
1 fichier(s) JSON invalide(s). Déploiement annulé.

API JavaScript

FonctionDescription
initContent(root)Charge le JSON et applique. Appelé automatiquement.
applyContent(data, root)Applique un objet directement (sans fetch).

Workflow client

Inviter le client sur GitHub (une seule fois)

Le client a besoin d'un compte GitHub gratuit (github.com → Sign up). Ensuite :

  1. Aller sur le repo GitHub du projet (ex : github.com/MonClient/monsite)
  2. Cliquer l'onglet Settings (en haut à droite)
  3. Dans le menu de gauche, cliquer Collaborators
  4. Cliquer le bouton vert Add people
  5. Taper l'email ou le pseudo GitHub du client
  6. Cliquer Send invitation
  7. Le client recevra un email d'invitation — il doit cliquer Accept invitation

Comment le client modifie le contenu

Une fois invité, le client peut modifier les textes du site directement depuis GitHub :

  1. Ouvrir le lien du repo que vous lui avez donné (ex : github.com/MonClient/monsite)
  2. Cliquer sur le dossier content/
  3. Cliquer sur le fichier à modifier (ex : accueil.json)
  4. Cliquer le crayon ✎️ (bouton en haut à droite du fichier, à côté de la poubelle)
  5. Modifier les textes entre les guillemets uniquement — ne pas toucher aux {, }, : ou aux noms de clés
  6. Cliquer le bouton vert Commit changes... (en haut à droite)
  7. Dans la popup, laisser le message par défaut et cliquer Commit changes
  8. Le site se met à jour automatiquement en ~15 secondes

Formatage disponible : le client peut utiliser **gras**, *italique* et [texte du lien](url) directement dans les valeurs JSON.

Le déploiement est automatique via GitHub Actions : à chaque commit sur main, le workflow valide le JSON, compile le contenu dans le HTML, et déploie via SSH/rsync. En cas de connexion instable, le déploiement retente automatiquement jusqu'à 3 fois.

Configuration initiale (une seule fois, par le développeur)

Les informations de connexion SSH se trouvent dans le fichier .deploy.env du projet (créé lors du setup).

Étape 1 — Récupérer les valeurs :

Ouvrir le fichier .deploy.env à la racine du projet et noter les 5 valeurs : PROD_HOST, PROD_PORT, PROD_USER, PROD_PATH, et la clé SSH privée (obtenue via cat ~/.ssh/id_ed25519 dans le terminal — copier tout le contenu, y compris les lignes -----BEGIN et -----END).

Étape 2 — Ouvrir les settings du repo GitHub :

  1. Aller sur le repo GitHub du projet (ex : github.com/MonClient/monsite)
  2. Cliquer l'onglet Settings (en haut à droite, à côté de « Insights »)
  3. Dans le menu de gauche, cliquer Secrets and variables
  4. Cliquer Actions (dans le sous-menu qui s'ouvre)

Étape 3 — Créer les 5 secrets :

Pour chaque secret du tableau ci-dessous, répéter ces 3 clics :

  1. Cliquer le bouton vert New repository secret
  2. Dans Name : taper le nom exactement comme dans le tableau
  3. Dans Secret : coller la valeur
  4. Cliquer Add secret
Name (à taper)Secret (à coller)Où trouver la valeur
SSH_PRIVATE_KEYLe contenu complet de la clé SSHTerminal : cat ~/.ssh/id_ed25519
PROD_HOSTL'adresse IP du serveur.deploy.env → ligne PROD_HOST=
PROD_PORTLe port SSH (souvent 65002 sur Hostinger).deploy.env → ligne PROD_PORT=
PROD_USERLe nom d'utilisateur SSH.deploy.env → ligne PROD_USER=
PROD_PATHLe chemin absolu sur le serveur.deploy.env → ligne PROD_PATH=

C'est fait. À partir de maintenant, chaque commit sur main déclenche le déploiement automatiquement (~15 secondes).

Sécurité

  • La clé SSH est stockée dans les GitHub Secrets — jamais visible, même par les admins du repo
  • Le client n'a accès qu'au repo de son site — pas aux autres projets ni au serveur
  • La clé SSH est restreinte au rsync vers un seul répertoire — pas d'accès shell au serveur
  • Isolation des clients — chaque projet a ses propres secrets, un client ne peut pas accéder au site d'un autre

Exemple complet

{
  "hero_titre": "Votre **agence digitale** à Lyon",
  "hero_texte": "Nous créons des sites web *modernes* et *performants*\npour les entreprises qui veulent se démarquer.",
  "hero_cta": { "text": "Demander un devis", "href": "/contact" },
  "hero_image": { "src": "/assets/images/hero.jpg", "alt": "Équipe au travail" },

  "services_titre": "Nos services",
  "services": [
    "**Design UI/UX** — Interfaces modernes et intuitives",
    "**Développement** — Sites rapides et accessibles",
    "**SEO** — Visibilité sur Google",
    "**Maintenance** — Suivi et mises à jour"
  ],

  "contact": {
    "tel": "04 12 34 56 78",
    "email": "contact@monagence.fr",
    "adresse": "12 rue de la République, 69001 Lyon"
  }
}

Sécurité du contenu

  • Le HTML brut est échappé avant le parsing (anti-XSS)
  • Les liens javascript:, vbscript: et data: sont bloqués
  • Seules les balises <strong>, <em>, <a> et <br> sont générées

Voir aussi