>

Introduction: Le Défi des Développeurs WooCommerce

Vous développez pour WooCommerce depuis quelque temps? Alors vous connaissez ce sentiment: vous cherchez LE hook parfait, vous scrollez dans la documentation officielle, mais vous n’arrivez pas à trouver rapidement ce que vous cherchez.

WooCommerce c’est plus de 1000 hooks et fonctions dispersées dans le code source. C’est puissant, oui. Mais c’est aussi compliqué à naviguer.

Le problème

La solution

Créer votre propre documentation structurée, catégorisée, avec exemples pratiques. Et l’automatiser au maximum!

C’est ce que nous allons explorer ensemble dans cet article. À la fin, vous saurez comment générer une documentation professionnelle de 1000+ pages en quelques secondes.

1. Avant de Commencer: Planification et Décisions

Avant de vous lancer dans la rédaction (ou plutôt dans l’automatisation), prenons un moment pour bien comprendre ce que vous voulez créer.

Quelle est votre audience?

Question fondamentale: Pour qui créez-vous cette documentation?

À Condorito.fr, nous avons choisi: développeurs WordPress/WooCommerce de niveau intermédiaire à avancé.

Quels éléments inclure?

Chaque page devrait contenir:

Optionnel mais très utile:

Choisir votre version de WooCommerce

Soyez explicite: « Cette documentation couvre WooCommerce 10.2.2 »

Pourquoi? Parce que les hooks changent entre les versions. Un hook retiré à la v11 ne doit pas être documenté si vous ciblez la v10.

// Dans votre configuration
WC_VERSION = "10.2.2"
GITHUB_REPO_URL = f"https://github.com/woocommerce/woocommerce/blob/{WC_VERSION}/plugins"

2. Comprendre les Hooks WooCommerce: Les Bases

Avant d’extraire, il faut comprendre ce qu’on extrait.

Les Trois Types de Hooks

1. Les Hooks d’Action (do_action)

// Dans le code WooCommerce (exemple simplifié)
do_action('woocommerce_new_order', $order_id);

// Votre code (injection)
add_action('woocommerce_new_order', 'ma_fonction', 10, 1);

function ma_fonction($order_id) {
    // Faire quelque chose après création de commande
    error_log("Nouvelle commande: " . $order_id);
}

Analogie: Un événement radio. WooCommerce crie « une commande a été créée! », et vous pouvez écouter cet événement et réagir.

2. Les Hooks de Filtre (apply_filters)

// Dans le code WooCommerce
$total = apply_filters('woocommerce_cart_total', $total);

// Votre code (modification)
add_filter('woocommerce_cart_total', 'modifier_total_panier', 10, 1);

function modifier_total_panier($total) {
    // Appliquer une remise personnalisée
    if (is_user_logged_in() && current_user_can('wholesale')) {
        return $total * 0.8; // -20%
    }
    return $total;
}

Analogie: Un tuyau d’eau. WooCommerce envoie une valeur, vous la modifiez, vous la renvoyez transformée.

3. Les Fonctions Publiques

// Fonction disponible n'importe où
$product = wc_get_product(42);

// Utilisation basique
if ($product) {
    echo $product->get_name(); // Affiche le nom du produit
}

Analogie: Une boîte à outils. Vous appelez une fonction, elle retourne un résultat.

La Différence: Hooks vs Fonctions

Aspect Hook Fonction
Quand l’utiliser Intervenir au bon moment Récupérer/modifier des données
Exemple woocommerce_new_order wc_get_order()
Syntaxe add_action() / add_filter() Appel direct
Timing À un moment spécifique N’importe quand

3. Architecture: Comment Tout Fonctionne Ensemble

Avant de coder, voyons le big picture. Voici comment se structure une documentation WooCommerce auto-générée:

├── Documentation Source
│   ├── Code WooCommerce (PHP)
│   ├── Fichier d'exemples (JSON)
│   └── Configuration (Python)
│
├── Traitement (Python Scripts)
│   ├── PHPParser (extraction)
│   ├── HTMLGenerator (génération)
│   └── Optimisations (traduction, SEO)
│
└── Documentation HTML (sortie)
    ├── index.html (page d'accueil)
    ├── hook-name.html (pages individuelles)
    ├── tag-category.html (pages par catégorie)
    └── all.html (liste complète)

Flux général

  1. Parser le code source WooCommerce → Extraire hooks/fonctions
  2. Enrichir avec exemples (fichier JSON)
  3. Assigner des tags/catégories
  4. Générer pages HTML individuelles
  5. Créer index, pages de tags, moteur de recherche
  6. Publier en ligne

Élégant, non?

4. Étape 1: Extraire les Hooks avec PHPParser

C’est le cœur du système. On va parser le code PHP de WooCommerce et en extraire tous les hooks.

Comment Fonctionne le Parser

Le principe est simple: utiliser des expressions régulières (regex) pour trouver les patterns.

// Pattern pour trouver do_action (hooks d'action)
action_pattern = r'do_action\s*\(\s*[\'"]([^\'"]+)[\'"]\s*(?:,\s*(.+?))?\s*\)'

// Ce qu'il cherche:
// do_action('hook_name', $param1, $param2)
// do_action("hook_name", $var)
// do_action( 'hook_name' )

Ce que le regex fait:

Résultat:

Extraction des Métadonnées

Pour chaque hook trouvé, on extrait aussi:

class PHPParser:
    def parse_file(self, file_path):
        # Pour chaque match regex trouvé:
        self.items.append({
            'type': 'action',
            'name': 'woocommerce_new_order',
            'file': 'includes/class-wc-order.php',
            'line': 342,
            'params': '$order_id',
            'docblock': '/** ... */',
        })

Code Complet: Le PHPParser

import re
import os

class PHPParser:
    def __init__(self, source_dir):
        self.source_dir = source_dir
        self.items = []
    
    def parse_directory(self):
        """Parcourt tous les fichiers PHP"""
        for root, dirs, files in os.walk(self.source_dir):
            dirs[:] = [d for d in dirs if d not in ['vendor', 'node_modules', '.git']]
            
            for file in files:
                if file.endswith('.php'):
                    file_path = os.path.join(root, file)
                    self.parse_file(file_path)
        
        return self.items
    
    def parse_file(self, file_path):
        """Extrait hooks et fonctions d'un fichier"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
        except:
            return
        
        relative_path = os.path.relpath(file_path, self.source_dir)
        
        # EXTRAIRE do_action (HOOKS D'ACTION)
        action_pattern = r'do_action\s*\(\s*[\'"]([^\'"]+)[\'"]\s*(?:,\s*(.+?))?\s*\)'
        
        for match in re.finditer(action_pattern, content):
            hook_name = match.group(1)
            params = match.group(2) if match.group(2) else ""
            
            self.items.append({
                'type': 'action',
                'name': hook_name,
                'file': relative_path,
                'params': params.strip(),
                'docblock': self.extract_docblock(content, match.start()),
                'line': content[:match.start()].count('\n') + 1
            })
        
        # EXTRAIRE apply_filters (HOOKS DE FILTRE)
        filter_pattern = r'apply_filters\s*\(\s*[\'"]([^\'"]+)[\'"]\s*(?:,\s*(.+?))?\s*\)'
        
        for match in re.finditer(filter_pattern, content):
            hook_name = match.group(1)
            params = match.group(2) if match.group(2) else ""
            
            self.items.append({
                'type': 'filter',
                'name': hook_name,
                'file': relative_path,
                'params': params.strip(),
                'docblock': self.extract_docblock(content, match.start()),
                'line': content[:match.start()].count('\n') + 1
            })
        
        # EXTRAIRE FONCTIONS PUBLIQUES
        func_pattern = r'(public\s+|static\s+)*function\s+([a-zA-Z_]\w*)\s*\((.*?)\)'
        
        for match in re.finditer(func_pattern, content, re.DOTALL):
            func_name = match.group(2)
            params = match.group(3)
            
            if func_name.startswith('_'):
                continue
            
            self.items.append({
                'type': 'function',
                'name': func_name,
                'file': relative_path,
                'params': params.strip(),
                'docblock': self.extract_docblock(content, match.start()),
                'line': content[:match.start()].count('\n') + 1
            })
    
    def extract_docblock(self, content, position):
        """Extrait la documentation PHP au-dessus d'un élément"""
        before = content[:position]
        matches = list(re.finditer(r'/\*\*.*?\*/', before, re.DOTALL))
        return matches[-1].group(0) if matches else ""


# Utilisation
if __name__ == "__main__":
    parser = PHPParser("./woocommerce")
    items = parser.parse_directory()
    print(f"Found {len(items)} items")
    
    for item in items[:5]:
        print(f"  - {item['type'].upper()}: {item['name']}")

Output:

Found 4621 items
  - ACTION: woocommerce_new_order
  - ACTION: woocommerce_order_status_changed
  - FILTER: woocommerce_cart_item_price
  - FILTER: woocommerce_product_get_price
  - FUNCTION: wc_get_order

Voilà. Vous avez maintenant une liste structurée de tous les hooks.

5. Étape 2: Enrichir avec des Exemples Pratiques

Une liste c’est bien. Mais une liste avec des exemples de code contextualisés, c’est infiniment mieux.

Créer le Fichier d’Exemples (JSON)

{
  "woocommerce_new_order": {
    "title": "Nouvelle Commande Créée",
    "description": "Déclenché après la création d'une nouvelle commande. Parfait pour envoyer des notifications personnalisées.",
    "tags": ["order-flow", "technical"],
    "code": "add_action('woocommerce_new_order', 'notifier_nouvelle_commande', 10, 1);\n\nfunction notifier_nouvelle_commande($order_id) {\n    $order = wc_get_order($order_id);\n    $customer_email = $order->get_billing_email();\n    \n    wp_mail(\n        'admin@exemple.com',\n        'Nouvelle commande #' . $order_id,\n        'Total: ' . $order->get_total() . 'EUR'\n    );\n}"
  },
  
  "woocommerce_product_get_price": {
    "title": "Modifier le Prix d'un Produit",
    "description": "Permet de modifier dynamiquement le prix. Idéal pour les remises conditionnelles.",
    "tags": ["pricing", "products"],
    "code": "add_filter('woocommerce_product_get_price', 'prix_grossiste', 10, 2);\n\nfunction prix_grossiste($price, $product) {\n    if (is_user_logged_in() && current_user_can('wholesale')) {\n        return $price * 0.8;\n    }\n    return $price;\n}"
  },
  
  "woocommerce_add_to_cart": {
    "title": "Article Ajouté au Panier",
    "description": "Se déclenche après l'ajout d'un article au panier.",
    "tags": ["cart", "technical"],
    "code": "add_action('woocommerce_add_to_cart', 'tracking_ajout_panier', 10, 6);\n\nfunction tracking_ajout_panier($cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data) {\n    $product = wc_get_product($product_id);\n    error_log(\"Produit ajouté: {$product->get_name()} x{$quantity}\");\n}"
  }
}

Charger les Exemples dans le Generator

import json

class HTMLGenerator:
    def __init__(self, output_dir, examples_file="./woo-examples.json"):
        self.output_dir = output_dir
        self.examples = self.load_examples()
    
    def load_examples(self):
        """Charge les exemples depuis JSON"""
        if os.path.exists(self.examples_file):
            try:
                with open(self.examples_file, 'r', encoding='utf-8') as f:
                    return json.load(f)
            except Exception as e:
                print(f"Erreur chargement exemples: {e}")
                return {}
        return {}
    
    def get_example_metadata(self, hook_name):
        """Récupère titre, description, tags d'un exemple"""
        if hook_name in self.examples:
            example = self.examples[hook_name]
            return {
                'title': example.get('title', ''),
                'description': example.get('description', ''),
                'tags': example.get('tags', []),
            }
        return None

6. Étape 3: Les Tags – Organiser avec Logique

Avec 4600 items, il faut une organisation. Les tags (catégories) sont LA clé.

Les 7 Catégories WooCommerce

Nous avons choisi 7 catégories qui couvrent 95% des use cases:

TAG_CATEGORIES = {
    'order-flow': {
        'icon': 'fa-solid fa-box-open',
        'label': 'Tunnel d\'Achat',
        'description': 'Tout le processus de commande'
    },
    'products': {
        'icon': 'fa-solid fa-boxes-stacked',
        'label': 'Gestion Produits',
        'description': 'Catalogue et variations'
    },
    'cart': {
        'icon': 'fa-solid fa-cart-shopping',
        'label': 'Panier',
        'description': 'Gestion du panier'
    },
    'pricing': {
        'icon': 'fa-solid fa-tag',
        'label': 'Tarification',
        'description': 'Prix et remises'
    },
    'ui': {
        'icon': 'fa-solid fa-display',
        'label': 'Interface',
        'description': 'Messages et formulaires'
    },
    'account': {
        'icon': 'fa-solid fa-user',
        'label': 'Espace Client',
        'description': 'Comptes et profils'
    },
    'technical': {
        'icon': 'fa-solid fa-screwdriver-wrench',
        'label': 'Utilitaires',
        'description': 'Briques techniques'
    }
}

Assigner les Tags dans le JSON

Chaque exemple obtient des tags:

{
  "woocommerce_new_order": {
    "tags": ["order-flow", "technical"],
    ...
  },
  "woocommerce_checkout_fields": {
    "tags": ["ui", "order-flow"],
    ...
  }
}

Logique:

7. Étape 4: Générer les Pages HTML

C’est ici que la magie opère. En quelques secondes, générer 4600 pages HTML.

Code Python pour Générer les Pages

class HTMLGenerator:
    def generate_page(self, item, cross_refs=None):
        """Génère une page HTML pour chaque hook/fonction"""
        
        safe_name = self.sanitize_filename(item['name'])
        filename = f"{safe_name}.html"
        filepath = os.path.join(self.output_dir, filename)
        
        example_meta = self.get_example_metadata(item['name'])
        should_translate = example_meta and example_meta.get('tags')
        
        code_example = self.generate_code_example(item)
        
        html_content = f"""<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <title>{item['name']} - Documentation WooCommerce</title>
    <link rel="stylesheet" href="../style2.css">
</head>
<body>
    {self.get_header(item['name'], breadcrumb)}
    
    <div>
        <h1>{item['name']}</h1>
        
        <div>
            <span>{item['type'].upper()}</span>
            <span>{item['file']} (ligne {item.get('line', '?')})</span>
        </div>
        
        <div>
            {self.format_docblock(item['docblock'], should_translate)}
        </div>
        
        <div>
            <h2>Paramètres</h2>
            {self.extract_params_from_docblock(item['docblock'], should_translate)}
        </div>
        
        <div>
            <h2>Exemple</h2>
            <pre>{code_example}</pre>
        </div>
    </div>
    
    {self.get_footer()}
</body>
</html>"""
        
        with open(filepath, 'w', encoding='utf-8') as f:
            f.write(html_content)
        
        return filepath


# Utilisation
if __name__ == "__main__":
    generator = HTMLGenerator("./output")
    
    for i, item in enumerate(items, 1):
        generator.generate_page(item)
        if i % 100 == 0:
            print(f"{i}/4621 pages générées...")
    
    print("Documentation générée!")

Performance:

8. Optimisations Majeures

Traduction Intelligente: Économiser 70% de Crédits API

WooCommerce étant anglophone, vous voudrez peut-être traduire les descriptions. Mais attention aux coûts.

Problème: Traduire 4600 items = coûts énormes

Solution: Traduire SEULEMENT les items avec exemples (les taggés)

def format_translated_content(self, original_text, should_translate=True):
    """Formate le contenu avec traduction optionnelle"""
    
    if not original_text:
        return ""
    
    if should_translate:
        translated = translate_to_french(original_text)
    else:
        translated = original_text
    
    if not should_translate:
        return f"<div><pre>{original_text}</pre></div>"
    
    return f"""
    <div><pre>{original_text}</pre></div>
    <details>
        <summary>traduction française</summary>
        <pre>{translated}</pre>
    </details>
    """

Résultat:

Moteur de Recherche Instantané

Générer un index JSON pour une recherche au clavier:

def generate_search_index(self, items):
    """Génère un index de recherche en JSON"""
    
    search_data = []
    for item in items:
        search_data.append({
            'name': item['name'],
            'type': item['type'],
            'url': f"{self.sanitize_filename(item['name'])}.html",
            'tags': self.get_example_metadata(item['name']).get('tags', [])
        })
    
    with open(os.path.join(self.output_dir, 'search-index.json'), 'w') as f:
        json.dump(search_data, f)

SEO: Sitemap et Meta Descriptions

def generate_sitemap(self, items, base_url):
    """Génère sitemap.xml pour le référencement"""
    
    xml = '<?xml version="1.0" encoding="UTF-8"?>\n'
    xml += '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
    
    for item in items:
        safe_name = self.sanitize_filename(item['name'])
        xml += f"""
    <url>
        <loc>{base_url}/docs/{safe_name}.html</loc>
        <lastmod>{date.today()}</lastmod>
        <priority>0.8</priority>
    </url>
    """
    
    xml += '</urlset>'
    
    with open(os.path.join(self.output_dir, 'sitemap.xml'), 'w') as f:
        f.write(xml)

9. L’Interface Utilisateur: Un Design Professionnel

Votre documentation doit être belle. C’est du code, pas un PDF.

Palette Couleurs WooCommerce

:root {
    --primary: #e0040b;
    --secondary: #fc5130;
    --dark: #2c3e50;
    --light: #ecf0f1;
}

.hero-intro {
    background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
    color: white;
    padding: 5rem 2rem;
    text-align: center;
}

.tag-card {
    background: white;
    border: 1px solid #e0e0e0;
    border-top: 4px solid var(--primary);
    border-radius: 15px;
    padding: 2rem;
    transition: transform 0.3s;
}

.tag-card:hover {
    transform: translateY(-8px);
    box-shadow: 0 15px 40px rgba(224, 4, 11, 0.2);
}

Responsive Design Mobile

@media (max-width: 768px) {
    .tags-grid {
        grid-template-columns: 1fr;
    }
    
    .hero-intro h1 {
        font-size: 2rem;
    }
    
    .tag-card {
        padding: 1.5rem;
    }
}

10. Mise en Production: Publier Votre Documentation

Où Héberger?

Options recommandées:

1. Netlify/Vercel (gratuit, facile)

netlify deploy --prod --dir ./output

2. GitHub Pages (gratuit)

git add output/
git commit -m "Update docs"
git push

3. Votre serveur (plus de contrôle)

scp -r ./output/* user@server:/var/www/docs/

Automatiser la Génération

Créer un script qui se déclenche tous les mois:

#!/bin/bash
# regenerate-docs.sh

cd /home/docs
python3 doc-gen21.py

git add output/
git commit -m "Auto-generated docs - $(date)"
git push origin main

Cron job:

0 0 1 * * /home/docs/regenerate-docs.sh >> /home/docs/cron.log 2>&1

11. Résultats et Métriques

Avant vs Après

Aspect Avant Après
Trouver LE hook 15-30 min < 1 min
Nombre de pages 0 4600+
Exemples 0 500+
Temps de dev +30 min/tâche -10 min/tâche

Métriques Réelles (Condorito.fr)

Pages générées: 4,621
Temps de génération: 28 secondes
Taille totale: 145 MB
Hooks avec exemples: 523 (11%)
Traductions sauvegardées: 4,098 (89% d'économie API!)

Trafic mensuel: ~8,500 visiteurs
Pages les plus consultées:
  1. woocommerce_new_order
  2. woocommerce_product_get_price
  3. wc_get_order
  4. woocommerce_add_to_cart
  5. woocommerce_checkout_fields

Temps moyen sur site: 3:45 min
Taux de rebond: 22%

Conclusion: C’est à Votre Tour

Créer une documentation complète de WooCommerce paraît compliqué au premier abord. Mais avec l’approche étape par étape que nous venons de voir, c’est étonnamment accessible.

Récapitulatif des étapes

  1. Parser le code source avec regex
  2. Enrichir avec exemples en JSON
  3. Catégoriser avec des tags logiques
  4. Générer les pages HTML automatiquement
  5. Optimiser (traduction, SEO, recherche)
  6. Designer une UI professionnelle
  7. Publier et maintenir

Bénéfices Concrets

Prochaines Étapes

Vous voulez la mettre en place? Récupérez le script, adaptez aux vos besoins, ajoutez vos propres exemples, et publiez.

Des questions? Commentez ci-dessous ou contactez-nous directement. Rejoignez notre newsletter pour les mises à jour.