Si vous avez déjà vu un TTFB à 1,5s sur une page “simple” et que personne n’arrive à expliquer pourquoi, vous avez déjà touché le vrai problème : WordPress n’est pas lent “par nature”, il est lent quand on le laisse faire trop de travail à chaque requête.

Ce qu’on va construire

Vous allez mettre en place une optimisation complète et réaliste d’un site WordPress 6.9.4 (avril 2026), orientée résultats : baisse du TTFB, réduction des requêtes PHP/SQL, chargement plus léger côté navigateur, et surtout un process de mesure pour éviter les optimisations placebo.

C’est destiné aux sites de contenu (blog, magazine, vitrine avec blog) et aux sites sous page builder (Divi 5, Elementor, Avada) qui ont souvent un “poids” front élevé et une surconsommation de CSS/JS.

À la fin, vous saurez :

  • Mesurer correctement (laboratoire + terrain) et isoler ce qui ralentit (serveur, thème, plugins, CDN, scripts tiers).
  • Configurer un cache de page + un object cache persistant (Redis) et vérifier qu’ils servent réellement.
  • Optimiser images, CSS/JS, base de données, WP-Cron, et quelques requêtes typiques qui plombent les pages.
  • Éviter les pièges classiques : hooks mal choisis, code collé au mauvais endroit, cache non purgé, conflits d’optimisation.

Résumé rapide

  • Mesurez d’abord (Query Monitor + WebPageTest/Lighthouse), sinon vous “optimisez” au hasard.
  • Cache de page (serveur ou plugin) + vérification des en-têtes (HIT/MISS) : c’est le plus gros levier sur le TTFB.
  • Object cache persistant (Redis) : gain net sur sites dynamiques/chargés en plugins.
  • Images : tailles correctes + WebP/AVIF + suppression des images “plein format” inutiles.
  • CSS/JS : désactiver ce qui ne sert pas page par page, et éviter les plugins “minify tout” agressifs.
  • WP-Cron + autoload options : réduire le travail invisible à chaque page.

Quand utiliser cette solution

  • Vous avez un TTFB élevé (> 600–800ms) même sur une page cacheable.
  • Votre site a grossi (plugins, builder, tracking) et vous sentez une dégradation progressive.
  • Vous visez Core Web Vitals stables (LCP/INP) et une expérience mobile correcte.
  • Vous avez un hébergement correct (PHP 8.1+), mais pas forcément “premium”.
  • Vous voulez une méthode reproductible (checklist + vérifications), pas une liste de “plugins miracles”.

Quand ne PAS utiliser cette solution

  • Votre site est en refonte majeure ou migre de builder : optimisez après stabilisation, sinon vous recommencez tout.
  • Vous êtes sur un hébergement qui impose déjà un cache serveur opaque (et interdit les plugins de cache) : adaptez-vous à leur stack (souvent Nginx microcache/Varnish) au lieu d’empiler.
  • Vous avez un site e-commerce avec panier/compte très dynamique : vous pouvez appliquer beaucoup d’étapes, mais le cache de page doit être configuré finement (exclusions, cookies). Ne copiez pas “cache partout”.
  • Vous n’avez pas d’environnement de test : certaines étapes (Redis, WP-Cron système, désactivation d’assets) peuvent casser des parcours.

Avant de commencer (prérequis)

Je vous recommande de faire ces optimisations sur une préproduction. J’ai souvent vu un site “accéléré” finir avec un checkout cassé ou un builder qui ne charge plus ses scripts, simplement parce que la personne testait en production.

Pré-requis techniques

  • WordPress 6.9.4 (ou supérieur).
  • PHP 8.1 minimum (8.2/8.3 souvent plus rapide selon extensions). Référence : PHP Supported Versions.
  • Accès administrateur WordPress + idéalement accès FTP/SSH.
  • Possibilité d’installer un plugin et de modifier wp-config.php (certaines étapes).

Sauvegarde et environnement

  • Sauvegarde fichiers + base (et test de restauration).
  • Si possible : clone sur un sous-domaine staging avec un robots.txt bloquant.
  • Notez votre état initial (TTFB/LCP/poids page) pour comparer.

Outils utiles

