#!/usr/bin/env python3
"""Brouillon pilier « Contrat de maintenance PrestaShop 2026 ».

Usage :
    .venv-scripts/bin/python scripts/create_pillar_maintenance_prestashop_2026.py
    .venv-scripts/bin/python scripts/create_pillar_maintenance_prestashop_2026.py --publish
"""

from __future__ import annotations

import json
import sys
import urllib.parse
import urllib.request
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "scripts"))

from article_studio.config import load_config  # noqa: E402
from article_studio import wp_client  # noqa: E402

BASE = "https://www.arnaud-merigeau.fr"

TITLE = (
    "Contrat de maintenance PrestaShop : ce qu'il doit contenir "
    "et ce que ça coûte vraiment en 2026"
)
SLUG = "contrat-maintenance-prestashop-2026"
YOAST_TITLE = "Contrat de maintenance PrestaShop : prix et contenu 2026"
YOAST_DESC = (
    "Ce que doit contenir un contrat de maintenance PrestaShop : SLA chiffré, "
    "sauvegardes testées, exclusions. Tarifs 2026 relevés et 9 clauses qui piègent."
)
FOCUS = "contrat de maintenance prestashop"
EXCERPT = (
    "Combien coûte la maintenance d'une boutique PrestaShop, ce qu'un contrat "
    "sérieux doit contenir ligne par ligne, les clauses qui coûtent cher, "
    "et les 12 questions à envoyer à ton prestataire actuel."
)

# --- Tarifs de mes formules : à valider avant publication -------------------
PRIX_VEILLE = "89 €"
PRIX_SERENITE = "219 €"
PRIX_CRITIQUE = "449 €"

CONTACT = f"{BASE}/contact/"
PS = f"{BASE}/freelance-prestashop/"
WP = f"{BASE}/freelance-wordpress/"
WOO = f"{BASE}/freelance-woocommerce/"
TICKET = f"{BASE}/produit/ticket-intervention-prestashop-wordpress/"
PACK_PERF = f"{BASE}/produit/pack-performance/"
SECU = f"{BASE}/comment-securiser-votre-boutique-prestashop/"
SKIMMER = f"{BASE}/skimmer-prestashop-2026-guide-detection/"
SURVEILLANCE = f"{BASE}/wordpress-prestashop-surveillance-fichiers/"
MIGRATION = f"{BASE}/migration-prestashop-1-7-vers-9-sans-perdre-seo/"
PS9 = f"{BASE}/prestashop-9/"
PS92 = f"{BASE}/prestashop-9-2-onepage-checkout-ask-ai-extra-properties/"
FE = f"{BASE}/facturation-electronique-prestashop-wordpress-2026/"
PHP84 = f"{BASE}/compatibilite-php-8-4-plugins-wordpress/"
MODULES = f"{BASE}/guide-modules-prestashop-indispensables-2026-ps8-ps9/"
BO = f"{BASE}/prestashop-backoffice-optimisation/"
GSC = f"{BASE}/guide-complet-google-search-console-pour-prestashop/"
POLITIQUE = f"{BASE}/politique-de-securite-themes-modules-prestashop/"
REAL = f"{BASE}/realisations/"
QUI = f"{BASE}/qui-appeler-developpeur-ecommerce-2026/"
ARTICLE_URL_PLACEHOLDER = f"{BASE}/{SLUG}/"

IMG_DIR = ROOT / "assets"
IMG_FEATURED = IMG_DIR / "contrat-maintenance-prestashop-2026-featured.png"
IMG_PALIERS = IMG_DIR / "maintenance-prestashop-2026-paliers.png"
IMG_PANNE = IMG_DIR / "maintenance-prestashop-2026-cout-panne.png"
IMG_CYCLE = IMG_DIR / "maintenance-prestashop-2026-cycle.png"

CATEGORY_IDS = [2, 44]  # PrestaShop, E-commerce
TAG_NAMES = [
    "maintenance prestashop",
    "contrat de maintenance",
    "tma prestashop",
    "sécurité prestashop",
    "sauvegarde prestashop",
    "sla",
    "infogérance e-commerce",
]

FAQ = [
    (
        "Combien coûte un contrat de maintenance PrestaShop en 2026 ?",
        "Entre 50 et 120 € HT par mois pour une formule de veille (mises à jour "
        "mineures, sauvegardes, monitoring), 120 à 300 € pour un contrat standard "
        "avec sauvegardes quotidiennes et une à deux heures d'intervention "
        "incluses, 300 à 600 € pour un contrat avancé avec SLA et correctifs "
        "illimités. Au-delà de 600 €, on parle d'astreinte et de pilotage "
        "continu. En régie, compte 60 à 120 € de l'heure.",
    ),
    (
        "La maintenance PrestaShop est-elle obligatoire ?",
        "Aucune loi ne t'oblige à signer un contrat. En revanche, si tu encaisses "
        "des paiements par carte, la conformité PCI-DSS impose de corriger les "
        "vulnérabilités connues, et le RGPD t'impose de garantir la sécurité des "
        "données clients. Une boutique non mise à jour te met en défaut sur les "
        "deux, et ton assureur le sait.",
    ),
    (
        "Que se passe-t-il si je ne mets jamais à jour PrestaShop ?",
        "Les failles publiées restent ouvertes, et elles sont publiques. En 2026, "
        "PrestaShop a corrigé sur la seule branche 8.2 un XSS stocké noté 9,3 sur "
        "10, une injection de formule dans les exports CSV notée 8,3 et une SSRF "
        "notée 8,2. Les kits d'exploitation suivent les publications de failles "
        "de très près. Le scénario type, c'est le skimmer injecté dans le tunnel "
        "de paiement, qui siphonne les numéros de carte pendant des semaines.",
    ),
    (
        "Quelle différence entre maintenance, TMA et infogérance ?",
        "La maintenance couvre le maintien en condition opérationnelle de "
        "l'application : correctifs, mises à jour, sauvegardes. La TMA "
        "(tierce maintenance applicative) ajoute les évolutions fonctionnelles "
        "avec un volant d'heures. L'infogérance concerne le serveur : système, "
        "PHP, base de données, supervision. Trois périmètres distincts, souvent "
        "vendus en bloc sans que personne ne sache qui fait quoi le jour de la "
        "panne.",
    ),
    (
        "Faut-il un contrat de maintenance pour une petite boutique ?",
        "Si ta boutique fait moins de 30 000 € de chiffre d'affaires annuel, un "
        "contrat à 200 € par mois n'a pas de sens. Prends une formule de veille, "
        "ou paie à l'intervention. Le seuil de bascule se situe autour de "
        "100 000 € de CA : à ce niveau, une journée d'arrêt coûte déjà plus cher "
        "qu'un mois de contrat standard.",
    ),
    (
        "Les mises à jour majeures sont-elles incluses dans la maintenance ?",
        "Presque jamais, et c'est normal. Passer de 1.7 à 8, ou de 8.2 à 9.x, "
        "c'est un projet : recette des modules, thème à reprendre, plan de "
        "redirections, tests de commande. Ça se chiffre à part. Un contrat "
        "sérieux inclut en revanche la préparation : inventaire des modules, "
        "détection des incompatibilités, calendrier.",
    ),
    (
        "Mon hébergeur fait déjà des sauvegardes, ça suffit ?",
        "Non. Les sauvegardes hébergeur vivent souvent sur la même infrastructure "
        "que le site, elles sont rarement testées, et leur rétention est courte. "
        "Un ransomware ou une suppression accidentelle propagée les emporte avec "
        "le reste. Exige une copie hors serveur, une rétention d'au moins 30 "
        "jours, et surtout un test de restauration réel au moins une fois par "
        "trimestre.",
    ),
    (
        "Qu'est-ce qu'un SLA correct pour une boutique PrestaShop ?",
        "Deux niveaux minimum. Incident bloquant, c'est-à-dire site inaccessible "
        "ou paiement cassé : prise en charge sous 4 heures ouvrées, correctif ou "
        "contournement sous 8 heures. Incident standard : prise en charge sous 24 "
        "heures ouvrées. Et surtout des heures ouvrées définies noir sur blanc, "
        "avec une règle claire pour le week-end et le Black Friday.",
    ),
    (
        "Puis-je changer de prestataire de maintenance facilement ?",
        "Seulement si ton contrat le prévoit. Vérifie trois points avant de "
        "signer : la propriété du code développé pour toi, la restitution des "
        "accès et des sauvegardes sous un délai chiffré, et l'absence de module "
        "propriétaire chiffré qui cesse de fonctionner à la fin du contrat. Sans "
        "ces clauses, tu n'as pas un prestataire, tu as un propriétaire.",
    ),
    (
        "PrestaShop 8.2 est-il encore maintenu en 2026 ?",
        "Oui, mais en support étendu : la branche 8.2 ne reçoit plus que des "
        "correctifs de sécurité et de bugs critiques, et cette période s'arrête à "
        "la sortie de PrestaShop 10. Concrètement, tu peux rester en 8.2 encore "
        "un moment, à condition d'appliquer chaque patch. Rester en 8.2 sans les "
        "appliquer, c'est le pire des deux mondes.",
    ),
    (
        "Combien d'heures de maintenance faut-il prévoir par mois ?",
        "Pour une boutique standard avec une vingtaine de modules, compte 1 à 2 "
        "heures par mois de travail réel hors incident : mises à jour, "
        "vérifications, rapport. Une boutique avec ERP, marketplace et "
        "développements spécifiques tourne plutôt entre 4 et 8 heures. Un "
        "prestataire qui annonce l'illimité vend en réalité une moyenne, et "
        "reprendra la main quand tu dépasseras.",
    ),
    (
        "Que faire si ma boutique PrestaShop est piratée maintenant ?",
        "Coupe le tunnel de commande plutôt que le site entier, change tous les "
        "mots de passe back-office, FTP et base, fais une copie forensique avant "
        "tout nettoyage, puis cherche le point d'entrée avant de restaurer. "
        "Restaurer une sauvegarde sans identifier la faille te fait réinstaller "
        "le problème. Si tu es dans cette situation, écris-moi avec l'URL.",
    ),
    (
        "La facturation électronique change-t-elle mes besoins de maintenance ?",
        "Oui. Depuis le 1er septembre 2026, toutes les entreprises assujetties à "
        "la TVA doivent être en mesure de recevoir des factures électroniques. "
        "Pour une boutique, ça veut dire un raccordement à une plateforme agréée, "
        "des formats structurés à produire, et un module de plus à maintenir dans "
        "la durée.",
    ),
    (
        "Maintenance en interne ou externalisée ?",
        "En interne, il te faut quelqu'un qui suive les publications de sécurité "
        "PrestaShop, sache lire un log, et soit disponible quand ça casse. Si "
        "cette personne existe déjà chez toi, garde la maintenance en interne et "
        "achète du renfort ponctuel. Sinon, l'externalisation coûte moins cher "
        "qu'un demi-poste, et elle est joignable en août.",
    ),
]


