Si votre site WordPress tourne sur un serveur Apache (comme la majorité) et que vous souhaitez optimiser la performance, voici des directives à insérer dans votre fichier .htaccess qui se trouve à la racine de votre site.

Le fichier de base comporte quelques lignes pour faire fonctionner l’url rewrite de votre WordPress. Vous devez conserver ce code.
Si votre site ne comporte pas de fichier .htaccess, vous devez le créer.

Éviter les réglages

Commençons directement par la bonne nouvelle, avec le plugin WP Rocket, vous n’avez pas besoin de passer par la modification du fichier .htaccess, car WP Rocket s’en charge pour vous.
En plus d’être un excellent plugin de cache, il optimise tous les réglages de votre site pour avoir un site WordPress performant.

En savoir plus sur le plugin WP Rocket

# BEGIN WordPress
# Les directives (lignes) entre « BEGIN WordPress » et « END WordPress » 
# sont générées
# dynamiquement, et doivent être modifiées uniquement via les filtres WordPress.
# Toute modification des directives situées entre ces marqueurs sera surchargée.
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
  RewriteBase /
  RewriteRule ^index\.php$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.php [L]
</IfModule>
# END WordPress

Mode gzip ou deflate

Commençons par activer la compression. Ce qui permettra au navigateur de recevoir des fichiers compressés de la part du serveur. On réduit donc la taille des transferts.

Pour les versions d’apache inférieurs à 2, on utilise le mode gzip :

<IfModule mod_gzip.c>
    mod_gzip_on Yes
    mod_gzip_dechunk Yes
    mod_gzip_item_include file .(html?|txt|css|js|svg|php|pl)$
    mod_gzip_item_include handler ^cgi-script$
    mod_gzip_item_include mime ^text/.*
    mod_gzip_item_include mime ^application/x-javascript.*
    mod_gzip_item_include mime ^image/svg+xml.*
    mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>

Pour les versions d’apache supérieurs à 2, c’est le mode deflate :

<IfModule mod_deflate.c>
# Insert filters / compress text, html, javascript, css, xml:
# mod_deflate can be used for Apache v2 and later and is the recommended GZip 
# mechanism to use
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/vtt
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE image/svg+xml svg svgz
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-woff
AddOutputFilterByType DEFLATE application/x-font-woff2
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE application/ld+json
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/eot
AddOutputFilterByType DEFLATE font/woff
AddOutputFilterByType DEFLATE font/woff2
AddOutputFilterByType DEFLATE font/opentype

# Exception: Images
SetEnvIfNoCase REQUEST_URI \.(?:gif|jpg|jpeg|png)$ no-gzip dont-vary

# Drop problematic browsers
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html

# Make sure proxies don't deliver the wrong content
<IfModule mod_headers.c>
Header append Vary User-Agent env=!dont-vary
</IfModule>

</IfModule>

Activer la date d’expiration des fichiers

Avec le mod_expires, vous allez définir des dates d’expirations par type de fichier.
Vous pouvez régler les délais comme vous le souhaitez.
Attention, au data (xml, json, html) qui doivent expirer rapidement et être le plus à jour possible.

Attention pour les fichiers ayant le même nom et qui sont modifiés. Ils ne seront pas vu par les visiteurs ayant déjà les fichiers en cache. C’est pour cela, qu’il faut utiliser des noms de fichiers avec des versions.