Précautions sécurité

  • Ne collez pas de snippets trouvés au hasard. Un seul ; manquant peut mettre votre site en écran blanc.
  • Si vous ajoutez du code, privilégiez un mu-plugin (chargé avant les plugins) plutôt que functions.php, surtout si vous changez de thème.
  • Évitez d’exposer des endpoints de debug ou des pages de test publiques.

Étape 1 : Mesurer proprement (sinon vous optimisez à l’aveugle)

Le but : séparer temps serveur (PHP/MySQL/cache) et temps navigateur (CSS/JS/images/tiers). Sans ça, vous risquez de “minifier” pendant que le vrai problème est une requête lente en admin-ajax.

1) Installer Query Monitor

  1. WP Admin → ExtensionsAjouter
  2. Recherchez Query Monitor → Installer → Activer

Ensuite, ouvrez une page lente en étant connecté, puis dans la barre d’admin en haut : Query Monitor → regardez :

  • Database Queries : nombre + temps total, et requêtes lentes.
  • HTTP API Calls : appels externes (tracking, APIs) côté serveur.
  • Hooks & Actions : callbacks coûteux.
  • Scripts & Styles : assets chargés et leur origine (thème, plugin, builder).

2) Mesures “terrain” et “labo”

  • Lighthouse (Chrome) : bon pour repérer le poids, le main-thread, le JS.
  • WebPageTest : meilleur pour simuler un mobile réel et voir le TTFB/LCP avec waterfall.

3) Créer un mini-log de performance (recommandé)

Créez un tableau simple (Google Sheet) et notez :

  • URL testée (homepage + un article + une page builder lourde)
  • TTFB (ms)
  • LCP (s)
  • Poids total (MB)
  • Nombre de requêtes
  • Cache HIT/MISS (quand vous l’aurez)

Résultat attendu : vous savez si votre priorité est serveur (TTFB) ou front (LCP/JS/images). Dans mon expérience, un blog sous builder a souvent les deux.


Étape 2 : Mettre un cache de page fiable (et vérifier qu’il sert vraiment)

Le cache de page est le levier n°1 sur le TTFB pour les pages publiques. Sans cache, chaque visiteur déclenche PHP + DB + hooks + builder.

Méthode A (recommandée) : cache serveur géré par l’hébergeur

Si votre hébergeur propose Nginx microcache/Varnish/LSCache, activez-le et demandez :

  • Comment vérifier un HIT/MISS (en-tête HTTP)
  • Comment purger (URL, purge globale)
  • Quelles pages sont exclues (admin, preview, pages avec cookies)

Méthode B : plugin de cache de page

Choisissez un plugin reconnu et maintenu. L’idée n’est pas d’en citer 15, mais d’en prendre un et de le configurer proprement.

Vérification (critique) : est-ce que la page est réellement servie en cache ?

Ouvrez votre page en navigation privée et inspectez les en-têtes.

curl -I https://exemple.com/ | sed -n '1,30p'

Vous cherchez des indices (selon votre stack) : X-Cache: HIT, CF-Cache-Status, X-Proxy-Cache, Age, etc.

Piège fréquent : “J’ai installé un cache, mais je suis toujours en MISS”. Causes typiques :

  • Vous testez en étant connecté (cookies → bypass cache).
  • Votre plugin de sécurité ajoute un cookie sur tous les visiteurs (et casse la cacheabilité).
  • Votre thème injecte un contenu dynamique non cacheable (ex : nonce dans le HTML public).

Résultat attendu : sur pages publiques, TTFB baisse fortement (souvent < 200–400ms selon serveur/CDN).


Étape 3 : Activer un object cache persistant (Redis) sans casser l’admin

Le cache de page accélère les pages publiques cacheables. L’object cache persistant accélère ce qui reste dynamique : pages non cacheées, admin, REST API, requêtes répétées, builders.

WordPress a une API d’object cache : WP_Object_Cache. Par défaut, c’est en mémoire par requête. Avec Redis/Memcached, vous le rendez persistant.

1) Vérifier que Redis est disponible

Selon l’hébergeur : activation dans le panel, ou installation serveur. Si vous êtes en mutualisé sans Redis, sautez cette étape.