def faq_schema() -> str:
    data = {
        "@context": "https://schema.org",
        "@type": "FAQPage",
        "mainEntity": [
            {
                "@type": "Question",
                "name": q,
                "acceptedAnswer": {"@type": "Answer", "text": a},
            }
            for q, a in FAQ
        ],
    }
    return json.dumps(data, ensure_ascii=False, indent=None)


def faq_html() -> str:
    return "\n".join(f"<h3>{q}</h3>\n<p>{a}</p>" for q, a in FAQ)


CONTENT = f"""
<p>Une boutique PrestaShop ne tombe jamais en panne le mardi matin. Elle tombe le vendredi à 18 h 40, pendant une opération commerciale, quand le module de paiement refuse toutes les cartes et que la seule personne qui connaît le serveur est en vacances. À ce moment précis, ce qui décide de la suite n'est ni ton hébergeur ni ta chance : c'est ce que tu as signé, ou pas signé, six mois plus tôt.</p>
<p>Le <strong>contrat de maintenance PrestaShop</strong> est le document le plus mal lu du e-commerce français. On le compare au prix, on regarde le nombre d'heures incluses, on signe. Et le jour de l'incident, on découvre que la sauvegarde vit sur le même serveur que le site, que « support réactif » n'engage à rien, et que le module développé sur mesure appartient au prestataire.</p>
<p>Ce guide déplie la question ligne par ligne : ce que la maintenance couvre vraiment, ce que le marché facture en 2026, les quatorze clauses qu'un contrat sérieux contient, les neuf pièges qui reviennent le plus souvent, et les douze questions à envoyer à ton prestataire actuel pour savoir en quinze minutes si tu es couvert ou juste facturé.</p>

<div class="wp-block-group has-background" style="background-color:#fff4eb;padding:24px;border-radius:12px">
<p><strong>La réponse courte.</strong> Un contrat de maintenance PrestaShop coûte entre 50 et 600 € HT par mois selon le niveau de service, ou 60 à 120 € de l'heure en régie. Il doit contenir au minimum : le périmètre exact (core, modules, thème, serveur), les correctifs de sécurité avec un délai chiffré, des sauvegardes externalisées avec test de restauration, un monitoring du tunnel de commande, un SLA à deux niveaux en heures ouvrées définies, un volant d'heures dont le report est précisé, un rapport mensuel, la liste des exclusions, et la propriété du code avec les conditions de réversibilité.</p>
</div>

<!--more-->

<h2>Sommaire</h2>
<ol>
<li><a href="#definition">Maintenance PrestaShop : de quoi on parle exactement</a></li>
<li><a href="#pourquoi-2026">Pourquoi 2026 est une mauvaise année pour improviser</a></li>
<li><a href="#cout-du-rien">Ce que coûte l'absence de contrat</a></li>
<li><a href="#tarifs">Les quatre niveaux de maintenance et leurs prix réels</a></li>
<li><a href="#forfait-regie">Forfait, régie ou ticket : comment trancher</a></li>
<li><a href="#quatorze-lignes">Les 14 lignes que ton contrat doit contenir</a></li>
<li><a href="#cycle">À quoi ressemble une vraie année de maintenance</a></li>
<li><a href="#pieges">Les 9 clauses qui coûtent cher</a></li>
<li><a href="#sla">Écrire un SLA qui veut dire quelque chose</a></li>
<li><a href="#sauvegardes">Sauvegardes : la seule question qui compte</a></li>
<li><a href="#exclusions">Ce qui n'est jamais inclus, et c'est normal</a></li>
<li><a href="#wordpress">PrestaShop, WordPress, WooCommerce : ce qui change</a></li>
<li><a href="#audit-contrat">Audite ton contrat actuel en 15 minutes</a></li>
<li><a href="#mon-offre">Comment je travaille</a></li>
<li><a href="#faq">Questions fréquentes</a></li>
</ol>

<figure class="wp-block-image size-large"><img src="__IMG_FEATURED__" alt="Contrat de maintenance PrestaShop 2026 : SLA, sauvegardes et correctifs de sécurité" width="1536" height="1024" loading="lazy" /><figcaption>Sur la seule branche 8.2, PrestaShop a publié en 2026 plusieurs correctifs de sécurité dont un XSS stocké noté 9,3 sur 10.</figcaption></figure>

<h2 id="definition">1. Maintenance PrestaShop : de quoi on parle exactement</h2>
<p>Le mot recouvre quatre métiers différents, et l'essentiel des malentendus vient de là. Quand ton prestataire dit « maintenance » et que tu entends « on s'occupe de tout », vous parlez rarement de la même chose.</p>

<h3>Les quatre familles</h3>
<p>La <strong>maintenance corrective</strong> répare ce qui est cassé : le formulaire de contact qui n'envoie plus rien, la commande qui reste bloquée en attente de paiement, le PDF de facture qui sort vide. C'est la seule que tout le monde a en tête.</p>
<p>La <strong>maintenance préventive</strong> évite la panne avant qu'elle arrive : appliquer les correctifs de sécurité, surveiller l'espace disque, purger les logs, vérifier que les sauvegardes tournent, tester la restauration. Elle ne se voit jamais, ce qui la rend difficile à vendre et facile à couper. C'est pourtant elle qui fait la différence entre une boutique qui tient cinq ans et une boutique qu'il faut refaire.</p>
<p>La <strong>maintenance adaptative</strong> suit l'écosystème : PHP change de version, un transporteur modifie son API, la réglementation impose un bouton de rétractation, une plateforme de paiement déprécie sa méthode d'intégration. Personne ne l'a demandée, elle s'impose.</p>
<p>La <strong>maintenance évolutive</strong> ajoute des fonctionnalités. C'est du développement, pas de la maintenance, même quand on la vend dans le même forfait sous forme d'heures incluses.</p>

<h3>Ce que la maintenance n'est pas</h3>
<p>Elle n'est pas l'<strong>hébergement</strong>. Ton hébergeur garantit que la machine tourne, pas que ton PrestaShop est à jour. Un serveur impeccable peut héberger une boutique truffée de failles.</p>
<p>Elle n'est pas l'<strong>infogérance système</strong>, qui couvre l'OS, PHP, MySQL, les certificats et la supervision serveur. Sur un mutualisé, l'hébergeur s'en charge. Sur un VPS, c'est une ligne à part, et une ligne oubliée.</p>
<p>Elle n'est pas la <strong>refonte</strong>, ni le <strong>marketing</strong>, ni le <strong>SEO</strong>. Un contrat de maintenance qui promet aussi « l'optimisation du référencement » dilue les trois. Vérifie combien d'heures sont réellement fléchées.</p>
<p>Elle n'est pas non plus la <strong>migration de version majeure</strong>. Passer de 1.7 à 8, ou de 8.2 à 9, se chiffre en jours de recette, pas en heures de forfait. J'ai détaillé la méthode dans mon guide de <a href="{MIGRATION}">migration PrestaShop 1.7 vers 9 sans perdre le SEO</a>.</p>

<h2 id="pourquoi-2026">2. Pourquoi 2026 est une mauvaise année pour improviser</h2>
<p>Trois chantiers se télescopent cette année, et aucun ne se règle en une soirée.</p>

<h3>La branche 8.2 vit en support étendu</h3>
<p>Depuis la sortie de PrestaShop 9, la branche 8.2 ne reçoit plus que des correctifs de sécurité et de bugs critiques. Cette phase s'arrête à la sortie de PrestaShop 10 : ce jour-là, 8.2 n'est plus maintenue du tout. Si tu es en 8.2, tu n'as pas un problème immédiat, tu as une échéance. La différence, c'est que l'échéance se prépare et que le problème se subit.</p>

<h3>Le rythme réel des correctifs de sécurité</h3>
<p>Sur la seule année 2026, la branche 8.2 a reçu plusieurs publications de sécurité. Un aperçu, avec les scores CVSS annoncés par le projet :</p>
<figure class="wp-block-table"><table>
<thead><tr><th>Version</th><th>Faille corrigée</th><th>Sévérité</th></tr></thead>
<tbody>
<tr><td>8.2.4</td><td>Énumération de comptes par temps de réponse sur le login front-office</td><td>5,3 / 10</td></tr>
<tr><td>8.2.5</td><td>XSS stocké via variables non échappées dans les templates du back-office</td><td>7,7 / 10</td></tr>
<tr><td>8.2.6</td><td>XSS stocké dans la vue Service client du back-office</td><td>9,3 / 10</td></tr>
<tr><td>8.2.8</td><td>Injection de formule dans les exports CSV</td><td>8,3 / 10</td></tr>
<tr><td>8.2.8</td><td>SSRF via les URL d'images à l'import CSV</td><td>8,2 / 10</td></tr>
<tr><td>8.2.8</td><td>Usurpation d'adresse IP via l'en-tête X-Forwarded-For</td><td>7,3 / 10</td></tr>
<tr><td>8.2.8</td><td>Injection SQL via les filtres de listes du back-office</td><td>6,5 / 10</td></tr>
</tbody></table><figcaption>Correctifs publiés sur la branche 8.2 en 2026, également portés sur la branche 9.x. Source : build.prestashop-project.org.</figcaption></figure>
<p>Regarde la ligne 8.2.6 : un XSS stocké à 9,3 dans la vue Service client, c'est-à-dire une page que ton équipe ouvre tous les jours. Le correctif existe depuis sa publication. La question n'est pas de savoir si PrestaShop fait son travail, il le fait. La question est de savoir qui, chez toi, applique le patch dans les jours qui suivent. Sans contrat, la réponse est presque toujours « personne, on verra ce week-end », et ce week-end n'arrive jamais.</p>
<p>Pour ce qui suit la faille, c'est-à-dire l'injection de code dans le tunnel de paiement, j'ai écrit un guide complet de <a href="{SKIMMER}">détection de skimmer sur PrestaShop</a> et un article plus large sur la <a href="{SECU}">sécurisation d'une boutique PrestaShop</a>. La <a href="{SURVEILLANCE}">surveillance de l'intégrité des fichiers</a> est le complément qui manque à 90 % des contrats.</p>

<h3>PrestaShop 9.2 arrive, et il change le tunnel</h3>
<p>La version 9.2 est en feature freeze depuis le 9 juillet 2026, la bêta publique est sortie le 22 juillet, et la version stable est attendue à l'automne. Elle apporte un <strong>One Page Checkout natif</strong>, un assistant « Ask AI » en back-office et le système d'<strong>Extra Properties</strong> pour étendre les entités du core proprement. J'en ai détaillé les conséquences dans mon article sur <a href="{PS92}">PrestaShop 9.2, One Page Checkout et Extra Properties</a>.</p>
<p>Pour un contrat de maintenance, ça se traduit simplement : si tu paies aujourd'hui un module de checkout en une page, tu vas devoir arbitrer. Et si tu as fait développer des champs personnalisés à coups d'overrides, tu as une dette à rembourser. Ces arbitrages appartiennent à la maintenance adaptative, celle que personne ne budgète.</p>

<h3>La facturation électronique est entrée en vigueur</h3>
<p>Depuis le 1er septembre 2026, toutes les entreprises assujetties à la TVA en France doivent être capables de <strong>recevoir</strong> des factures électroniques. L'obligation d'émission suit selon la taille de l'entreprise. Pour une boutique, ça veut dire un raccordement à une plateforme agréée, des formats structurés à produire, et un composant supplémentaire dans la chaîne. Tout est détaillé dans mon guide sur la <a href="{FE}">facturation électronique pour PrestaShop et WordPress</a>. Un module de plus, c'est une ligne de plus à maintenir, à tester après chaque montée de version, et à surveiller quand la plateforme change son API.</p>

<h3>PHP, et les licences que tout le monde oublie</h3>
<p>Les versions de PHP se périment plus vite que les boutiques. Passer une boutique en PHP 8.4 casse régulièrement des modules anciens, comme je l'ai constaté côté WordPress dans mon test de <a href="{PHP84}">compatibilité PHP 8.4 des plugins</a>. Ajoute à ça les licences annuelles des modules payants, qui expirent en silence : le module continue de tourner, mais tu ne reçois plus ses mises à jour de sécurité. C'est un angle mort classique, que j'ai abordé dans le <a href="{MODULES}">guide des modules PrestaShop indispensables</a>.</p>

<h2 id="cout-du-rien">3. Ce que coûte l'absence de contrat</h2>
<p>La maintenance se vend mal parce qu'elle s'oppose à un coût invisible. Rendons-le visible.</p>

<figure class="wp-block-image size-large"><img src="__IMG_PANNE__" alt="Coût d'une journée d'arrêt d'une boutique PrestaShop selon le chiffre d'affaires annuel" width="1280" height="720" loading="lazy" /><figcaption>Chiffre d'affaires annuel divisé par 365. Le calcul est grossier, mais il suffit à cadrer la discussion.</figcaption></figure>

<h3>L'arrêt</h3>
<p>Une boutique à 300 000 € de chiffre d'affaires annuel génère en moyenne 822 € par jour. Trois jours d'arrêt, et tu as dépensé l'équivalent d'un an de contrat standard, sans compter les paniers qui ne reviennent pas et les campagnes payantes qui tournent dans le vide pendant l'incident. Le calcul est volontairement simpliste : il ignore la saisonnalité, et un arrêt le 25 novembre coûte plusieurs fois la moyenne.</p>

<h3>Le piratage</h3>
<p>Le nettoyage d'une boutique compromise se facture généralement entre 1 500 et 4 000 € selon la profondeur de l'infection, et ça n'inclut ni la notification CNIL si des données personnelles ont fuité, ni la reconstruction de la confiance client, ni le déréférencement Google si le site a servi à du spam. Ajoute le risque contractuel avec ton prestataire de paiement, qui peut suspendre ton compte marchand le temps de l'enquête. Un skimmer dans le checkout, c'est-à-dire quelques lignes de JavaScript qui recopient les numéros de carte, tourne parfois pendant des mois sans que rien ne paraisse anormal côté marchand.</p>

<h3>La dette de version</h3>
<p>C'est le coût le plus sournois. Une boutique maintenue passe de version en version par petits sauts. Une boutique abandonnée trois ans se retrouve en 1.7 sur PHP 7.4, avec quinze modules dont l'éditeur a disparu, et la seule sortie devient une refonte à cinq chiffres. La maintenance ne fait pas économiser de l'argent sur l'année, elle évite le mur.</p>

<h2 id="tarifs">4. Les quatre niveaux de maintenance et leurs prix réels</h2>
<p>J'ai relevé les offres publiques du marché français en septembre 2026. Les prestataires ne s'accordent ni sur le vocabulaire ni sur le périmètre, mais les paliers de prix, eux, se ressemblent.</p>

<figure class="wp-block-image size-large"><img src="__IMG_PALIERS__" alt="Les quatre paliers de tarifs de maintenance PrestaShop en 2026" width="1280" height="760" loading="lazy" /><figcaption>Fourchettes constatées sur les offres publiques françaises, prix HT mensuels, septembre 2026.</figcaption></figure>

<figure class="wp-block-table"><table>
<thead><tr><th>Niveau</th><th>Prix HT / mois</th><th>Contenu typique</th><th>Pour qui</th></tr></thead>
<tbody>
<tr><td><strong>Veille</strong></td><td>50 à 120 €</td><td>Mises à jour mineures du core et des modules, sauvegarde hebdomadaire, monitoring de disponibilité, support au fil de l'eau</td><td>Boutique jusqu'à 100 k€ de CA, catalogue simple, peu de modules</td></tr>
<tr><td><strong>Standard</strong></td><td>120 à 300 €</td><td>Tout le niveau veille, plus sauvegardes quotidiennes, tests après mise à jour, 1 à 2 h d'intervention incluses, rapport mensuel</td><td>Boutique de 100 à 500 k€, une quinzaine de modules, un ou deux transporteurs</td></tr>
<tr><td><strong>Avancé</strong></td><td>300 à 600 €</td><td>Correctifs sans limite raisonnable, optimisation de performance mensuelle, réponse sous 4 h ouvrées, interlocuteur nommé</td><td>Boutique de 500 k€ à 2 M€, ERP connecté, développements spécifiques</td></tr>
<tr><td><strong>Critique</strong></td><td>600 € et plus</td><td>Astreinte élargie, environnement de recette permanent, feuille de route trimestrielle, SLA contractuel avec engagement</td><td>Boutique où une heure d'arrêt se compte en milliers d'euros</td></tr>
<tr><td><strong>Régie</strong></td><td>60 à 120 € / h</td><td>Tu paies ce qui est fait, rien d'autre</td><td>Boutique stable, ou marchand qui a déjà une compétence technique en interne</td></tr>
</tbody></table><figcaption>Relevé d'offres publiques françaises, septembre 2026. Les prestataires cités publiquement s'échelonnent de 29 € pour une formule d'entrée très légère à 359 € pour un contrat avec heures incluses.</figcaption></figure>

<p>Deux remarques sur ces chiffres. D'abord, un freelance spécialisé se situe en général sous le prix d'une agence à périmètre équivalent, parce qu'il n'y a pas de chef de projet à refacturer entre toi et la personne qui corrige. Ensuite, les écarts de prix à niveau annoncé identique s'expliquent presque toujours par une seule variable : les heures incluses. Un contrat à 99 € sans heure incluse et un contrat à 249 € avec quatre heures ne se comparent pas, ils ne vendent pas la même chose.</p>

<h2 id="forfait-regie">5. Forfait, régie ou ticket : comment trancher</h2>
<p>Le débat revient à chaque renouvellement. Voici comment je le tranche avec mes clients.</p>
<p>Le <strong>forfait mensuel</strong> a un mérite que la régie n'aura jamais : il finance le travail que personne ne demande. Les correctifs de sécurité, la vérification des sauvegardes, la purge des logs, personne ne t'appelle pour ça. En régie, ces tâches ne sont jamais commandées, donc jamais faites. Le forfait a un défaut symétrique : les mois calmes, tu paies pour rien de visible.</p>
<p>La <strong>régie</strong> convient si tu as déjà quelqu'un en interne qui suit la boutique, et que tu achètes du renfort ponctuel. Elle devient un piège dès que le prestataire n'est pas engagé sur un délai : le jour de l'incident, tu es un client parmi d'autres, et tu passes après ceux qui ont signé un SLA.</p>
<p>Le <strong>ticket à l'unité</strong> a sa place pour un besoin isolé et cadré : un bug identifié, un module à installer, une correction de faille précise. C'est exactement ce que couvre mon <a href="{TICKET}">ticket d'intervention</a>. Ça ne remplace pas un contrat, ça sert de porte d'entrée.</p>
<p>Le seuil de bascule, en pratique : en dessous de 100 000 € de chiffre d'affaires annuel, la régie ou une formule de veille suffit. Entre 100 000 et 500 000 €, le forfait standard devient rentable dès le premier incident évité. Au-dessus, la vraie question n'est plus le prix du contrat mais le délai d'intervention garanti.</p>

<h2 id="quatorze-lignes">6. Les 14 lignes que ton contrat doit contenir</h2>
<p>Prends ton contrat actuel et coche. S'il en manque plus de quatre, tu as un devis, pas un contrat.</p>

<h3>1. Le périmètre exact</h3>
<p>Quelles versions, quels modules, quel thème, quel serveur. Un contrat qui dit « votre site PrestaShop » ne dit rien. Le bon niveau de détail : le core, la liste nominative des modules couverts, le thème avec sa version, et une mention explicite du serveur, inclus ou exclu.</p>

<h3>2. Les correctifs de sécurité, avec un délai</h3>
<p>« Mises à jour de sécurité appliquées dans les 48 heures suivant la publication d'un correctif critique » est une phrase engageante. « Veille sécurité » n'en est pas une. Demande aussi ce qui se passe quand PrestaShop publie un correctif hors des heures ouvrées, ce qui est arrivé plus d'une fois.</p>

<h3>3. Les mises à jour du core et des modules</h3>
<p>Avec la distinction entre versions mineures, incluses, et versions majeures, facturées. Et une règle pour les modules tiers dont la licence a expiré : qui prévient, qui paie, sous quel délai.</p>

<h3>4. Les sauvegardes, en quatre paramètres</h3>
<p>Fréquence, lieu de stockage hors serveur principal, durée de rétention, et délai de restauration garanti. Une sauvegarde sans délai de restauration écrit ne vaut rien : tu ne sais pas si tu récupères ta boutique en deux heures ou en deux jours.</p>

<h3>5. Le test de restauration</h3>
<p>La ligne que presque personne n'écrit. Une sauvegarde qui n'a jamais été restaurée est une hypothèse, pas une garantie. Exige un test réel au moins trimestriel, sur un environnement séparé, avec un compte rendu.</p>

<h3>6. Le monitoring, et son périmètre</h3>
<p>La disponibilité de la page d'accueil ne suffit pas. Un site peut répondre 200 pendant que le tunnel de commande est cassé. Le monitoring utile surveille un parcours d'achat complet, les erreurs 500, l'expiration du certificat SSL et celle du nom de domaine.</p>

<h3>7. L'environnement de recette</h3>
<p>Où sont testées les mises à jour avant la production ? Si la réponse est « directement en ligne, la nuit », change de prestataire. Un staging à jour, c'est la différence entre une mise à jour et un pari.</p>

<h3>8. Le SLA, à deux niveaux minimum</h3>
<p>Voir la section suivante, c'est le sujet le plus maltraité de tous.</p>

<h3>9. Le volant d'heures et son report</h3>
<p>Combien d'heures incluses, ce qui les consomme, ce qui n'est pas décompté (un correctif de bug relève-t-il des heures incluses ou de la garantie ?), et si les heures non consommées se reportent. Le report est rare, mais il se négocie, souvent sur un trimestre glissant.</p>

<h3>10. Le rapport mensuel</h3>
<p>Lisible par quelqu'un qui n'est pas développeur : ce qui a été fait, la disponibilité du mois, les mises à jour appliquées, l'état des sauvegardes, les points à surveiller. Sans rapport, tu paies un abonnement dont tu ne peux rien dire au bout d'un an.</p>

<h3>11. L'interlocuteur, et son suppléant</h3>
<p>Qui tu appelles, et qui répond quand cette personne est absente. Le point faible du freelance, il faut le dire honnêtement, c'est la continuité. Un bon contrat freelance prévoit ce qui se passe en cas d'indisponibilité : un confrère identifié, ou un accès documenté que tu peux transmettre.</p>

<h3>12. Les exclusions, écrites</h3>
<p>Un contrat qui ne dit pas ce qu'il ne couvre pas est un contrat qui te le dira le jour de la facture.</p>

<h3>13. La propriété du code et des accès</h3>
<p>Tout ce qui est développé pour toi t'appartient, et les accès sont à ton nom, pas à celui du prestataire. Le nom de domaine surtout : vérifie aujourd'hui qui est le titulaire du tien, la surprise est fréquente.</p>

<h3>14. La réversibilité</h3>
<p>À la fin du contrat, restitution des accès, des sauvegardes et de la documentation sous un délai chiffré. Sans clause de sortie, tu es captif, et le prix du renouvellement s'en ressentira.</p>

<h3>Les deux lignes juridiques qu'on oublie</h3>
<p>Ton prestataire accède à des données personnelles de clients : il est sous-traitant au sens du RGPD, ce qui impose un contrat de sous-traitance conforme à l'article 28. Et vérifie son attestation de responsabilité civile professionnelle. Ces deux documents prennent cinq minutes à demander, et ils disent beaucoup sur le sérieux d'en face.</p>

<h2 id="cycle">7. À quoi ressemble une vraie année de maintenance</h2>
<p>Un contrat n'est pas une assurance : il y a du travail dedans, réparti dans le temps. Voilà le rythme réel.</p>

<figure class="wp-block-image size-large"><img src="__IMG_CYCLE__" alt="Cycle quotidien, mensuel, trimestriel et annuel d'un contrat de maintenance PrestaShop" width="1280" height="700" loading="lazy" /><figcaption>Le quotidien est automatisé, le trimestriel est manuel, l'annuel est stratégique.</figcaption></figure>

<p>Le <strong>quotidien</strong> doit être automatisé : sauvegarde de la base et des fichiers, surveillance de la disponibilité et du tunnel, alerte sur les erreurs 500 et sur les modifications de fichiers non prévues. Si quelqu'un fait ça à la main, tu paies un humain pour le travail d'un cron.</p>
<p>Le <strong>mensuel</strong> est semi-manuel : appliquer les mises à jour de modules après lecture des notes de version, purger les logs et le cache, vérifier les performances, écrire le rapport. Une à deux heures pour une boutique standard.</p>
<p>Le <strong>trimestriel</strong> est là où se joue la vraie qualité : test de restauration réel, revue des performances mobiles, revue des accès back-office, c'est-à-dire supprimer les comptes des prestataires partis et des salariés qui ne sont plus là. Cette revue-là remonte plus de problèmes que toutes les autres réunies. Pour la partie perf, mon <a href="{PACK_PERF}">pack performance</a> couvre le chantier quand il devient trop lourd pour un forfait.</p>
<p>L'<strong>annuel</strong> est stratégique : plan de version, revue des licences de modules, audit de sécurité complet, et un point sur ce que la boutique devra encaisser l'année suivante. C'est le moment où l'on décide de migrer vers <a href="{PS9}">PrestaShop 9</a>, pas le jour où la 8.2 cesse d'être maintenue.</p>

<h2 id="pieges">8. Les 9 clauses qui coûtent cher</h2>

<h3>1. « Interventions illimitées »</h3>
<p>Toujours suivi de « dans la limite du raisonnable », et le raisonnable, c'est celui du prestataire. Demande le nombre d'heures moyen constaté sur un client comparable, et ce qui se passe au-delà.</p>

<h3>2. Les heures qui expirent en silence</h3>
<p>Deux heures incluses par mois non reportables, sur une boutique stable, c'est vingt-quatre heures payées et peut-être six consommées. Négocie un report trimestriel, ou baisse le forfait.</p>

<h3>3. La sauvegarde sur le même serveur</h3>
<p>Très répandu, parce que c'est gratuit. Inutile face à un ransomware, une erreur de manipulation ou une défaillance de l'hébergeur. Exige une copie externalisée.</p>

<h3>4. Le SLA en jours ouvrés flous</h3>
<p>« Nous nous engageons à traiter votre demande dans les meilleurs délais » n'engage personne. « Sous 48 heures » sans préciser ouvrées ou calendaires te fait perdre le week-end.</p>

<h3>5. Le module maison qui te tient</h3>
<p>Le prestataire a développé un module de livraison spécifique, il en garde la propriété, et la licence s'éteint à la fin du contrat. Tu ne changes plus de prestataire, tu déménages. Fais écrire la cession des droits dès le devis.</p>

<h3>6. L'engagement de 24 mois à tacite reconduction</h3>
<p>Acceptable si le prix est bas et le contenu clair. Toxique quand le prestataire ne rend pas de compte : tu paies deux ans un service dont tu ne peux rien vérifier. Douze mois avec préavis de deux mois est un bon équilibre.</p>

<h3>7. L'absence de test de restauration</h3>
<p>Je le remets ici parce que c'est le piège le plus fréquent et le plus grave. La sauvegarde est planifiée, tout le monde est rassuré, et le jour de la restauration on découvre que le dump de la base est tronqué depuis huit mois.</p>

<h3>8. L'hébergement inclus qui n'est pas inclus</h3>
<p>Beaucoup de contrats mentionnent la « supervision serveur » sans couvrir l'infogérance. Le jour où PHP doit passer une version majeure, tu découvres que ça n'est dans le périmètre de personne.</p>

<h3>9. Le prestataire qui détient le domaine</h3>
<p>Ce n'est pas une clause, c'est pire : c'est un oubli. Vérifie le titulaire de ton nom de domaine dans le whois maintenant, avant d'en avoir besoin.</p>

<h2 id="sla">9. Écrire un SLA qui veut dire quelque chose</h2>
<p>Un SLA utile tient en quatre éléments : une classification des incidents, un délai de prise en charge, un délai de rétablissement, et une plage horaire.</p>

<figure class="wp-block-table"><table>
<thead><tr><th>Niveau</th><th>Exemples</th><th>Prise en charge</th><th>Contournement ou correctif</th></tr></thead>
<tbody>
<tr><td><strong>P1, bloquant</strong></td><td>Site inaccessible, paiement refusé, commandes non enregistrées, faille exploitée</td><td>4 h ouvrées</td><td>8 h ouvrées</td></tr>
<tr><td><strong>P2, majeur</strong></td><td>Transporteur indisponible, e-mails transactionnels non envoyés, back-office inaccessible</td><td>1 jour ouvré</td><td>3 jours ouvrés</td></tr>
<tr><td><strong>P3, mineur</strong></td><td>Affichage cassé sur une page, export à corriger, texte à modifier</td><td>3 jours ouvrés</td><td>Prochaine fenêtre de maintenance</td></tr>
</tbody></table><figcaption>Exemple de grille à deux ou trois niveaux. Les délais se négocient, leur existence ne se négocie pas.</figcaption></figure>

<p>Trois précisions à faire figurer. Les <strong>heures ouvrées</strong>, définies précisément : 9 h - 18 h du lundi au vendredi hors jours fériés, par exemple. Le régime des <strong>périodes de pointe</strong> : Black Friday, soldes, fêtes de fin d'année, où un SLA standard ne suffit pas et où l'astreinte se facture. Et le <strong>canal d'alerte</strong> : un incident P1 signalé par e-mail à 19 h ne sera pas vu, il faut un numéro ou un canal dédié.</p>
<p>Sur les pénalités, sois pragmatique. Chez un freelance ou une petite structure, une clause pénale se négocie rarement et elle ne répare rien : ce que tu veux, c'est que le site reparte, pas 200 € d'avoir. Le vrai levier, c'est la clause de sortie sans préavis en cas de manquement répété au SLA.</p>

<h2 id="sauvegardes">10. Sauvegardes : la seule question qui compte</h2>
<p>Pose-la telle quelle à ton prestataire : « la dernière fois que tu as restauré ma boutique sur un environnement de test, c'était quand, et combien de temps ça a pris ? ». Une réponse hésitante te dit tout.</p>
<p>Le cadre à exiger tient en cinq points. Une sauvegarde <strong>quotidienne</strong> de la base et des fichiers pour une boutique active, hebdomadaire seulement si le catalogue ne bouge pas. Une copie <strong>hors serveur principal</strong>, chez un autre fournisseur si possible. Une <strong>rétention</strong> d'au moins 30 jours, parce qu'une compromission se découvre rarement le jour même. Un <strong>délai de restauration</strong> écrit, c'est ton RTO. Et un <strong>test réel trimestriel</strong>, documenté.</p>
<p>Ajoute une exigence que peu de contrats prévoient : la sauvegarde doit être <strong>immuable</strong> ou au moins inaccessible depuis le serveur du site. Si un attaquant qui prend la main sur ta boutique peut aussi effacer tes sauvegardes, tu n'as pas de sauvegardes, tu as une copie.</p>

<h2 id="exclusions">11. Ce qui n'est jamais inclus, et c'est normal</h2>
<p>Un contrat honnête exclut explicitement une bonne partie des choses. Les <strong>licences des modules payants</strong>, à renouveler chaque année, restent à ta charge. L'<strong>hébergement</strong> aussi. Les <strong>migrations majeures</strong> se chiffrent en projet. Le <strong>remplacement d'un module</strong> devenu incompatible après une montée de version n'est pas un bug, c'est un achat. La <strong>refonte graphique</strong> et les <strong>nouvelles fonctionnalités</strong> sortent du périmètre par définition. Les <strong>interventions liées à une manipulation du client</strong> ou d'un tiers, également : si quelqu'un installe un module trouvé sur un forum et casse la production, ce n'est pas de la maintenance, c'est du dépannage.</p>
<p>Un prestataire qui n'exclut rien ne s'engage sur rien. La liste d'exclusions est un signe de sérieux, pas de mesquinerie.</p>

<h2 id="wordpress">12. PrestaShop, WordPress, WooCommerce : ce qui change</h2>
<p>Les trois plateformes ne demandent pas le même effort, et les contrats devraient le refléter.</p>
<p>Sur <strong>PrestaShop</strong>, le risque principal vient des overrides et des modules tiers. Le core est solide, mais chaque montée de version rejoue la question de la compatibilité de vingt modules. La maintenance y est un travail de recette autant que de correction, ce qui explique que les tarifs soient plus élevés que sur WordPress.</p>
<p>Sur <strong>WordPress</strong>, le volume de mises à jour est plus important mais chacune est plus légère, et l'automatisation couvre davantage de terrain. Le risque se déplace vers les plugins abandonnés et les thèmes premium jamais mis à jour. Détails sur ma page <a href="{WP}">freelance WordPress</a>.</p>
<p>Sur <strong>WooCommerce</strong>, tu cumules les deux : le rythme WordPress et la complexité e-commerce, avec des mises à jour majeures de WooCommerce qui touchent régulièrement le tunnel. Voir <a href="{WOO}">freelance WooCommerce</a>.</p>
<p>Un point commun : sur les trois, le monitoring doit surveiller le parcours d'achat, pas la page d'accueil. Et le suivi de l'indexation compte autant que le suivi technique, sujet que j'ai traité dans le <a href="{GSC}">guide Google Search Console pour PrestaShop</a>.</p>

<h2 id="audit-contrat">13. Audite ton contrat actuel en 15 minutes</h2>
<p>Copie ces douze questions, envoie-les à ton prestataire, et compare les réponses à ce que tu viens de lire. Les réponses évasives sont des réponses.</p>
<ol>
<li>Quelle version de PrestaShop tourne actuellement, et quel est le dernier correctif de sécurité appliqué ?</li>
<li>Mes sauvegardes sont stockées où, avec quelle rétention, et quand as-tu restauré pour de vrai la dernière fois ?</li>
<li>Combien de temps prend une restauration complète, mesuré, pas estimé ?</li>
<li>Que surveille exactement le monitoring, et qui reçoit l'alerte à 22 h ?</li>
<li>Où sont testées les mises à jour avant la production ?</li>
<li>Quel est le délai de prise en charge d'un incident bloquant, en heures, et sur quelle plage ?</li>
<li>Combien d'heures ai-je consommées ces six derniers mois ?</li>
<li>Quels modules ne sont plus maintenus par leur éditeur sur ma boutique ?</li>
<li>Quelles licences de modules expirent dans les douze prochains mois ?</li>
<li>Qui est titulaire de mon nom de domaine, et qui détient les accès administrateur ?</li>
<li>Le code développé pour moi m'appartient-il, et sous quelle licence ?</li>
<li>Si j'arrête demain, sous quel délai je récupère accès, sauvegardes et documentation ?</li>
</ol>
<p>Un prestataire sérieux répond aux douze en une heure. S'il faut trois relances, tu connais déjà le comportement que tu auras le jour de l'incident.</p>

<h2 id="mon-offre">14. Comment je travaille</h2>
<p>Je suis Arnaud Mérigeau, freelance PrestaShop et WordPress, certifié PrestaShop Experts, basé à Bordeaux, missions partout en France. Plus de quinze ans sur ces socles, et l'essentiel de mon temps passé sur des boutiques que je n'ai pas construites moi-même. C'est utile : je passe autant de temps à lire du code écrit par d'autres qu'à en écrire.</p>
<p>Trois formules, sans engagement de 24 mois.</p>

<figure class="wp-block-table"><table>
<thead><tr><th>Formule</th><th>Prix HT / mois</th><th>Ce qu'il y a dedans</th></tr></thead>
<tbody>
<tr><td><strong>Veille</strong></td><td>{PRIX_VEILLE}</td><td>Correctifs de sécurité du core sous 48 h, mises à jour mineures, sauvegarde quotidienne externalisée, monitoring de disponibilité et du tunnel, rapport mensuel</td></tr>
<tr><td><strong>Sérénité</strong></td><td>{PRIX_SERENITE}</td><td>Tout Veille, plus 2 h d'intervention incluses reportables sur le trimestre, mises à jour de modules testées sur staging, test de restauration trimestriel, revue de performance</td></tr>
<tr><td><strong>Critique</strong></td><td>{PRIX_CRITIQUE}</td><td>Tout Sérénité, plus 4 h incluses, SLA bloquant sous 4 h ouvrées, astreinte pendant les opérations commerciales, feuille de route trimestrielle</td></tr>
</tbody></table><figcaption>Tarifs indicatifs, ajustés selon le nombre de modules, la présence d'un ERP et le volume de commandes.</figcaption></figure>

<p>Ce que je mets systématiquement dans le contrat, et que tu peux exiger de n'importe qui d'autre : sauvegarde hors serveur avec test de restauration réel, correctifs de sécurité sous 48 heures, staging pour toute mise à jour, rapport mensuel lisible, propriété totale du code de ton côté, et réversibilité sous 5 jours ouvrés à la fin du contrat.</p>
<p>Ce que je ne fais pas : promettre de l'illimité, facturer une astreinte 24/7 que je ne pourrais pas tenir seul, ni maintenir une 1.6 indéfiniment sans plan de sortie. Sur ce dernier point, autant le dire tôt : si ta boutique est en 1.6 ou en 1.7 sur un PHP obsolète, la bonne dépense n'est pas un contrat de maintenance, c'est une <a href="{MIGRATION}">migration</a>.</p>
<p>Pour démarrer, trois entrées possibles. Un <a href="{TICKET}">ticket d'intervention</a> si tu as un problème isolé et que tu veux tester la collaboration. Le <a href="{PACK_PERF}">pack performance</a> si le sujet est la vitesse. Ou directement le <a href="{CONTACT}">formulaire de contact</a> avec l'URL de ta boutique, sa version, et ce qui t'inquiète : je réponds sous 24 h ouvrées avec un premier diagnostic. Tu peux aussi regarder mes <a href="{REAL}">réalisations</a> et ma page <a href="{PS}">freelance PrestaShop</a>, ou l'article qui explique <a href="{QUI}">quel profil appeler selon le chantier</a>.</p>
<p>Si tu veux vérifier ma méthode avant de me parler, tout est public : ma <a href="{POLITIQUE}">politique de sécurité pour les thèmes et modules</a>, mon guide de <a href="{BO}">optimisation du back-office</a> et le reste du blog.</p>

<h2 id="faq">15. Questions fréquentes</h2>
{faq_html()}

<h2 id="conclusion">Pour finir</h2>
<p>Un contrat de maintenance ne se juge pas au prix mensuel. Il se juge à trois choses : ce qui est écrit sur les sauvegardes, ce qui est écrit sur les délais, et ce qui est écrit sur la sortie. Le reste est de la mise en forme.</p>
<p>Si ton contrat actuel ne contient aucune de ces trois choses, tu ne paies pas une maintenance, tu paies une présence. Et le vendredi à 18 h 40, une présence ne répond pas.</p>
<p><a href="{CONTACT}">Envoie-moi l'URL de ta boutique</a> avec sa version et ton contrat actuel s'il y en a un. Je te dis en vingt minutes si tu es couvert, sur-facturé, ou les deux.</p>

<script type="application/ld+json">{faq_schema()}</script>
"""

