Aller au contenu
Courrier Cabinet Choisir un forfait

Accélérer WordPress : ce qui marche vraiment (testé sur banc d’essai)

Accélérer WordPress : ce qui marche vraiment (testé sur banc d’essai)

Le cache de page est ce qui accélère le plus WordPress : sur notre banc d’essai, le temps jusqu’au premier octet (TTFB) est passé de 41 ms à 0,3 ms, et le serveur est passé de 44 à plus de 14 000 pages par seconde. Le deuxième gain le plus important vient d’OPcache (190 ms sans, 41 ms avec), le troisième de la recherche de l’extension qui ralentit le site : notre imitation d’une telle extension ajoutait environ 265 ms à chaque requête. Viennent ensuite, par ordre d’impact mesuré, les workers PHP-FPM, la compression, les images, le cache d’objets et, en dernier, le nettoyage de l’autoload : 3 Mo d’options chargées automatiquement n’ont ajouté qu’environ 4 ms.

Comment nous avons testé

Banc d’essai RichHost, octobre 2026 : un conteneur isolé avec 2 vCPU / 8 Go de RAM, Ubuntu 24.04, nginx 1.24, PHP 8.3-FPM, MariaDB 10.11, WordPress 6.7.2, thème Twenty Twenty-Five, 300 articles générés. Les requêtes partaient de la même machine (127.0.0.1), le réseau et le TLS ne sont donc pas pris en compte. Le TTFB correspond à la médiane et au 90e centile (p90) de 40 requêtes curl après trois requêtes de préchauffage ; le débit a été mesuré avec ab (300 requêtes, 10 simultanées) ; pages testées : la page d’accueil et un article. L’« extension lourde » est notre mu-plugin qui exécute 150 requêtes SQL supplémentaires et attend 250 ms une API externe. Nous avons modifié un seul facteur à la fois. Ce sont des chiffres de laboratoire issus du banc d’essai, pas des valeurs de production de RichHost.

Résultats

Scénario TTFB médian (accueil / article) TTFB p90 Requêtes par seconde
OPcache désactivé 190 / 195 ms 210 / 216 ms 9,7 / 9,8
OPcache activé 41 / 45 ms 45 / 51 ms 44,1 / 41,6
OPcache + cache d’objets Redis* 39,7 / 39,6 ms 49,4 / 46,2 ms 47,3 / 48,4
OPcache + cache de page nginx 0,3 / 0,3 ms 0,4 / 0,3 ms 21 581 / 14 749
Extension lourde, sans cache de page 309 / 311 ms 325 / 323 ms 15,3 / 15,0
Extension lourde + cache d’objets Redis 306 / 306 ms 319 / 314 ms 15,3 / 15,4
Extension lourde + cache de page 0,2 / 0,3 ms 0,3 / 0,3 ms 18 703 / 15 202
Administrateur connecté (cache contourné) 44,8 / 45,9 ms 49,6 / 56,2 ms 39,8 / 38,8
+3 Mo d’options en autoload 45,4 / 45,4 ms 59,5 / 59,0 ms 42,3 / 39,3

* Les lignes Redis proviennent d’une série de mesures distincte, dans laquelle la référence sans cache d’objets était de 43,7 / 46,8 ms.

TTFB médian de WordPress sur le banc d'essai : 190 ms sans OPcache, 309 ms avec une extension lourde, 41 ms avec OPcache, 0,3 ms avec le cache de page
TTFB sur le banc d’essai RichHost : le cache de page supprime à la fois le travail PHP et le retard de l’extension lourde

Deux constats sont moins évidents que ne le laissent penser les conseils habituels. D’abord, le cache de page ne corrige pas une extension lente, il la masque aux visiteurs anonymes. Un administrateur, un client WooCommerce avec un panier ou toute personne ayant un cookie de connexion reçoit la page non mise en cache : 45 ms sur un site vierge et plus de 300 ms avec l’extension lourde. Ensuite, un autoload surchargé, souvent cité comme la première chose à corriger, n’a presque pas modifié la vitesse sur notre banc.

Étape 1. Cache de page