2) Installer un plugin Redis Object Cache

  1. WP Admin → Extensions → Ajouter
  2. Installez un plugin de cache Redis maintenu (ex : “Redis Object Cache” sur wordpress.org)
  3. Activez-le

Plugin officiel populaire : wordpress.org/plugins/redis-cache

3) Activer et tester

Dans les réglages du plugin, activez l’object cache. Ensuite :

  • Vérifiez que Object Cache: Enabled
  • Surveillez l’admin : si vous voyez des lenteurs ou des comportements bizarres, il y a souvent un souci de préfixe, de DB, ou de cache non purgé.

4) Ajuster un préfixe Redis (utile en multi-sites / environnements)

Sur certains hébergements, plusieurs sites partagent Redis. Un préfixe évite les collisions.

Dans wp-config.php (au-dessus de “That’s all”):

define( 'WP_CACHE_KEY_SALT', 'exemple_com:' ); // Préfixe unique pour éviter les collisions Redis

Résultat attendu : baisse du temps serveur sur pages non cacheées, admin plus réactive, moins de temps DB observé dans Query Monitor.


Étape 4 : Images : arrêter l’hémorragie (WebP/AVIF, tailles, lazy-load)

Sur les blogs, les images sont souvent 60–90% du poids total. Le problème n’est pas “WordPress ne compresse pas”, c’est surtout : mauvaises dimensions, images héro en 4000px, et thumbnails absents.

1) Vérifier les tailles d’images réellement utilisées

Ouvrez un article, inspectez l’image principale : si vous voyez un fichier 2500–4000px affiché en 800px, vous gaspillez.

2) Ajuster les tailles d’images (code) via un mu-plugin

Créez le fichier wp-content/mu-plugins/bpcab-perf.php. Si le dossier mu-plugins n’existe pas, créez-le.

<?php
/**
 * Plugin Name: BPCAB - Performance (mu-plugin)
 * Description: Ajustements de performance sûrs pour WordPress 6.9.4+.
 * Author: Vous
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Limite la taille max des images uploadées.
 * Évite les uploads 6000px qui finissent affichés en 1200px.
 */
add_filter( 'big_image_size_threshold', function( $threshold ) {
	// 2560 est un bon compromis pour la plupart des thèmes modernes
	return 2560;
} );

/**
 * Ajuste la qualité JPEG (si vous servez encore du JPEG).
 * Attention : trop bas = artefacts visibles.
 */
add_filter( 'jpeg_quality', function( $quality, $context ) {
	// Contexte 'image_resize' / 'edit_image' selon les cas
	return 82;
}, 10, 2 );

Où coller : fichier wp-content/mu-plugins/bpcab-perf.php via FTP/SSH ou gestionnaire de fichiers.

Résultat attendu : les nouveaux uploads sont plafonnés, et les JPEG sont un peu plus légers.

3) Activer WebP/AVIF (pratique)

WordPress gère nativement des formats modernes selon la config serveur (librairies image). Si votre serveur supporte AVIF/WebP, vous pouvez convertir via un plugin d’optimisation d’images (ou via votre CDN).

Je préfère souvent la conversion via CDN (Cloudflare Images / Bunny / etc.) pour éviter de charger le CPU du serveur WordPress.

Vérification : dans DevTools → Network → cliquez une image → regardez content-type (image/webp ou image/avif).


Étape 5 : CSS/JS : charger moins, charger mieux (sans “optimiseur magique”)

Les plugins “minify/combine tout” cassent régulièrement Divi/Elementor/Avada, surtout quand ils réordonnent des scripts. Je préfère une approche chirurgicale : désactiver ce qui est inutile, et s’assurer que vos propres assets sont enqueued proprement.

Référence enqueue : wp_enqueue_script() et wp_enqueue_style().

1) Désactiver les emojis (petit gain, zéro risque)

Ajoutez au mu-plugin :

/**
 * Désactive les emojis WordPress (scripts + styles).
 */
add_action( 'init', function() {
	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' );
} );

2) Stopper les embeds si vous ne les utilisez pas

Si vous n’intégrez pas de contenus externes via oEmbed (YouTube, X, etc.), vous pouvez couper. Sinon, ne le faites pas.

/**
 * Désactive wp-embed si vous n'utilisez pas d'oEmbed.
 */