<IfModule mod_expires.c>
    ExpiresActive on
    ExpiresDefault                              "access plus 1 month"
    ExpiresByType text/cache-manifest           "access plus 0 seconds"
    ExpiresByType text/html                     "access plus 0 seconds"
    ExpiresByType text/xml                      "access plus 0 seconds"
    ExpiresByType application/xml               "access plus 0 seconds"
    ExpiresByType application/json              "access plus 0 seconds"
    ExpiresByType application/rss+xml           "access plus 1 hour"
    ExpiresByType application/atom+xml          "access plus 1 hour"
    ExpiresByType image/x-icon                  "access plus 1 week"
    ExpiresByType image/gif                     "access plus 3 months"
    ExpiresByType image/png                     "access plus 3 months"
    ExpiresByType image/jpeg                    "access plus 3 months"
    ExpiresByType image/webp                    "access plus 3 months"
    ExpiresByType video/ogg                     "access plus 3 months"
    ExpiresByType audio/ogg                     "access plus 3 months"
    ExpiresByType video/mp3                     "access plus 3 months"
    ExpiresByType video/webm                    "access plus 3 months"
    ExpiresByType image/avif                    "access plus 3 months"
    ExpiresByType image/avif-sequence           "access plus 3 months"
    ExpiresByType font/ttf                      "access plus 3 months"
    ExpiresByType font/otf                      "access plus 3 months"
    ExpiresByType font/woff                     "access plus 3 months"
    ExpiresByType font/woff2                    "access plus 3 months"
    ExpiresByType image/svg+xml                 "access plus 3 months"
    ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
    ExpiresByType text/css                      "access plus 1 year"
    ExpiresByType application/javascript        "access plus 1 year"
</IfModule>

Le cache-control

En complément au mode_expires, nous allons ajouter en plus un cache-control.

<IfModule mod_headers.c>
<FilesMatch "\.(ico|pdf|jpg|jpeg|png|gif|webp|avif|woff|woff2)$">
# 3 months
Header set Cache-Control "max-age=7776000, private"
</FilesMatch>
<FilesMatch "\.(css)$">
# 3 months
Header set Cache-Control "max-age=7776000, private"
</FilesMatch>
<FilesMatch "\.(js)$">
Header set Cache-Control "max-age=216000, private"
</FilesMatch>
<FilesMatch "\.(xml|txt)$">
Header set Cache-Control "max-age=172800, private"
</FilesMatch>
<FilesMatch "\.(html|htm)$">
Header set Cache-Control "max-age=7200"
</FilesMatch>
</IfModule>

Désactiver Etag

Comme nous avons réglé une date d’expiration pour les fichiers, nous pouvons désactiver les Etag.
Cela permettra de réduire les appels serveurs et donnera la priorité aux dates d’expirations.

<IfModule mod_headers.c>
Header unset ETag
</IfModule>
FileETag None

Réglages additionnels

Quelques petits réglages additionnels :

  • ajouter le header Keep-alive pour les connexions http1 (c’est ignoré pour http2)
  • Enlever la signature serveur
  • et cacher la version de PHP et du serveur. Pour php, il faut ajuster aussi dans le php.ini.
# ENABLE KEEP ALIVE Not REQUIRED in HTTP2 and 3
<ifModule mod_headers.c>
Header set Connection keep-alive
</ifModule>

# disable server signature
ServerSignature Off

#Unset X-Powered-By from Page Header
<IfModule mod_headers.c>
Header unset X-Powered-By
Header unset Server
</IfModule>

Le fichier final

Vous pouvez retrouver le fichier complet sur le repository Github ou le copier ci-dessous. Attention, parfois le copier/coller peut insérer des erreurs.

  # disable directory exploration
  Options -Indexes
  
  <IfModule mod_gzip.c>
    mod_gzip_on Yes
    mod_gzip_dechunk Yes
    mod_gzip_item_include file .(html?|txt|css|js|svg|php)$
    mod_gzip_item_include handler ^cgi-script$
    mod_gzip_item_include mime ^text/.*
    mod_gzip_item_include mime ^application/x-javascript.*
    mod_gzip_item_include mime ^image/svg+xml.*
    mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>


<IfModule mod_deflate.c>
# Insert filters / compress text, html, javascript, css, xml:
# mod_deflate can be used for Apache v2 and later and is the recommended GZip
# mechanism to use
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/vtt
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE image/svg+xml svg svgz
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-woff
AddOutputFilterByType DEFLATE application/x-font-woff2
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE application/ld+json
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/eot
AddOutputFilterByType DEFLATE font/woff
AddOutputFilterByType DEFLATE font/woff2
AddOutputFilterByType DEFLATE font/opentype