Sans cache, WordPress exécute PHP à chaque requête, lance 22 à 29 requêtes SQL (notre compteur sur la page d’accueil et un article) et reconstruit le HTML. Un cache de page sert du HTML déjà prêt : le TTFB est donc tombé de 41-45 ms à 0,2-0,3 ms, aussi bien pour le site vierge que pour le site avec l’extension lourde. Un vrai site ajoute le temps réseau, mais le travail du serveur disparaît presque entièrement.

Voici la configuration nginx fastcgi_cache que nous avons testée. Elle ne met en cache que les requêtes GET anonymes et contourne le cache pour les requêtes POST, les URL avec paramètres, l’administration, l’API REST et les visiteurs ayant un cookie de connexion, de commentaire ou de panier WooCommerce :

fastcgi_cache_path /var/cache/nginx/wp levels=1:2 keys_zone=WPCACHE:64m max_size=1g inactive=60m use_temp_path=off;

server {
  # ... listen, server_name, root, index ...

  set $skip_cache 0;
  if ($request_method = POST) { set $skip_cache 1; }
  if ($query_string != "") { set $skip_cache 1; }
  if ($request_uri ~* "/wp-admin/|/wp-json/|/xmlrpc.php|wp-.*\.php|/feed/|sitemap(_index)?\.xml") { set $skip_cache 1; }
  if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in|woocommerce_items_in_cart|woocommerce_cart_hash") { set $skip_cache 1; }

  location / { try_files $uri $uri/ /index.php?$args; }

  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    fastcgi_cache WPCACHE;
    fastcgi_cache_key "$scheme$request_method$host$request_uri";
    fastcgi_cache_valid 200 301 10m;
    fastcgi_cache_use_stale error timeout updating http_500 http_503;
    fastcgi_cache_background_update on;
    fastcgi_cache_lock on;
    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache $skip_cache;
    add_header X-Cache $upstream_cache_status always;
  }
}

Vérification des règles (l’en-tête X-Cache indique d’où vient la page) :

$ curl -sI http://127.0.0.1:8081/post-293/ | grep X-Cache
X-Cache: MISS
$ curl -sI http://127.0.0.1:8081/post-293/ | grep X-Cache
X-Cache: HIT
$ curl -sI -b wordpress_logged_in_abc=x http://127.0.0.1:8081/post-293/ | grep X-Cache
X-Cache: BYPASS
$ curl -sI http://127.0.0.1:8081/post-293/?utm_source=x | grep X-Cache
X-Cache: BYPASS

Deux points à connaître à l’avance. Les pages restent en cache 10 minutes (fastcgi_cache_valid) : après la modification d’un article, les visiteurs anonymes peuvent donc voir l’ancienne version pendant 10 minutes au maximum, sauf si vous mettez en place la purge du cache, par exemple avec l’extension Nginx Helper. fastcgi_cache_use_stale et fastcgi_cache_lock empêchent des centaines de visiteurs de solliciter PHP en même temps lorsqu’une entrée du cache expire. Sur un hébergement mutualisé, vous n’avez généralement pas accès à nginx : une extension fait alors le même travail, WP Super Cache, W3 Total Cache, ou LiteSpeed Cache si le serveur tourne sous LiteSpeed. Nous présentons les autres niveaux de cache et leurs besoins en mémoire dans notre article sur le cache et la RAM d’un hébergement.

Étape 2. OPcache

OPcache garde le code PHP compilé en mémoire, si bien que WordPress n’a pas à analyser des milliers de fichiers à chaque requête. OPcache désactivé, le banc a donné un TTFB de 190-195 ms et 9,7 requêtes par seconde ; activé, 41-45 ms et 42-44 requêtes, soit environ 4,5 fois plus rapide. C’est la vitesse que perçoivent tous ceux qui passent à côté du cache de page : administrateurs, rédacteurs, clients de la boutique.

Vérifiez OPcache pour le site, pas dans le terminal : PHP en ligne de commande (CLI) et PHP-FPM peuvent différer. Sur notre banc, php -v indique PHP 8.4 alors que le site tourne sous PHP 8.3-FPM, et OPcache est désactivé pour la CLI. Une vérification plus sûre consiste à créer à la racine du site un fichier temporaire contenant <?php var_dump(opcache_get_status(false)['opcache_enabled'] ?? false); : ouvrez-le dans un navigateur (sur le banc, il a affiché bool(true)) puis supprimez-le aussitôt. Les réglages par défaut du paquet Ubuntu ont suffi sur le banc.