add_action( 'wp_enqueue_scripts', function() {
	wp_deregister_script( 'wp-embed' );
}, 100 );

3) Désactiver jQuery Migrate sur le front (si compatible)

Sur des sites anciens, jQuery Migrate est parfois requis par un vieux plugin. Sur beaucoup de sites modernes, c’est du poids inutile. Testez en staging.

/**
 * Retire jQuery Migrate sur le front si aucun plugin ne l'exige.
 * Testez soigneusement : un vieux slider peut casser.
 */
add_action( 'wp_default_scripts', function( $scripts ) {
	if ( is_admin() ) {
		return;
	}

	if ( isset( $scripts->registered['jquery'] ) && ! empty( $scripts->registered['jquery']->deps ) ) {
		$scripts->registered['jquery']->deps = array_diff(
			$scripts->registered['jquery']->deps,
			array( 'jquery-migrate' )
		);
	}
} );

Résultat attendu : moins de JS chargé sur toutes les pages, sans casser le rendu.


Étape 6 : Base de données & WP-Cron : réduire le bruit de fond

Deux ralentisseurs fréquents : une table options gonflée (autoload) et un WP-Cron déclenché à chaque visite (surtout sur sites à trafic).

1) Diagnostiquer l’autoload (sans casser)

Dans Query Monitor, regardez les requêtes sur wp_options. Un autoload énorme augmente la mémoire et le temps à chaque requête.

Pour aller plus loin, utilisez WP-CLI si vous l’avez :

wp option list --autoload=on --fields=option_name,size_bytes --orderby=size_bytes --order=desc --format=table | head -n 30

Résultat attendu : vous identifiez 5–10 options géantes (souvent des builders, des plugins de cache, des plugins stats) qui n’ont rien à faire en autoload.

2) Passer WP-Cron en cron système (recommandé si vous avez accès serveur)

WP-Cron est un pseudo-cron déclenché par les visites. Sur un site à trafic, ça crée un bruit constant. Référence : WP-Cron (Plugin Handbook).

Dans wp-config.php :

define( 'DISABLE_WP_CRON', true ); // Désactive WP-Cron déclenché par les visites

Puis créez un cron système (exemple toutes les 5 minutes) :

*/5 * * * * curl -s https://exemple.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1

Piège fréquent : activer DISABLE_WP_CRON et oublier le cron système. Symptôme : publications planifiées qui ne partent plus, emails retardés.


Étape 7 : Réduire les requêtes inutiles (exemple concret dans functions.php)

Beaucoup de lenteurs viennent de petites choses répétées : widgets qui chargent 10 requêtes, requêtes de “posts populaires” non indexées, shortcodes qui font des WP_Query sans cache.

Objectif : un exemple utile et sûr

On va :

  • Éviter la génération de certains liens inutiles dans le <head>.
  • Limiter les révisions (DB plus petite, moins de nettoyage).
  • Mettre en cache un WP_Query typique (liste “Derniers articles”) avec transients.

Code (à ajouter dans le mu-plugin)

/**
 * Nettoie quelques éléments du <head> (gains modestes mais propres).
 */
add_action( 'init', function() {
	// Liens RSD/WLW : rarement utiles en 2026
	remove_action( 'wp_head', 'rsd_link' );
	remove_action( 'wp_head', 'wlwmanifest_link' );

	// Version WP dans le head (petit gain + réduit l'info exposée)
	remove_action( 'wp_head', 'wp_generator' );
} );

/**
 * Limite les révisions (réduit la croissance DB).
 * À mettre aussi dans wp-config.php si vous préférez une constante.
 */
add_filter( 'wp_revisions_to_keep', function( $num, $post ) {
	return 10;
}, 10, 2 );

/**
 * Exemple : shortcode [bpcab_recent_posts] qui met en cache une requête.
 * Utile si vous l'insérez dans des pages builder (Divi/Elementor/Avada).
 */