SOCIAL_WHO = f"""Je suis Arnaud Mérigeau, freelance PrestaShop & WordPress certifié Experts, basé à Bordeaux. +15 ans sur des boutiques que je n'ai pas construites moi-même.

Une question sur ta maintenance ? Envoie l'URL.

{CONTACT}
"""

SOCIAL_LINKEDIN = f"""« Sauvegarde quotidienne » figure dans ton contrat de maintenance.

Question suivante : la dernière fois que quelqu'un l'a restaurée pour de vrai, c'était quand ?

C'est la ligne qui manque dans la quasi-totalité des contrats PrestaShop que je relis. La sauvegarde est planifiée, tout le monde est rassuré, et le jour où il faut restaurer on découvre que le dump de la base est tronqué depuis huit mois.

Pendant ce temps, sur la seule branche 8.2, PrestaShop a corrigé cette année un XSS stocké noté 9,3/10 dans la vue Service client, une injection de formule dans les exports CSV à 8,3 et une SSRF à 8,2. Les correctifs existent. La question, c'est qui les applique chez toi.

J'ai écrit le guide que j'aurais aimé donner à mes clients avant qu'ils signent ailleurs : les 14 lignes qu'un contrat doit contenir, les tarifs réels du marché en 2026, les 9 clauses qui piègent, et 12 questions à envoyer tel quel à ton prestataire actuel.

{ARTICLE_URL_PLACEHOLDER}

""" + SOCIAL_WHO

