Sélectionner une page

Guide Complet : Création d’un Thème WordPress 6.8.2 Compatible Divi

Table des Matières

  1. Prérequis et Préparation
  2. Structure de Base du Thème
  3. Configuration pour WordPress 6.8.2
  4. Compatibilité Divi
  5. Fichiers de Template
  6. CSS et Styles
  7. JavaScript et Interactions
  8. Optimisation et Performance
  9. Tests et Débogage
  10. Déploiement

Prérequis et Préparation

Environnement de Développement

Outils nécessaires :

  • WordPress 6.8.2 en local (Local WP, XAMPP, ou WAMP)
  • Éditeur de code (VS Code, Sublime Text, PHPStorm)
  • Navigateur avec outils de développement
  • Plugin Divi ou thème Divi installé
  • PHP 8.0+ (recommandé pour WordPress 6.8.2)

Extensions VS Code recommandées :

  • PHP Intelephense
  • WordPress Snippets
  • Auto Rename Tag
  • Bracket Pair Colorizer
  • GitLens

Configuration WordPress

// wp-config.php - Configuration de développement
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
define('SCRIPT_DEBUG', true);
define('SAVEQUERIES', true);

Structure de Base du Thème

Architecture des Dossiers

mon-theme-divi/
├── style.css                 # Fichier principal (obligatoire)
├── index.php                 # Template principal (obligatoire)
├── functions.php             # Fonctions du thème
├── screenshot.png            # Capture d'écran du thème (1200x900px)
├── readme.txt                # Documentation du thème
├── theme.json                # Configuration moderne WordPress
├── 
├── assets/                   # Ressources statiques
│   ├── css/
│   │   ├── admin.css
│   │   ├── blocks.css
│   │   ├── divi-compatibility.css
│   │   └── responsive.css
│   ├── js/
│   │   ├── admin.js
│   │   ├── divi-integration.js
│   │   ├── main.js
│   │   └── customizer.js
│   ├── images/
│   │   ├── logo.png
│   │   └── placeholder.jpg
│   └── fonts/
│       └── custom-fonts.woff2
├── 
├── inc/                      # Fichiers d'inclusion
│   ├── class-theme-setup.php
│   ├── divi-compatibility.php
│   ├── customizer.php
│   ├── template-functions.php
│   ├── security.php
│   └── performance.php
├── 
├── templates/                # Templates de blocs (WordPress 6.8+)
│   ├── index.html
│   ├── single.html
│   ├── page.html
│   └── archive.html
├── 
├── parts/                    # Parties de templates
│   ├── header.html
│   ├── footer.html
│   └── navigation.html
├── 
├── patterns/                 # Motifs de blocs
│   ├── hero-section.php
│   ├── call-to-action.php
│   └── testimonials.php
├── 
├── template-parts/           # Parties de templates PHP
│   ├── header/
│   │   ├── site-header.php
│   │   └── navigation.php
│   ├── footer/
│   │   └── site-footer.php
│   └── content/
│       ├── content-single.php
│       ├── content-page.php
│       └── content-archive.php
├── 
├── page-templates/           # Templates de pages personnalisées
│   ├── page-landing.php
│   ├── page-contact.php
│   └── page-portfolio.php
├── 
└── languages/                # Fichiers de traduction
    ├── mon-theme.pot
    ├── fr_FR.po
    └── fr_FR.mo

Configuration pour WordPress 6.8.2

style.css – En-tête du Thème

/*
Theme Name: Mon Thème Divi Compatible
Theme URI: https://example.com/themes/mon-theme-divi
Description: Un thème WordPress moderne compatible avec Divi, optimisé pour WordPress 6.8.2. Inclut le support complet des blocs Gutenberg, des couleurs globales, et une intégration transparente avec le Divi Builder.
Author: Votre Nom
Author URI: https://example.com
Version: 1.0.0
Requires at least: 6.1
Tested up to: 6.8
Requires PHP: 8.0
License: GPL v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: mon-theme-divi
Domain Path: /languages
Tags: divi-compatible, block-theme, responsive, accessibility-ready, translation-ready

This theme, like WordPress, is licensed under the GPL.
Use it to make something cool, have fun, and share what you've learned.
*/

/* Reset CSS moderne */
*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    line-height: 1.15;
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
    background-color: var(--wp--preset--color--white);
    color: var(--wp--preset--color--black);
}

functions.php – Configuration Principale

<?php
/**
 * Fonctions et définitions du thème Mon Thème Divi Compatible
 *
 * @package MonThemeDivi
 * @version 1.0.0
 */

// Sécurité : Empêcher l'accès direct
if (!defined('ABSPATH')) {
    exit;
}

// Constantes du thème
define('THEME_VERSION', '1.0.0');
define('THEME_NAME', 'mon-theme-divi');
define('THEME_PATH', get_template_directory());
define('THEME_URL', get_template_directory_uri());

/**
 * Configuration principale du thème
 */
class MonThemeDivi_Setup {

    /**
     * Constructeur
     */
    public function __construct() {
        add_action('after_setup_theme', array($this, 'theme_setup'));
        add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
        add_action('enqueue_block_editor_assets', array($this, 'block_editor_assets'));
        add_action('init', array($this, 'init_theme'));
        add_action('widgets_init', array($this, 'widgets_init'));
    }

    /**
     * Configuration du thème
     */
    public function theme_setup() {
        // Support de la traduction
        load_theme_textdomain('mon-theme-divi', THEME_PATH . '/languages');

        // Support des fonctionnalités WordPress 6.8.2
        add_theme_support('title-tag');
        add_theme_support('post-thumbnails');
        add_theme_support('automatic-feed-links');
        add_theme_support('html5', array(
            'search-form',
            'comment-form',
            'comment-list',
            'gallery',
            'caption',
            'style',
            'script',
            'navigation-widgets'
        ));

        // Support personnalisé pour WordPress 6.8.2
        add_theme_support('custom-background');
        add_theme_support('custom-header', array(
            'default-image' => '',
            'width' => 1200,
            'height' => 300,
            'flex-width' => true,
            'flex-height' => true,
        ));
        add_theme_support('custom-logo', array(
            'height' => 100,
            'width' => 400,
            'flex-width' => true,
            'flex-height' => true,
        ));

        // Support avancé de l'éditeur de blocs Gutenberg
        add_theme_support('wp-block-styles');
        add_theme_support('responsive-embeds');
        add_theme_support('editor-styles');
        add_theme_support('align-wide');
        add_theme_support('align-full');
        add_theme_support('custom-spacing');
        add_theme_support('custom-units');
        add_theme_support('link-color');
        add_theme_support('border');

        // Palette de couleurs globales
        add_theme_support('editor-color-palette', array(
            array(
                'name' => __('Primaire', 'mon-theme-divi'),
                'slug' => 'primary',
                'color' => '#2271b1',
            ),
            array(
                'name' => __('Secondaire', 'mon-theme-divi'),
                'slug' => 'secondary',
                'color' => '#72aee6',
            ),
            array(
                'name' => __('Accent', 'mon-theme-divi'),
                'slug' => 'accent',
                'color' => '#d63638',
            ),
            array(
                'name' => __('Neutre Foncé', 'mon-theme-divi'),
                'slug' => 'neutral-dark',
                'color' => '#1d2327',
            ),
            array(
                'name' => __('Neutre Clair', 'mon-theme-divi'),
                'slug' => 'neutral-light',
                'color' => '#f6f7f7',
            ),
        ));

        // Tailles de police personnalisées
        add_theme_support('editor-font-sizes', array(
            array(
                'name' => __('Petit', 'mon-theme-divi'),
                'size' => 14,
                'slug' => 'small'
            ),
            array(
                'name' => __('Normal', 'mon-theme-divi'),
                'size' => 16,
                'slug' => 'normal'
            ),
            array(
                'name' => __('Moyen', 'mon-theme-divi'),
                'size' => 20,
                'slug' => 'medium'
            ),
            array(
                'name' => __('Grand', 'mon-theme-divi'),
                'size' => 24,
                'slug' => 'large'
            ),
            array(
                'name' => __('Très Grand', 'mon-theme-divi'),
                'size' => 32,
                'slug' => 'x-large'
            ),
        ));

        // Support DIVI - Configuration avancée
        if (function_exists('et_setup_theme')) {
            add_theme_support('divi-builder');
            add_theme_support('divi-modules');
            add_theme_support('divi-visual-builder');
            add_theme_support('divi-library');
        }

        // Enregistrement des menus
        register_nav_menus(array(
            'primary' => __('Menu Principal', 'mon-theme-divi'),
            'footer' => __('Menu Pied de Page', 'mon-theme-divi'),
            'social' => __('Menu Réseaux Sociaux', 'mon-theme-divi'),
        ));

        // Tailles d'images personnalisées
        add_image_size('hero-large', 1920, 1080, true);
        add_image_size('card-medium', 600, 400, true);
        add_image_size('thumbnail-small', 300, 200, true);
    }

    /**
     * Chargement des scripts et styles
     */
    public function enqueue_scripts() {
        // Détection de Divi
        $is_divi_active = function_exists('et_setup_theme');
        $is_divi_builder_page = $is_divi_active && function_exists('et_divi_is_builder_page') && et_divi_is_builder_page();

        // CSS principal
        wp_enqueue_style(
            'mon-theme-style',
            get_stylesheet_uri(),
            array(),
            THEME_VERSION
        );

        // CSS spécifique aux blocs
        wp_enqueue_style(
            'mon-theme-blocks',
            THEME_URL . '/assets/css/blocks.css',
            array('wp-block-library'),
            THEME_VERSION
        );

        // CSS de compatibilité Divi (seulement si Divi est actif)
        if ($is_divi_active) {
            wp_enqueue_style(
                'mon-theme-divi-compat',
                THEME_URL . '/assets/css/divi-compatibility.css',
                array(),
                THEME_VERSION
            );
        }

        // CSS responsive
        wp_enqueue_style(
            'mon-theme-responsive',
            THEME_URL . '/assets/css/responsive.css',
            array('mon-theme-style'),
            THEME_VERSION
        );

        // JavaScript principal
        wp_enqueue_script(
            'mon-theme-main',
            THEME_URL . '/assets/js/main.js',
            array('jquery'),
            THEME_VERSION,
            array('strategy' => 'defer') // Nouvelle syntaxe WordPress 6.8
        );

        // JavaScript d'intégration Divi
        if ($is_divi_active) {
            wp_enqueue_script(
                'mon-theme-divi-integration',
                THEME_URL . '/assets/js/divi-integration.js',
                array('jquery', 'divi-custom-script'),
                THEME_VERSION,
                array('strategy' => 'defer')
            );
        }

        // Variables JavaScript
        wp_localize_script('mon-theme-main', 'MonThemeAjax', array(
            'ajaxurl' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('mon_theme_nonce'),
            'isDivi' => $is_divi_active,
            'isBuilder' => $is_divi_builder_page,
        ));

        // Support des commentaires
        if (is_singular() && comments_open() && get_option('thread_comments')) {
            wp_enqueue_script('comment-reply');
        }
    }

    /**
     * Assets pour l'éditeur de blocs
     */
    public function block_editor_assets() {
        wp_enqueue_style(
            'mon-theme-editor',
            THEME_URL . '/assets/css/editor.css',
            array('wp-edit-blocks'),
            THEME_VERSION
        );

        wp_enqueue_script(
            'mon-theme-editor-js',
            THEME_URL . '/assets/js/editor.js',
            array('wp-blocks', 'wp-dom-ready', 'wp-edit-post'),
            THEME_VERSION
        );
    }