add_shortcode( 'bpcab_recent_posts', function( $atts ) {
	$atts = shortcode_atts(
		array(
			'count' => 5,
		),
		$atts,
		'bpcab_recent_posts'
	);

	$count = max( 1, min( 20, (int) $atts['count'] ) );

	$cache_key = 'bpcab_recent_posts_' . $count;
	$html      = get_transient( $cache_key );

	if ( false !== $html ) {
		return $html;
	}

	$q = new WP_Query(
		array(
			'post_type'              => 'post',
			'posts_per_page'         => $count,
			'no_found_rows'          => true,  // Performance : pas de pagination
			'ignore_sticky_posts'    => true,
			'update_post_meta_cache' => false, // Performance : si vous n'utilisez pas les metas
			'update_post_term_cache' => false, // Performance : si vous n'utilisez pas les catégories/tags ici
		)
	);

	ob_start();

	echo '<div class="bpcab-recent-posts">';
	echo '<ul>';

	if ( $q->have_posts() ) {
		while ( $q->have_posts() ) {
			$q->the_post();
			printf(
				'<li><a href="%s">%s</a></li>',
				esc_url( get_permalink() ),
				esc_html( get_the_title() )
			);
		}
	}

	echo '</ul>';
	echo '</div>';

	wp_reset_postdata();

	$html = ob_get_clean();

	// Cache 5 minutes (ajustez selon votre fréquence de publication)
	set_transient( $cache_key, $html, 5 * MINUTE_IN_SECONDS );

	return $html;
} );

Où l’utiliser

  • Dans un article : collez [bpcab_recent_posts count="5"].
  • Dans Divi/Elementor/Avada : utilisez un module/widget “Shortcode”.

Résultat attendu : la requête “derniers articles” n’est plus exécutée à chaque chargement (surtout utile sur pages builder avec plusieurs blocs dynamiques).


Étape 8 : Polices & scripts tiers : gagner des secondes “gratuites”

Je vois très souvent un site “optimisé” côté WordPress, mais plombé par 6 tags marketing, 2 trackers, un chat, et Google Fonts via 4 variantes. Le navigateur attend, parse, exécute, et votre INP se dégrade.

1) Héberger vos polices localement

  • Réduisez les variantes (2 graisses max si possible).
  • Servez en WOFF2, preload si nécessaire (avec parcimonie).

2) Charger Analytics/Tags proprement

  • Évitez 2 solutions en parallèle (ex : GA via plugin + GTM via thème).
  • Chargez en defer quand possible (selon script).

Si vous devez ajouter defer à un script que vous enqueuez vous-même :

/**
 * Ajoute l'attribut defer à un script spécifique (handle).
 * Attention : ne mettez pas defer partout, certains scripts doivent rester synchrones.
 */
add_filter( 'script_loader_tag', function( $tag, $handle, $src ) {
	$handles_defer = array( 'bpcab-analytics' );

	if ( in_array( $handle, $handles_defer, true ) ) {
		return sprintf(
			'<script src="%s" defer></script>',
			esc_url( $src )
		);
	}

	return $tag;
}, 10, 3 );

Résultat attendu : moins de blocage du main-thread, meilleur INP, waterfall plus propre.


Le résultat complet

Voici un fichier unique que vous pouvez copier tel quel. Il regroupe les optimisations “safe” vues plus haut. Ne copiez pas ça dans functions.php au hasard : utilisez un mu-plugin pour éviter qu’un changement de thème supprime vos optimisations.

Fichier : wp-content/mu-plugins/bpcab-perf.php

<?php
/**
 * Plugin Name: BPCAB - Performance (mu-plugin)
 * Description: Optimisations pragmatiques pour WordPress 6.9.4+ (PHP 8.1+).
 * Author: Vous
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * 1) Images : limite la taille max des images uploadées.
 */
add_filter( 'big_image_size_threshold', function( $threshold ) {
	return 2560;
} );

/**
 * 2) Images : qualité JPEG (si JPEG).
 */
add_filter( 'jpeg_quality', function( $quality, $context ) {
	return 82;
}, 10, 2 );

/**
 * 3) Head : retire quelques éléments rarement utiles.
 */
add_action( 'init', function() {
	remove_action( 'wp_head', 'rsd_link' );
	remove_action( 'wp_head', 'wlwmanifest_link' );
	remove_action( 'wp_head', 'wp_generator' );

	// 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' );
} );

/**
 * 4) Désactive wp-embed si vous n'utilisez pas d'oEmbed.
 * Commentez cette ligne si vous intégrez souvent YouTube/Twitter/etc.
 */