Étape 3. Trouver l’extension lente

L’imitation d’extension lourde a fait passer le TTFB de 41-45 ms à 309-311 ms. Il existe trois moyens de trouver le coupable.

Query Monitor. Une extension d’administration qui affiche dans la barre d’outils le nombre et la durée des requêtes SQL par extension, ainsi que les requêtes HTTP sortantes.

wp profile. Une commande du paquet wp-cli/profile-command (à installer avec wp package install wp-cli/profile-command) qui montre quelle étape du chargement consomme le temps. Sortie réelle du banc avec l’imitation activée :

$ wp profile stage --url=http://127.0.0.1:8080/post-293/ --fields=stage,time,query_time,query_count
stage        time      query_time  query_count
bootstrap    0.2059s   0.0017s     4
main_query   0.2701s   0.0107s     155
template     0.0751s   0.0062s     20
total (3)    0.5512s   0.0186s     179

$ wp profile stage main_query --spotlight --url=http://127.0.0.1:8080/post-293/ --fields=hook,time,query_time,query_count
hook                   time      query_time  query_count
pre_get_posts:before   0.2779s   0.0151s     150
wp                     0.2765s   0.0151s     150

Sans l’imitation, main_query prenait 0,005 s et 5 requêtes ; avec elle, 0,27 s et 155, et --spotlight a réduit la recherche au hook wp. Les temps absolus sont plus élevés que dans un navigateur, car WP-CLI tourne sans OPcache, mais la comparaison des étapes reste valable. La sous-commande wp profile hook, qui désigne la fonction exacte, n’a pas fonctionné avec WP-CLI 2.12 sur le banc : elle nécessite une version plus récente de WP-CLI.

Slow log de PHP-FPM. Si vous pouvez modifier les réglages du pool, deux lignes suffisent pour que FPM enregistre une trace de pile pour chaque requête de plus d’une seconde :

; /etc/php/8.3/fpm/pool.d/www.conf
request_slowlog_timeout = 1s
slowlog = /var/log/php8.3-fpm-slow.log

Pour le tester, nous avons ajouté une fonction qui « attend une API » pendant 1,5 s. Le journal a pointé directement vers la fonction et le fichier :

[24-Oct-2026 23:45:18]  [pool www] pid 17625
script_filename = /var/www/bench/index.php
[0x00007f56fc215510] usleep() /var/www/bench/wp-content/mu-plugins/r1-slowapi.php:3
[0x00007f56fc2154c0] r1_bench_fetch_remote_rates() /var/www/bench/wp-content/mu-plugins/r1-slowapi.php:4
[0x00007f56fc215440] {closure}() /var/www/bench/wp-includes/class-wp-hook.php:324
...
[0x00007f56fc215100] wp() /var/www/bench/wp-blog-header.php:16

Que faire du coupable : le mettre à jour, le remplacer par une alternative plus légère ou demander au développeur de mettre en cache la réponse de l’API externe (par exemple dans un transient), pour que le site ne l’attende pas à chaque affichage de page.

Étape 4. Workers PHP-FPM

Un worker PHP-FPM traite une seule requête à la fois, les autres attendent dans une file. Nous avons envoyé 20 requêtes lentes simultanées (extension lourde, sans cache) avec pm.max_children = 5 puis 20.

Temps de réponse sous 20 requêtes simultanées : médiane de 1272 ms avec 5 workers PHP-FPM et de 846 ms avec 20, p95 de 1693 et 1642 ms
Plus de workers réduisent la médiane, mais pas les réponses les plus lentes : le serveur n’avait toujours que deux cœurs CPU

Avec 20 workers, la médiane est passée de 1272 ms à 846 ms et le débit de 14,0 à 18,8 requêtes par seconde. Mais le p95 a à peine bougé (1693 contre 1642 ms) : il n’y avait toujours que deux cœurs CPU, que les workers se disputaient. Chaque worker utilisait en outre 40 à 42 Mo de RAM sur le banc, donc 20 workers occupent environ 0,8 Go rien que pour PHP. Règle approximative : pm.max_children est égal à la mémoire que vous pouvez accorder à PHP divisée par la taille d’un worker :