    /**
     * Initialisation du thème
     */
    public function init_theme() {
        // Optimisations de performance
        remove_action('wp_head', 'print_emoji_detection_script', 7);
        remove_action('admin_print_scripts', 'print_emoji_detection_script');
        remove_action('wp_print_styles', 'print_emoji_styles');
        remove_action('admin_print_styles', 'print_emoji_styles');

        // Support du lazy loading
        add_filter('wp_lazy_loading_enabled', '__return_true');

        // Types de contenu personnalisés
        $this->register_post_types();

        // Taxonomies personnalisées
        $this->register_taxonomies();
    }

    /**
     * Enregistrement des zones de widgets
     */
    public function widgets_init() {
        register_sidebar(array(
            'name' => __('Barre latérale principale', 'mon-theme-divi'),
            'id' => 'sidebar-primary',
            'description' => __('Zone de widgets principale', 'mon-theme-divi'),
            'before_widget' => '<section id="%1$s" class="widget %2$s">',
            'after_widget' => '</section>',
            'before_title' => '<h3 class="widget-title">',
            'after_title' => '</h3>',
        ));

        register_sidebar(array(
            'name' => __('Pied de page 1', 'mon-theme-divi'),
            'id' => 'footer-1',
            'description' => __('Zone de widgets du pied de page 1', 'mon-theme-divi'),
            'before_widget' => '<section id="%1$s" class="widget %2$s">',
            'after_widget' => '</section>',
            'before_title' => '<h4 class="widget-title">',
            'after_title' => '</h4>',
        ));

        register_sidebar(array(
            'name' => __('Pied de page 2', 'mon-theme-divi'),
            'id' => 'footer-2',
            'description' => __('Zone de widgets du pied de page 2', 'mon-theme-divi'),
            'before_widget' => '<section id="%1$s" class="widget %2$s">',
            'after_widget' => '</section>',
            'before_title' => '<h4 class="widget-title">',
            'after_title' => '</h4>',
        ));
    }

    /**
     * Enregistrement des types de contenu personnalisés
     */
    private function register_post_types() {
        // Portfolio
        register_post_type('portfolio', array(
            'labels' => array(
                'name' => __('Portfolio', 'mon-theme-divi'),
                'singular_name' => __('Projet', 'mon-theme-divi'),
            ),
            'public' => true,
            'has_archive' => true,
            'supports' => array('title', 'editor', 'thumbnail', 'excerpt'),
            'show_in_rest' => true,
        ));
    }

    /**
     * Enregistrement des taxonomies personnalisées
     */
    private function register_taxonomies() {
        // Catégorie de portfolio
        register_taxonomy('portfolio_category', 'portfolio', array(
            'labels' => array(
                'name' => __('Catégories Portfolio', 'mon-theme-divi'),
                'singular_name' => __('Catégorie Portfolio', 'mon-theme-divi'),
            ),
            'hierarchical' => true,
            'public' => true,
            'show_in_rest' => true,
        ));
    }
}

// Initialisation du thème
new MonThemeDivi_Setup();

// Inclusion des fichiers auxiliaires
require_once THEME_PATH . '/inc/divi-compatibility.php';
require_once THEME_PATH . '/inc/customizer.php';
require_once THEME_PATH . '/inc/template-functions.php';
require_once THEME_PATH . '/inc/security.php';
require_once THEME_PATH . '/inc/performance.php';

Compatibilité Divi

inc/divi-compatibility.php

<?php
/**
 * Compatibilité avec Divi
 *
 * @package MonThemeDivi
 */

// Sécurité
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Classe de compatibilité Divi
 */
class MonThemeDivi_Compatibility {

    /**
     * Constructeur
     */
    public function __construct() {
        add_action('init', array($this, 'init'));
        add_action('wp', array($this, 'conditional_hooks'));
        add_filter('body_class', array($this, 'add_body_classes'));
        add_action('wp_head', array($this, 'divi_compatibility_css'));
    }

    /**
     * Initialisation
     */
    public function init() {
        if ($this->is_divi_active()) {
            $this->setup_divi_hooks();
            $this->setup_divi_filters();
        }
    }

    /**
     * Vérifier si Divi est actif
     */
    public function is_divi_active() {
        return function_exists('et_setup_theme');
    }

    /**
     * Vérifier si c'est une page Divi Builder
     */
    public function is_divi_builder_page() {
        return $this->is_divi_active() && function_exists('et_divi_is_builder_page') && et_divi_is_builder_page();
    }

    /**
     * Configuration des hooks Divi
     */
    private function setup_divi_hooks() {
        // Hooks d'en-tête
        add_action('et_header_top', array($this, 'custom_header_top'));
        add_action('et_before_main_content', array($this, 'before_main_content'));
        add_action('et_after_main_content', array($this, 'after_main_content'));

        // Hooks de pied de page
        add_action('et_footer_top', array($this, 'custom_footer_top'));

        // Hooks du builder
        add_action('et_builder_ready', array($this, 'register_custom_modules'));
        add_action('et_builder_framework_loaded', array($this, 'builder_framework_loaded'));
    }

    /**
     * Configuration des filtres Divi
     */
    private function setup_divi_filters() {
        // Modifier les options de page Divi
        add_filter('et_divi_page_options', array($this, 'modify_page_options'));

        // Modifier les layouts Divi
        add_filter('et_divi_force_layout', array($this, 'force_custom_layout'));

        // Modifier les styles Divi
        add_filter('et_divi_builder_styles', array($this, 'modify_builder_styles'));

        // Modifier le contenu des modules
        add_filter('et_module_shortcode_output', array($this, 'modify_module_output'), 10, 3);
    }

    /**
     * Hooks conditionnels selon le contexte
     */
    public function conditional_hooks() {
        if ($this->is_divi_builder_page()) {
            // Désactiver certains éléments sur les pages Divi
            remove_action('wp_head', 'wp_generator');
            add_filter('show_admin_bar', '__return_false');
        }
    }

    /**
     * Ajouter des classes CSS au body
     */
    public function add_body_classes($classes) {
        if ($this->is_divi_active()) {
            $classes[] = 'divi-compatible-theme';
        }

        if ($this->is_divi_builder_page()) {
            $classes[] = 'divi-builder-active';
        }

        return $classes;
    }

    /**
     * En-tête personnalisé pour Divi
     */
    public function custom_header_top() {
        // Code d'en-tête personnalisé
        echo '<div class="custom-header-element">';
        // Votre contenu personnalisé
        echo '</div>';
    }

    /**
     * Avant le contenu principal
     */
    public function before_main_content() {
        echo '<div class="theme-main-wrapper">';
    }

    /**
     * Après le contenu principal
     */
    public function after_main_content() {
        echo '</div><!-- .theme-main-wrapper -->';
    }

    /**
     * Pied de page personnalisé pour Divi
     */
    public function custom_footer_top() {
        // Code de pied de page personnalisé
        echo '<div class="custom-footer-element">';
        // Votre contenu personnalisé
        echo '</div>';
    }

    /**
     * Modifier les options de page Divi
     */
    public function modify_page_options($options) {
        global $post;

        if (is_front_page()) {
            $options['hide_nav'] = 'off';
            $options['show_title'] = 'off';
        }

        // Options spécifiques par template
        if (is_page_template('page-landing.php')) {
            $options['hide_nav'] = 'on';
            $options['hide_footer'] = 'on';
        }

        return $options;
    }

    /**
     * Forcer un layout personnalisé
     */
    public function force_custom_layout($layout_id) {
        if (is_single() && get_post_type() === 'portfolio') {
            // Retourner l'ID d'un layout Divi spécifique pour les portfolios
            return get_theme_mod('portfolio_divi_layout', $layout_id);
        }

        return $layout_id;
    }

    /**
     * Modifier les styles du builder
     */
    public function modify_builder_styles($styles) {
        // Ajouter des styles personnalisés au builder
        $custom_styles = '
            .et_pb_section.custom-section {
                background-color: var(--wp--preset--color--primary);
            }
        ';

        return $styles . $custom_styles;
    }

    /**
     * Modifier la sortie des modules
     */
    public function modify_module_output($output, $render_slug, $module) {
        // Exemple : Modifier tous les modules de texte
        if ($render_slug === 'et_pb_text') {
            $output = '<div class="custom-text-wrapper">' . $output . '</div>';
        }

        return $output;
    }

    /**
     * Enregistrer des modules personnalisés
     */
    public function register_custom_modules() {
        if (class_exists('ET_Builder_Module')) {
            // Inclure vos modules personnalisés ici
            // require_once THEME_PATH . '/inc/modules/custom-module.php';
        }
    }

    /**
     * Framework du builder chargé
     */
    public function builder_framework_loaded() {
        // Actions à effectuer quand le framework est chargé
    }

    /**
     * CSS de compatibilité dans le head
     */
    public function divi_compatibility_css() {
        if (!$this->is_divi_active()) {
            return;
        }

        ?>
        <style id="divi-compatibility-css">
            /* Styles de compatibilité Divi */
            .divi-compatible-theme .et_pb_section {
                position: relative;
            }

            .divi-compatible-theme .et_pb_row {
                max-width: var(--wp--style--global--content-size, 1080px);
            }

            /* Ajustements pour le Visual Builder */
            .et-db .custom-header-element,
            .et-db .custom-footer-element {
                display: none;
            }

            /* Responsive pour Divi */
            @media (max-width: 980px) {
                .divi-compatible-theme .et_pb_column {
                    margin-bottom: 30px;
                }
            }
        </style>
        <?php
    }
}

// Initialisation de la compatibilité Divi
new MonThemeDivi_Compatibility();

/**
 * Fonctions utilitaires pour Divi
 */

/**
 * Obtenir l'ID d'un layout Divi par nom
 */
function get_divi_layout_id_by_name($layout_name) {
    $layouts = get_posts(array(
        'post_type' => 'et_pb_layout',
        'name' => $layout_name,
        'posts_per_page' => 1,
        'fields' => 'ids'
    ));

    return !empty($layouts) ? $layouts[0] : false;
}

/**
 * Vérifier si un module Divi est actif sur la page
 */
function has_divi_module($module_type, $post_id = null) {
    if (!function_exists('et_setup_theme')) {
        return false;
    }

    $post_id = $post_id ?: get_the_ID();
    $content = get_post_field('post_content', $post_id);

    return strpos($content, '[' . $module_type) !== false;
}

/**
 * Désactiver l'en-tête Divi sur certaines pages
 */
function disable_divi_header_conditionally() {
    if (is_page_template('page-landing.php')) {
        remove_action('et_header_top', 'et_divi_output_header');
    }
}
add_action('template_redirect', 'disable_divi_header_conditionally');

/**
 * Désactiver le pied de page Divi sur certaines pages
 */
function disable_divi_footer_conditionally() {
    if (is_page_template('page-landing.php')) {
        remove_action('et_footer_top', 'et_divi_output_footer');
    }
}
add_action('template_redirect', 'disable_divi_footer_conditionally');

theme.json – Configuration Moderne