add_action( 'wp_enqueue_scripts', function() {
	wp_deregister_script( 'wp-embed' );
}, 100 );

/**
 * 5) Retire jQuery Migrate sur le front (testez en staging).
 */
add_action( 'wp_default_scripts', function( $scripts ) {
	if ( is_admin() ) {
		return;
	}

	if ( isset( $scripts->registered['jquery'] ) && ! empty( $scripts->registered['jquery']->deps ) ) {
		$scripts->registered['jquery']->deps = array_diff(
			$scripts->registered['jquery']->deps,
			array( 'jquery-migrate' )
		);
	}
} );

/**
 * 6) Limite les révisions.
 */
add_filter( 'wp_revisions_to_keep', function( $num, $post ) {
	return 10;
}, 10, 2 );

/**
 * 7) Shortcode cacheable pour pages builder.
 */
add_shortcode( 'bpcab_recent_posts', function( $atts ) {
	$atts = shortcode_atts(
		array(
			'count' => 5,
		),
		$atts,
		'bpcab_recent_posts'
	);

	$count = max( 1, min( 20, (int) $atts['count'] ) );

	$cache_key = 'bpcab_recent_posts_' . $count;
	$html      = get_transient( $cache_key );

	if ( false !== $html ) {
		return $html;
	}

	$q = new WP_Query(
		array(
			'post_type'              => 'post',
			'posts_per_page'         => $count,
			'no_found_rows'          => true,
			'ignore_sticky_posts'    => true,
			'update_post_meta_cache' => false,
			'update_post_term_cache' => false,
		)
	);

	ob_start();

	echo '<div class="bpcab-recent-posts">';
	echo '<ul>';

	if ( $q->have_posts() ) {
		while ( $q->have_posts() ) {
			$q->the_post();
			printf(
				'<li><a href="%s">%s</a></li>',
				esc_url( get_permalink() ),
				esc_html( get_the_title() )
			);
		}
	}

	echo '</ul>';
	echo '</div>';

	wp_reset_postdata();

	$html = ob_get_clean();

	set_transient( $cache_key, $html, 5 * MINUTE_IN_SECONDS );

	return $html;
} );

/**
 * 8) Ajoute defer à des scripts spécifiques (si vous en avez).
 * Exemple : si vous enregistrez un script 'bpcab-analytics'.
 */
add_filter( 'script_loader_tag', function( $tag, $handle, $src ) {
	$handles_defer = array( 'bpcab-analytics' );

	if ( in_array( $handle, $handles_defer, true ) ) {
		return sprintf(
			'<script src="%s" defer></script>',
			esc_url( $src )
		);
	}

	return $tag;
}, 10, 3 );

Personnalisation rapide

  • Si vous utilisez des embeds (YouTube, etc.) : commentez la partie wp_deregister_script( 'wp-embed' );.
  • Si un plugin ancien casse sans jQuery Migrate : retirez le bloc “jQuery Migrate”.
  • Si vous publiez rarement : augmentez le TTL du transient (ex : 30 minutes).

Adapter pour Divi 5 / Elementor / Avada

Divi 5

  • Divi charge beaucoup d’assets globaux. Votre meilleur levier est d’éviter d’empiler des modules qui injectent chacun leur JS (sliders, carrousels, effets).
  • Utilisez le shortcode [bpcab_recent_posts] dans un module “Code” ou “Texte”.
  • Testez la suppression de jQuery Migrate : Divi moderne s’en sort généralement, mais certains modules tiers non.

Elementor

  • Elementor + add-ons = explosion d’assets. Faites un inventaire dans Query Monitor → “Scripts & Styles”.
  • Préférez un widget “Shortcode” pour afficher des listes dynamiques cacheées (transients) plutôt que des widgets qui requêtent à chaque chargement.
  • Si vous utilisez beaucoup de popups/animations, surveillez l’INP : ce n’est pas “un problème serveur”.

Avada (Fusion Builder)

  • Avada peut charger des fichiers CSS/JS en fonction des éléments utilisés, mais des options globales peuvent forcer des bundles lourds.
  • Le shortcode cacheé fonctionne très bien dans un élément “Code Block” / “Shortcode”.
  • Sur Avada, je vois souvent des polices externes multiples : passer en local fait une différence immédiate.

