Un TTFB supérieur à 800 ms sur une fiche produit PrestaShop, c'est souvent un signal Google classé "poor" dans les CWV — et un facteur de ranking qui joue contre vous. Cache mal configuré, requêtes SQL non optimisées, overrides PHP lourds : voici comment diagnostiquer et réduire le Time To First Byte sur PrestaShop.
Comprendre ce que mesure le TTFB
Le TTFB (Time To First Byte) est le temps écoulé entre la requête HTTP du navigateur et la réception du premier octet de la réponse serveur. Il se décompose en trois phases :
- Temps de traitement réseau : DNS, TCP handshake, TLS negotiation
- Temps d'attente serveur : PHP, MySQL, cache
- Début de transfert : premier octet de la réponse HTML
Dans PrestaShop, c'est presque exclusivement le temps de traitement PHP + MySQL qui pose problème. Un serveur bien configuré avec un bon cache descend sous les 200 ms. Sans cache, 1 à 3 secondes sont courantes sur un catalogue de taille moyenne.
Mesurer le TTFB avec précision
Avant d'optimiser, mesurez. Plusieurs outils donnent des lectures différentes :
- Chrome DevTools → Network → première requête HTML : colonne "Waiting (TTFB)" — le plus fiable pour du local
- WebPageTest.org : mesure depuis des sondes externes, plus représentatif
- curl -w "%{time_starttransfer}" : pour automatiser les mesures en CI
# Mesure TTFB via curl
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
https://votre-boutique.com/produit.html
Le cache Smarty : premier levier
PrestaShop utilise Smarty comme moteur de templates. Par défaut, le cache Smarty est activé mais parfois mal configuré — notamment après des déploiements où le dossier var/cache/ n'a pas été vidé proprement.
Vérifier et activer le cache Smarty
Dans le back-office : Paramètres avancés → Performances. Activez :
- Cache Smarty : oui
- Mise en cache multi-boutique : non (sauf si vous avez réellement plusieurs boutiques)
- Cache des fichiers PHP : "Recompiler les fichiers de templates à chaque accès" → non en production
Programmatiquement, dans un override ou un module :
<?php
// Forcer le cache Smarty en lecture uniquement
$this->context->smarty->setCaching(Smarty::CACHING_LIFETIME_SAVED);
$this->context->smarty->cache_lifetime = 3600; // 1 heure
Cache personnalisé dans un override de controller
Si vous overridez ProductController et ajoutez de la logique métier lourde, implémentez du cache applicatif :
<?php
class ProductControllerCore extends FrontController
{
public function initContent(): void
{
$cacheKey = 'product_data_' . (int)$this->product->id . '_' . (int)$this->context->language->id;
$cached = Cache::retrieve($cacheKey);
if ($cached === false) {
$cached = $this->buildExpensiveProductData();
Cache::store($cacheKey, $cached, 3600);
}
$this->context->smarty->assign('custom_data', $cached);
parent::initContent();
}
}
Identifier les requêtes SQL lentes
Le TTFB explose souvent à cause de requêtes N+1 dans les overrides. PrestaShop propose un mode debug SQL natif.
Activer le debug SQL
Dans config/defines.inc.php (à ne jamais faire en production) :
<?php
define('_PS_DEBUG_SQL_', true);
En production, utilisez le slow query log MySQL :
# my.cnf
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 0.5
log_queries_not_using_indexes = 1
Optimiser avec DBQuery
Si vous avez des requêtes personnalisées dans vos overrides, utilisez DbQuery et évitez les sous-requêtes imbriquées :
<?php
class MyProductRepository
{
public function getProductsWithStock(int $categoryId, int $langId): array
{
$query = new DbQuery();
$query->select('p.id_product, pl.name, sa.quantity')
->from('product', 'p')
->innerJoin('product_lang', 'pl', 'p.id_product = pl.id_product AND pl.id_lang = ' . $langId)
->innerJoin('stock_available', 'sa', 'p.id_product = sa.id_product AND sa.id_product_attribute = 0')
->innerJoin('category_product', 'cp', 'p.id_product = cp.id_product')
->where('cp.id_category = ' . $categoryId)
->where('p.active = 1')
->orderBy('p.position ASC');
return Db::getInstance()->executeS($query);
}
}
Ajoutez des index MySQL sur les colonnes filtrées fréquemment. Sur un catalogue de 10 000+ produits, un index manquant sur category_product.id_category peut coûter 500 ms par requête.
Cache HTTP avec Nginx
Le cache applicatif PrestaShop ne suffit pas si chaque requête PHP est quand même exécutée. Un cache HTTP Nginx en amont évite totalement l'exécution PHP pour les pages cachables.
Configuration FastCGI Cache
# nginx.conf — zone de cache globale
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=prestashop_cache:100m inactive=60m max_size=1g;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
server {
# ...
set $skip_cache 0;
# Ne pas cacher si l'utilisateur est connecté ou a un panier
if ($http_cookie ~* "PrestaShop-[a-z0-9]+") {
set $skip_cache 1;
}
# Ne pas cacher les pages admin et le checkout
if ($request_uri ~* "/(admin|checkout|order|cart)") {
set $skip_cache 1;
}
location ~ \.php$ {
fastcgi_cache prestashop_cache;
fastcgi_cache_valid 200 60m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-FastCGI-Cache $upstream_cache_status;
# ... reste de la config PHP-FPM
}
}
Le header X-FastCGI-Cache: HIT vous confirme que Nginx sert la réponse sans toucher PHP. Le TTFB descend alors sous les 20-50 ms pour les pages en cache.
Optimiser PHP-FPM
PHP-FPM mal dimensionné crée de la contention — les workers attendent et le TTFB monte.
Configuration pool adaptée
; /etc/php/8.2/fpm/pool.d/prestashop.conf
[prestashop]
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500
; OPcache — critique pour le TTFB
php_admin_value[opcache.enable] = 1
php_admin_value[opcache.memory_consumption] = 256
php_admin_value[opcache.max_accelerated_files] = 20000
php_admin_value[opcache.validate_timestamps] = 0
OPcache avec validate_timestamps = 0 est le réglage le plus impactant en production : PHP ne vérifie plus si les fichiers ont changé à chaque requête. Couplez-le avec un opcache_reset() dans votre script de déploiement.
Identifier les overrides qui pèsent lourd
Les overrides PrestaShop sont souvent la source de TTFB élevés car ils s'exécutent dans le chemin critique de chaque requête.
Profiler avec Symfony Stopwatch
PrestaShop 8+ inclut Symfony. Utilisez le Stopwatch pour mesurer vos overrides :
<?php
use Symfony\Component\Stopwatch\Stopwatch;
class MyHeavyOverride extends MyHeavyOverrideCore
{
public function expensiveMethod(): array
{
$stopwatch = new Stopwatch();
$stopwatch->start('myHeavyOverride');
$result = parent::expensiveMethod();
$result = array_merge($result, $this->addCustomData());
$event = $stopwatch->stop('myHeavyOverride');
if ($event->getDuration() > 100) {
PrestaShopLogger::addLog(
'myHeavyOverride trop lent: ' . $event->getDuration() . 'ms',
2
);
}
return $result;
}
}
Lazy loading des données non critiques
Ne chargez pas en synchrone ce qui n'est pas nécessaire au premier rendu. Les avis clients, les produits similaires, les widgets peuvent être chargés en AJAX après le LCP :
<?php
// ❌ Tout charger dans initContent()
public function initContent(): void
{
$this->context->smarty->assign([
'reviews' => $this->loadAllReviews(), // 300ms
'relatedProducts' => $this->loadRelatedProducts(), // 200ms
'crossSell' => $this->loadCrossSell(), // 150ms
]);
parent::initContent();
}
// ✅ Seulement les données critiques au premier rendu
public function initContent(): void
{
$this->context->smarty->assign([
'product' => $this->getProductData(), // 50ms
]);
parent::initContent();
}
Checklist TTFB PrestaShop
- Cache Smarty activé et non invalidé à chaque requête
- OPcache avec
validate_timestamps = 0en production - Slow query log actif pour détecter les requêtes > 500 ms
- Index MySQL sur les colonnes filtrées dans vos requêtes custom
- FastCGI Cache Nginx pour les pages publiques sans session
- PHP-FPM correctement dimensionné (pm.max_children selon la RAM)
- Overrides auditées avec un profiler, données non critiques en AJAX
- TTFB cible : < 200 ms sur les pages en cache, < 800 ms sans cache
Conclusion
Réduire le TTFB sur PrestaShop n'est pas une action unique — c'est une combinaison de cache HTTP, cache applicatif, OPcache et audit SQL. Dans la plupart des projets, activer le FastCGI Cache Nginx et corriger 2-3 requêtes lentes dans les overrides suffit à passer sous les 200 ms. C'est ce que Google mesure dans ses CWV et ce qui fait la différence entre un site "needs improvement" et un site "good".
Besoin d'aide pour auditer les performances de votre boutique PrestaShop ? Contactez-moi pour en discuter !