{
    "version": 3,
    "settings": {
        "layout": {
            "contentSize": "1080px",
            "wideSize": "1200px"
        },
        "color": {
            "custom": true,
            "customDuotone": true,
            "customGradient": true,
            "defaultDuotones": false,
            "defaultGradients": false,
            "defaultPalette": false,
            "duotone": [],
            "gradients": [
                {
                    "name": "Dégradé Primaire",
                    "gradient": "linear-gradient(135deg, #2271b1 0%, #72aee6 100%)",
                    "slug": "primary-gradient"
                }
            ],
            "palette": [
                {
                    "name": "Primaire",
                    "slug": "primary",
                    "color": "#2271b1"
                },
                {
                    "name": "Secondaire",
                    "slug": "secondary",
                    "color": "#72aee6"
                },
                {
                    "name": "Accent",
                    "slug": "accent",
                    "color": "#d63638"
                },
                {
                    "name": "Neutre Foncé",
                    "slug": "neutral-dark",
                    "color": "#1d2327"
                },
                {
                    "name": "Neutre Clair",
                    "slug": "neutral-light",
                    "color": "#f6f7f7"
                },
                {
                    "name": "Blanc",
                    "slug": "white",
                    "color": "#ffffff"
                },
                {
                    "name": "Noir",
                    "slug": "black",
                    "color": "#000000"
                }
            ]
        },
        "typography": {
            "custom": true,
            "customFontSize": true,
            "fontFamilies": [
                {
                    "name": "Système",
                    "slug": "system",
                    "fontFamily": "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
                }
            ],
            "fontSizes": [
                {
                    "name": "Petit",
                    "slug": "small",
                    "size": "14px"
                },
                {
                    "name": "Normal",
                    "slug": "normal",
                    "size": "16px"
                },
                {
                    "name": "Moyen",
                    "slug": "medium",
                    "size": "20px"
                },
                {
                    "name": "Grand",
                    "slug": "large",
                    "size": "24px"
                },
                {
                    "name": "Très Grand",
                    "slug": "x-large",
                    "size": "32px"
                },
                {
                    "name": "Énorme",
                    "slug": "xx-large",
                    "size": "48px"
                }
            ]
        },
        "spacing": {
            "custom": true,
            "units": ["px", "em", "rem", "vh", "vw", "%"],
            "spacingScale": {
                "steps": 0
            },
            "spacingSizes": [
                {
                    "name": "1",
                    "slug": "10",
                    "size": "10px"
                },
                {
                    "name": "2",
                    "slug": "20",
                    "size": "20px"
                },
                {
                    "name": "3",
                    "slug": "30",
                    "size": "30px"
                },
                {
                    "name": "4",
                    "slug": "40",
                    "size": "40px"
                },
                {
                    "name": "5",
                    "slug": "50",
                    "size": "50px"
                }
            ]
        },
        "border": {
            "custom": true,
            "color": true,
            "radius": true,
            "style": true,
            "width": true
        },
        "dimensions": {
            "custom": true
        },
        "position": {
            "sticky": true
        },
        "custom": {
            "maxWidth": "1200px",
            "contentWidth": "1080px"
        }
    },
    "styles": {
        "color": {
            "background": "var(--wp--preset--color--white)",
            "text": "var(--wp--preset--color--neutral-dark)"
        },
        "typography": {
            "fontFamily": "var(--wp--preset--font-family--system)",
            "fontSize": "var(--wp--preset--font-size--normal)",
            "lineHeight": "1.6"
        },
        "spacing": {
            "blockGap": "30px"
        },
        "elements": {
            "link": {
                "color": {
                    "text": "var(--wp--preset--color--primary)"
                },
                ":hover": {
                    "color": {
                        "text": "var(--wp--preset--color--secondary)"
                    }
                }
            },
            "h1": {
                "typography": {
                    "fontSize": "var(--wp--preset--font-size--xx-large)",
                    "lineHeight": "1.2"
                }
            },
            "h2": {
                "typography": {
                    "fontSize": "var(--wp--preset--font-size--x-large)",
                    "lineHeight": "1.3"
                }
            },
            "h3": {
                "typography": {
                    "fontSize": "var(--wp--preset--font-size--large)",
                    "lineHeight": "1.4"
                }
            },
            "button": {
                "color": {
                    "background": "var(--wp--preset--color--primary)",
                    "text": "var(--wp--preset--color--white)"
                },
                "border": {
                    "radius": "4px"
                },
                "spacing": {
                    "padding": {
                        "top": "12px",
                        "right": "24px",
                        "bottom": "12px",
                        "left": "24px"
                    }
                },
                ":hover": {
                    "color": {
                        "background": "var(--wp--preset--color--secondary)"
                    }
                }
            }
        },
        "blocks": {
            "core/group": {
                "spacing": {
                    "margin": {
                        "top": "0",
                        "bottom": "30px"
                    }
                }
            },
            "core/paragraph": {
                "spacing": {
                    "margin": {
                        "bottom": "20px"
                    }
                }
            }
        }
    },
    "templateParts": [
        {
            "name": "header",
            "title": "En-tête",
            "area": "header"
        },
        {
            "name": "footer",
            "title": "Pied de page",
            "area": "footer"
        }
    ],
    "customTemplates": [
        {
            "name": "page-landing",
            "title": "Page de destination",
            "postTypes": ["page"]
        },
        {
            "name": "single-portfolio",
            "title": "Projet Portfolio",
            "postTypes": ["portfolio"]
        }
    ]
}

Fichiers de Template

index.php

<?php
/**
 * Template principal
 *
 * @package MonThemeDivi
 */

get_header(); ?>

<main id="primary" class="site-main">
    <div class="container">
        <?php if (have_posts()) : ?>

            <?php if (is_home() && !is_front_page()) : ?>
                <header class="page-header">
                    <h1 class="page-title"><?php single_post_title(); ?></h1>
                </header>
            <?php endif; ?>

            <div class="posts-container">
                <?php while (have_posts()) : the_post(); ?>
                    <?php get_template_part('template-parts/content/content', get_post_format()); ?>
                <?php endwhile; ?>
            </div>

            <?php
            the_posts_navigation(array(
                'prev_text' => __('Articles précédents', 'mon-theme-divi'),
                'next_text' => __('Articles suivants', 'mon-theme-divi'),
            ));
            ?>

        <?php else : ?>

            <?php get_template_part('template-parts/content/content', 'none'); ?>

        <?php endif; ?>
    </div>
</main>

<?php
get_sidebar();
get_footer();

header.php

<?php
/**
 * En-tête du site
 *
 * @package MonThemeDivi
 */
?>
<!doctype html>
<html <?php language_attributes(); ?>>
<head>
    <meta charset="<?php bloginfo('charset'); ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="profile" href="https://gmpg.org/xfn/11">

    <?php wp_head(); ?>
</head>

<body <?php body_class(); ?>>
<?php wp_body_open(); ?>

<div id="page" class="site">
    <a class="skip-link screen-reader-text" href="#primary">
        <?php esc_html_e('Aller au contenu principal', 'mon-theme-divi'); ?>
    </a>

    <?php
    // Si Divi est actif et gère l'en-tête, ne pas afficher notre en-tête
    if (function_exists('et_setup_theme') && !get_theme_mod('custom_header_override', false)) :
        // Laisser Divi gérer l'en-tête
    else :
    ?>
        <header id="masthead" class="site-header">
            <div class="container">
                <div class="site-branding">
                    <?php if (has_custom_logo()) : ?>
                        <div class="site-logo">
                            <?php the_custom_logo(); ?>
                        </div>
                    <?php else : ?>
                        <h1 class="site-title">
                            <a href="<?php echo esc_url(home_url('/')); ?>" rel="home">
                                <?php bloginfo('name'); ?>
                            </a>
                        </h1>
                        <?php
                        $description = get_bloginfo('description', 'display');
                        if ($description || is_customize_preview()) :
                        ?>
                            <p class="site-description"><?php echo $description; ?></p>
                        <?php endif; ?>
                    <?php endif; ?>
                </div>

                <nav id="site-navigation" class="main-navigation">
                    <button class="menu-toggle" aria-controls="primary-menu" aria-expanded="false">
                        <span class="screen-reader-text"><?php esc_html_e('Menu principal', 'mon-theme-divi'); ?></span>
                        <span class="hamburger"></span>
                    </button>

                    <?php
                    wp_nav_menu(array(
                        'theme_location' => 'primary',
                        'menu_id' => 'primary-menu',
                        'container' => false,
                        'menu_class' => 'nav-menu',
                        'fallback_cb' => false,
                    ));
                    ?>
                </nav>
            </div>
        </header>
    <?php endif; ?>
</div>

footer.php

<?php
/**
 * Pied de page du site
 *
 * @package MonThemeDivi
 */
?>

    <?php
    // Si Divi est actif et gère le pied de page, ne pas afficher notre pied de page
    if (function_exists('et_setup_theme') && !get_theme_mod('custom_footer_override', false)) :
        // Laisser Divi gérer le pied de page
    else :
    ?>
        <footer id="colophon" class="site-footer">
            <?php if (is_active_sidebar('footer-1') || is_active_sidebar('footer-2')) : ?>
                <div class="footer-widgets">
                    <div class="container">
                        <div class="footer-widgets-grid">
                            <?php if (is_active_sidebar('footer-1')) : ?>
                                <div class="footer-widget-area">
                                    <?php dynamic_sidebar('footer-1'); ?>
                                </div>
                            <?php endif; ?>

                            <?php if (is_active_sidebar('footer-2')) : ?>
                                <div class="footer-widget-area">
                                    <?php dynamic_sidebar('footer-2'); ?>
                                </div>
                            <?php endif; ?>
                        </div>
                    </div>
                </div>
            <?php endif; ?>

            <div class="site-info">
                <div class="container">
                    <div class="site-info-content">

<p>&copy; <?php echo date('Y'); ?> <?php bloginfo('name'); ?>. 
                           <?php esc_html_e('Tous droits réservés.', 'mon-theme-divi'); ?>
                        </p>

                        <?php
                        wp_nav_menu(array(
                            'theme_location' => 'footer',
                            'menu_class' => 'footer-menu',
                            'container' => false,
                            'fallback_cb' => false,
                        ));
                        ?>
                    </div>
                </div>
            </div>
        </footer>
    <?php endif; ?>

</div><!-- #page -->

<?php wp_footer(); ?>

</body>
</html>

single.php

<?php
/**
 * Template pour les articles individuels
 *
 * @package MonThemeDivi
 */

get_header();

// Vérifier si Divi gère cette page
$is_divi_page = function_exists('et_divi_is_builder_page') && et_divi_is_builder_page();
?>

<main id="primary" class="site-main">
    <?php if (!$is_divi_page) : ?>
        <div class="container">
    <?php endif; ?>

    <?php while (have_posts()) : the_post(); ?>

        <?php if ($is_divi_page) : ?>
            <!-- Divi gère le contenu -->
            <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
                <?php the_content(); ?>
            </article>
        <?php else : ?>
            <?php get_template_part('template-parts/content/content', 'single'); ?>
        <?php endif; ?>

        <?php if (!$is_divi_page) : ?>
            <?php
            the_post_navigation(array(
                'prev_text' => '<span class="nav-subtitle">' . esc_html__('Article précédent:', 'mon-theme-divi') . '</span> <span class="nav-title">%title</span>',
                'next_text' => '<span class="nav-subtitle">' . esc_html__('Article suivant:', 'mon-theme-divi') . '</span> <span class="nav-title">%title</span>',
            ));
            ?>

            <?php
            if (comments_open() || get_comments_number()) :
                comments_template();
            endif;
            ?>
        <?php endif; ?>

    <?php endwhile; ?>

    <?php if (!$is_divi_page) : ?>
        </div>
    <?php endif; ?>
</main>

<?php
if (!$is_divi_page) {
    get_sidebar();
}
get_footer();

page.php