# Exception: Images
SetEnvIfNoCase REQUEST_URI \.(?:gif|jpg|jpeg|png)$ no-gzip dont-vary

# Drop problematic browsers
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html

# Make sure proxies don't deliver the wrong content
<IfModule mod_headers.c>
Header append Vary User-Agent env=!dont-vary
</IfModule>

</IfModule>

<IfModule mod_expires.c>
    ExpiresActive on
    ExpiresDefault                              "access plus 1 month"
    ExpiresByType text/cache-manifest           "access plus 0 seconds"
    ExpiresByType text/html                     "access plus 0 seconds"
    ExpiresByType text/xml                      "access plus 0 seconds"
    ExpiresByType application/xml               "access plus 0 seconds"
    ExpiresByType application/json              "access plus 0 seconds"
    ExpiresByType application/rss+xml           "access plus 1 hour"
    ExpiresByType application/atom+xml          "access plus 1 hour"
    ExpiresByType image/x-icon                  "access plus 1 week"
    ExpiresByType image/gif                     "access plus 3 months"
    ExpiresByType image/png                     "access plus 3 months"
    ExpiresByType image/jpeg                    "access plus 3 months"
    ExpiresByType image/webp                    "access plus 3 months"
    ExpiresByType video/ogg                     "access plus 3 months"
    ExpiresByType audio/ogg                     "access plus 3 months"
    ExpiresByType video/mp3                     "access plus 3 months"
    ExpiresByType video/webm                    "access plus 3 months"
    ExpiresByType image/avif                    "access plus 3 months"
    ExpiresByType image/avif-sequence           "access plus 3 months"
    ExpiresByType font/ttf                      "access plus 3 months"
    ExpiresByType font/otf                      "access plus 3 months"
    ExpiresByType font/woff                     "access plus 3 months"
    ExpiresByType font/woff2                    "access plus 3 months"
    ExpiresByType image/svg+xml                 "access plus 3 months"
    ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
    ExpiresByType text/css                      "access plus 1 year"
    ExpiresByType application/javascript        "access plus 1 year"
</IfModule>



<IfModule mod_headers.c>
<FilesMatch "\.(ico|pdf|jpg|jpeg|png|gif|webp|avif|woff|woff2)$">
# 3 months
Header set Cache-Control "max-age=7776000, private"
</FilesMatch>
<FilesMatch "\.(css)$">
# 3 months
Header set Cache-Control "max-age=7776000, private"
</FilesMatch>
<FilesMatch "\.(js)$">
Header set Cache-Control "max-age=216000, private"
</FilesMatch>
<FilesMatch "\.(xml|txt)$">
Header set Cache-Control "max-age=172800, private"
</FilesMatch>
<FilesMatch "\.(html|htm)$">
Header set Cache-Control "max-age=7200, private"
</FilesMatch>
</IfModule>


<IfModule mod_headers.c>
Header unset ETag
</IfModule>
FileETag None

# ENABLE KEEP ALIVE Not REQUIRED in HTTP2 and 3
<ifModule mod_headers.c>
Header set Connection keep-alive
</ifModule>

# disable server signature
ServerSignature Off

#Unset X-Powered-By from Page Header
<IfModule mod_headers.c>
Header unset X-Powered-By
Header unset Server
</IfModule>

# BEGIN WordPress
# Les directives (lignes) entre « BEGIN WordPress » et « END WordPress » 
# sont générées
# dynamiquement, et doivent être modifiées uniquement via les filtres WordPress.
# Toute modification des directives situées entre ces marqueurs sera surchargée.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

Attention, mon fichier ne prend pas en compte les directives de sécurité que l’on pourrait ajouter dans le .htaccess. Il se concentre uniquement sur les réglages de bases pour une meilleure performance de vos sites WordPress.