SOCIAL_X = f"""Ton contrat de maintenance PrestaShop dit « sauvegarde quotidienne ».

La vraie question : quand a-t-elle été restaurée pour de vrai ?

Les 14 lignes d'un contrat sérieux, les prix 2026 et les 9 pièges :
{ARTICLE_URL_PLACEHOLDER}
"""

SOCIAL_FACEBOOK = f"""Combien coûte la maintenance d'une boutique PrestaShop ?

Entre 50 et 600 € par mois selon le niveau. Mais le prix n'est pas le sujet : ce qui compte, c'est ce qui est écrit sur les sauvegardes, sur les délais d'intervention, et sur ce qui se passe quand tu pars.

Guide complet : tarifs réels du marché 2026, les 14 lignes d'un contrat sérieux, les 9 clauses qui coûtent cher, et 12 questions à poser à ton prestataire actuel.

{ARTICLE_URL_PLACEHOLDER}

""" + SOCIAL_WHO


def get_or_create_tag(base: str, user: str, password: str, name: str) -> int:
    slug = name.lower().replace(" ", "-").replace("é", "e").replace("è", "e")
    lookup = f"{base}/wp-json/wp/v2/tags?slug={urllib.parse.quote(slug)}"
    _, tags = wp_client._request("GET", lookup, user, password)
    if tags:
        return int(tags[0]["id"])
    _, tag = wp_client._request(
        "POST",
        f"{base}/wp-json/wp/v2/tags",
        user,
        password,
        data=json.dumps({"name": name, "slug": slug}).encode("utf-8"),
        headers={"Content-Type": "application/json"},
    )
    return int(tag["id"])