Vérification finale

Checklist technique

  • Cache de page : vérifiez un HIT en navigation privée via curl -I.
  • Object cache : plugin Redis actif, pas d’erreurs, admin stable.
  • Query Monitor : baisse du temps DB et moins de requêtes sur pages critiques.
  • Images : poids réduit, formats modernes servis si possible, pas d’images surdimensionnées.
  • WP-Cron : si désactivé, cron système en place et fonctionnel.

Tableau de diagnostic (symptômes courants)

Symptôme Cause probable Vérification Solution
TTFB élevé même avec cache Cache bypass (cookies, pages exclues), cache non actif curl -I + en-têtes HIT/MISS, test en incognito Corriger exclusions, retirer cookie inutile, config cache serveur/plugin
LCP élevé mais TTFB bas Images héro trop lourdes, CSS/JS bloquants, polices externes Waterfall WebPageTest, DevTools “Largest Contentful Paint” Optimiser image LCP, réduire JS, héberger polices localement
Admin lente Pas d’object cache, plugins lourds, appels HTTP Query Monitor (HTTP API Calls, hooks coûteux) Redis object cache, supprimer plugin inutile, corriger appels externes
Publications planifiées ne partent plus DISABLE_WP_CRON sans cron système Test publication planifiée + logs serveur Ajouter cron système, ou réactiver WP-Cron
JS cassé après optimisation Suppression jQuery Migrate ou plugin minify agressif Console JS, désactivation temporaire du snippet Réactiver Migrate, exclure scripts, éviter combine/réordonnancement

Si le résultat n’est pas celui attendu

  • Vous ne voyez aucun gain : vous testez connecté. Testez en navigation privée, et videz le cache du plugin + CDN + navigateur.
  • Erreur 500 après ajout du code : code collé au mauvais endroit, parenthèse/point-virgule manquant. Supprimez temporairement wp-content/mu-plugins/bpcab-perf.php via FTP pour récupérer le site.
  • Le builder ne charge plus certains modules : jQuery Migrate retiré alors qu’un add-on en dépend. Remettez le bloc en commentaire ou retirez-le.
  • Le cache ne “HIT” jamais : un plugin ajoute un cookie à tous les visiteurs. Vérifiez les cookies en incognito, désactivez temporairement le plugin suspect (souvent sécurité/consentement) et retestez.
  • Les changements d’images ne s’appliquent pas : vous regardez d’anciennes images déjà générées. Régénérez les miniatures (plugin dédié) après avoir changé tailles/threshold.

Pièges et erreurs courantes

Erreur Cause Solution
Coller le snippet dans le mauvais fichier Ajout dans un plugin de cache, ou dans un thème parent mis à jour Utilisez un mu-plugin (wp-content/mu-plugins/) ou un thème enfant
Oublier de purger les caches Cache plugin/CDN/navigateur garde l’ancien rendu Purge cache plugin + CDN, puis test incognito
Utiliser un hook inadapté Ex : retirer des scripts trop tôt/trop tard Pour scripts/styles : wp_enqueue_scripts ou wp_default_scripts selon le cas
Minifier/combiner “tout” Réordonnancement JS, dépendances cassées Approche chirurgicale + exclusions, testez module par module
Désactiver WP-Cron sans cron système Oubli de configuration serveur Ajoutez un cron système ou réactivez WP-Cron
Optimiser sur production Pas de filet de sécurité Staging + sauvegarde + déploiement progressif
Suivre un vieux tutoriel incompatible Code 2018 basé sur pratiques obsolètes Vérifiez la compatibilité WordPress 6.9.4+ / PHP 8.1+ et testez

Variante / alternative

Alternative “sans code” (plus simple, parfois moins fine)

  • Plugin de cache de page + optimisation d’images (conversion WebP/AVIF) + désactivation d’assets via une interface.
  • Avantage : rapide à déployer.
  • Inconvénient : vous empilez parfois des couches (cache + minify agressif + lazy-load redondant) et vous perdez la maîtrise.