<?php
/**
 * Template pour les pages
 *
 * @package MonThemeDivi
 */

get_header();

// Vérifier si Divi gère cette page
$is_divi_page = function_exists('et_divi_is_builder_page') && et_divi_is_builder_page();
?>

<main id="primary" class="site-main">
    <?php if (!$is_divi_page) : ?>
        <div class="container">
    <?php endif; ?>

    <?php while (have_posts()) : the_post(); ?>

        <?php if ($is_divi_page) : ?>
            <!-- Divi gère le contenu -->
            <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
                <?php the_content(); ?>
            </article>
        <?php else : ?>
            <?php get_template_part('template-parts/content/content', 'page'); ?>
        <?php endif; ?>

        <?php if (!$is_divi_page && comments_open() || get_comments_number()) : ?>
            <?php comments_template(); ?>
        <?php endif; ?>

    <?php endwhile; ?>

    <?php if (!$is_divi_page) : ?>
        </div>
    <?php endif; ?>
</main>

<?php
if (!$is_divi_page) {
    get_sidebar();
}
get_footer();

CSS et Styles

assets/css/divi-compatibility.css

/**
 * Styles de compatibilité Divi
 *
 * @package MonThemeDivi
 */

/* ============================
   COMPATIBILITÉ GÉNÉRALE DIVI
   ============================ */

/* Réinitialisation pour éviter les conflits */
.divi-compatible-theme .et_pb_section,
.divi-compatible-theme .et_pb_row,
.divi-compatible-theme .et_pb_column {
    box-sizing: border-box;
}

/* Assurer la compatibilité avec notre thème */
.divi-compatible-theme .et_pb_section {
    position: relative;
    clear: both;
}

.divi-compatible-theme .et_pb_row {
    max-width: var(--wp--style--global--wide-size, 1200px);
    margin: 0 auto;
}

/* ============================
   MODULES DIVI PERSONNALISÉS
   ============================ */

/* Module Texte */
.divi-compatible-theme .et_pb_text {
    font-family: var(--wp--preset--font-family--system);
    line-height: 1.6;
}

.divi-compatible-theme .et_pb_text h1,
.divi-compatible-theme .et_pb_text h2,
.divi-compatible-theme .et_pb_text h3,
.divi-compatible-theme .et_pb_text h4,
.divi-compatible-theme .et_pb_text h5,
.divi-compatible-theme .et_pb_text h6 {
    color: var(--wp--preset--color--neutral-dark);
    font-weight: 600;
    margin-bottom: 1rem;
}

/* Module Bouton */
.divi-compatible-theme .et_pb_button {
    background-color: var(--wp--preset--color--primary) !important;
    color: var(--wp--preset--color--white) !important;
    border: 2px solid var(--wp--preset--color--primary) !important;
    border-radius: 4px !important;
    padding: 12px 24px !important;
    font-size: 16px !important;
    font-weight: 500 !important;
    text-decoration: none !important;
    transition: all 0.3s ease !important;
    display: inline-block !important;
}

.divi-compatible-theme .et_pb_button:hover {
    background-color: var(--wp--preset--color--secondary) !important;
    border-color: var(--wp--preset--color--secondary) !important;
    transform: translateY(-2px) !important;
    box-shadow: 0 4px 12px rgba(34, 113, 177, 0.3) !important;
}

/* Module Image */
.divi-compatible-theme .et_pb_image {
    margin-bottom: 30px;
}

.divi-compatible-theme .et_pb_image img {
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
    transition: transform 0.3s ease;
}

.divi-compatible-theme .et_pb_image:hover img {
    transform: scale(1.02);
}

/* ============================
   SECTIONS ET LAYOUTS DIVI
   ============================ */

/* Section Hero personnalisée */
.divi-compatible-theme .et_pb_section.hero-section {
    background: linear-gradient(135deg, var(--wp--preset--color--primary) 0%, var(--wp--preset--color--secondary) 100%);
    color: var(--wp--preset--color--white);
    min-height: 70vh;
    display: flex;
    align-items: center;
}

.divi-compatible-theme .hero-section .et_pb_text h1,
.divi-compatible-theme .hero-section .et_pb_text h2 {
    color: var(--wp--preset--color--white);
    text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}

/* Section Services */
.divi-compatible-theme .et_pb_section.services-section .et_pb_column {
    background: var(--wp--preset--color--white);
    border-radius: 12px;
    padding: 30px !important;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
    transition: transform 0.3s ease, box-shadow 0.3s ease;
    margin-bottom: 30px;
}

.divi-compatible-theme .services-section .et_pb_column:hover {
    transform: translateY(-8px);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.15);
}

/* ============================
   VISUAL BUILDER DIVI
   ============================ */

/* Masquer les éléments du thème dans le Visual Builder */
.et-db .site-header,
.et-db .site-footer,
.et-db .custom-header-element,
.et-db .custom-footer-element {
    display: none !important;
}

/* Ajustements pour le Visual Builder */
.et-db #page-container {
    margin-top: 0 !important;
    padding-top: 0 !important;
}

.et-db .et_pb_section {
    position: relative !important;
}

/* ============================
   RESPONSIVE DIVI
   ============================ */

/* Tablette */
@media (max-width: 980px) {
    .divi-compatible-theme .et_pb_row {
        padding: 20px;
    }

    .divi-compatible-theme .et_pb_column {
        margin-bottom: 30px !important;
    }

    .divi-compatible-theme .hero-section {
        min-height: 50vh;
        text-align: center;
    }

    .divi-compatible-theme .et_pb_button {
        padding: 10px 20px !important;
        font-size: 14px !important;
    }
}

/* Mobile */
@media (max-width: 767px) {
    .divi-compatible-theme .et_pb_row {
        padding: 15px;
    }

    .divi-compatible-theme .et_pb_section {
        padding: 40px 0 !important;
    }

    .divi-compatible-theme .hero-section {
        min-height: 40vh;
    }

    .divi-compatible-theme .et_pb_text h1 {
        font-size: 28px !important;
        line-height: 1.3 !important;
    }

    .divi-compatible-theme .et_pb_text h2 {
        font-size: 24px !important;
        line-height: 1.4 !important;
    }

    .divi-compatible-theme .services-section .et_pb_column {
        padding: 20px !important;
        margin-bottom: 20px;
    }
}

/* ============================
   MODULES DIVI AVANCÉS
   ============================ */

/* Module Slider */
.divi-compatible-theme .et_pb_slider .et_pb_slide {
    background-attachment: fixed;
}

.divi-compatible-theme .et_pb_slider .et_pb_slide_description {
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(10px);
    border-radius: 12px;
    padding: 40px;
}

/* Module Portfolio/Galerie */
.divi-compatible-theme .et_pb_portfolio_item,
.divi-compatible-theme .et_pb_gallery_item {
    border-radius: 8px;
    overflow: hidden;
    transition: transform 0.3s ease;
}

.divi-compatible-theme .et_pb_portfolio_item:hover,
.divi-compatible-theme .et_pb_gallery_item:hover {
    transform: scale(1.05);
}

/* Module Contact Form */
.divi-compatible-theme .et_pb_contact_form .input,
.divi-compatible-theme .et_pb_contact_form .et_pb_contact_select,
.divi-compatible-theme .et_pb_contact_form textarea {
    border: 2px solid #e0e0e0 !important;
    border-radius: 4px !important;
    padding: 12px 16px !important;
    font-size: 16px !important;
    transition: border-color 0.3s ease !important;
}

.divi-compatible-theme .et_pb_contact_form .input:focus,
.divi-compatible-theme .et_pb_contact_form .et_pb_contact_select:focus,
.divi-compatible-theme .et_pb_contact_form textarea:focus {
    border-color: var(--wp--preset--color--primary) !important;
    outline: none !important;
    box-shadow: 0 0 0 3px rgba(34, 113, 177, 0.1) !important;
}

/* ============================
   ANIMATIONS DIVI PERSONNALISÉES
   ============================ */

/* Animation fade-in pour les modules */
.divi-compatible-theme .et_pb_module {
    opacity: 0;
    transform: translateY(30px);
    transition: opacity 0.6s ease, transform 0.6s ease;
}

.divi-compatible-theme .et_pb_module.et-animated {
    opacity: 1;
    transform: translateY(0);
}

/* Animation pour les boutons */
.divi-compatible-theme .et_pb_button {
    position: relative;
    overflow: hidden;
}

.divi-compatible-theme .et_pb_button::before {
    content: '';
    position: absolute;
    top: 0;
    left: -100%;
    width: 100%;
    height: 100%;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
    transition: left 0.5s ease;
}

.divi-compatible-theme .et_pb_button:hover::before {
    left: 100%;
}

/* ============================
   INTÉGRATION DARK MODE
   ============================ */

@media (prefers-color-scheme: dark) {
    .divi-compatible-theme.dark-mode .et_pb_section {
        background-color: var(--wp--preset--color--neutral-dark);
        color: var(--wp--preset--color--neutral-light);
    }

    .divi-compatible-theme.dark-mode .et_pb_text {
        color: var(--wp--preset--color--neutral-light);
    }

    .divi-compatible-theme.dark-mode .services-section .et_pb_column {
        background: #2a2a2a;
        color: var(--wp--preset--color--neutral-light);
    }
}

/* ============================
   AMÉLIORATIONS D'ACCESSIBILITÉ
   ============================ */

.divi-compatible-theme .et_pb_button:focus {
    outline: 2px solid var(--wp--preset--color--accent) !important;
    outline-offset: 2px !important;
}

.divi-compatible-theme .et_pb_text a:focus {
    outline: 2px solid var(--wp--preset--color--accent);
    outline-offset: 2px;
    text-decoration: underline;
}

/* Améliorer le contraste pour l'accessibilité */
.divi-compatible-theme .et_pb_text {
    color: #333;
}

.divi-compatible-theme .et_pb_section.dark-section .et_pb_text {
    color: #fff;
}

/* ============================
   UTILITAIRES DIVI
   ============================ */

/* Classes utilitaires pour Divi */
.divi-compatible-theme .et_pb_section.no-padding {
    padding: 0 !important;
}

.divi-compatible-theme .et_pb_section.small-padding {
    padding: 40px 0 !important;
}

.divi-compatible-theme .et_pb_section.large-padding {
    padding: 100px 0 !important;
}

.divi-compatible-theme .et_pb_row.no-gutters .et_pb_column {
    padding: 0 !important;
}

/* Classes pour les espacements */
.divi-compatible-theme .mb-0 { margin-bottom: 0 !important; }
.divi-compatible-theme .mb-10 { margin-bottom: 10px !important; }
.divi-compatible-theme .mb-20 { margin-bottom: 20px !important; }
.divi-compatible-theme .mb-30 { margin-bottom: 30px !important; }
.divi-compatible-theme .mb-40 { margin-bottom: 40px !important; }
.divi-compatible-theme .mb-50 { margin-bottom: 50px !important; }

/* Classes pour l'alignement */
.divi-compatible-theme .text-center { text-align: center !important; }
.divi-compatible-theme .text-left { text-align: left !important; }
.divi-compatible-theme .text-right { text-align: right !important; }

assets/css/responsive.css

/**
 * Styles responsive
 *
 * @package MonThemeDivi
 */

/* ============================
   BREAKPOINTS
   ============================ */

/* 
Desktop Large: 1200px+
Desktop: 992px - 1199px  
Tablet: 768px - 991px
Mobile Large: 576px - 767px
Mobile: 575px et moins
*/

/* ============================
   DESKTOP LARGE (1200px+)
   ============================ */

