1. Résumé exécutif
Cette mission, menée en tant que consultant WordPress externe pour Inbound Value (missionné par mon agence VirtuoseWeb.fr), s'est concentrée sur la réalisation de plusieurs développements clés pour le site Airess.net. Ces travaux incluent la création d'une section blog, la publication d'articles stratégiques, et la mise en place d'un tunnel de conversion avec une landing page et une synchronisation Odoo.
En complément de ces réalisations, un audit technique et fonctionnel a été effectué. Les principaux constats révèlent des performances perfectibles, une maintenance potentiellement complexifiée par l'utilisation de WPBakery, et l'absence de fonctionnalités comme le multilinguisme. Les recommandations s'orientent vers une optimisation technique continue, l'amélioration SEO, et une réflexion sur l'infrastructure d'hébergement pour assurer la pérennité et l'évolutivité du site.
2. Contexte & Périmètre
- Client : Airess.net
- Intervenant : Simon Béros (VirtuoseWeb.fr), consultant externe pour Inbound Value.
- Site : https://airess.net/ (WordPress)
- Technologies principales : WPBakery Page Builder, thème pré-construit.
- Objectif principal de la mission : Réalisation de développements spécifiques incluant la création d'une section blog, la publication d'articles, la mise en place d'une landing page avec formulaire CF7, et l'intégration avec Odoo.
- Objectifs secondaires (initiative du consultant) : Audit de l'existant, identification des points d'amélioration et formulation de recommandations stratégiques.
- Outils/Plugins installés notables :
- WPBakery Page Builder
- ACF Pro (Advanced Custom Fields Pro) - Licence agence VirtuoseWeb.fr
- Plugin de duplication de pages/articles
- Contact Form 7 (CF7)
- FluentSnippet (utilisé pour les injections de code JS/CSS et le hook PHP pour Odoo)
- Environ 152+ lignes de CSS additionnel personnalisé (voir `css/style.css` et Annexe)
3. Travaux réalisés
- Création de la Page “Blog” et ajout au menu principal : airess.net/blog/
- Publication de 3 Articles de Blog (1 cornerstone + 2 sous-articles) :
- Création d'une Landing Page pour Lead Magnet : « Le guide pratique de la conformité incendie 2025 »
- Mise en place d'une Welcome Page pour la délivrance de la ressource : welcome-page-01/. Utilisation d'un champ ACF et d'un shortcode personnalisé pour le bouton de téléchargement dynamique (voir snippets PHP et HTML en Annexe).
- Configuration d'un formulaire Contact Form 7 sur la landing page, incluant un code JavaScript pour la redirection vers la Welcome Page après soumission (voir snippet JS en Annexe).
- Synchronisation avec Odoo : Implémentation d'un script PHP (hook sur CF7 via FluentSnippet) pour envoyer les données des formulaires vers l'instance Odoo du client (voir snippet PHP en Annexe).
- Ajout de CSS additionnel (plus de 152 lignes) pour des ajustements graphiques et fonctionnels spécifiques (intégralité dans `css/style.css`, extrait en Annexe).
4. Constats & Enjeux (Audit complémentaire)
- Maintenance et Évolutivité : L'utilisation de WPBakery avec un thème pré-construit peut complexifier la maintenance à long terme et limiter la flexibilité pour des évolutions futures par rapport à des solutions plus modernes (constructeurs basés sur Gutenberg, Bricks Builder).
- Potentiel International : Le site n'est pas multilingue, ce qui représente une opportunité manquée pour le référencement et l'audience à l'international.
- Performances Techniques :
- GTmetrix & PageSpeed Insights : Les scores indiquent des marges d'amélioration significatives, notamment sur mobile (LCP, TBT). (Voir PDF Rapport GTmetrix et Rapport PageSpeed Insights).
- Temps de chargement initial perfectible, absence de mise en cache avancée et de CDN.
- Hébergement Actuel : Les fonctionnalités (sauvegardes, interface de gestion) pourraient être optimisées pour une meilleure gestion et sécurité.
5. Recommandations (Suite à l'audit)
Ces recommandations découlent de l'audit complémentaire et visent à améliorer durablement la performance, la visibilité et la maintenabilité du site Airess.net. Leur mise en œuvre dépendra des priorités et du budget du client.
- Optimisation Technique & Performance :
- Mise en place d'un plugin de cache performant (ex: WP Rocket, LiteSpeed Cache).
- Intégration d'un Content Delivery Network (CDN) (ex: Cloudflare, Bunny CDN).
- Optimisation des images (compression, formats nouvelle génération comme WebP).
- Minification des ressources CSS/JS (souvent gérée par les plugins de cache).
- Amélioration SEO & Contenu :
- Audit SEO approfondi (technique, contenu, backlinks).
- Optimisation sémantique continue (balisage Hn, méta-données, maillage interne).
- Considérer une stratégie multilingue (ex: WPML, Polylang) si pertinent pour l'activité.
- Évolution Technologique (Moyen/Long Terme) :
- Planifier une refonte technique vers un constructeur plus moderne (ex: Bricks Builder, ou un écosystème Gutenberg avancé) pour améliorer les performances natives et faciliter la maintenance.
- Hébergement & Maintenance :
- Évaluer des solutions d'hébergement spécialisées WordPress (ex: Hostinger, Kinsta, o2switch) offrant de meilleures performances, sécurité, et des outils de gestion adaptés.
- Mettre en place un plan de maintenance préventive régulier (mises à jour, sauvegardes).
- Qualité des Visuels : Envisager d'investir dans des photographies et visuels professionnels pour renforcer l'image de marque.
6. Prochaines Étapes Suggérées
- Validation et Tests Odoo : Finaliser les tests de la synchronisation Odoo avec des données réelles pour confirmer le bon fonctionnement (vérifier URL, BDD, droits CRM de l'utilisateur Odoo).
- Priorisation des Recommandations : Discuter avec Airess.net pour établir un ordre de priorité pour la mise en œuvre des recommandations issues de l'audit.
- Plan d'Action Court Terme : Identifier les actions rapides à mettre en place (ex: configuration basique du cache, optimisation d'images critiques).
- Réflexion Stratégique Long Terme : Si la refonte est envisagée, entamer l'élaboration d'un cahier des charges détaillé, incluant budget, planning et livrables.
7. Annexes
Liens Utiles & Pages Créées
- Page Blog : https://airess.net/blog/
- Article "Réglementation sécurité incendie..." : Lien vers l'article
- Article "Le registre de sécurité..." : Lien vers l'article
- Article "Installation des extincteurs..." : Lien vers l'article
- Landing Page "Guide conformité incendie" : Lien vers la landing page
- Welcome Page (après soumission formulaire) : https://airess.net/welcome-page-01/
Rapports de Performance (PDF)
- Rapport PageSpeed Insights : Consulter le Rapport PageSpeed Insights
- Rapport GTmetrix : Consulter le Rapport GTmetrix
Ces rapports sont hébergés sur le site Airess.net.
Extraits de Code Documentés
JavaScript : Redirection Contact Form 7
Ce script, à placer via un plugin comme Fluent Snippet ou dans les options JS du thème, redirige l'utilisateur vers /welcome-page-01/
après la soumission réussie du formulaire Contact Form 7 avec l'ID 2505
.
document.addEventListener('wpcf7mailsent', function(event) {
// Ne s’exécute que pour le formulaire CF7 ID 2505 (à adapter si besoin)
if (event.detail.contactFormId == 2505) {
// Redirection immédiate vers la page de remerciement
window.location.href = '/welcome-page-01/';
// Pour un délai de 3 secondes avant redirection, décommentez et utilisez :
/*
setTimeout(function() {
window.location.href = '/welcome-page-01/';
}, 3000);
*/
}
}, false);
PHP : Activation Globale des Shortcodes ACF
Ce snippet, à ajouter dans le fichier functions.php
de votre thème enfant ou via un plugin de snippets, garantit que les shortcodes ACF (comme [acf field="votre_champ"]
) sont interprétés par WordPress.
add_action('acf/init', function(){
// Vérifie si la fonction acf_update_setting existe
if (function_exists('acf_update_setting')) {
// Active le shortcode natif ACF
acf_update_setting('enable_shortcode', true);
}
// Affiche un commentaire HTML pour débogage (optionnel, utile en développement)
// echo "\n<!-- ACF shortcode activé via acf/init -->\n";
});
PHP : Shortcode ACF pour Lien Ressource Dynamique
Ce code (pour functions.php
ou un plugin de snippets) crée le shortcode [lien_ressource_cliquable]
. Il affiche un lien vers une URL stockée dans un champ ACF nommé url_lien_ressource
du post/page courant.
// Enregistre le shortcode [lien_ressource_cliquable]
add_shortcode('lien_ressource_cliquable', function () {
// Assurez-vous que la fonction get_field existe (ACF est actif)
if (!function_exists('get_field')) {
return '<!-- Erreur : ACF n\'est pas actif -->';
}
// Récupère l'URL du champ ACF nommé 'url_lien_ressource' pour le post courant
$url = get_field('url_lien_ressource', get_the_ID());
if ( ! empty($url) ) {
// Retourne le lien HTML si l'URL est trouvée
return sprintf(
'<a href="%1$s" target="_blank" rel="noopener noreferrer" class="text-sky-600 hover:underline font-semibold text-lg inline-block py-2 px-4 bg-sky-500 text-white rounded-md hover:bg-sky-600 transition-colors duration-200"%gt;%2$s</a>',
esc_url( $url ),
esc_html( 'Votre ressource vous attend. Cliquez ici pour la télécharger.' )
);
}
// Message si le champ est vide ou non défini (utile pour le débogage)
return '<!-- ACF: Champ "url_lien_ressource" vide ou non défini pour ce contenu. -->';
});
WordPress Contenu : Utilisation du champ ACF comme bouton
Pour afficher une URL d'un champ ACF (ici, url_lien_ressource
) sous forme de bouton directement dans l'éditeur de contenu WordPress (Gutenberg, Classique, ou un constructeur de page acceptant les shortcodes), utilisez :
<!-- Méthode 1: Shortcode ACF direct avec style inline -->
<a href="[acf field='url_lien_ressource']"
style="display:inline-block; padding:0.6em 1.2em; background-color:#0073AA; color:#ffffff; text-decoration:none; border-radius:4px; font-weight:500;"
target="_blank"
rel="noopener noreferrer">
Récupérer ma ressource via shortcode ACF
</a>
<!-- Méthode 2: Utilisation du shortcode PHP personnalisé [lien_ressource_cliquable] (voir snippet PHP ci-dessus) -->
<p>[lien_ressource_cliquable]</p>
La méthode 2 est plus propre si le style du bouton est défini dans le code PHP du shortcode ou via CSS.
PHP : Intégration Odoo avec Contact Form 7 (Backend)
Ce script PHP s'accroche à l'événement de soumission de Contact Form 7 (wpcf7_mail_sent
).
Pour un formulaire spécifique (dont le titre doit être adapté dans $form_title_cible
), il récupère les données et tente de créer un lead dans Odoo via l'API JSON-RPC.
Les identifiants de connexion Odoo ($odoo_url
, $odoo_db
, $odoo_username
, $odoo_api_key
) et les noms des champs CF7 ($posted_data['your-name']
, etc.) DOIVENT ÊTRE CONFIGURÉS avec les valeurs réelles.
Ce code est destiné à être placé dans le fichier functions.php
du thème enfant ou via un plugin de gestion de snippets. Des logs d'erreur sont prévus pour le débogage.
/**
* Hook Contact Form 7 submission to send data to Odoo CRM.
*/
add_action('wpcf7_mail_sent', function($contact_form) {
// ✔️ Adapter le titre du formulaire CF7 ciblé
$form_title_cible = 'NomDeVotreFormulaire'; // EXEMPLE: 'Formulaire Contact Landing Page'
$form_title = $contact_form->title();
if ($form_title !== $form_title_cible) {
// error_log("Formulaire non ciblé : " . $form_title . ". Cible : " . $form_title_cible); // Pour débogage
return;
}
$submission = WPCF7_Submission::get_instance();
if (!$submission) {
error_log("Soumission CF7 non trouvée pour " . $form_title);
return;
}
$posted_data = $submission->get_posted_data();
// 🌐 [CONFIGURATION ODOO - À ADAPTER IMPÉRATIVEMENT]
$odoo_url = 'https://VOTRE_INSTANCE.odoo.com'; // Remplacez par votre URL Odoo
$odoo_db = 'NOM_VOTRE_BDD'; // Remplacez par le nom de votre BDD Odoo
$odoo_username = 'UTILISATEUR_API_ODOO@example.com';// Remplacez par le login utilisateur Odoo lié à la clé API
$odoo_api_key = 'VOTRE_CLE_API_ODOO'; // Remplacez par votre clé API Odoo
// ✔️ Adapter les noms des champs CF7 aux variables Odoo
// Les noms comme 'your-name', 'your-email' sont les noms par défaut des champs CF7.
// Vérifiez les noms exacts de vos champs dans l'éditeur CF7.
$name = isset($posted_data['your-name']) ? sanitize_text_field($posted_data['your-name']) : '';
$company = isset($posted_data['your-company']) ? sanitize_text_field($posted_data['your-company']) : ''; // Adaptez si le champ a un autre nom
$email = isset($posted_data['your-email']) ? sanitize_email($posted_data['your-email']) : '';
$job_title = isset($posted_data['your-jobtitle']) ? sanitize_text_field($posted_data['your-jobtitle']) : ''; // Adaptez
$phone = isset($posted_data['your-tel']) ? sanitize_text_field($posted_data['your-tel']) : ''; // Adaptez
$lead_title = $company ? "$company - $name" : $name;
if (empty($lead_title) && !empty($email)) $lead_title = "Prospect: " . $email;
if (empty($lead_title)) $lead_title = "Nouveau prospect via formulaire " . $form_title_cible;
$odoo_lead_data = [
'name' => $lead_title,
'contact_name' => $name,
'partner_name' => $company,
'email_from' => $email,
'phone' => $phone,
'function' => $job_title,
'description' => "Lead généré depuis le formulaire WordPress: " . $form_title_cible . "\nSource: " . site_url() . "\n\nDonnées brutes:\n" . print_r($posted_data, true),
// 'team_id' => 1, // Optionnel: ID de l'équipe de vente si connue
// 'user_id' => ID_UTILISATEUR_COMMERCIAL_ODOO, // Optionnel
// 'campaign_id' => ID_CAMPAGNE_ODOO, // Optionnel
// 'medium_id' => ID_MEDIUM_ODOO, // Optionnel
// 'source_id' => ID_SOURCE_ODOO, // Optionnel
];
$endpoint = rtrim($odoo_url, '/') . '/jsonrpc';
// 1️⃣ Authentification
$auth_payload = ['jsonrpc' => '2.0', 'method' => 'call', 'params' => ['service' => 'common', 'method' => 'authenticate', 'args' => [$odoo_db, $odoo_username, $odoo_api_key, []]], 'id' => 'auth_' . uniqid()];
$auth_response = wp_remote_post($endpoint, ['headers' => ['Content-Type' => 'application/json'], 'body' => json_encode($auth_payload), 'timeout' => 20, 'sslverify' => true]); // Mettre sslverify à true en production
if (is_wp_error($auth_response)) {
error_log("Erreur de connexion API Odoo (Auth): " . $auth_response->get_error_message());
return;
}
$auth_body = wp_remote_retrieve_body($auth_response);
$auth_result = json_decode($auth_body, true);
$uid = $auth_result['result'] ?? 0;
if (!$uid) {
error_log("Échec de l'authentification API Odoo. Vérifiez URL/DB/Login/Clé. Réponse: " . $auth_body . " Payload: " . json_encode($auth_payload));
return;
}
// 2️⃣ Création du Lead
$create_payload = ['jsonrpc' => '2.0', 'method' => 'call', 'params' => ['service' => 'object', 'method' => 'execute_kw', 'args' => [$odoo_db, $uid, $odoo_api_key, 'crm.lead', 'create', [$odoo_lead_data]]], 'id' => 'create_' . uniqid()];
$create_response = wp_remote_post($endpoint, ['headers' => ['Content-Type' => 'application/json'], 'body' => json_encode($create_payload), 'timeout' => 20, 'sslverify' => true]); // Mettre sslverify à true en production
if (is_wp_error($create_response)) {
error_log("Erreur API Odoo (Création Lead): " . $create_response->get_error_message());
return;
}
$create_body = wp_remote_retrieve_body($create_response);
$create_result = json_decode($create_body, true);
if (!empty($create_result['error'])) {
error_log("Erreur retournée par API Odoo lors de la création du lead: " . print_r($create_result['error'], true) . " Données envoyées: " . json_encode($odoo_lead_data));
return;
}
$new_lead_id = $create_result['result'] ?? 0;
if ($new_lead_id) {
error_log("Lead Odoo créé avec succès. ID: " . $new_lead_id . " pour le formulaire: " . $form_title);
} else {
error_log("Échec de la création du lead Odoo. Réponse: " . $create_body . " Données envoyées: " . json_encode($odoo_lead_data));
}
});
JavaScript : Synchronisation Odoo (Placeholder Client)
Ce script est un exemple de ce qui pourrait être fait côté client. La logique principale d'envoi à Odoo est gérée par le PHP ci-dessus. Ce JS client peut améliorer l'UX, par exemple en désactivant le bouton d'envoi après un clic pour éviter les soumissions multiples.
// Code JavaScript côté client pour interagir avec Fluent Snippet / Odoo.
// Ce script peut être utilisé pour des validations de formulaire avant envoi,
// l'affichage de messages de statut, ou d'autres interactions utilisateur.
// La logique principale de transmission des données à Odoo est gérée côté serveur (PHP).
console.log("Placeholder pour le script JS de synchronisation Odoo (côté client).");
// Exemple : Désactiver le bouton de soumission après un clic pour éviter les doubles envois.
/*
const odooForm = document.querySelector('#form-cf7-odoo'); // Sélecteur à adapter au formulaire CF7
if (odooForm) {
odooForm.addEventListener('submit', function(e) {
// Il est préférable de gérer la désactivation via l'événement 'wpcf7submit' de CF7
// pour s'assurer que la validation CF7 a eu lieu.
});
}
document.addEventListener( 'wpcf7submit', function( event ) {
const formIdCible = '2505'; // ID du formulaire CF7 à cibler pour la désactivation du bouton
if ( event.detail.contactFormId == formIdCible ) { // Adaptez l'ID si nécessaire
const submitButton = event.target.querySelector('input[type="submit"]');
if (submitButton) {
submitButton.disabled = true;
submitButton.value = 'Envoi en cours...';
}
}
}, false );
*/
CSS Additionnel (Extrait Représentatif)
L'ensemble du CSS additionnel (plus de 152 lignes) est inclus dans le fichier css/style.css
. Il contient des styles pour WPBakery, des cartes d'articles, des listes personnalisées, etc. Voici un extrait :
/* === Style de la carte WPBakery (Post Grid) === */
.vc_grid-item-mini {
background: #ffffff;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
transition: transform 0.2s ease, box-shadow 0.2s ease;
overflow: hidden;
display: flex;
flex-direction: column;
height: 100%; /* Assure que les cartes ont la même hauteur dans une grille */
}
.vc_grid-item-mini .vc_gitem-zone-a { /* Zone image */
border-top-left-radius: 8px;
border-top-right-radius: 8px;
overflow: hidden;
aspect-ratio: 16 / 9; /* Maintient un ratio pour l'image */
}
.vc_grid-item-mini .vc_gitem-zone-a img {
width: 100%;
height: 100%;
object-fit: cover; /* Assure que l'image couvre la zone */
}
.vc_grid-item-mini .vc_gitem-zone-c { /* Zone contenu */
padding: 20px;
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.vc_grid-item-mini h4 { /* Titre de la carte */
margin-bottom: 12px;
font-weight: 600; /* semi-bold */
line-height: 1.4;
font-size: 1.15rem;
color: #333;
}
.vc_gitem-post-data-source-post_excerpt p { /* Extrait */
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3; /* Limite à 3 lignes */
overflow: hidden;
margin-bottom: 16px;
color: #555;
font-size: 0.95rem;
line-height: 1.6;
flex-grow: 1; /* Permet à l'extrait de prendre l'espace disponible */
}
.vc_grid-item-mini .vc_btn3-container a { /* Bouton "Lire la suite" */
align-self: flex-start;
padding: 0.5em 1em;
border-radius: 6px;
background-color: #0ea5e9; /* sky-500 */
color: white;
text-decoration: none;
font-weight: 500;
transition: background-color 0.2s ease;
}
.vc_grid-item-mini .vc_btn3-container a:hover {
background-color: #0284c7; /* sky-600 */
}
.vc_grid-item-mini:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
}
/* ... (plus de styles dans css/style.css) ... */