Guide Complet : Création d’un Thème WordPress 6.8.2 Compatible Divi
Table des Matières
- Prérequis et Préparation
- Structure de Base du Thème
- Configuration pour WordPress 6.8.2
- Compatibilité Divi
- Fichiers de Template
- CSS et Styles
- JavaScript et Interactions
- Optimisation et Performance
- Tests et Débogage
- 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>© <?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
-
Vérifications finales :
- [ ] Tests sur environnement de staging
- [ ] Optimisation des images
- [ ] Minification CSS/JS
- [ ] Test de performance
- [ ] Validation W3C
- [ ] Test d’accessibilité
- [ ] Compatibilité navigateurs
-
Fichiers à inclure :
- [ ] Tous les fichiers du thème
- [ ] Documentation
- [ ] Fichiers de traduction
- [ ] Screenshot.png
- [ ] Readme.txt
-
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 :