Audit RGAA niveau A : ce qui est inclus dans votre forfait FolioDesign
Chez FolioDesign, nous avons pris un engagement clair : chaque site que nous livrons est accompagné d'un audit de conformité RGAA niveau A. Ce n'est pas un argument commercial vague — c'est un diagnostic structuré, basé sur 25 critères précis, que nous remettons à chaque client avec son site. Voici ce que cela signifie concrètement, et pourquoi c'est déjà beaucoup.
Qu'est-ce qu'un audit niveau A ?
Un audit RGAA niveau A consiste à vérifier que votre site respecte les critères d'accessibilité les plus fondamentaux définis par le référentiel français et les standards internationaux WCAG. Ce sont les exigences de base sans lesquelles un site devient inutilisable pour une partie significative des internautes.
Concrètement, nous vérifions 25 critères répartis en plusieurs grandes thématiques :
- Images : chaque image porteuse d'information dispose-t-elle d'un texte alternatif ? Les images décoratives sont-elles correctement ignorées par les lecteurs d'écran ?
- Liens : chaque lien a-t-il un intitulé explicite ? Un lien "Découvrir" sans contexte est non conforme — il doit indiquer ce que l'on découvre.
- Formulaires : chaque champ est-il correctement étiqueté pour être compris par un lecteur d'écran ?
- Structure des titres : la hiérarchie H1/H2/H3 est-elle logique et cohérente ? Une seule balise H1 par page, des niveaux sans saut.
- Langue déclarée : la langue de la page est-elle spécifiée dans le code HTML ?
- Navigation clavier : tous les éléments interactifs sont-ils accessibles sans souris ?
- Multimédia : les vidéos comportent-elles des alternatives pour les personnes sourdes ou malvoyantes ?
- Titre de page : chaque page a-t-elle un titre unique et descriptif ?
Le résultat est un rapport clair : critères conformes, critères non conformes avec explication, et critères non applicables selon le contenu réel du site. Rien d'inventé, rien de flou.
Pourquoi être transparent sur le niveau A ?
Certaines agences préfèrent promettre la conformité totale sans préciser de quel niveau elles parlent. Chez FolioDesign, nous faisons le choix inverse : nous indiquons clairement que le niveau A est inclus, et que le niveau AA est disponible en option.
Cette transparence n'est pas une faiblesse — c'est une force. Le niveau A couvre les erreurs qui rendent un site inutilisable. Le corriger, c'est déjà s'adresser correctement aux 12 millions de Français en situation de handicap et améliorer l'expérience de tous les utilisateurs. Prétendre livrer le niveau AA sans le vérifier rigoureusement serait malhonnête.
Nous fonctionnons comme un médecin qui vous dit "votre bilan est bon sur ces 25 points, voici les 3 points à améliorer" — pas comme un vendeur qui vous promet une santé parfaite sans examen.
Quand faut-il viser le niveau AA ?
Le niveau AA est requis par l'European Accessibility Act (EAA) pour les entreprises qui y seront soumises. Il est également attendu dans le cadre des marchés publics, et devient progressivement la norme de référence dans les appels d'offres privés.
Pour une PME qui vend des services aux particuliers et réalise plus de 2 millions d'euros de chiffre d'affaires, ou qui emploie plus de 10 salariés, le niveau AA deviendra obligatoire pour les nouveaux services numériques dès juin 2025, et pour les services existants d'ici 2030.
Si votre activité vous projette vers ces marchés — ou si vous souhaitez simplement offrir la meilleure expérience possible à l'ensemble de vos visiteurs — le niveau AA est disponible en option chez FolioDesign. Il s'appuie sur le travail déjà réalisé au niveau A et nécessite des vérifications complémentaires, notamment sur les contrastes de couleurs et la navigation avancée.
Le rôle de Folia dans la conformité
Folia, l'assistant IA intégré à la plateforme partenaire FolioDesign, joue un rôle concret dans la conformité de vos pages dès leur création. Ce n'est pas un outil d'audit — c'est un outil de prévention qui réduit le nombre d'erreurs avant même le premier audit.
Concrètement, Folia prend en charge automatiquement plusieurs des éléments les plus fréquemment défaillants lors des audits RGAA :
- Les textes alternatifs des images : Folia génère automatiquement un attribut alt pertinent pour chaque image importée. C'est l'erreur numéro un dans les audits — et elle est résolue en amont.
- Les meta descriptions : chaque page se voit attribuer une description optimisée, compréhensible et unique — ce qui contribue à la fois à l'accessibilité et au référencement.
- La structure des titres : Folia organise le contenu avec une hiérarchie cohérente dès la rédaction, évitant les sauts de niveaux et les titres redondants.
Ces automatismes ne remplacent pas l'audit — ils en réduisent le travail correctif. Au moment du diagnostic, les critères les plus courants sont souvent déjà conformes.
La plateforme partenaire : une base technique solide
FolioDesign s'appuie sur une plateforme partenaire qui intègre nativement plusieurs mécanismes d'accessibilité dans son code de base. Les attributs ARIA sur les éléments interactifs, la gestion du focus clavier, les données structurées schema.org — autant d'éléments techniques qui seraient complexes à implémenter manuellement et qui sont ici présents d'office.
Cette base solide signifie que nous ne partons pas de zéro à chaque audit. Nous travaillons sur des fondations déjà saines, ce qui permet de concentrer le diagnostic sur le contenu spécifique du client plutôt que sur des problèmes génériques de structure.
Accessibilité et SEO : le même travail bien fait
Un bénéfice que les dirigeants de PME apprécient particulièrement : les éléments qui rendent un site accessible sont souvent exactement les mêmes qui améliorent son référencement naturel.
Google indexe mieux les images avec des textes alt. Il valorise les pages dont la structure de titres est logique. Il tient compte de la pertinence des intitulés de liens. Les meta descriptions influencent le taux de clic dans les résultats de recherche. En d'autres termes : l'audit niveau A que nous livrons ne sert pas seulement les utilisateurs en situation de handicap — il sert aussi votre visibilité sur Google, directement.
C'est l'un des avantages concrets de l'approche FolioDesign : un seul travail bien fait produit des effets sur plusieurs tableaux simultanément.
En résumé
L'audit niveau A inclus dans vos forfaits FolioDesign, c'est 25 critères vérifiés, un rapport clair et honnête, une base technique solide grâce à la plateforme partenaire, et une automatisation des erreurs les plus fréquentes grâce à Folia. Le niveau AA est disponible pour ceux qui en ont besoin ou qui anticipent les obligations réglementaires à venir.
Vous voulez savoir ce que l'audit révélerait sur votre site actuel ? Découvrez les forfaits FolioDesign et ce que comprend concrètement le diagnostic de conformité inclus dans chaque offre.
🚀 Guide de configuration (3 étapes simples)
📊 Étape 1 : Créer le Google Sheet
- Créez un nouveau Google Sheet
- Nommez-le :
Commentaires Blog - Créez ces colonnes dans la première ligne :
- ✓ A1: name
- ✓ B1: email
- ✓ C1: comment
- ✓ D1: page_url
- ✓ E1: page_title
- ✓ F1: timestamp
- ✓ G1: status
- ✓ H1: Logs
- ✓ I1: custom_fields
- ✓ J1: moderation_flags
- ✓ K1: reports_count
- ✓ L1: reports_details
- ✓ M1: reports_last_date
- ✓ N1: comment_id (unique)
⚙️ Étape 2 : Configurer Google Apps Script (Code v4 FINAL — signalement corrigé)
- Dans votre Google Sheet, allez dans Extensions → Apps Script
- Supprimez le code par défaut
- Copiez-collez le code ci-dessous 👇
// ============================================================
// WIDGET BLOG COMMENTS — Google Apps Script v4
// CORRECTIONS v4 :
// - handleReport ne crée JAMAIS de nouvelle ligne
// - Recherche du commentaire par comment_id (col N)
// ET par timestamp (col F) en fallback
// - Email envoyé même si comment_id introuvable
// (signalement orphelin stocké dans feuille "Signalements")
// - Logs ultra-détaillés pour diagnostic
// ============================================================
function doPost(e) {
try {
// Compatible avec Content-Type: text/plain ET application/json
// (le widget envoie text/plain pour contourner la restriction no-cors)
const rawBody = e.postData ? e.postData.contents : '';
Logger.log('📨 Body brut reçu: ' + rawBody.substring(0, 200));
if (!rawBody || rawBody.trim() === '') {
Logger.log('❌ Body vide reçu');
return jsonResponse({ status: 'error', message: 'Body vide' });
}
const data = JSON.parse(rawBody);
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
if (!data || typeof data !== 'object') {
return jsonResponse({ status: 'error', message: 'Données invalides' });
}
Logger.log('✅ Action reçue: ' + (data.action || 'new_comment'));
if (data.action === 'report') {
return handleReport(data, sheet);
}
return handleNewComment(data, sheet);
} catch (error) {
Logger.log('❌ Erreur doPost: ' + error.toString());
return jsonResponse({ status: 'error', message: error.toString() });
}
}
// ------------------------------------------------------------
// NOUVEAU COMMENTAIRE
// ------------------------------------------------------------
function handleNewComment(data, sheet) {
const customFieldsJson = data.custom_fields || '';
const moderationFlags = data.moderation_flags || '';
const commentId = Utilities.getUuid();
const row = [
data.name || '',
data.email || '',
data.comment || '',
data.page_url || '',
data.page_title || '',
data.timestamp || new Date().toISOString(),
data.status || 'pending',
'', // Logs
customFieldsJson,
moderationFlags,
0, // reports_count (col K)
'', // reports_details (col L)
'', // reports_last_date (col M)
commentId // comment_id (col N)
];
sheet.appendRow(row);
Logger.log('✅ Nouveau commentaire ajouté | id=' + commentId);
if (data.enable_notification && data.admin_email) {
sendAdminNotification(data, moderationFlags);
}
return jsonResponse({
status: 'success',
message: 'Commentaire enregistré',
comment_id: commentId
});
}
// ------------------------------------------------------------
// SIGNALEMENT — NE CRÉE JAMAIS DE NOUVELLE LIGNE
// ------------------------------------------------------------
function handleReport(data, sheet) {
Logger.log('════════════════════════════════════════════');
Logger.log('🚩 handleReport v4 — début');
Logger.log('📦 Données reçues: ' + JSON.stringify(data));
Logger.log('════════════════════════════════════════════');
const reporterName = data.reporter_name || 'Anonyme';
const reporterEmail = data.reporter_email || 'Non fourni';
const reportReason = data.report_reason || 'Non spécifié';
const reportDetails = data.report_details || 'Aucun détail';
const reportDate = new Date().toISOString();
const commentId = (data.comment_id || '').toString().trim();
const adminEmail = (data.admin_email || '').toString().trim();
Logger.log('🔑 comment_id reçu: "' + commentId + '"');
Logger.log('📧 admin_email reçu: "' + adminEmail + '"');
// ── Chercher la ligne du commentaire ──────────────────────
const allValues = sheet.getDataRange().getValues();
let commentRow = -1;
if (commentId !== '') {
// Priorité : recherche par comment_id (col N = index 13)
Logger.log('🔍 Recherche par comment_id dans colonne N (' + allValues.length + ' lignes)...');
for (let i = 1; i < allValues.length; i++) {
const cellId = (allValues[i][13] || '').toString().trim();
Logger.log(' Ligne ' + (i+1) + ': "' + cellId + '"');
if (cellId === commentId) {
commentRow = i + 1;
Logger.log('✅ Trouvé par comment_id à la ligne ' + commentRow);
break;
}
}
}
// Fallback : recherche par timestamp (col F = index 5)
if (commentRow === -1 && data.comment_timestamp) {
Logger.log('🔍 Fallback: recherche par timestamp...');
const ts = (data.comment_timestamp || '').toString().trim();
for (let i = 1; i < allValues.length; i++) {
if ((allValues[i][5] || '').toString().trim() === ts) {
commentRow = i + 1;
Logger.log('✅ Trouvé par timestamp à la ligne ' + commentRow);
break;
}
}
}
// ── Mettre à jour la ligne (si trouvée) ───────────────────
let newCount = 1;
if (commentRow !== -1) {
const currentCount = parseInt(sheet.getRange(commentRow, 11).getValue()) || 0;
const currentDetails = sheet.getRange(commentRow, 12).getValue() || '';
newCount = currentCount + 1;
sheet.getRange(commentRow, 11).setValue(newCount);
Logger.log('✅ reports_count mis à jour: ' + currentCount + ' → ' + newCount);
const detailLine = '[' + reportDate + '] Par: ' + reporterName +
' (' + reporterEmail + ') | Raison: ' + reportReason +
' | Détails: ' + reportDetails;
const newDetails = currentDetails ? currentDetails + '\n\n' + detailLine : detailLine;
sheet.getRange(commentRow, 12).setValue(newDetails);
sheet.getRange(commentRow, 13).setValue(reportDate);
Logger.log('✅ Détails et date mis à jour');
} else {
// Commentaire introuvable — on NE crée PAS de nouvelle ligne
Logger.log('⚠️ Commentaire introuvable. Enregistrement dans feuille "Signalements".');
enregistrerSignalementOrphelin(data, reporterName, reporterEmail, reportReason, reportDetails, reportDate);
}
// ── Envoyer l'email admin ─────────────────────────────────
if (adminEmail !== '') {
Logger.log('📧 Envoi email signalement à: ' + adminEmail);
try {
sendReportNotification(data, newCount, reporterName, reporterEmail, reportReason, reportDetails, commentRow);
Logger.log('✅ Email signalement envoyé');
} catch (emailError) {
Logger.log('❌ Erreur envoi email: ' + emailError.toString());
}
} else {
Logger.log('⚠️ Aucun email admin configuré.');
Logger.log(' → Vérifiez le champ "Email admin pour signalements" dans le content editor du widget.');
Logger.log(' → Ou remplissez le champ "Email de l\'administrateur" (notifications générales).');
}
Logger.log('🚩 handleReport v4 — fin');
Logger.log('════════════════════════════════════════════');
return jsonResponse({
status: 'success',
message: 'Signalement traité',
reports_count: newCount,
row_updated: commentRow
});
}
// Sauvegarde orpheline si le commentaire est introuvable dans le Sheet
function enregistrerSignalementOrphelin(data, reporterName, reporterEmail, reportReason, reportDetails, reportDate) {
try {
const ss = SpreadsheetApp.getActiveSpreadsheet();
let feuille = ss.getSheetByName('Signalements');
if (!feuille) {
feuille = ss.insertSheet('Signalements');
feuille.appendRow(['date', 'comment_id', 'comment_text', 'reporter_name', 'reporter_email', 'reason', 'details']);
}
feuille.appendRow([
reportDate,
data.comment_id || '',
data.comment_text || '',
reporterName,
reporterEmail,
reportReason,
reportDetails
]);
Logger.log('✅ Signalement orphelin enregistré dans "Signalements"');
} catch (err) {
Logger.log('❌ Erreur enregistrement orphelin: ' + err.toString());
}
}
// ------------------------------------------------------------
// EMAILS
// ------------------------------------------------------------
function sendAdminNotification(data, moderationFlags) {
try {
const subject = '📧 Nouveau commentaire sur "' + data.page_title + '"';
const body =
'Un nouveau commentaire a été posté sur votre site :\n\n' +
'👤 Nom : ' + (data.name || '') + '\n' +
'📧 Email : ' + (data.email || 'Non fourni') + '\n' +
'📄 Page : ' + (data.page_title || '') + '\n' +
'🔗 URL : ' + (data.page_url || '') + '\n' +
'📅 Date : ' + (data.timestamp || '') + '\n' +
'✅ Statut : ' + (data.status || '') + '\n\n' +
'💬 Commentaire :\n' + (data.comment || '') + '\n\n' +
(moderationFlags ? '🚨 Modération : ' + moderationFlags + '\n\n' : '') +
'---\nAccédez à votre Google Sheet pour gérer ce commentaire.';
MailApp.sendEmail(data.admin_email, subject, body);
Logger.log('✅ Email nouveau commentaire envoyé');
} catch (error) {
Logger.log('❌ Erreur envoi email commentaire: ' + error.toString());
}
}
function sendReportNotification(data, reportsCount, reporterName, reporterEmail, reportReason, reportDetails, rowUpdated) {
const subject = '🚩 SIGNALEMENT — "' + (data.page_title || 'Page inconnue') + '"';
const rowInfo = rowUpdated !== -1
? 'Ligne mise à jour dans le Sheet : ' + rowUpdated
: '⚠️ Commentaire introuvable dans le Sheet (voir feuille "Signalements")';
const body =
'🚨 ALERTE SIGNALEMENT 🚨\n\n' +
'━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' +
'📊 Total signalements : ' + reportsCount + '\n' +
rowInfo + '\n' +
'━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n' +
'💬 COMMENTAIRE SIGNALÉ\n' +
'📄 Page : ' + (data.page_title || 'N/A') + '\n' +
'🔗 URL : ' + (data.comment_page_url || 'N/A') + '\n' +
'👤 Auteur : ' + (data.comment_name || 'N/A') + '\n' +
'📧 Email auteur : ' + (data.comment_email || 'Non fourni') + '\n' +
'🔑 comment_id : ' + (data.comment_id || 'Non fourni') + '\n\n' +
'📝 Texte :\n"' + (data.comment_text || '') + '"\n\n' +
'━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n' +
'🚩 SIGNALÉ PAR\n' +
'👤 Nom : ' + reporterName + '\n' +
'📧 Email : ' + reporterEmail + '\n' +
'🚫 Raison : ' + reportReason + '\n' +
'📋 Détails : ' + reportDetails + '\n\n' +
'━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n' +
'⚠️ Veuillez vérifier ce commentaire dans votre Google Sheet.';
MailApp.sendEmail(data.admin_email, subject, body);
Logger.log('✅ Email signalement envoyé à ' + data.admin_email);
}
// ------------------------------------------------------------
// HELPER
// ------------------------------------------------------------
function jsonResponse(obj) {
return ContentService
.createTextOutput(JSON.stringify(obj))
.setMimeType(ContentService.MimeType.JSON);
}
- Cliquez sur 💾 Enregistrer
- ⚠️ IMPORTANT : Cliquez sur "Déployer" → "Gérer les déploiements"
- Cliquez sur ✏️ (Modifier) à côté du déploiement existant
- Changez "Version" → "Nouvelle version"
- Cliquez sur "Déployer"
- ✅ Votre webhook est maintenant mis à jour !
🔍 Pour voir les logs de débogage :
- Dans Google Apps Script, cliquez sur "Exécutions"(icône horloge)
- Cliquez sur la dernière exécution
- Vous verrez tous les logs détaillés du traitement du signalement
🔗 Étape 3 : Connecter à vos Collections
- Dans votre site, allez dans Collections
- Cliquez sur "Connect to Google Sheets"
- Autorisez et sélectionnez votre Google Sheet
- Configurez le mapping des colonnes
- Activez la synchronisation bidirectionnelle automatique
- Notez le nom de la collection créée
- Mettez à jour le champ "Nom de la collection" ci-dessous ⬇️
Laisser un commentaire
emoji
💬 Ceci est un exemple de commentaire pour prévisualiser les styles.
0 sur 0 commentaires affichés
❌ Erreur de chargement
Signaler un commentaire
We got it.
Thank you for contacting us.
We’ll get back to you as soon as possible.












Partagez votre avis sur cet article ( 0 )