def save_exports(article_url: str, content: str, post_id: int | None = None) -> Path:
    out = ROOT / "exports" / "contrat-maintenance-prestashop-2026"
    social = out / "social"
    article = out / "article"
    social.mkdir(parents=True, exist_ok=True)
    article.mkdir(parents=True, exist_ok=True)

    (article / "content.html").write_text(content.strip() + "\n", encoding="utf-8")
    (article / "seo.yaml").write_text(
        "\n".join(
            [
                f"titre_seo: {YOAST_TITLE}",
                f"slug: {SLUG}",
                f"meta_description: {YOAST_DESC}",
                f"focus_keyword: {FOCUS}",
                "categorie_wp: PrestaShop, E-commerce",
                f"tags: {', '.join(TAG_NAMES)}",
                f'h1: "{TITLE}"',
                f"excerpt: {EXCERPT}",
                "",
                "requetes_cibles:",
                "  - maintenance prestashop (1137 impressions/3 mois, pos 24)",
                "  - freelance maintenance prestashop (487, pos 18.8)",
                "  - maintenance site prestashop (411, pos 19.5)",
                "  - maintenance site web prestashop (408, pos 15.2)",
                "  - agence maintenance prestashop (325, pos 32)",
                "  - contrat de maintenance prestashop (266, pos 39.9)",
                "  - contrat maintenance prestashop (243, pos 37.9)",
                "  - maintenance site internet prestashop (223, pos 16.9)",
                "  - forfait maintenance prestashop (33, pos 24)",
                "  - maintenance boutique prestashop (85, pos 21.5)",
                "",
                "variante_titre_seo_2: Maintenance PrestaShop : prix, contenu et pièges du contrat",
                "variante_meta_2: 50 à 600 €/mois selon le niveau. Les 14 lignes d'un contrat sérieux, les 9 clauses qui piègent, 12 questions à poser à ton prestataire.",
                "",
                "variante_titre_seo_3: Combien coûte la maintenance PrestaShop en 2026 ?",
                "variante_meta_3: Tarifs relevés du marché français, ce que couvre vraiment un contrat, et comment auditer le tien en 15 minutes.",
                "",
            ]
        ),
        encoding="utf-8",
    )

    posts = {
        "linkedin.txt": SOCIAL_LINKEDIN.replace(ARTICLE_URL_PLACEHOLDER, article_url),
        "x.txt": SOCIAL_X.replace(ARTICLE_URL_PLACEHOLDER, article_url),
        "facebook.txt": SOCIAL_FACEBOOK.replace(ARTICLE_URL_PLACEHOLDER, article_url),
    }
    for name, text in posts.items():
        (social / name).write_text(text.strip() + "\n", encoding="utf-8")

    (out / "README.txt").write_text(
        "Article pilier « Contrat de maintenance PrestaShop 2026 »\n"
        f"URL prévue : {article_url}\n"
        f"Post ID : {post_id or 'n/a'}\n\n"
        "À valider avant publication :\n"
        f"- tarifs des formules ({PRIX_VEILLE} / {PRIX_SERENITE} / {PRIX_CRITIQUE})\n"
        "- engagements SLA de la section 14\n\n"
        "Visuels : assets/contrat-maintenance-prestashop-2026-featured.png\n"
        "          assets/maintenance-prestashop-2026-paliers.png\n"
        "          assets/maintenance-prestashop-2026-cout-panne.png\n"
        "          assets/maintenance-prestashop-2026-cycle.png\n",
        encoding="utf-8",
    )
    return out