$ ps --no-headers -o rss,cmd -C php-fpm8.3
10644 php-fpm: master process (/etc/php/8.3/fpm/php-fpm.conf)
42888 php-fpm: pool www
41148 php-fpm: pool www

Plus de workers raccourcissent la file d’attente, ils ne rendent pas le code plus rapide. Les autres réglages de la pile sont traités dans notre guide sur la configuration du serveur.

Étape 5. Compression gzip

Le HTML de la page d’accueil du banc pesait 56,8 Ko sans compression et 12,3 Ko avec gzip, soit 4,6 fois moins. Le piège : le nginx.conf par défaut d’Ubuntu n’active gzip que pour le HTML, car la ligne gzip_types est commentée. Résultat, la feuille de style des blocs du cœur de WordPress (style.min.css) était servie sans compression, avec 114 706 octets. Après l’ajout de gzip_types, le même fichier pesait 15 608 octets :

gzip on;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_vary on;
gzip_proxied any;
gzip_types text/css application/javascript application/json image/svg+xml text/xml application/xml application/rss+xml;

Pour vérifier votre propre site, comparez la taille de la réponse avec et sans demande de compression :

$ curl -s -o /dev/null -w "%{size_download}\n" http://127.0.0.1:8080/
56776
$ curl -s -o /dev/null -H "Accept-Encoding: gzip" -w "%{size_download}\n" http://127.0.0.1:8080/
12319

Étape 6. Images et CDN

Les images n’influencent pas le TTFB, mais elles représentent généralement l’essentiel du poids de la page. Nous avons fait passer deux vraies photos PNG par l’éditeur d’images de WordPress (GD), avec la qualité par défaut et sans redimensionnement :

Photo PNG JPEG (qualité 82) WebP (86) AVIF (82)
741×500 px 630 Ko 84,4 Ko 76,3 Ko 86,3 Ko
600×400 px 456 Ko 50,1 Ko 49,0 Ko 52,5 Ko

Le vrai gain consiste à ne pas utiliser le PNG pour les photos : 7 à 9 fois plus léger. Passer du JPEG au WebP avec les réglages par défaut de WordPress n’a fait gagner que 2 à 10 %, et l’AVIF via GD en qualité 82 était même plus lourd que le JPEG. Activez donc le WebP, mais n’en attendez pas de miracles. Des tailles d’image correctes comptent davantage (WordPress réduit les originaux de plus de 2560 px de large et génère des tailles intermédiaires), tout comme le chargement différé natif. Nous n’avons mesuré ni les grandes photos de smartphone ni un CDN : un banc local ne présente pas la latence réseau qu’un CDN réduit.

Étape 7. Cache d’objets (Redis)

Un cache d’objets Redis conserve les résultats des requêtes à la base de données d’un affichage de page à l’autre. Sur le banc (Redis 7.0, php-redis et un drop-in minimal), le nombre de requêtes SQL par page est tombé de 22-29 à zéro, le TTFB de 43,7-46,8 ms à 39,6-39,7 ms, et le débit a augmenté de 10 à 20 %. Redis n’a pas sauvé l’extension lourde : ses 150 requêtes directes et l’attente de l’API sont restées, avec 306 ms contre 311-313 ms sans Redis. La base de données du banc est petite et locale, une grande boutique ou une base distante peut donc y gagner davantage. Le cache d’objets est surtout utile là où le cache de page ne s’applique pas : espace client, panier, administration.

Étape 8. Autoload : à vérifier, mais pas en premier

WordPress charge à chaque requête les options marquées autoload. Nous avons ajouté 60 options de 50 Ko chacune (environ 3 Mo au total), et le TTFB médian n’a augmenté que de 0,4 à 4,4 ms, le p90 de 8 à 14 ms. Nettoyez donc l’autoload lorsqu’il atteint des dizaines de mégaoctets ou que l’outil Santé du site signale sa taille, mais pas à la place du cache de page et d’OPcache. Pour vérifier la taille et les options les plus volumineuses :

