Aller au contenu

#Import et export

Deux routes pour déplacer un thème entier : le télécharger en un fichier, le reposer ailleurs. C’est la sauvegarde avant une expérimentation, le transport d’un thème d’un site à un autre, et l’archive qu’on garde hors ligne.

Pour modifier un fichier, ce n’est pas ici : voir Fichiers.

#Un JSON, et pas une archive ZIP

Shopify livre un .zip. Nous livrons un .json qui contient les mêmes fichiers, et le choix est assumé.

Produire une archive demanderait une dépendance pour empaqueter, une autre pour dépaqueter, et l’inspection du contenu à l’import deviendrait autrement plus délicate — une archive peut cacher des chemins traversants, des liens symboliques, des fichiers qui se décompressent en gigaoctets. Un JSON est lisible, se relit à l’œil nu, et son import se valide champ par champ.

Note

Le jour où l’on acceptera les .zip de Shopify, le format d’import restera celui-ci : il suffira de convertir à l’entrée.

#Exporter

GET/api/themes/<id>/export
200
json
{
  "format": "webcosa-theme",
  "format_version": 1,
  "nom": "Origo",
  "version": "1.0.0",
  "origine": "origo",
  "exporte_le": "2026-08-05T09:41:12.003Z",
  "fichiers": {
    "layout/theme.liquid": "<!doctype html>\n<html lang=\"fr\">…</html>\n",
    "templates/index.json": "{\n  \"sections\": { … },\n  \"order\": [\"entete\", \"hero\"]\n}\n",
    "config/settings_schema.json": "[\n  { \"name\": \"Couleurs\", \"settings\": [] }\n]\n"
  }
}
404 — thème inconnu, ou d’un autre site
json
{ "error": "introuvable" }

Portée lecture. Une clé de sauvegarde doit pouvoir exporter sans obtenir au passage le droit d’écrire les thèmes.

La réponse porte deux en-têtes qui comptent :

En-têtes de la réponse
Content-Type: application/json; charset=utf-8
Content-Disposition: attachment; filename="origo-1.0.0.json"
Cache-Control: no-store

Le nom de fichier est dérivé du nom du thème — accents retirés, minuscules, tout ce qui n’est ni lettre ni chiffre remplacé par un tiret — suivi de sa version. no-store parce qu’on retélécharge un thème justement quand on vient de le modifier.

formatchaîne

Toujours webcosa-theme. C’est ce que l’import exige à la lettre.

format_versionentier

La version du format d’archive, pas celle du thème. Vaut 1, et l’import n’accepte que 1 : une archive produite par une version future sera refusée franchement plutôt que lue de travers.

nomchaîne

Le nom du thème au moment de l’export.

versionchaîne

L’étiquette de version du thème.

originechaîne ou null

Le thème du catalogue dont il descend. Présent dans l’archive, ignoré à l’import — voir plus bas.

exporte_lehorodatage

Purement informatif. Rien ne le relit.

fichiersobjet

Une carte chemincontenu, en clair. C’est le thème entier : Liquid, JSON de configuration, CSS, SVG.

curl -s "https://cms.webcosa.com/api/themes/$THEME/export" \-H "Authorization: Bearer $WEBCOSA_CLE" \-o origo-sauvegarde.json 27 fichiers, 412 Ko
Danger

L’archive contient le code complet du thème, config/settings_data.json compris — donc les valeurs de réglages du site : couleurs, textes, adresses, numéros de téléphone. Ce n’est pas un secret d’authentification, mais ce n’est pas non plus un fichier à laisser traîner dans un dossier partagé.

#Importer

POST/api/themes/importer

Corps de la requête

json
{
  "format": "webcosa-theme",
  "format_version": 1,
  "nom": "Origo — reprise",
  "version": "1.0.0",
  "fichiers": {
    "layout/theme.liquid": "<!doctype html>…",
    "templates/index.json": "{ \"sections\": {}, \"order\": [] }",
    "config/settings_schema.json": "[]"
  }
}
201
json
{ "ok": true, "themeId": "55555555-5555-4555-8555-555555555555" }
400 — ce n’est pas une archive Webcosa
json
{
  "error": "archive_invalide",
  "message": "Ce fichier n'est pas un thème Webcosa, ou il vient d'une version que cette installation ne sait pas lire."
}
400 — il manque un fichier indispensable
json
{
  "error": "fichier_requis_manquant",
  "message": "Il manque un fichier indispensable. Attendus : layout/theme.liquid, config/settings_schema.json, templates/index.json."
}
402 — site inactif
json
{ "error": "site_inactif", "etat": "expire", "message": "Ce site n'est plus actif : ses modifications sont bloquées. Reprends un abonnement depuis le CMS (Réglages → Abonnement)." }

Portée themes. Un import crée toujours un thème neuf, en brouillon : il ne remplace jamais un thème existant, et il n’y a pas de « réimporter par-dessus ». Le corps est le contenu d’un fichier d’export, tel quel.