@media (min-width: 992px) and (max-width: 1199px) {
    .container {
        max-width: 960px;
        padding: 0 20px;
    }

    .site-header .site-branding h1 {
        font-size: 24px;
    }

    .main-navigation .nav-menu {
        gap: 15px;
    }
}

/* ============================
   TABLET (768px - 991px)
   ============================ */

@media (min-width: 768px) and (max-width: 991px) {
    .container {
        max-width: 720px;
        padding: 0 15px;
    }

    .site-header {
        padding: 15px 0;
    }

    .site-header .container {
        flex-direction: column;
        gap: 15px;
    }

    .main-navigation {
        width: 100%;
    }

    .main-navigation .nav-menu {
        justify-content: center;
        flex-wrap: wrap;
        gap: 10px;
    }

    .posts-container {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 30px;
    }

    .footer-widgets-grid {
        grid-template-columns: 1fr 1fr;
        gap: 30px;
    }
}

/* ============================
   MOBILE LARGE (576px - 767px)
   ============================ */

@media (min-width: 576px) and (max-width: 767px) {
    .container {
        max-width: 540px;
        padding: 0 15px;
    }

    .site-header .container {
        flex-direction: column;
        text-align: center;
    }

    .menu-toggle {
        display: block;
        background: none;
        border: none;
        cursor: pointer;
        padding: 10px;
    }

    .main-navigation {
        display: none;
        width: 100%;
        margin-top: 15px;
    }

    .main-navigation.toggled {
        display: block;
    }

    .main-navigation .nav-menu {
        flex-direction: column;
        background: var(--wp--preset--color--white);
        border: 1px solid #e0e0e0;
        border-radius: 8px;
        padding: 20px;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
    }

    .posts-container {
        display: grid;
        grid-template-columns: 1fr;
        gap: 30px;
    }

    .footer-widgets-grid {
        grid-template-columns: 1fr;
        gap: 30px;
    }
}

/* ============================
   MOBILE (575px et moins)
   ============================ */

@media (max-width: 575px) {
    .container {
        padding: 0 15px;
    }

    .site-header {
        padding: 10px 0;
    }

    .site-branding h1 {
        font-size: 20px;
        margin-bottom: 5px;
    }

    .site-description {
        font-size: 14px;
    }

    .menu-toggle {
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        width: 40px;
        height: 40px;
        background: var(--wp--preset--color--primary);
        color: white;
        border: none;
        border-radius: 4px;
        margin: 10px auto;
    }

    .hamburger {
        width: 20px;
        height: 2px;
        background: currentColor;
        position: relative;
        transition: all 0.3s ease;
    }

    .hamburger::before,
    .hamburger::after {
        content: '';
        position: absolute;
        width: 100%;
        height: 2px;
        background: currentColor;
        transition: all 0.3s ease;
    }

    .hamburger::before {
        top: -6px;
    }

    .hamburger::after {
        bottom: -6px;
    }

    .menu-toggle.toggled .hamburger {
        background: transparent;
    }

    .menu-toggle.toggled .hamburger::before {
        transform: rotate(45deg);
        top: 0;
    }

    .menu-toggle.toggled .hamburger::after {
        transform: rotate(-45deg);
        bottom: 0;
    }

    .main-navigation .nav-menu li a {
        padding: 15px;
        border-bottom: 1px solid #f0f0f0;
        display: block;
    }

    .main-navigation .nav-menu li:last-child a {
        border-bottom: none;
    }

    .site-main {
        padding: 20px 0;
    }

    .page-header h1,
    .entry-title {
        font-size: 24px;
        line-height: 1.3;
    }

    .entry-content {
        font-size: 16px;
        line-height: 1.6;
    }

    .posts-navigation {
        margin-top: 40px;
    }

    .nav-links {
        display: flex;
        flex-direction: column;
        gap: 15px;
    }

    .site-footer {
        padding: 30px 0;
    }

    .footer-widgets-grid {
        grid-template-columns: 1fr;
        gap: 30px;
    }

    .site-info {
        text-align: center;
        font-size: 14px;
    }

    .footer-menu {
        flex-direction: column;
        gap: 10px;
        margin-top: 15px;
    }
}

/* ============================
   RESPONSIVE POUR DIVI
   ============================ */

/* Tablet avec Divi */
@media (min-width: 768px) and (max-width: 991px) {
    .divi-compatible-theme .et_pb_section {
        padding: 60px 0 !important;
    }

    .divi-compatible-theme .et_pb_row {
        padding: 0 20px;
    }

    .divi-compatible-theme .et_pb_column {
        margin-bottom: 40px !important;
    }

    .divi-compatible-theme .et_pb_text h1 {
        font-size: 32px !important;
    }

    .divi-compatible-theme .et_pb_text h2 {
        font-size: 28px !important;
    }
}

/* Mobile avec Divi */
@media (max-width: 767px) {
    .divi-compatible-theme .et_pb_section {
        padding: 40px 0 !important;
    }

    .divi-compatible-theme .et_pb_row {
        padding: 0 15px;
    }

    .divi-compatible-theme .et_pb_column {
        margin-bottom: 30px !important;
        padding: 0 !important;
    }

    .divi-compatible-theme .et_pb_text {
        text-align: center;
    }

    .divi-compatible-theme .et_pb_text h1 {
        font-size: 28px !important;
        line-height: 1.2 !important;
        margin-bottom: 20px !important;
    }

    .divi-compatible-theme .et_pb_text h2 {
        font-size: 24px !important;
        line-height: 1.3 !important;
        margin-bottom: 18px !important;
    }

    .divi-compatible-theme .et_pb_text h3 {
        font-size: 20px !important;
        line-height: 1.4 !important;
        margin-bottom: 16px !important;
    }

    .divi-compatible-theme .et_pb_button {
        width: 100%;
        text-align: center !important;
        padding: 15px 20px !important;
        font-size: 16px !important;
        margin-bottom: 15px !important;
    }

    .divi-compatible-theme .services-section .et_pb_column {
        padding: 20px !important;
        margin-bottom: 20px;
    }

    .divi-compatible-theme .hero-section {
        min-height: 50vh;
        text-align: center;
        padding: 60px 0 !important;
    }
}

/* ============================
   OPTIMISATIONS PERFORMANCE
   ============================ */

/* Réduire les animations sur les appareils à faible performance */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }

    .divi-compatible-theme .et_pb_module {
        transition: none !important;
    }

    .divi-compatible-theme .et_pb_button {
        transition: none !important;
    }

    .divi-compatible-theme .et_pb_image img {
        transition: none !important;
    }
}

/* Optimisations pour les connexions lentes */
@media (prefers-reduced-data: reduce) {
    .divi-compatible-theme .et_pb_image img {
        content-visibility: auto;
        contain: layout style paint;
    }

    .divi-compatible-theme .et_pb_section {
        background-attachment: scroll !important;
    }
}

/* ============================
   PRINT STYLES
   ============================ */

@media print {
    .site-header,
    .site-footer,
    .menu-toggle,
    .main-navigation,
    .posts-navigation,
    .comments-area,
    .widget-area {
        display: none !important;
    }

    .site-main {
        width: 100% !important;
        margin: 0 !important;
        padding: 0 !important;
    }

    .entry-content {
        font-size: 12pt;
        line-height: 1.5;
    }

    .entry-title {
        font-size: 18pt;
        margin-bottom: 12pt;
    }

    /* Divi print styles */
    .divi-compatible-theme .et_pb_section {
        background: none !important;
        padding: 20pt 0 !important;
        page-break-inside: avoid;
    }

    .divi-compatible-theme .et_pb_button {
        background: none !important;
        border: 1pt solid #000 !important;
        color: #000 !important;
        text-decoration: none !important;
    }
}

JavaScript et Interactions

assets/js/main.js

/**
 * JavaScript principal du thème
 *
 * @package MonThemeDivi
 */