$ wp option list --autoload=on --format=total_bytes
44236
$ wp db query "SELECT option_name, LENGTH(option_value) bytes FROM wp_options WHERE autoload IN ('yes','on','auto','auto-on') ORDER BY bytes DESC LIMIT 5"
option_name                         bytes
_transient_wp_core_block_css_files  20490
_transient_wp_styles_for_blocks     10690
rewrite_rules                       8495
wp_user_roles                       3133
cron                                1027

44 Ko, c’est normal pour un site vierge. Si le haut de la liste contient des centaines de kilooctets laissés par une extension supprimée depuis longtemps, vous pouvez retirer cette option de l’autoload avec wp option set-autoload option_name off, après avoir sauvegardé la base de données.

Hébergement mutualisé ou VPS : ce que vous pouvez faire

Étape Hébergement mutualisé VPS
Cache de page Une extension de cache (WP Super Cache, W3 Total Cache, LiteSpeed Cache sur LiteSpeed) nginx fastcgi_cache avec la configuration ci-dessus
OPcache Vérifier avec un fichier de test ; s’il est désactivé, l’activer dans les réglages PHP du panneau ou demander au support opcache.enable=1 dans le php.ini de FPM
Extensions lentes Query Monitor Query Monitor, wp profile, slow log de PHP-FPM
Workers PHP Les limites sont fixées par l’hébergeur ; si le site les atteint, il faut une autre offre pm.max_children selon la mémoire, comme à l’étape 4
Compression Généralement déjà active, à vérifier avec curl gzip_types dans nginx
Cache d’objets Seulement si l’hébergeur propose Redis ou Memcached redis-server, php-redis et une extension de cache d’objets

Si les pages non mises en cache restent lentes après le cache de page, OPcache et la revue des extensions, et que les workers manquent aux heures de pointe, il est temps d’envisager une offre plus grande ou un VPS ; nous expliquons séparément quel type d’hébergement choisir. Les prérequis serveur de WordPress sont réunis dans notre guide de l’hébergement WordPress, et les offres d’hébergement RichHost sont des hébergements mutualisés sur disques NVMe avec le panneau de contrôle maison doté d’un assistant IA et un certificat SSL Let’s Encrypt gratuit.

FAQ

Faut-il une extension de cache si le serveur a déjà un cache nginx ?

Non. Deux caches de page en même temps compliquent seulement la purge. Gardez-en un : le cache serveur sur un VPS ou une extension sur un hébergement mutualisé.

Pourquoi PageSpeed Insights a-t-il à peine changé après la mise en cache ?

PageSpeed évalue toute la page (images, scripts, polices) et mesure depuis les serveurs de Google, avec la latence réseau. Le cache ne réduit que la partie serveur ; les étapes 5 et 6 traitent le reste.

À partir de combien d’extensions est-ce trop ?

Nous n’avons pas mesuré le nombre d’extensions, mais une seule extension avec 150 requêtes et un appel d’API coûtait environ 265 ms par requête. Ce qui compte, c’est ce que fait chaque extension à chaque affichage de page, pas leur nombre ; Query Monitor et wp profile le montrent.

Sur le même sujet

Tous les articles
Messagerie professionnelle sur votre domaine : boîtes mail illimitées
Types d’hébergement29.10.2026

Messagerie professionnelle sur votre domaine : boîtes mail illimitées

Email sur votre propre domaine dans chaque offre RichHost : boîtes et taille illimitées, envois depuis des IP propres, IMAP/SMTP, SSL gratuit,…

Erreur critique WordPress : trouver la cause et réparer le site
Dépannage d’hébergement21.10.2026

Erreur critique WordPress : trouver la cause et réparer le site

Pas à pas : comment trouver la cause de « There has been a critical error on this website » et de…

Migrer WordPress vers un autre hébergeur : extension ou manuel
Migration et transfert d’hébergement07.10.2026

Migrer WordPress vers un autre hébergeur : extension ou manuel

Trois façons de migrer WordPress vers un autre hébergeur : Duplicator, All-in-One WP Migration et la migration manuelle en SSH. Commandes pour…