formatchaînerequis

Doit valoir exactement webcosa-theme.

format_versionentierrequis

Doit valoir 1. Aucune autre valeur n’est acceptée.

nomchaînerequis

De 1 à 80 caractères, espaces de bordure retirés. C’est le nom que portera le thème créé — change-le si tu réimportes sur le même site, sinon deux thèmes homonymes cohabiteront dans la liste.

versionchaînedéfaut : 1.0.0

Jusqu’à 20 caractères. Absente, le thème est créé en 1.0.0.

originechaîne ou null

Accepté par le schéma, jusqu’à 40 caractères — puis écrasé à null. Un thème importé ne descend plus d’un de nos modèles ; lui laisser une filiation ferait croire à des mises à jour qui ne viendront jamais.

Le champ n’est donc conservé dans l’archive que pour la lisibilité humaine.

fichiersobjetrequis

Une carte de chaînes vers des chaînes. Une valeur qui n’est pas une chaîne — un nombre, un objet imbriqué — fait échouer la validation avec archive_invalide, avant tout contrôle de chemin.

#Ce que l’archive doit contenir

L’archive est validée deux fois : d’abord sa forme, puis chacun de ses fichiers, avec exactement les mêmes règles qu’une écriture unitaire.

errorCause
archive_invalideUn champ de tête manquant, mal typé, ou format_version différent de 1
videfichiers ne contient aucune entrée
trop_de_fichiersPlus de 120 entrées
fichier_trop_grosUne entrée dépasse 524 288 unités de code UTF-16
chemin_invalideUne entrée est hors des six dossiers, porte une extension refusée, ou tente une traversée
fichier_requis_manquantIl manque layout/theme.liquid, templates/index.json ou config/settings_schema.json
creation_impossibleLa ligne du thème n’a pas pu être écrite
ecriture_impossibleLes fichiers n’ont pas pu être écrits — le thème créé est alors effacé, pour ne pas laisser une coquille
Attention

À la différence de PUT /api/themes/<id>/fichiers, l’import ne vérifie pas la syntaxe Liquid. Une archive dont une section ne compile pas s’installe sans erreur ; le défaut n’apparaît qu’au rendu, sous forme de commentaire HTML dans la page. Voir Le bac à sable.

C’est cohérent avec la provenance attendue — une archive vient d’un export, donc d’un thème qui s’écrivait déjà fichier par fichier — mais ce n’est pas une garantie sur laquelle s’appuyer.

#Ce qu’un thème importé peut faire

Liquid ne donne accès ni au disque, ni au réseau, ni à du JavaScript serveur : un thème ne peut pas lire la base ni sortir du site. Mais il produit du HTML, et rien n’échappe ce HTML — pas plus ici que chez Shopify.

Danger

Un thème venu d’ailleurs peut donc poser une balise script sur le site de celui qui l’installe, sous son domaine, avec accès à ses cookies.

Aujourd’hui c’est acceptable : on n’importe que ce qu’on a soi-même exporté, et le seul site atteint est le sien. N’importe pas une archive dont tu n’es pas l’auteur. Le jour où des thèmes circuleront entre comptes, il faudra assainir le HTML rendu — et cette décision se prend avant d’ouvrir cette porte, pas après.

Le corps de la requête ne contient aucun identifiant de site, et c’est délibéré. Le thème atterrit sur le site résolu par l’authentification, et nulle part ailleurs : accepter un site_id dans l’archive rendrait cette route capable d’écrire chez le voisin, à l’endroit précis du produit où l’on accepte du code venu du dehors.

#Déplacer un thème d’un site à un autre

  1. Exporter depuis le site source

    curl -s "https://cms.webcosa.com/api/themes/$SOURCE/export" \-H "Authorization: Bearer $WEBCOSA_CLE" \-H "X-Webcosa-Site-Cible: atelier-durand" \-o theme.json
  2. Renommer, si les deux sites sont proches

    Deux thèmes appelés « Origo » sur des sites différents ne gênent personne. Deux sur le même site, si.

    jq '.nom = "Origo — repris de Durand"' theme.json > theme-a-importer.json
  3. Importer sur le site cible

    L’en-tête change, la clé non : elle atteint tous les sites de son porteur.

    curl -s -X POST https://cms.webcosa.com/api/themes/importer \-H "Authorization: Bearer $WEBCOSA_CLE" \-H "X-Webcosa-Site-Cible: menuiserie-bertin" \-H "Content-Type: application/json" \--data-binary @theme-a-importer.json{"ok":true,"themeId":"55555555-5555-4555-8555-555555555555"}
  4. Regarder avant de publier

    Le thème est arrivé en brouillon. Les réglages de config/settings_data.json viennent du site d’origine : couleurs, textes, coordonnées. Relisez-les avant le PATCH de publication décrit dans Thèmes.