(function($) {
    'use strict';

    /**
     * Classe principale du thème
     */
    class MonThemeMain {
        constructor() {
            this.init();
            this.bindEvents();
        }

        /**
         * Initialisation
         */
        init() {
            this.setupMobileMenu();
            this.setupAccessibility();
            this.setupLazyLoading();
            this.setupSmoothScroll();
            this.setupAnimations();

            // Initialisation spécifique à Divi
            if (window.MonThemeAjax && window.MonThemeAjax.isDivi) {
                this.initDiviIntegration();
            }
        }

        /**
         * Liaison des événements
         */
        bindEvents() {
            $(document).ready(() => this.onDocumentReady());
            $(window).on('load', () => this.onWindowLoad());
            $(window).on('resize', this.debounce(() => this.onWindowResize(), 250));
            $(window).on('scroll', this.throttle(() => this.onWindowScroll(), 16));
        }

        /**
         * Document ready
         */
        onDocumentReady() {
            this.initializeComponents();
            this.setupKeyboardNavigation();

            // Animation d'entrée
            $('body').addClass('loaded');
        }

        /**
         * Window load
         */
        onWindowLoad() {
            this.optimizePerformance();
            this.setupParallax();
            this.initAnimationsOnScroll();
        }

        /**
         * Window resize
         */
        onWindowResize() {
            this.adjustMobileMenu();
            this.recalculateAnimations();
        }

        /**
         * Window scroll
         */
        onWindowScroll() {
            this.updateHeaderOnScroll();
            this.triggerScrollAnimations();
            this.updateProgressBar();
        }

        /**
         * Configuration du menu mobile
         */
        setupMobileMenu() {
            const $menuToggle = $('.menu-toggle');
            const $navigation = $('.main-navigation');

            $menuToggle.on('click', function(e) {
                e.preventDefault();

                const isExpanded = $(this).attr('aria-expanded') === 'true';

                $(this)
                    .attr('aria-expanded', !isExpanded)
                    .toggleClass('toggled');

                $navigation.toggleClass('toggled');

                // Gérer le focus
                if (!isExpanded) {
                    $navigation.find('a').first().focus();
                }
            });

            // Fermer le menu avec Escape
            $(document).on('keydown', function(e) {
                if (e.key === 'Escape' && $navigation.hasClass('toggled')) {
                    $menuToggle.click().focus();
                }
            });

            // Fermer le menu en cliquant à l'extérieur
            $(document).on('click', function(e) {
                if (!$(e.target).closest('.main-navigation, .menu-toggle').length) {
                    if ($navigation.hasClass('toggled')) {
                        $menuToggle.click();
                    }
                }
            });
        }

        /**
         * Configuration de l'accessibilité
         */
        setupAccessibility() {
            // Liens de saut
            $('.skip-link').on('click', function(e) {
                const target = $(this.getAttribute('href'));
                if (target.length) {
                    target.focus();
                }
            });

            // Focus visible pour la navigation au clavier
            $('a, button, input, textarea, select').on('focus', function() {
                $(this).addClass('focus-visible');
            }).on('blur', function() {
                $(this).removeClass('focus-visible');
            });

            // Améliorer l'accessibilité des boutons
            $('button:not([aria-label]):not([aria-labelledby])').each(function() {
                const text = $(this).text().trim();
                if (!text) {
                    $(this).attr('aria-label', 'Bouton');
                }
            });
        }

        /**
         * Configuration du lazy loading
         */
        setupLazyLoading() {
            if ('IntersectionObserver' in window) {
                const imageObserver = new IntersectionObserver((entries, observer) => {
                    entries.forEach(entry => {
                        if (entry.isIntersecting) {
                            const img = entry.target;
                            const src = img.getAttribute('data-src');

                            if (src) {
                                img.src = src;
                                img.removeAttribute('data-src');
                                img.classList.remove('lazy');
                                img.classList.add('loaded');
                            }

                            observer.unobserve(img);
                        }
                    });
                });

                document.querySelectorAll('img[data-src]').forEach(img => {
                    imageObserver.observe(img);
                });
            }
        }

        /**
         * Configuration du défilement fluide
         */
        setupSmoothScroll() {
            $('a[href*="#"]:not([href="#"])').on('click', function(e) {
                const target = $(this.hash);

                if (target.length) {
                    e.preventDefault();

                    $('html, body').animate({
                        scrollTop: target.offset().top - 80
                    }, 800, 'easeInOutCubic');

                    // Mettre le focus sur l'élément cible
                    target.focus();
                }
            });
        }

        /**
         * Configuration des animations
         */
        setupAnimations() {
            // Animation des compteurs
            this.animateCounters();

            // Animation des barres de progression
            this.animateProgressBars();

            // Animation des éléments au scroll
            this.setupScrollAnimations();
        }

        /**
         * Animation des compteurs
         */
        animateCounters() {
            $('.counter').each(function() {
                const $this = $(this);
                const countTo = parseInt($this.attr('data-count'));
                const duration = parseInt($this.attr('data-duration')) || 2000;

                const observer = new IntersectionObserver((entries) => {
                    entries.forEach(entry => {
                        if (entry.isIntersecting && !$this.hasClass('animated')) {
                            $this.addClass('animated');

                            $({ countNum: 0 }).animate({
                                countNum: countTo
                            }, {
                                duration: duration,
                                easing: 'swing',
                                step: function() {
                                    $this.text(Math.floor(this.countNum));
                                },
                                complete: function() {
                                    $this.text(countTo);
                                }
                            });
                        }
                    });
                });

                observer.observe(this);
            });
        }

        /**
         * Animation des barres de progression
         */
        animateProgressBars() {
            $('.progress-bar').each(function() {
                const $this = $(this);
                const progress = $this.attr('data-progress');

                const observer = new IntersectionObserver((entries) => {
                    entries.forEach(entry => {
                        if (entry.isIntersecting && !$this.hasClass('animated')) {
                            $this.addClass('animated');
                            $this.css('width', progress + '%');
                        }
                    });
                });

                observer.observe(this);
            });
        }

        /**
         * Configuration des animations au scroll
         */
        setupScrollAnimations() {
            if ('IntersectionObserver' in window) {
                const animationObserver = new IntersectionObserver((entries) => {
                    entries.forEach(entry => {
                        if (entry.isIntersecting) {
                            entry.target.classList.add('animate-in');
                        }
                    });
                }, {
                    threshold: 0.1,
                    rootMargin: '0px 0px -50px 0px'
                });

                document.querySelectorAll('.animate-on-scroll').forEach(el => {
                    animationObserver.observe(el);
                });
            }
        }

        /**
         * Intégration Divi
         */
        initDiviIntegration() {
            // Attendre que Divi soit prêt
            if (window.et_pb_custom) {
                this.enhanceDiviModules();
            } else {
                $(window).on('et_builder_api_ready', () => {
                    this.enhanceDiviModules();
                });
            }
        }

        /**
         * Amélioration des modules Divi
         */
        enhanceDiviModules() {
            // Améliorer les boutons Divi
            $('.et_pb_button').each(function() {
                const $button = $(this);

                // Ajouter un effet de ripple
                $button.on('click', function(e) {
                    const ripple = $('<span class="ripple"></span>');
                    const rect = this.getBoundingClientRect();
                    const size = Math.max(rect.width, rect.height);
                    const x = e.clientX - rect.left - size / 2;
                    const y = e.clientY - rect.top - size / 2;

                    ripple.css({
                        width: size + 'px',
                        height: size + 'px',
                        left: x + 'px',
                        top: y + 'px'
                    });

                    $button.append(ripple);

                    setTimeout(() => {
                        ripple.remove();
                    }, 600);
                });
            });

            // Améliorer les modules de texte
            $('.et_pb_text').each(function() {
                const $text = $(this);

                // Ajouter des classes pour le style
                $text.find('h1, h2, h3, h4, h5, h6').addClass('enhanced-heading');
                $text.find('p').addClass('enhanced-paragraph');
            });

            // Améliorer les galleries/portfolios
            $('.et_pb_portfolio_item, .et_pb_gallery_item').each(function() {
                const $item = $(this);

                $item.on('mouseenter', function() {
                    $(this).addClass('hover-effect');
                }).on('mouseleave', function() {
                    $(this).removeClass('hover-effect');
                });
            });
        }

        /**
         * Mise à jour de l'en-tête au scroll
         */
        updateHeaderOnScroll() {
            const scrollTop = $(window).scrollTop();
            const $header = $('.site-header');

            if (scrollTop > 100) {
                $header.addClass('scrolled');
            } else {
                $header.removeClass('scrolled');
            }
        }

        /**
         * Déclenchement des animations au scroll
         */
        triggerScrollAnimations() {
            const windowTop = $(window).scrollTop();
            const windowBottom = windowTop + $(window).height();

            $('.animate-on-scroll:not(.animated)').each(function() {
                const $this = $(this);
                const elementTop = $this.offset().top;

                if (elementTop < windowBottom - 100) {
                    $this.addClass('animated');
                }
            });
        }

        /**
         * Mise à jour de la barre de progression
         */
        updateProgressBar() {
            const scrollTop = $(window).scrollTop();
            const docHeight = $(document).height() - $(window).height();
            const scrollPercent = (scrollTop / docHeight) * 100;

            $('.reading-progress-bar').css('width', scrollPercent + '%');
        }

        /**
         * Optimisation des performances
         */
        optimizePerformance() {
            // Précharger les images importantes
            this.preloadCriticalImages();

            // Optimiser les animations
            this.optimizeAnimations();

            // Gérer la mémoire
            this.setupMemoryManagement();
        }

        /**
         * Préchargement des images critiques
         */
        preloadCriticalImages() {
            const criticalImages = [
                // Ajouter les URLs des images critiques
            ];

            criticalImages.forEach(src => {
                const link = document.createElement('link');
                link.rel = 'preload';
                link.as = 'image';
                link.href = src;
                document.head.appendChild(link);
            });
        }

        /**
         * Utilitaires
         */
        debounce(func, wait) {
            let timeout;
            return function executedFunction(...args) {
                const later = () => {
                    clearTimeout(timeout);
                    func(...args);
                };
                clearTimeout(timeout);
                timeout = setTimeout(later, wait);
            };
        }

        throttle(func, limit) {
            let inThrottle;
            return function() {
                const args = arguments;
                const context = this;
                if (!inThrottle) {
                    func.apply(context, args);
                    inThrottle = true;
                    setTimeout(() => inThrottle = false, limit);
                }
            };
        }
    }

    // Initialisation du thème
    new MonThemeMain();

})(jQuery);

/**
 * Easing personnalisé pour jQuery
 */
jQuery.extend(jQuery.easing, {
    easeInOutCubic: function (x, t, b, c, d) {
        if ((t/=d/2) < 1) return c/2*t*t*t + b;
        return c/2*((t-=2)*t*t + 2) + b;
    }
});

assets/js/divi-integration.js

/**
 * Intégration Divi avancée
 *
 * @package MonThemeDivi
 */