Alternative “plus avancée” (stack serveur)

  • Nginx + FastCGI cache (microcache) + Redis + CDN (cache HTML + images).
  • Avantage : performances excellentes, moins de plugins.
  • Inconvénient : nécessite compétences sysadmin et monitoring.

Conseils sécurité, performance et maintenance

  • Surveillez les mises à jour : un plugin “optimiseur” non maintenu est une source de failles et de bugs. Référence : Hardening WordPress.
  • Mesurez après chaque changement : une optimisation qui “semble logique” peut empirer l’INP (ex : defer sur un script critique).
  • Gardez un inventaire des scripts tiers : chaque tag marketing a un coût. Faites le tri trimestriellement.
  • Object cache : purgez Redis après de grosses mises à jour (theme/builder) si vous voyez des incohérences.
  • Ne cachez pas ce qui ne doit pas l’être : pages compte, admin, preview, endpoints sensibles. Un mauvais cache peut exposer des données.

Pour aller plus loin

  • Ajouter un endpoint interne de “health performance” (temps DB, hit rate Redis) réservé aux admins.
  • Mettre en cache des blocs dynamiques via transients (ex : “articles populaires”, “produits liés”) et invalider à la publication.
  • Mettre en place un CDN qui cache aussi le HTML public (avec règles de purge WordPress).
  • Optimiser les requêtes lentes identifiées par Query Monitor (index DB, suppression de plugins, refactor de shortcodes).

Ressources


FAQ

Dois-je forcément installer un plugin de cache ?

Non. Si votre hébergeur fournit un cache serveur bien intégré (avec purge et exclusions), c’est souvent meilleur. Le point non négociable : vérifier que vous avez des HIT sur les pages publiques.

Redis est-il utile si j’ai déjà un cache de page ?

Oui, surtout pour l’admin, les pages non cacheées, les sites avec beaucoup de plugins, ou des builders. Sur un blog très simple et 100% cacheable, le gain peut être faible.

Pourquoi éviter les plugins “combine/minify tout” ?

Parce que le gain marginal est souvent inférieur au risque : scripts réordonnés, dépendances cassées, comportements aléatoires sur Divi/Elementor/Avada. Je préfère supprimer les assets inutiles plutôt que de “compresser le chaos”.

Est-ce que désactiver jQuery Migrate est “safe” en 2026 ?

Souvent oui, mais pas toujours. Le risque vient des plugins anciens (sliders, popups, add-ons) qui utilisent des APIs jQuery obsolètes. Testez en staging et surveillez la console.

Mon TTFB est bon, mais mon score Lighthouse reste moyen : pourquoi ?

Parce que Lighthouse pénalise surtout le rendu côté navigateur : JS lourd, main-thread occupé, images non optimisées, polices externes, scripts tiers. Travaillez le LCP/INP, pas seulement le serveur.

Dois-je désactiver wp-embed ?

Seulement si vous n’utilisez pas d’oEmbed. Si vos auteurs intègrent souvent YouTube, Spotify, etc., gardez-le.

Où mettre le code : functions.php, plugin de snippets, mu-plugin ?

Pour des optimisations “site-wide”, le mu-plugin est le plus stable. functions.php d’un thème parent est un anti-pattern (mise à jour = perte). Les plugins de snippets peuvent être pratiques, mais un snippet cassé peut parfois bloquer l’admin selon l’outil.

Comment savoir si mon cache est cassé par un cookie ?

Testez en incognito, puis comparez les cookies reçus. Si un cookie est posé sur tous les visiteurs (même sans consentement), votre cache de page peut bypass. Les plugins de sécurité/consentement sont des suspects fréquents.

Faut-il régénérer les miniatures après changement des tailles ?

Oui si vous voulez que les anciennes images profitent des nouvelles tailles. Sinon, seules les nouvelles images seront correctes.

Quelle est la première optimisation à faire si je n’ai qu’une heure ?

Cache de page + vérification HIT/MISS + optimisation de l’image LCP (souvent l’image en haut de page). C’est là que j’obtiens le plus souvent un “effet waouh” rapide.

Comment éviter de casser le site en optimisant ?

Staging + changements progressifs + une seule variable à la fois + mesure après chaque étape. Et gardez un accès FTP/SSH pour désactiver un mu-plugin si nécessaire.