def ping_indexnow(article_url: str) -> None:
    key = "5f8e4b8b35b143b988c607967725f4b9"
    payload = {
        "host": "www.arnaud-merigeau.fr",
        "key": key,
        "keyLocation": f"https://www.arnaud-merigeau.fr/{key}.txt",
        "urlList": [article_url],
    }
    req = urllib.request.Request(
        "https://api.indexnow.org/indexnow",
        data=json.dumps(payload).encode("utf-8"),
        headers={"Content-Type": "application/json; charset=utf-8"},
        method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=20) as resp:
            print(f"IndexNow {resp.status} — {article_url}")
    except Exception as exc:  # noqa: BLE001
        print(f"IndexNow ignoré : {exc}")


def main() -> int:
    publish = "--publish" in sys.argv
    cfg = load_config()
    base = cfg.wp_base_url.rstrip("/")

    if not cfg.wp_user or not cfg.wp_application_password:
        print("Credentials WP manquants dans .secrets/.env")
        return 1

    print("Upload des visuels…")
    media_ids: dict[str, int] = {}
    media_urls: dict[str, str] = {}
    for path, alt in (
        (IMG_FEATURED, "Contrat de maintenance PrestaShop 2026 : SLA, sauvegardes et correctifs de sécurité"),
        (IMG_PALIERS, "Les quatre paliers de tarifs de maintenance PrestaShop en 2026"),
        (IMG_PANNE, "Coût d'une journée d'arrêt d'une boutique PrestaShop selon le chiffre d'affaires"),
        (IMG_CYCLE, "Cycle quotidien, mensuel, trimestriel et annuel d'un contrat de maintenance PrestaShop"),
    ):
        if not path.is_file():
            print(f"  manquant : {path.name}")
            continue
        media = wp_client.upload_media(
            base,
            cfg.wp_user,
            cfg.wp_application_password,
            path,
            alt_text=alt,
            title=path.stem.replace("-", " "),
        )
        media_ids[path.name] = int(media["id"])
        media_urls[path.name] = media.get("source_url", "")
        print(f"  {path.name} -> id {media['id']} ({media.get('source_url')})")

    content = CONTENT.strip()
    for token, name in (
        ("__IMG_FEATURED__", IMG_FEATURED.name),
        ("__IMG_PALIERS__", IMG_PALIERS.name),
        ("__IMG_PANNE__", IMG_PANNE.name),
        ("__IMG_CYCLE__", IMG_CYCLE.name),
    ):
        url = media_urls.get(name)
        if not url:
            print(f"  URL manquante pour {name}, le placeholder {token} reste dans le contenu")
            continue
        content = content.replace(token, url)

    print("Tags…")
    tag_ids = [
        get_or_create_tag(base, cfg.wp_user, cfg.wp_application_password, t)
        for t in TAG_NAMES
    ]

    payload: dict = {
        "title": TITLE,
        "content": content,
        "excerpt": EXCERPT,
        "status": "publish" if publish else "draft",
        "slug": SLUG,
        "author": cfg.wp_author_id,
        "categories": CATEGORY_IDS,
        "tags": tag_ids,
        "meta": {
            "_yoast_wpseo_title": YOAST_TITLE,
            "_yoast_wpseo_metadesc": YOAST_DESC,
            "_yoast_wpseo_focuskw": FOCUS,
        },
    }
    featured = media_ids.get(IMG_FEATURED.name)
    if featured:
        payload["featured_media"] = featured

    print("Création de l'article…")
    _, post = wp_client._request(
        "POST",
        f"{base}/wp-json/wp/v2/posts",
        cfg.wp_user,
        cfg.wp_application_password,
        data=json.dumps(payload).encode("utf-8"),
        headers={"Content-Type": "application/json"},
    )

    post_id = post.get("id")
    link = post.get("link") or f"{base}/{SLUG}/"
    print(f"{'Publié' if publish else 'Brouillon créé'} — ID {post_id}")
    print(f"Lien : {link}")
    print(f"Aperçu : {base}/?p={post_id}&preview=true")

    out = save_exports(f"{base}/{SLUG}/", content, post_id=post_id)
    print(f"Exports : {out}")
    if publish:
        ping_indexnow(link)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