(function($) {
    'use strict';

    /**
     * Classe d'intégration Divi
     */
    class DiviIntegration {
        constructor() {
            this.init();
        }

        init() {
            // Attendre que Divi soit prêt
            if (typeof window.et_pb_custom !== 'undefined') {
                this.onDiviReady();
            } else {
                $(window).on('et_builder_api_ready', () => {
                    this.onDiviReady();
                });
            }

            // Événements du Visual Builder
            this.setupBuilderEvents();
        }

        /**
         * Divi est prêt
         */
        onDiviReady() {
            this.enhanceModules();
            this.setupCustomAnimations();
            this.setupResponsiveEnhancements();
            this.setupAccessibilityEnhancements();
        }

        /**
         * Configuration des événements du Builder
         */
        setupBuilderEvents() {
            // Détecter l'entrée/sortie du Visual Builder
            $(document).on('et_builder_api_ready', () => {
                console.log('Divi Builder API prêt');
                this.onBuilderLoad();
            });

            // Événements de modification du contenu
            $(document).on('et_builder_render_complete', () => {
                this.onContentRender();
            });
        }

        /**
         * Chargement du Builder
         */
        onBuilderLoad() {
            // Masquer les éléments du thème dans le builder
            if ($('body').hasClass('et-db')) {
                $('.theme-header-custom, .theme-footer-custom').hide();
            }
        }

        /**
         * Rendu du contenu terminé
         */
        onContentRender() {
            // Réappliquer nos améliorations après le rendu
            this.enhanceModules();
            this.reinitializeComponents();
        }

        /**
         * Amélioration des modules Divi
         */
        enhanceModules() {
            this.enhanceTextModules();
            this.enhanceButtonModules();
            this.enhanceImageModules();
            this.enhanceContactForms();
            this.enhanceSliders();
            this.enhancePortfolios();
        }

        /**
         * Amélioration des modules de texte
         */
        enhanceTextModules() {
            $('.et_pb_text').each(function() {
                const $text = $(this);

                // Ajouter des classes personnalisées
                $text.find('h1, h2, h3, h4, h5, h6').each(function() {
                    $(this).addClass('theme-heading');
                });

                $text.find('p').addClass('theme-paragraph');

                // Améliorer les listes
                $text.find('ul, ol').addClass('theme-list');

                // Ajouter un effet de surbrillance aux liens
                $text.find('a').each(function() {
                    if (!$(this).hasClass('et_pb_button')) {
                        $(this).addClass('theme-link');
                    }
                });
            });
        }

        /**
         * Amélioration des boutons
         */
        enhanceButtonModules() {
            $('.et_pb_button').each(function() {
                const $button = $(this);

                // Ajouter des classes thème
                $button.addClass('theme-button');

                // Effet de ripple
                if (!$button.hasClass('ripple-enhanced')) {
                    $button.addClass('ripple-enhanced');

                    $button.on('click', function(e) {
                        const $ripple = $('<span class="button-ripple"></span>');
                        const rect = this.getBoundingClientRect();
                        const size = Math.max(rect.width, rect.height);
                        const x = e.clientX - rect.left - size / 2;
                        const y = e.clientY - rect.top - size / 2;

                        $ripple.css({
                            width: size + 'px',
                            height: size + 'px',
                            left: x + 'px',
                            top: y + 'px'
                        });

                        $button.append($ripple);

                        setTimeout(() => {
                            $ripple.remove();
                        }, 600);
                    });
                }

                // Améliorer l'accessibilité
                if (!$button.attr('role')) {
                    $button.attr('role', 'button');
                }
            });
        }

        /**
         * Amélioration des images
         */
        enhanceImageModules() {
            $('.et_pb_image').each(function() {
                const $image = $(this);
                const $img = $image.find('img');

                // Lazy loading personnalisé
                if ($img.length && !$img.hasClass('lazy-enhanced')) {
                    $img.addClass('lazy-enhanced');

                    // Observer pour le lazy loading
                    if ('IntersectionObserver' in window) {
                        const imageObserver = new IntersectionObserver((entries) => {
                            entries.forEach(entry => {
                                if (entry.isIntersecting) {
                                    const img = entry.target;
                                    img.classList.add('loaded');
                                    imageObserver.unobserve(img);
                                }
                            });
                        });

                        imageObserver.observe($img[0]);
                    }
                }

                // Effet de zoom au survol
                $image.addClass('theme-image-container');
            });
        }

        /**
         * Amélioration des formulaires de contact
         */
        enhanceContactForms() {
            $('.et_pb_contact_form').each(function() {
                const $form = $(this);

                // Améliorer les champs
                $form.find('.input, textarea, select').each(function() {
                    const $field = $(this);

                    // Ajouter des labels flottants
                    if (!$field.siblings('.floating-label').length) {
                        const placeholder = $field.attr('placeholder');
                        if (placeholder) {
                            $field.wrap('<div class="field-wrapper"></div>');
                            $field.after(`<label class="floating-label">${placeholder}</label>`);
                        }
                    }

                    // Événements pour les labels flottants
                    $field.on('focus blur', function() {
                        const $wrapper = $(this).closest('.field-wrapper');
                        $wrapper.toggleClass('focused', $(this).is(':focus'));
                        $wrapper.toggleClass('filled', $(this).val().length > 0);
                    });
                });

                // Validation en temps réel
                $form.find('.input[required], textarea[required]').on('blur', function() {
                    const $field = $(this);
                    const isValid = $field[0].checkValidity();

                    $field.toggleClass('invalid', !isValid);
                    $field.closest('.field-wrapper').toggleClass('invalid', !isValid);
                });
            });
        }

        /**
         * Amélioration des sliders
         */
        enhanceSliders() {
            $('.et_pb_slider').each(function() {
                const $slider = $(this);

                // Ajouter des indicateurs de progression
                if (!$slider.find('.slider-progress').length) {
                    $slider.append('<div class="slider-progress"><div class="progress-bar"></div></div>');
                }

                // Améliorer la navigation
                $slider.find('.et-pb-arrow-prev, .et-pb-arrow-next').each(function() {
                    $(this).attr('role', 'button');
                    $(this).attr('tabindex', '0');
                });

                // Support du clavier
                $slider.on('keydown', function(e) {
                    if (e.key === 'ArrowLeft') {
                        $slider.find('.et-pb-arrow-prev').click();
                    } else if (e.key === 'ArrowRight') {
                        $slider.find('.et-pb-arrow-next').click();
                    }
                });
            });
        }

        /**
         * Amélioration des portfolios
         */
        enhancePortfolios() {
            $('.et_pb_portfolio_item').each(function() {
                const $item = $(this);

                // Effet de survol amélioré
                $item.on('mouseenter', function() {
                    $(this).addClass('theme-hover-effect');
                }).on('mouseleave', function() {
                    $(this).removeClass('theme-hover-effect');
                });

                // Améliorer l'accessibilité
                $item.find('a').attr('role', 'link');

                // Ajouter un focus visible
                $item.find('a').on('focus', function() {
                    $item.addClass('focused');
                }).on('blur', function() {
                    $item.removeClass('focused');
                });
            });
        }

        /**
         * Animations personnalisées
         */
        setupCustomAnimations() {
            // Animation de fade-in pour les modules
            $('.et_pb_module').each(function() {
                const $module = $(this);

                if ('IntersectionObserver' in window) {
                    const animationObserver = new IntersectionObserver((entries) => {
                        entries.forEach(entry => {
                            if (entry.isIntersecting) {
                                entry.target.classList.add('theme-animated');
                                animationObserver.unobserve(entry.target);
                            }
                        });
                    }, {
                        threshold: 0.1,
                        rootMargin: '0px 0px -50px 0px'
                    });

                    animationObserver.observe(this);
                }
            });

            // Animation des compteurs
            this.setupCounterAnimations();
        }

        /**
         * Animation des compteurs
         */
        setupCounterAnimations() {
            $('.et_pb_number_counter').each(function() {
                const $counter = $(this);
                const $number = $counter.find('.percent');

                if ($number.length && !$number.hasClass('animated')) {
                    const observer = new IntersectionObserver((entries) => {
                        entries.forEach(entry => {
                            if (entry.isIntersecting) {
                                $number.addClass('animated');
                                observer.unobserve(entry.target);
                            }
                        });
                    });

                    observer.observe($counter[0]);
                }
            });
        }

        /**
         * Améliorations responsive
         */
        setupResponsiveEnhancements() {
            // Optimisations pour mobile
            if (window.innerWidth <= 768) {
                this.optimizeForMobile();
            }

            // Écouter les changements d'orientation
            $(window).on('orientationchange resize', () => {
                setTimeout(() => {
                    this.handleResponsiveChanges();
                }, 100);
            });
        }

        /**
         * Optimisations pour mobile
         */
        optimizeForMobile() {
            // Désactiver les animations coûteuses sur mobile
            $('.et_pb_module').addClass('mobile-optimized');

            // Optimiser les sliders pour le tactile
            $('.et_pb_slider').each(function() {
                const $slider = $(this);
                $slider.addClass('touch-optimized');
            });
        }

        /**
         * Gestion des changements responsive
         */
        handleResponsiveChanges() {
            // Recalculer les hauteurs et positions
            this.recalculateModuleHeights();

            // Réinitialiser les animations si nécessaire
            this.reinitializeAnimations();
        }

        /**
         * Améliorations d'accessibilité
         */
        setupAccessibilityEnhancements() {
            // Améliorer la navigation au clavier
            $('.et_pb_module').each(function() {
                const $module = $(this);

                // Ajouter un focus visible
                $module.find('a, button, input, textarea, select').on('focus', function() {
                    $(this).addClass('theme-focus-visible');
                }).on('blur', function() {
                    $(this).removeClass('theme-focus-visible');
                });
            });

            // Améliorer les lecteurs d'écran
            this.enhanceScreenReaderSupport();
        }

        /**
         * Support des lecteurs d'écran
         */
        enhanceScreenReaderSupport() {
            // Ajouter des labels ARIA manquants
            $('.et_pb_button:not([aria-label])').each(function() {
                const text = $(this).text().trim();
                if (text) {
                    $(this).attr('aria-label', text);
                }
            });

            // Améliorer les sliders
            $('.et_pb_slider').each(function() {
                $(this).attr('role', 'region');
                $(this).attr('aria-label', 'Carrousel d\'images');
            });

            // Améliorer les tabs
            $('.et_pb_tabs').each(function() {
                $(this).attr('role', 'tabpanel');
            });
        }

        /**
         * Réinitialisation des composants
         */
        reinitializeComponents() {
            // Réappliquer les améliorations après modification du contenu
            this.enhanceModules();
            this.setupCustomAnimations();
        }

        /**
         * Recalculer les hauteurs des modules
         */
        recalculateModuleHeights() {
            $('.et_pb_module').each(function() {
                // Forcer le recalcul de la hauteur
                $(this).css('height', 'auto');
            });
        }

        /**
         * Réinitialiser les animations
         */
        reinitializeAnimations() {
            $('.et_pb_module.theme-animated').removeClass('theme-animated');
            this.setupCustomAnimations();
        }
    }

    // Initialisation de l'intégration Divi
    new DiviIntegration();

})(jQuery);

/**
 * Utilitaires Divi globaux
 */
window.MonThemeDivi = {
    /**
     * Vérifier si un module Divi existe sur la page
     */
    hasModule: function(moduleType) {
        return $('.' + moduleType).length > 0;
    },

    /**
     * Obtenir tous les modules d'un type
     */
    getModules: function(moduleType) {
        return $('.' + moduleType);
    },

    /**
     * Ajouter une classe à tous les modules d'un type
     */
    addClassToModules: function(moduleType, className) {
        $('.' + moduleType).addClass(className);
    },

    /**
     * Émettre un événement personnalisé
     */
    trigger: function(eventName, data) {
        $(document).trigger('divi_theme_' + eventName, data);
    },

    /**
     * Écouter un événement personnalisé
     */
    on: function(eventName, callback) {
        $(document).on('divi_theme_' + eventName, callback);
    }
};

Optimisation et Performance

inc/performance.php

<?php
/**
 * Optimisations de performance
 *
 * @package MonThemeDivi
 */

// Sécurité
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Classe d'optimisation des performances
 */
class MonThemeDivi_Performance {

    /**
     * Constructeur
     */
    public function __construct() {
        add_action('init', array($this, 'init_optimizations'));
        add_action('wp_enqueue_scripts', array($this, 'optimize_scripts'), 20);
        add_action('wp_head', array($this, 'add_preload_links'), 1);
        add_filter('script_loader_tag', array($this, 'optimize_script_tags'), 10, 3);
        add_filter('style_loader_tag', array($this, 'optimize_style_tags'), 10, 4);
    }

    /**
     * Initialisation des optimisations
     */
    public function init_optimizations() {
        // Désactiver les fonctionnalités inutiles
        $this->disable_unused_features();

        // Optimiser les requêtes
        $this->optimize_queries();

        // Optimiser les images
        $this->optimize_images();

        // Optimiser les feeds
        $this->optimize_feeds();
    }

    /**
     * Désactiver les fonctionnalités inutiles
     */
    private function disable_unused_features() {
        // Désactiver les emojis
        remove_action('wp_head', 'print_emoji_detection_script', 7);
        remove_action('admin_print_scripts', 'print_emoji_detection_script');
        remove_action('wp_print_styles', 'print_emoji_styles');
        remove_action('admin_print_styles', 'print_emoji_styles');
        remove_filter('the_content_feed', 'wp_staticize_emoji');
        remove_filter('comment_text_rss', 'wp_staticize_emoji');
        remove_filter('wp_mail', 'wp_staticize_emoji_for_email');

        // Désactiver les embeds
        add_filter('embed_oembed_discover', '__return_false');
        remove_action('wp_head', 'wp_oembed_add_discovery_links');
        remove_action('wp_head', 'wp_oembed_add_host_js');

        // Désactiver XML-RPC
        add_filter('xmlrpc_enabled', '__return_false');

        // Désactiver les pingbacks
        add_filter('wp_headers', array($this, 'disable_x_pingback'));

        // Désactiver les générateurs de version
        remove_action('wp_head', 'wp_generator');
        remove_action('wp_head', 'wlwmanifest_link');
        remove_action('wp_head', 'rsd_link');

        // Désactiver les shortlinks
        remove_action('wp_head', 'wp_shortlink_wp_head');

        // Désactiver les API REST pour les non-connectés (optionnel)
        if (!is_user_logged_in()) {
            add_filter('rest_authentication_errors', array($this, 'restrict_rest_api'));
        }
    }

    /**
     * Optimiser les requêtes
     */
    private function optimize_queries() {
        // Supprimer les meta queries inutiles
        add_filter('posts_clauses', array($this, 'optimize_posts_clauses'), 10, 2);

        // Optimiser les requêtes d'archives
        add_action('pre_get_posts', array($this, 'optimize_archive_queries'));

        // Limiter les révisions
        if (!defined('WP_POST_REVISIONS')) {
            define('WP_POST_REVISIONS', 3);
        }

        // Optimiser la corbeille
        if (!defined('EMPTY_TRASH_DAYS')) {
            define('EMPTY_TRASH_DAYS', 7);
        }
    }

    /**
     * Optimiser les images
     */
    private function optimize_images() {
        // Activer le lazy loading
        add_filter('wp_lazy_loading_enabled', '__return_true');

        // Optimiser les thumbnails
        add_filter('intermediate_image_sizes_advanced', array($this, 'remove_unused_image_sizes'));

        // Ajouter des tailles responsive
        add_filter('wp_calculate_image_srcset', array($this, 'optimize_image_srcset'), 10, 5);

        // Optimiser la qualité JPEG
        add_filter('jpeg_quality', array($this, 'optimize_jpeg_quality'));
        add_filter('wp_editor_set_quality', array($this, 'optimize_jpeg_quality'));
    }

    /**
     * Optimiser les scripts
     */
    public function optimize_scripts() {
        // Déplacer jQuery vers le footer (sauf si Divi l'utilise)
        if (!function_exists('et_setup_theme')) {
            wp_scripts()->add_data('jquery', 'group', 1);
            wp_scripts()->add_data('jquery-core', 'group', 1);
            wp_scripts()->add_data('jquery-migrate', 'group', 1);
        }

        // Désactiver les scripts inutiles sur certaines pages
        if (!is_admin()) {
            wp_deregister_script('wp-embed');

            // Désactiver les scripts de blocs si pas nécessaire
            if (!$this->needs_block_scripts()) {
                wp_dequeue_style('wp-block-library');
                wp_dequeue_style('wp-block-library-theme');
                wp_dequeue_style('global-styles');
            }
        }
    }

    /**
     * Ajouter des liens de préchargement
     */
    public function add_preload_links() {
        // Précharger les polices critiques
        ?>
        <link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

        <?php
        // Précharger les ressources critiques
        $critical_resources = array(
            THEME_URL . '/assets/css/critical.css' => 'style',
            THEME_URL . '/assets/js/critical.js' => 'script',
        );

        foreach ($critical_resources as $url => $type) {
            if (file_exists(str_replace(THEME_URL, THEME_PATH, $url))) {
                echo "<link rel='preload' href='{$url}' as='{$type}' crossorigin>\n";
            }
        }

        // Précharger les images hero
        $hero_image = $this->get_hero_image();
        if ($hero_image) {
            echo "<link rel='preload' href='{$hero_image}' as='image'>\n";
        }
    }

    /**
     * Optimiser les balises de script
     */
    public function optimize_script_tags($tag, $handle, $src) {
        // Ajouter async/defer selon le script
        $async_scripts = array('google-analytics', 'gtag');
        $defer_scripts = array('mon-theme-main', 'divi-integration');

        if (in_array($handle, $async_scripts)) {
            $tag = str_replace('<script ', '<script async ', $tag);
        } elseif (in_array($handle, $defer_scripts)) {
            $tag = str_replace('<script ', '<script defer ', $tag);
        }

        return $tag;
    }

    /**
     * Optimiser les balises de style
     */
    public function optimize_style_tags($html, $handle, $href, $media) {
        // Précharger les CSS non critiques
        $non_critical_styles = array('mon-theme-responsive', 'divi-compatibility');

        if (in_array($handle, $non_critical_styles)) {
            $html = str_replace("rel='stylesheet'", "rel='preload' as='style' onload=\"this.onload=null;this.rel='stylesheet'\"", $html);
            $html .= "
<noscript><link rel='stylesheet' href='{$href}' media='{$media}'></noscript>";
        }

        return $html;
    }

    /**
     * Désactiver X-Pingback
     */
    public function disable_x_pingback($headers) {
        unset($headers['X-Pingback']);
        return $headers;
    }

    /**
     * Restreindre l'API REST
     */
    public function restrict_rest_api($result) {
        if (!empty($result)) {
            return $result;
        }

        return new WP_Error('rest_disabled', __('L\'API REST est désactivée.', 'mon-theme-divi'), array('status' => 401));
    }

    /**
     * Optimiser les clauses de posts
     */
    public function optimize_posts_clauses($clauses, $query) {
        global $wpdb;

        // Éviter les requêtes inutiles sur les meta
        if (!is_admin() && $query->is_main_query()) {
            // Optimiser selon le contexte
            if (is_home() || is_archive()) {
                // Limiter les champs sélectionnés
                $clauses['fields'] = $wpdb->posts . '.ID, ' . 
                                   $wpdb->posts . '.post_title, ' . 
                                   $wpdb->posts . '.post_excerpt, ' . 
                                   $wpdb->posts . '.post_date, ' . 
                                   $wpdb->posts . '.post_name, ' . 
                                   $wpdb->posts . '.post_type';
            }
        }

        return $clauses;
    }

    /**
     * Optimiser les requêtes d'archives
     */
    public function optimize_archive_queries($query) {
        if (!is_admin() && $query->is_main_query()) {
            // Optimiser les pages d'archives
            if (is_home() || is_archive()) {
                $query->set('no_found_rows', true);
                $query->set('update_post_meta_cache', false);
                $query->set('update_post_term_cache', false);
            }
        }
    }

    /**
     * Supprimer les tailles d'images inutiles
     */
    public function remove_unused_image_sizes($sizes) {
        // Supprimer les tailles non utilisées
        unset($sizes['medium_large']);
        unset($sizes['1536x1536']);
        unset($sizes['2048x2048']);

        return $sizes;
    }

    /**
     * Optimiser le srcset des images
     */
    public function optimize_image_srcset($sources, $size_array, $image_src, $image_meta, $attachment_id) {
        // Limiter le nombre de sources dans le srcset
        if (count($sources) > 5) {
            $sources = array_slice($sources, 0, 5, true);
        }

        return $sources;
    }

    /**
     * Optimiser la qualité JPEG
     */
    public function optimize_jpeg_quality($quality) {
        return 85; // Équilibre entre qualité et taille
    }

    /**
     * Vérifier si les scripts de blocs sont nécessaires
     */
    private function needs_block_scripts() {
        // Vérifier si la page utilise des blocs
        if (is_singular()) {
            global $post;
            return has_blocks($post->post_content);
        }

        return false;
    }

    /**
     * Obtenir l'image hero de la page
     */
    private function get_hero_image() {
        if (is_singular()) {
            $thumbnail_id = get_post_thumbnail_id();
            if ($thumbnail_id) {
                $image = wp_get_attachment_image_src($thumbnail_id, 'hero-large');
                return $image ? $image[0] : null;
            }
        }

        return null;
    }
}

// Initialisation des optimisations
new MonThemeDivi_Performance();

/**
 * Optimisations supplémentaires
 */

/**
 * Mettre en cache les requêtes coûteuses
 */
function cache_expensive_queries() {
    // Exemple de mise en cache d'une requête
    $cache_key = 'theme_popular_posts';
    $popular_posts = wp_cache_get($cache_key);

    if (false === $popular_posts) {
        $popular_posts = new WP_Query(array(
            'posts_per_page' => 5,
            'meta_key' => 'post_views',
            'orderby' => 'meta_value_num',
            'order' => 'DESC'
        ));

        wp_cache_set($cache_key, $popular_posts, '', 3600); // Cache 1 heure
    }

    return $popular_posts;
}

/**
 * Optimiser la base de données
 */
function optimize_database() {
    // Nettoyer les révisions anciennes
    global $wpdb;

    $wpdb->query("
        DELETE FROM {$wpdb->posts} 
        WHERE post_type = 'revision' 
        AND post_date < DATE_SUB(NOW(), INTERVAL 30 DAY)
    ");

    // Nettoyer les meta orphelines
    $wpdb->query("
        DELETE pm FROM {$wpdb->postmeta} pm
        LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
        WHERE p.ID IS NULL
    ");
}

/**
 * Ajouter des headers de cache
 */
function add_cache_headers() {
    if (!is_admin() && !is_user_logged_in()) {
        $expires = 3600; // 1 heure

        header("Cache-Control: public, max-age={$expires}");
        header("Expires: " . gmdate('D, d M Y H:i:s', time() + $expires) . ' GMT');
        header("Pragma: cache");
    }
}
add_action('wp_head', 'add_cache_headers', 1);

/**
 * Compression Gzip
 */
function enable_gzip_compression() {
    if (!ob_get_level()) {
        ob_start('ob_gzhandler');
    }
}
add_action('init', 'enable_gzip_compression');

/**
 * Optimiser les requêtes de menu
 */
function optimize_menu_queries($args, $menu, $wp_nav_menu_args) {
    // Éviter les requêtes de meta inutiles
    $args['meta_query'] = array();
    return $args;
}
add_filter('wp_get_nav_menu_items', 'optimize_menu_queries', 10, 3);

/**
 * Critical CSS inline
 */
function inline_critical_css() {
    $critical_css_file = THEME_PATH . '/assets/css/critical.css';

    if (file_exists($critical_css_file)) {
        echo '<style id="critical-css">';
        echo file_get_contents($critical_css_file);
        echo '</style>';
    }
}
add_action('wp_head', 'inline_critical_css', 1);

/**
 * Optimiser les widgets
 */
function optimize_widgets() {
    // Désactiver les widgets inutiles
    unregister_widget('WP_Widget_Calendar');
    unregister_widget('WP_Widget_Meta');
    unregister_widget('WP_Widget_Links');
}
add_action('widgets_init', 'optimize_widgets', 11);

Tests et Débogage

Tests de Compatibilité

# Tests à effectuer

1. Test avec Divi activé/désactivé
2. Test avec Visual Builder
3. Test avec différents modules Divi
4. Test responsive sur tous les appareils
5. Test de performance avec GTmetrix/PageSpeed
6. Test d'accessibilité avec WAVE
7. Test de compatibilité navigateurs
8. Test avec différents plugins populaires

Débogage

// Mode debug pour le thème
if (defined('WP_DEBUG') && WP_DEBUG) {
    // Logs spécifiques au thème
    function theme_debug_log($message) {
        error_log('[MonThemeDivi] ' . $message);
    }

    // Afficher les requêtes
    function show_queries() {
        if (current_user_can('administrator')) {
            global $wpdb;
            echo '
<pre>';
            print_r($wpdb->queries);
            echo '</pre>';
        }
    }
    add_action('wp_footer', 'show_queries');
}

Déploiement

Checklist de Déploiement

  1. Vérifications finales :

    • [ ] Tests sur environnement de staging
    • [ ] Optimisation des images
    • [ ] Minification CSS/JS
    • [ ] Test de performance
    • [ ] Validation W3C
    • [ ] Test d’accessibilité
    • [ ] Compatibilité navigateurs
  2. Fichiers à inclure :

    • [ ] Tous les fichiers du thème
    • [ ] Documentation
    • [ ] Fichiers de traduction
    • [ ] Screenshot.png
    • [ ] Readme.txt
  3. Configuration serveur :

    • [ ] PHP 8.0+
    • [ ] MySQL 5.7+
    • [ ] Compression Gzip activée
    • [ ] Cache serveur configuré
    • [ ] SSL activé

Script de Déploiement

#!/bin/bash
# Script de déploiement du thème

echo "Déploiement du thème Mon Thème Divi Compatible..."

# Minification CSS
npx cssnano assets/css/style.css assets/css/style.min.css

# Minification JS
npx terser assets/js/main.js -o assets/js/main.min.js

# Optimisation des images
npx imagemin assets/images/* --out-dir=assets/images/optimized

# Génération du fichier pot pour les traductions
wp i18n make-pot . languages/mon-theme-divi.pot

echo "Déploiement terminé !"

Conclusion

Ce guide complet vous permet de créer un thème WordPress 6.8.2 entièrement compatible avec Divi. Le thème ainsi créé bénéficie :

  • Compatibilité totale avec Divi Builder
  • Optimisations modernes pour WordPress 6.8.2
  • Performance optimisée
  • Accessibilité respectée
  • Responsive design
  • Code maintenable et extensible

Pour aller plus loin, consultez la documentation officielle de WordPress et de Divi, et n’hésitez pas à adapter ce code selon vos besoins spécifiques.

Ressources utiles :