Easy return - no questions asked
Install, set up and take profit
Priority Help & Satisfaction Over Sales
Recently Viewed Products
Recently Viewed Products Carousel — Cookie-Based, No Login Required
Help customers rediscover products they have already shown interest in. This module tracks recently viewed products using cookies and displays them in a beautiful carousel or grid layout — no login required. It is the easiest way to increase pages per session, reduce bounce rates, and recover potential sales from customers who browsed but did not buy.
- Cookie-based tracking — works for all visitors, no account or login needed
- AJAX loading — recently viewed products load asynchronously without slowing down the initial page render
- Carousel or grid layout — choose the display format that matches your theme's design language
- Product details — shows image, name, price, and discount badge for each viewed product
- Configurable history depth — display the last 4, 8, 12, or any number of recently viewed products
- Smart exclusion — automatically excludes the currently viewed product from the list
Browsing is not linear. Customers compare, leave, return, and reconsider. This module ensures the products that caught their eye are always one click away. $49 for a permanent license. Compatible with PrestaShop 1.7, 8.x, and 9.x.
Bring Back the Products Customers Were Considering
A visitor who browses five products over fifteen minutes has told you exactly what they are interested in — but they might not remember which items they viewed when they return to your store. A recently viewed products widget surfaces those exact items immediately, removing friction and reigniting interest without any effort from the visitor. This module adds a polished recently viewed carousel or grid anywhere on your PrestaShop store, powered by cookies so it works for every visitor without requiring an account or login.
Reduce Bounce and Keep Shoppers Exploring
When customers land on a product they're not ready to buy, the next step is usually to leave — unless a recently viewed widget gives them a shortcut back to other items they were considering. This gentle navigation aid keeps shoppers in your catalog longer, increases pages per session, and reduces the frustration of needing to use the browser back button repeatedly. Display up to twelve recently viewed products as a carousel on product pages, the cart, or a custom position.
Works for Every Visitor — No Account Needed
Viewing history is stored in cookies so it works instantly for guest visitors as well as logged-in customers, with no database writes for every product view. The widget is fully styled to match your theme and is responsive for mobile shoppers. Pair it with Product Extra Info Tabs and Product Sales & Views Live Stats, and browse our Customer Experience & Engagement collection for more ways to delight shoppers.
Key Features
- Cookie-based viewing history works for all visitors — no login or account required
- Display up to twelve recently viewed products as a carousel or grid widget
- Place on product pages, cart page, homepage, or any custom hook position
- Keeps shoppers in your catalog longer and reduces bounce-to-competitor exits
- Fully responsive and styled to match your PrestaShop theme automatically
Who Benefits Most
- inventory_2 Stores with large catalogs where shoppers browse across many products before deciding
- phone_iphone Mobile stores where navigating back through product history is especially frustrating
- shopping_cart Shops looking to increase average pages-per-session and reduce cart abandonment
- repeat Return visitor scenarios where shoppers pick up their research from a previous session
Learn More
- Recently Viewed Products: Helping Customers Find What They Forgot
- Cross-Selling and Upselling: When Helpful Suggestions Beat Pushy Tactics
-
Referencemprrecentlyviewed
-
PrestaShop CompatibilityPS 1.7 – 9.x
-
Pricing ModelOne-time Purchase
-
Module TypeFront-office
-
GDPR RelevantNo
-
Business GoalBoost Conversions
-
External Account NeededNo
-
Module ComplexityFeature-Rich Module
-
Customer Journey StageEngage Shoppers
-
Works With PlatformNo External Platform
Keep the products a visitor was considering visible and within one click at all times — reducing the drop-off that happens when customers have to search again for an item they liked but did not immediately buy. Viewing history is stored in a browser cookie, so the widget works for all visitors including guests with no account or login required, from the very first page view. Configurable cookie duration, minimum view thresholds, and multiple layout options (carousel, list, grid) let you tailor the experience to fit your store's design.
OPcache is a PHP extension that caches compiled PHP code in memory, so PHP does not have to recompile it on every request. You should absolutely enable it — it can improve PrestaShop performance by 30-50% with zero downsides for production. Most hosting providers have it enabled by default. The important setting is opcache.validate_timestamps: set to 1 on development, but many production servers set it to 0 for maximum performance (which means you need to manually reset OPcache after deploying code changes).
Why Regular Technical Audits Matter
PrestaShop stores degrade over time. Modules get installed and forgotten. PHP versions fall behind. Error logs fill up with warnings that nobody reads. Database tables grow bloated with abandoned cart data and expired sessions. Security patches go unapplied. Each of these issues is small on its own, but together they compound into slow page loads, security vulnerabilities, and eventually downtime or data loss.
The problem is that most store owners only discover these issues when something breaks. A customer complains about slow checkout. Google drops your rankings because your site fails Core Web Vitals. Or worse, you discover your admin panel is compromised because you never changed the default admin path and your PHP version had a known vulnerability.
A 30-minute technical health audit, performed monthly, prevents all of this. It is not a deep dive into every configuration setting. It is a focused checklist that catches the most common and most dangerous issues before they become emergencies. This guide walks through each check with approximate time estimates, giving you a repeatable process you can follow every month.
Check 1: PHP Version and Configuration (3 Minutes)
PHP is the engine that runs PrestaShop, and running an outdated version is both a performance and security risk. PHP versions receive active support for two years and security fixes for one additional year after that. After that, known vulnerabilities go unpatched.
Checking Your PHP Version
Go to your PrestaShop back office and navigate to Advanced Parameters > Information. The PHP version is listed in the Server Information section. Alternatively, you can check in your hosting control panel (cPanel, Plesk, or similar).
As of 2026, the actively supported PHP versions are 8.2, 8.3, and 8.4. If you are running PHP 8.1 or older, upgrading should be a priority. PrestaShop 8.x requires PHP 7.2 or later but performs significantly better on PHP 8.1 and above. PrestaShop 1.7.x supports PHP 7.1 through 8.1, depending on the specific version.
Key PHP Settings to Verify
While on the Information page, check these PHP configuration values:
memory_limit should be at least 256M for PrestaShop. If it is lower, you may experience white pages or incomplete operations when handling large catalogs or generating reports.
max_execution_time should be at least 300 (5 minutes). Lower values can cause timeouts during import operations, cache rebuilds, and module installations.
upload_max_filesize and post_max_size should be at least 16M, or higher if you regularly upload large product images or import files.
OPcache should be enabled. OPcache stores compiled PHP code in memory, dramatically reducing page load times. If it is disabled, your store is running significantly slower than it could be.
Check 2: Error Log Review (4 Minutes)
Error logs tell you what is breaking behind the scenes, even when the front end appears to work normally. Warnings and notices that do not crash the page still indicate problems that waste server resources and can escalate into real failures.
PrestaShop Logs
In the back office, go to Advanced Parameters > Logs. Sort by date (newest first) and scan the last week of entries. Focus on Severity 3 (Error) and Severity 4 (Critical) messages. Common critical errors include database connection failures, file permission errors, module exceptions, and payment processing errors.
If you see repeated errors from the same module, that module has a bug that needs attention. If you see database errors, your database server may be running out of connections or disk space.
PHP Error Log
The PHP error log location depends on your hosting environment. Common locations include /var/log/php/error.log, /var/log/apache2/error.log, or a path specified in your hosting control panel. Check the last 100 lines for fatal errors, warnings, and deprecation notices.
Deprecation notices are especially important to track. They warn you that a function or feature your code uses will be removed in a future PHP version. Addressing these now prevents your store from breaking when you upgrade PHP.
What to Do with Errors
Do not try to fix every error during the audit. The audit is for identification. Create a list of the most critical and most frequent errors, prioritized by severity. Fatal errors and critical errors need immediate attention. Warnings should be addressed within the month. Notices and deprecation warnings can be scheduled for your next maintenance window.
Check 3: Module Audit (5 Minutes)
Modules are the most common source of security vulnerabilities, performance problems, and compatibility issues in PrestaShop. A quick module audit identifies dead weight and potential risks.
Identifying Unused Modules
Go to Modules > Module Manager. Look for modules that are installed but disabled. These modules still have files on your server and potentially have database tables, but they are not serving any purpose. They increase your attack surface (a vulnerability in a disabled module's files can still be exploited) and slow down backups.
For each disabled module, decide whether you will use it again. If not, uninstall it completely (not just disable). Uninstalling removes the module's database tables and configuration. After uninstalling, also delete the module's directory from /modules/ to remove its files from the server entirely.
Checking for Updates
In the Module Manager, look for modules with available updates. Outdated modules are a primary vector for security exploits. Update notifications appear as badges on the module listing. Prioritize updates for modules that handle sensitive data: payment modules, customer account modules, and any module that processes forms.
Before updating any module, check the changelog to understand what changed. If the update includes security fixes, apply it immediately. If it is a feature update, test it on a staging environment first if possible.
Counting Total Modules
Check how many modules are installed in total. PrestaShop ships with many modules by default, and stores accumulate more over time. Each active module adds hooks that execute on every page load, increasing response time. If you have more than 80 to 100 active modules, review the list critically. Many default PrestaShop modules (like the social sharing buttons, customer data privacy notice, and statistics modules) can be disabled if you do not use them, resulting in measurable performance improvement.
Check 4: Database Health (4 Minutes)
Your PrestaShop database grows continuously. Every customer visit creates session data. Every abandoned cart stays in the database. Every log entry accumulates. Over months and years, this bloat slows down queries and increases backup times.
Checking Database Size
In your hosting control panel (cPanel > phpMyAdmin, for example), check the total database size. A healthy PrestaShop database for a small to medium store (under 10,000 products) should be under 500 MB. If yours is significantly larger, data bloat is likely the cause.
Identifying Large Tables
In phpMyAdmin, click on your database and sort tables by size. The usual culprits for bloat are: ps_connections and ps_connections_page (visitor tracking data that can grow to gigabytes), ps_log (PrestaShop's internal log table), ps_mail (email history), ps_cart and ps_cart_product (abandoned cart data), ps_guest (anonymous visitor records), and ps_pagenotfound (404 error tracking).
These tables can be safely cleaned of old data. For example, you do not need connection data from two years ago. PrestaShop has a built-in feature for cleaning some of these tables: go to Advanced Parameters > Administration and look for the "Automatically check for module updates" and data cleanup options. For more thorough cleanup, the free PrestaShop Cleaner module can purge old statistics data, abandoned carts, and expired sessions.
Checking for Missing Indexes
While in phpMyAdmin, check the structure of your most important tables (ps_product, ps_category_product, ps_stock_available) and verify that indexes exist on the columns used in search and filtering. Missing indexes cause slow queries that affect page load times. However, do not add indexes without understanding the trade-offs, as each index slows down write operations slightly.
Check 5: Security Basics (5 Minutes)
Security vulnerabilities in PrestaShop stores are actively exploited. Automated scanners continuously probe the internet for vulnerable installations. Five minutes of security checks can prevent a catastrophic breach.
Admin Panel URL
Your admin panel should not be accessible at a predictable URL like /admin/ or /backoffice/. PrestaShop generates a randomized admin directory name during installation (like /admin738xyz/). Verify that your admin URL is still randomized by checking the admin directory name on your server. If someone has renamed it to something guessable, rename it back to a random string.
SSL Certificate
Your entire store must run on HTTPS. Check by visiting your store's URL with http:// and verifying that it redirects to https://. In the back office, go to Shop Parameters > General and verify that "Enable SSL" and "Enable SSL on all pages" are both set to Yes.
Also check your SSL certificate's expiration date. Let's Encrypt certificates expire every 90 days and should auto-renew, but auto-renewal fails silently more often than you would expect. Click the padlock icon in your browser's address bar to see the certificate details and expiration date. If it expires within the next 30 days, verify that auto-renewal is configured and working.
File Permissions
Incorrect file permissions are a security risk. On Linux servers, your PrestaShop files should generally be owned by the web server user (typically www-data or apache) and have these permissions: directories at 755 (owner can read/write/execute, others can read/execute), files at 644 (owner can read/write, others can read only), and configuration files like config/settings.inc.php or app/config/parameters.php at 640 or 440 (restricted read access).
Check a few critical files to verify permissions are not too open. No file should be 777 (world-writable). If you find 777 permissions, fix them immediately. They allow any user on the server to modify those files.
Debug Mode
Verify that debug mode is disabled on your production store. Debug mode exposes detailed error messages, file paths, and database queries to visitors, which is valuable information for attackers. Check the file /config/defines.inc.php and ensure _PS_MODE_DEV_ is set to false. In PrestaShop 8.x, also check the .env file for the APP_DEBUG setting.
Known Vulnerabilities
Check whether your PrestaShop version has known security vulnerabilities. Visit the PrestaShop security advisories page and compare the listed versions with yours. If your version is affected by any advisory that you have not patched, prioritize applying the fix.
Check 6: Performance Quick Test (4 Minutes)
Performance directly affects conversion rates. Every additional second of page load time reduces conversions measurably. A quick performance test identifies major bottlenecks.
Running a Lighthouse Audit
Open Google Chrome, navigate to your store's homepage, open Chrome DevTools (F12), and click the Lighthouse tab. Run an audit for Performance, Best Practices, and SEO on a Mobile device. The test takes about 30 seconds.
Focus on the Performance score. A score below 50 indicates serious performance problems. Between 50 and 89 means there is room for improvement. Above 90 is good. The audit report shows specific issues and estimates of how much time each fix would save.
Key Metrics to Check
From the Lighthouse report, pay attention to Largest Contentful Paint (LCP), which measures how long it takes for the main content to appear. It should be under 2.5 seconds. First Input Delay (FID) or Interaction to Next Paint (INP) measures responsiveness. It should be under 200 milliseconds. Cumulative Layout Shift (CLS) measures visual stability. It should be under 0.1.
If LCP is high, the most common causes in PrestaShop are unoptimized images (large product images served without compression or proper sizing), slow server response time (check your hosting plan and database performance), render-blocking CSS and JavaScript (disable unnecessary modules that add their assets to every page), and disabled caching (Smarty cache and CCC should be enabled in production).
Checking Cache Configuration
In the back office, go to Advanced Parameters > Performance. Verify these settings: Smarty cache should be Yes with the cache type set to "File". CCC (Combine, Compress, Cache) should have CSS and JavaScript minification and combination enabled. Template compilation should be set to "Recompile templates if the files have been updated" (not "Force compilation" which is for development only).
If any of these are misconfigured, fixing them provides an immediate and noticeable performance improvement.
Check 7: SEO Basics (3 Minutes)
Technical SEO issues prevent search engines from properly crawling and indexing your store. A few quick checks catch the most impactful problems.
Robots.txt
Visit yourdomain.com/robots.txt in your browser. Verify that it exists and contains sensible rules. PrestaShop generates a robots.txt file automatically. Check that it is not blocking important pages. Your product pages, category pages, and CMS pages should not be disallowed. Common mistakes include blocking all URLs with parameters (which blocks filtered category pages and search results) and blocking the /modules/ directory (which can prevent CSS and JavaScript from being loaded by search engine renderers).
Also verify that the robots.txt includes a sitemap directive pointing to your XML sitemap: Sitemap: https://www.yourdomain.com/1_index_sitemap.xml.
XML Sitemap
Visit the sitemap URL listed in your robots.txt. Verify that it loads, that it is recent (check the last modification dates), and that it contains your important pages. If the sitemap is outdated or empty, regenerate it. If you use the built-in PrestaShop sitemap generator, go to Modules > Module Manager, find the Google Sitemap module, and click Configure to regenerate.
Check the number of URLs in the sitemap against your expected count. If you have 1,000 products but the sitemap only lists 200 URLs, something is wrong with the generation process. Common causes include products being disabled or out of stock being excluded from the sitemap, category visibility settings filtering out products, and the sitemap generation process timing out before completing.
Canonical URLs
Visit a few product pages and view the page source (Ctrl+U). Look for the <link rel="canonical"> tag in the head section. It should contain the clean URL of the current page without any query parameters. If canonical tags are missing or incorrect, duplicate content issues will harm your SEO. In the back office, go to Shop Parameters > Traffic & SEO and verify that "Disable Apache's MultiViews option" and "Disable Apache's mod_security module" are configured correctly for your server.
Check 8: Backup Verification (3 Minutes)
Backups that have never been tested are not backups. They are wishful thinking. This check verifies that your backup system is actually working.
Checking Backup Recency
Determine where your backups are stored. This varies by hosting provider. Check your hosting control panel for backup tools (cPanel has a Backup section, Plesk has a Backup Manager). If you use a backup module in PrestaShop, check its configuration and recent backup log.
Your most recent backup should be no more than 24 hours old for active stores. If your last backup is older than a week, your backup system is either not configured, not running, or failing silently. Fix this immediately. Data loss from a server failure or hack without a recent backup can be business-ending.
Verifying Backup Completeness
A complete PrestaShop backup includes the entire database (all tables, not just product data) and the file system (all PrestaShop files, including uploaded images, module files, and theme customizations). Many backup solutions only capture the database or only capture the files. Verify that yours captures both.
Check the backup file sizes. A database backup for a small store should be at least several megabytes. If it is suspiciously small (under 1 MB for an active store), it might be empty or corrupted. A file backup should include your /img/ directory, which is typically the largest directory and can be several gigabytes for stores with many product images.
Offsite Backup Storage
Backups stored on the same server as your store are vulnerable to the same failures. If the server's hard drive fails, you lose both the store and the backup. Verify that your backups are copied to a separate location: a different server, cloud storage (like Amazon S3, Google Cloud Storage, or Dropbox), or downloaded to a local computer.
Check 9: Update Status (2 Minutes)
Running outdated software is the single most common reason PrestaShop stores get hacked. This final check verifies that your core installation and critical modules are up to date.
PrestaShop Core Version
Check your current PrestaShop version in the back office footer or on the Advanced Parameters > Information page. Compare it against the latest stable release on the PrestaShop website or GitHub releases page. If you are more than one minor version behind (for example, running 8.1.2 when 8.1.5 is available), plan an update. If you are running a version with known security vulnerabilities, update urgently.
PrestaShop major version upgrades (like 1.7 to 8.x) are complex migration projects, not simple updates. Do not attempt these without thorough planning and testing. But minor version updates (like 8.1.2 to 8.1.5) are generally safe and primarily contain security and bug fixes.
Critical Module Updates
Some modules handle sensitive operations and must be kept current: payment modules (any module that processes credit cards, PayPal, or other payment methods), the PrestaShop autoupgrade module (used for core updates), and any security-related modules. Check the Module Manager for available updates on these specific modules.
Your 30-Minute Audit Checklist Summary
Here is the complete checklist with time allocations that you can follow each month:
Minutes 1-3: PHP Version and Configuration. Check PHP version is supported. Verify memory_limit, max_execution_time, and OPcache status.
Minutes 4-7: Error Log Review. Scan PrestaShop logs for Severity 3 and 4 entries. Check PHP error log for fatal errors and deprecation notices. Note recurring errors for follow-up.
Minutes 8-12: Module Audit. Review disabled modules and uninstall unused ones. Check for available updates, especially on payment and security modules. Count total active modules and identify candidates for removal.
Minutes 13-16: Database Health. Check total database size. Identify bloated tables. Plan cleanup of old connection, log, and cart data.
Minutes 17-21: Security Basics. Verify admin URL is randomized. Check SSL certificate and expiration. Verify file permissions. Confirm debug mode is off. Check for known vulnerabilities in your version.
Minutes 22-25: Performance Quick Test. Run Lighthouse audit on homepage. Check LCP, INP, and CLS metrics. Verify cache and CCC settings in back office.
Minutes 26-28: SEO Basics. Check robots.txt for errors. Verify sitemap is current and complete. Spot-check canonical URLs on product pages.
Minutes 29-30: Backup and Updates. Verify backup recency and completeness. Check PrestaShop core and critical module versions against latest releases.
This audit does not fix problems. It identifies them. After completing the checklist, you should have a prioritized list of issues to address. Critical security issues and broken functionality come first. Performance optimizations and cleanup tasks come second. Minor improvements and future planning come third. By performing this audit monthly, you catch problems early, maintain a clear picture of your store's technical health, and avoid the nasty surprises that come from months of neglected maintenance.
For more details, read our guides: Is Your Store Slow? How to Check and What to Do About It and Essential PrestaShop Modules: The Must-Have List for Every Store.
How PrestaShop Email Templates Work
PrestaShop sends transactional emails at every key point in the customer journey: account creation, order confirmation, shipping notification, password reset, and more. These emails are generated from template files stored on your server, and they are fully customizable. Understanding how the template system works is the first step toward creating professional, branded order confirmation emails that reinforce your store's identity.
Every PrestaShop email consists of two template files: an HTML version for email clients that support rich formatting, and a plain text (TXT) version for email clients that do not. Both files must exist for an email to send correctly. The HTML version is what the vast majority of your customers will see. The TXT version serves as a fallback and is also used by accessibility tools and some corporate email filters.
Email templates live in the mails/ directory structure. The exact location depends on whether you are using core emails, theme-overridden emails, or module-specific emails. Understanding this hierarchy is essential because PrestaShop checks multiple locations for each template and uses the first one it finds.
The Email Template Directory Structure
PrestaShop organizes email templates in a specific directory hierarchy. When it needs to send an email, it searches these locations in order of priority:
Theme-Level Overrides (Highest Priority)
Templates in /themes/your-theme/mails/en/ (where en is the language ISO code) take priority over all other locations. If you want to customize an email template without modifying core files, this is where your custom templates should go. This approach survives PrestaShop updates because theme files are not overwritten during core updates.
Core Templates (Default)
The default templates live in /mails/en/ in your PrestaShop root directory. These are the templates that ship with PrestaShop and are used when no theme override exists. Editing these files directly works but is not recommended because your changes will be lost when you update PrestaShop.
Module-Specific Templates
Modules that send their own emails store templates in /modules/module-name/mails/en/. For example, the order notification emails sent by the core payment modules are stored in their respective module directories. You can override these by placing modified copies in your theme's mails/ directory with the same filename.
Language Subdirectories
Each mails/ directory contains subdirectories for each installed language, using the language ISO code: en for English, fr for French, de for German, and so on. When PrestaShop sends an email, it uses the template from the directory matching the customer's language preference. If a template does not exist in the customer's language, PrestaShop falls back to the default language.
Anatomy of an Order Confirmation Template
The order confirmation email is the most important transactional email your store sends. It is the file named order_conf.html (and its companion order_conf.txt) in your mails directory. Let us examine its structure.
HTML Template Structure
PrestaShop email templates are standalone HTML documents. They do not use external CSS files because most email clients strip external stylesheets. All styling must be inline CSS. A typical order confirmation template includes these sections:
The document starts with a standard HTML doctype and head section. The body contains a table-based layout (because email clients have poor support for modern CSS layout methods like flexbox and grid). Within this layout, you find a header section with your store logo, the main content area with order details, a product table listing each item ordered, pricing summary with subtotals and totals, shipping information, payment method details, and a footer with store contact information and legal notices.
The Variable System
PrestaShop uses a simple variable replacement system in email templates. Variables are enclosed in curly braces: {variable_name}. When the email is generated, PrestaShop replaces each variable with its actual value. The order confirmation template uses these key variables:
{firstname} and {lastname} contain the customer's name. {order_name} is the order reference number (like ABCDEF123). {shop_name} is your store's name as configured in the back office. {shop_url} is your store's URL. {shop_logo} is the path to your store's logo image. {date} is the order date. {payment} is the payment method used. {total_paid} is the total amount paid. {delivery_company} and {delivery_address} contain shipping carrier and address information.
For the product list, PrestaShop uses a special block syntax. The product items section is wrapped in a loop that repeats for each product in the order: {items} contains the pre-formatted HTML for the entire product list table, including product names, quantities, prices, and any customization details.
Available Variables Reference
To see all available variables for a specific email template, look at the PHP code that sends the email. For order confirmation, check the PaymentModule class (in /classes/PaymentModule.php). The validateOrder() method builds the array of template variables. Each key in the array corresponds to a variable name you can use in the template.
Common variables available in order confirmation emails include: {id_order}, {order_name}, {delivery_block_txt}, {invoice_block_txt}, {delivery_block_html}, {invoice_block_html}, {delivery_company}, {delivery_firstname}, {delivery_lastname}, {delivery_address1}, {delivery_address2}, {delivery_city}, {delivery_postal_code}, {delivery_country}, {delivery_phone}, {invoice_company}, {invoice_firstname}, {invoice_lastname}, {invoice_address1}, {invoice_address2}, {invoice_city}, {invoice_postal_code}, {invoice_country}, {invoice_phone}, {message}, and {total_products}.
Customizing the Order Confirmation Template
Step 1: Create a Theme Override
Never edit the core template files directly. Instead, copy the template to your theme's mails directory:
Copy /mails/en/order_conf.html to /themes/your-theme/mails/en/order_conf.html. Do the same for order_conf.txt. If the mails/en/ directory does not exist in your theme, create it.
If your store supports multiple languages, copy the templates for each language directory. Your French order confirmation goes in /themes/your-theme/mails/fr/order_conf.html and so on.
Step 2: Modify the HTML Layout
Open the HTML template in a text editor (not a visual editor that might add unwanted code). Email HTML is different from web HTML in several important ways:
Use tables for layout, not divs. Email clients, especially Outlook, have very limited CSS support. A three-column layout must use a <table> with three <td> elements, not CSS columns or flexbox.
Use inline styles on every element. Instead of <p class="heading"> with a separate stylesheet, use <p style="font-size:18px; font-weight:bold; color:#333333;">. Every styled element needs its own inline style attribute.
Set explicit widths on tables and cells. Email clients do not always respect percentage-based widths. Use a fixed width for your main content table (600 pixels is the standard) with percentage-based internal columns.
Use web-safe fonts. Not all email clients support custom fonts. Stick to Arial, Helvetica, Georgia, Times New Roman, Verdana, or Trebuchet MS. You can try loading a custom font as a fallback, but always specify a web-safe font as the final fallback.
Step 3: Add Your Branding
Replace the default PrestaShop header with your store's branding. This typically involves updating the logo (the {shop_logo} variable automatically uses your store's logo, but you might want a specific email version), changing the header background color to match your brand, adding your brand's color scheme to headings and links, and including your store's tagline or a brief marketing message.
Keep the overall structure simple. Overly complex email designs break in different email clients. A clean, single-column layout with your brand colors and logo is more effective and more reliable than an elaborate multi-column design.
Step 4: Customize the Product Table
The default product table in PrestaShop's order confirmation is functional but basic. You can enhance it by adding product images (use absolute URLs to images hosted on your server, not relative paths), adding links to product pages so customers can easily reorder or leave reviews, adding custom fields like estimated delivery dates or personalized messages, and adjusting the table styling to match your brand.
When adding product images, keep them small (50 to 80 pixels wide) and always include an alt attribute. Some email clients block images by default, and the alt text ensures customers can still identify their products.
Adding Custom Fields to Order Emails
PrestaShop's default variables cover the standard order information, but you might want to include additional data like loyalty points earned, estimated delivery date, a personalized thank-you message, or cross-sell product recommendations.
Adding Variables via a Module
The cleanest way to add custom variables is through a module that hooks into the email sending process. Create a module that registers the actionEmailSendBefore hook (available in PrestaShop 1.7.6 and later) or the actionGetExtraMailTemplateVars hook. In your hook handler, add your custom variables to the template variables array:
Your hook function receives the template variables array by reference. You can add new variables to this array, and they become available in the template using the standard {variable_name} syntax. For example, after adding loyalty_points to the array in your hook, you can use {loyalty_points} in your order confirmation HTML template.
Using Existing Database Data
You can pull any data from your PrestaShop database into email variables. Common examples include the customer's total order count (to show "Thank you for your 5th order!"), the customer's loyalty point balance, custom product fields stored in product features or attributes, and warehouse or supplier information for the ordered products.
Multilingual Email Setup
If your store serves customers in multiple languages, every email template needs a version for each language. PrestaShop handles language selection automatically based on the customer's language preference, but you need to provide the templates.
Creating Language-Specific Templates
For each language your store supports, create a directory under your theme's mails folder: /themes/your-theme/mails/en/, /themes/your-theme/mails/fr/, /themes/your-theme/mails/de/, and so on. Copy and translate each template file into the appropriate directory.
Do not use automated translation for transactional emails. These emails represent your store's communication with customers, and poor translations damage trust. Have each language version written or reviewed by a native speaker.
Right-to-Left Language Support
If you support languages like Arabic or Hebrew, your email templates need RTL (right-to-left) layout support. Add dir="rtl" to the main table element and adjust text alignment and padding in your inline styles. Create separate templates for RTL languages rather than trying to make a single template work for both directions.
Date and Currency Formatting
PrestaShop automatically formats dates and currency values according to the customer's language and currency settings. The {date}, {total_paid}, and other formatted values already reflect the correct locale. However, if you add custom variables with dates or currency values, make sure to format them correctly for the target language.
SMTP Configuration for Reliable Delivery
The best email template in the world is useless if your emails do not reach the inbox. PrestaShop's default email configuration uses PHP's built-in mail() function, which is unreliable for transactional emails. Most of these emails end up in spam folders or are rejected entirely by modern email providers.
Why SMTP Matters
SMTP (Simple Mail Transfer Protocol) with proper authentication is essential for email deliverability. When you send email through PHP's mail() function, the email comes from your web server's IP address with no authentication. Email providers like Gmail, Outlook, and Yahoo see this as a red flag and often classify these emails as spam.
With SMTP, your emails are sent through an authenticated email server with proper SPF, DKIM, and DMARC records. This proves to receiving email servers that the email is legitimate and authorized by your domain.
Configuring SMTP in PrestaShop
Go to Advanced Parameters > E-mail in your PrestaShop back office. Change the method from "Use PHP's mail() function" to "Set my own SMTP parameters." Enter your SMTP server details: the server address, port (typically 587 for TLS or 465 for SSL), encryption type, username, and password.
Common SMTP providers for PrestaShop include Gmail SMTP (smtp.gmail.com, port 587, TLS, requires an App Password if 2FA is enabled), Amazon SES (affordable for high volume), SendGrid (generous free tier), Mailgun (developer-friendly with good logging), and your hosting provider's SMTP server (check with your host for settings).
Testing SMTP Configuration
After configuring SMTP, use the "Send a test email" button at the bottom of the email configuration page. Enter your own email address and check that the test email arrives in your inbox (not spam). If the test email fails, check your SMTP credentials, verify that your server can reach the SMTP server on the configured port (some hosting providers block outgoing port 25 and 587), and check if your SMTP provider requires specific security settings.
SPF, DKIM, and DMARC Records
For maximum deliverability, configure these DNS records for your domain. SPF (Sender Policy Framework) specifies which servers are authorized to send email on behalf of your domain. DKIM (DomainKeys Identified Mail) adds a digital signature to your emails that proves they were sent by your domain. DMARC (Domain-based Message Authentication, Reporting, and Conformance) tells receiving servers what to do with emails that fail SPF or DKIM checks.
Your SMTP provider will give you the specific DNS records to add. For example, if you use SendGrid, they provide SPF and DKIM records during the domain authentication setup process. Add these as TXT records in your domain's DNS settings.
Testing Email Templates
Sending Test Emails
PrestaShop does not have a built-in way to preview specific email templates. To test your order confirmation template, you need to place a real test order. Create a test customer account, add products to the cart, and complete the checkout with a test payment method. If you have a sandbox payment module configured, use that. Otherwise, the bank wire or check payment methods let you complete an order without actual payment processing.
Testing Across Email Clients
Email rendering varies dramatically between email clients. What looks perfect in Gmail might be broken in Outlook. At minimum, test your templates in Gmail (web), Outlook (desktop and web), Apple Mail, Yahoo Mail, and at least one mobile email app. Services like Litmus or Email on Acid automate this testing by rendering your email in dozens of email clients simultaneously, but they are paid services.
Common Rendering Issues
If your email looks broken in Outlook, it is almost certainly a CSS issue. Outlook uses Microsoft Word's rendering engine for HTML emails, which has extremely limited CSS support. It does not support background images on table cells (use background colors instead), padding on block elements (use table cell padding), max-width (use fixed widths), margin for centering (use align="center" on tables), or CSS floats.
For mobile responsiveness, wrap your content table in a container with max-width:600px and add a media query in the head style block (which some email clients support) that sets table widths to 100% on small screens. This is not perfect responsive design, but it prevents horizontal scrolling on most mobile devices.
Common Issues and Troubleshooting
Missing Images in Emails
This is the most common email template problem. Images in emails must use absolute URLs (starting with https://), not relative paths. If your template references /img/logo.png, change it to https://www.yourdomain.com/img/logo.png. The {shop_logo} variable automatically generates an absolute URL, but any images you add manually must use full URLs.
Also verify that your images are accessible from outside your network. If your store is behind a firewall or HTTP authentication, email clients cannot load the images. Test by opening the image URL in a private/incognito browser window.
Broken Layout After Editing
Email HTML is fragile. A single unclosed tag or missing table cell can break the entire layout. Always validate your HTML after editing. Count your opening and closing table, tr, and td tags. Every <table> needs a </table>, every <tr> needs a </tr>, and every <td> needs a </td>. Check that every row in a table has the same number of cells (or uses colspan to make up the difference).
Variables Not Being Replaced
If you see literal {variable_name} text in your sent emails instead of actual values, check the variable name for typos. Variable names are case-sensitive. Also verify that the variable exists for the specific email type you are customizing. Not all variables are available in all email templates. The order-specific variables like {order_name} are only available in order-related emails.
Emails Not Sending at All
If emails are not being sent, check the PrestaShop back office under Advanced Parameters > E-mail. There you can see a log of sent emails. If the log shows failures, check your SMTP configuration. If no emails appear in the log, the email might not be triggered at all. Verify that your order status transitions are configured to send emails (Orders > Statuses > edit status > check "Send an email to the customer").
Also check your server's PHP error log for email-related errors. Common issues include PHP's mail() function being disabled by the hosting provider, SMTP authentication failures due to changed passwords, and network connectivity issues between your server and the SMTP server.
Emails Going to Spam
Even with proper SMTP configuration, emails can still land in spam. The most common reasons are missing or incorrect SPF/DKIM/DMARC records, email content that triggers spam filters (excessive use of capital letters, spam trigger words like "free" or "act now", too many images with little text), sending from an IP address with a poor reputation (common with shared hosting), and the "from" email address domain not matching the SMTP server domain.
Fix the DNS records first, then review your email content. Use a tool like mail-tester.com to analyze your emails for spam triggers. Send a test email to the address they provide, and they return a detailed report showing what might cause spam classification.
Theme-Specific Email Overrides
Some PrestaShop themes include their own email templates that match the theme's design. If your theme has templates in /themes/your-theme/mails/, these override the core templates automatically.
Checking for Theme Email Templates
Look in your active theme's directory for a mails folder. If it exists, the theme provides custom email templates. These templates usually match the theme's color scheme and header/footer design, giving your emails visual consistency with your storefront.
Customizing Theme Email Templates
If your theme provides email templates, edit those instead of copying from the core mails/ directory. The theme templates may use a different HTML structure or include additional CSS that is specific to the theme's design system. Starting from the theme's version ensures visual consistency.
Keeping Templates in Sync with Theme Updates
When you update your theme, check whether the update includes changes to email templates. If it does, your customizations might be overwritten. Before updating, back up your customized templates. After updating, compare the new templates with your backups and reapply your customizations to the updated versions. This is tedious but necessary to maintain both your customizations and any improvements or fixes the theme developer has made.
Best Practices for Order Confirmation Emails
A well-crafted order confirmation email does more than confirm the transaction. It builds trust, reduces support inquiries, and creates opportunities for engagement.
Include a clear order reference number prominently at the top. Customers need this number when contacting support or tracking their order. List every product with its name, quantity, price, and any options or customizations. Include the complete breakdown of subtotal, shipping cost, taxes, discounts, and total. Show the delivery address so customers can verify it and contact you immediately if it is wrong. Include the payment method used and any relevant transaction details. Provide a link to the order tracking page or the customer's order history in their account. Add your customer service contact information so customers know how to reach you if something is wrong.
Keep the design clean and mobile-friendly. More than half of all emails are read on mobile devices. Use a single-column layout, large readable text (minimum 14px for body text), and buttons with adequate touch targets (minimum 44px height). Your order confirmation email is a reflection of your store's professionalism. Invest the time to get it right.
For more details, read our guides: Email Configuration in PrestaShop: SMTP, Gmail and Transactional Email and Order Status Workflow in PrestaShop: Customization and Automation.
PrestaShop .htaccess Redirects: Writing Rules Without Breaking Your Store
The .htaccess file is one of the most powerful and dangerous files in your PrestaShop installation. A single misplaced character can take your entire store offline. But mastering .htaccess redirects is essential for SEO - you need them when changing URLs, migrating from another platform, removing old products, or restructuring your category tree. This guide teaches you how to write safe, effective redirect rules specifically for PrestaShop.
How PrestaShop Uses .htaccess
PrestaShop automatically generates and manages the .htaccess file. When you enable Friendly URLs in SEO & URLs settings, or click "Generate .htaccess file," PrestaShop writes rewrite rules between two marker comments:
# ~~start~~ Do not remove this comment, Prestashop will keep this comment block
# -- Your PrestaShop rules here --
# ~~end~~ Do not remove this comment, Prestashop will keep this comment blockCritical rule - Never add your custom redirects inside this block. PrestaShop will overwrite them the next time it regenerates the file. Place your custom rules BEFORE the PrestaShop block.
Understanding Redirect Types
301 - Permanent Redirect
Use when a page has permanently moved to a new URL. Search engines transfer the old page's SEO value (link juice) to the new URL. This is the most common redirect for e-commerce.
302 - Temporary Redirect
Use when a page is temporarily unavailable and will return to the original URL. Search engines keep the old URL indexed. Use this for seasonal pages, A/B tests, or maintenance.
410 - Gone
Use when a page has been permanently removed and there is no replacement. This tells search engines to remove the URL from their index. Useful for discontinued products with no alternative.
Basic Redirect Syntax
Simple One-to-One Redirects
# Redirect a single URL to a new location
Redirect 301 /old-page.html https://yourstore.com/new-page.html
# Redirect an old product URL
Redirect 301 /old-product-name.html https://yourstore.com/en/new-product-name.html
# Redirect an old category
Redirect 301 /old-category/ https://yourstore.com/en/new-category/Important - The first path (after 301) is relative to your domain root and must start with /. The second URL must be the full absolute URL including https://.
Pattern-Based Redirects with RewriteRule
For more complex redirects, use mod_rewrite with RewriteRule:
RewriteEngine On
# Redirect all pages from old domain structure
RewriteRule ^old-folder/(.*)$ https://yourstore.com/new-folder/$1 [R=301,L]
# Redirect product IDs to friendly URLs
RewriteRule ^product\.php\?id_product=([0-9]+)$ https://yourstore.com/en/product-$1.html [R=301,L]
# Redirect all .htm pages to .html
RewriteRule ^(.+)\.htm$ https://yourstore.com/$1.html [R=301,L]Common PrestaShop Redirect Scenarios
Scenario 1 - Migrating from Another Platform
When migrating from WooCommerce, Magento, or Shopify, your old URL structure will not match PrestaShop's. You need to redirect every old URL to its new PrestaShop equivalent.
# WooCommerce to PrestaShop - typical product URL migration
RewriteRule ^product/old-product-slug/?$ https://yourstore.com/en/new-prestashop-url.html [R=301,L]
# WooCommerce category to PrestaShop category
RewriteRule ^product-category/old-category/?$ https://yourstore.com/en/2-new-category.html [R=301,L]
# Magento to PrestaShop
RewriteRule ^catalog/product/view/id/([0-9]+)/?$ https://yourstore.com/en/product-$1.html [R=301,L]Scenario 2 - Removing a Language or Changing URL Structure
# Redirect old non-language URLs to new language-prefixed URLs
RewriteRule ^product-name\.html$ https://yourstore.com/en/product-name.html [R=301,L]
# Redirect old language prefix to new one
RewriteRule ^gb/(.*)$ https://yourstore.com/en/$1 [R=301,L]Scenario 3 - Forcing HTTPS and WWW
# Force HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Force www
RewriteCond %{HTTP_HOST} ^yourstore\.com$ [NC]
RewriteRule ^(.*)$ https://www.yourstore.com/$1 [R=301,L]
# Force non-www
RewriteCond %{HTTP_HOST} ^www\.yourstore\.com$ [NC]
RewriteRule ^(.*)$ https://yourstore.com/$1 [R=301,L]Scenario 4 - Removing Trailing Slashes
# Remove trailing slash (except for directories)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ https://yourstore.com/$1 [R=301,L]Scenario 5 - Bulk Product Redirects
When you have hundreds of old URLs to redirect, use a RewriteMap or include a separate file:
# Create a file called redirects.conf with your mappings
# Then include it (if your hosting allows)
# Or list them individually
Redirect 301 /old-product-1.html https://yourstore.com/en/new-product-1.html
Redirect 301 /old-product-2.html https://yourstore.com/en/new-product-2.html
Redirect 301 /old-product-3.html https://yourstore.com/en/new-product-3.htmlRules That Can Break PrestaShop
Infinite Redirect Loops
The most dangerous mistake. This happens when a rule redirects URL A to URL B, and another rule (or PrestaShop's own rules) redirects URL B back to URL A. The browser shows "Too many redirects" and the page never loads.
# DANGEROUS - can cause loops
RewriteRule ^(.*)$ https://yourstore.com/$1 [R=301,L]
# This redirects EVERYTHING, including the target URL itselfPrevention - always use conditions to prevent loops:
# SAFE - prevents loop by checking if already on correct host
RewriteCond %{HTTP_HOST} !^www\.yourstore\.com$ [NC]
RewriteRule ^(.*)$ https://www.yourstore.com/$1 [R=301,L]Breaking API and Back Office Access
Overly broad redirect rules can break the PrestaShop back office, webservice API, and module controllers:
# DANGEROUS - redirects everything including admin URLs
RewriteRule ^(.*)$ https://yourstore.com/en/$1 [R=301,L]
# SAFE - exclude admin directory and API
RewriteCond %{REQUEST_URI} !^/admin [NC]
RewriteCond %{REQUEST_URI} !^/api [NC]
RewriteCond %{REQUEST_URI} !^/modules [NC]
RewriteRule ^(.*)$ https://yourstore.com/en/$1 [R=301,L]Breaking Static Assets
Redirect rules that match CSS, JavaScript, and image files will break your store's appearance and functionality:
# DANGEROUS - redirects images and CSS
RewriteRule ^(.*)$ https://newdomain.com/$1 [R=301,L]
# SAFE - exclude static files
RewriteCond %{REQUEST_URI} !\.(css|js|jpg|jpeg|png|gif|svg|webp|woff|woff2|ttf|eot|ico)$ [NC]
RewriteRule ^(.*)$ https://newdomain.com/$1 [R=301,L]Testing Your Redirects Safely
Step 1 - Always Back Up First
cp .htaccess .htaccess.backupStep 2 - Test with 302 First
Use temporary (302) redirects during testing. If something goes wrong, search engines have not cached the permanent redirect. Switch to 301 only after confirming everything works.
Step 3 - Test with curl
# Check redirect chain
curl -I -L https://yourstore.com/old-page.html
# Check specific redirect
curl -I https://yourstore.com/old-page.html
# Look for: HTTP/1.1 301 Moved Permanently
# And: Location: https://yourstore.com/en/new-page.htmlStep 4 - Verify in Google Search Console
After implementing redirects, use the URL Inspection tool in Google Search Console to verify that Google can follow the redirects correctly.
Where to Place Custom Rules
# YOUR CUSTOM REDIRECTS GO HERE (before PrestaShop block)
Redirect 301 /old-page.html https://yourstore.com/new-page.html
Redirect 301 /old-category/ https://yourstore.com/en/new-category/
# ~~start~~ Do not remove this comment, Prestashop will keep this comment block
# ... PrestaShop auto-generated rules ...
# ~~end~~ Do not remove this comment, Prestashop will keep this comment blockWhen to Use a Module Instead
Consider using a redirect module instead of manual .htaccess editing when:
- You have non-technical staff who need to manage redirects
- You need to manage hundreds of redirects with a UI
- You want automatic 404 detection and redirect suggestions
- You need redirect analytics (how many times each redirect is hit)
- You want to import/export redirects in bulk via CSV
Redirect modules store the mappings in the database and use a single PHP-based catch-all rule instead of adding lines to .htaccess. This is often safer and more maintainable for large redirect sets.
Quick Reference Cheat Sheet
| Task | Rule |
|---|---|
| Single page redirect | Redirect 301 /old https://site.com/new |
| Pattern redirect | RewriteRule ^old/(.*)$ https://site.com/new/$1 [R=301,L] |
| Force HTTPS | RewriteCond %{HTTPS} off + RewriteRule |
| Exclude directory | RewriteCond %{REQUEST_URI} !^/admin |
| Exclude file types | RewriteCond %{REQUEST_URI} !\.(css|js|jpg)$ |
| Remove trailing slash | RewriteCond %{REQUEST_FILENAME} !-d |
For more details, read our guides: PrestaShop .htaccess: Security and Performance Rules You Need and What Are Friendly URLs and Why Every PrestaShop Store Needs Them.
Lazy Loading in 2026: What Browsers Handle Natively vs What Needs a Module
Lazy loading is a performance optimization technique that defers the loading of off-screen resources until the user scrolls near them. In 2026, native browser support for lazy loading has matured significantly, but there are still scenarios where PrestaShop store owners need additional modules or custom implementations. This guide explains exactly what browsers handle on their own, what gaps remain, and how to implement the best lazy loading strategy for your PrestaShop store.
What Native Lazy Loading Covers in 2026
The HTML loading="lazy" attribute is now supported by over 95% of browsers worldwide. This includes Chrome (since v77), Firefox (since v75), Safari (since v15.4), Edge (since v79), and all Chromium-based browsers. This means for most visitors to your store, native lazy loading works out of the box.
How Native Lazy Loading Works
Adding loading="lazy" to an <img> or <iframe> tag tells the browser to defer loading that resource until it is within a certain distance from the viewport. The browser handles all the timing and intersection logic internally, with zero JavaScript overhead.
<!-- Native lazy loading for images -->
<img src="product-image.jpg"
loading="lazy"
width="800"
height="600"
alt="Product Name">
<!-- Native lazy loading for iframes -->
<iframe src="https://www.youtube.com/embed/VIDEO_ID"
loading="lazy"
width="560"
height="315"></iframe>What Browsers Handle Natively
| Feature | Native Support | Notes |
|---|---|---|
Images (<img>) | Yes - all major browsers | Use loading="lazy" attribute |
Iframes (<iframe>) | Yes - all major browsers | Use loading="lazy" attribute |
Responsive images (<picture>) | Yes | Put loading="lazy" on the <img> inside |
| srcset images | Yes | Works with loading="lazy" on the <img> |
| Above-the-fold detection | Partial | Browsers try to detect, but not always accurate |
What Browsers Do NOT Handle
| Feature | Native Support | Solution Needed |
|---|---|---|
| CSS background images | No | IntersectionObserver API or module |
| Video elements | No | Custom JavaScript or module |
| Placeholder/blur-up effects | No | JavaScript library or module |
| Priority hints for above-fold images | Partial | fetchpriority="high" attribute |
| Dynamic/AJAX-loaded content | No | JavaScript-based lazy loading |
| Third-party widget deferral | No | Custom implementation |
Implementing Native Lazy Loading in PrestaShop
For PrestaShop 8.x and 9.x Themes
Modern PrestaShop themes (like Hummingbird for PS 9) often include native lazy loading by default. To verify or add it to your theme, edit your template files where product images are rendered.
For product listing pages, find the template that renders product thumbnails (typically themes/yourtheme/templates/catalog/_partials/miniatures/product.tpl):
{* Before - no lazy loading *}
<img src="{$product.cover.bySize.home_default.url}"
alt="{$product.name}">
{* After - with native lazy loading *}
<img src="{$product.cover.bySize.home_default.url}"
loading="lazy"
width="{$product.cover.bySize.home_default.width}"
height="{$product.cover.bySize.home_default.height}"
alt="{$product.name}">Critical Rule: Never Lazy Load Above-the-Fold Images
The most common lazy loading mistake is applying it to images that are visible without scrolling. This actually hurts performance because the browser delays loading content that the user sees immediately. Google's Core Web Vitals will penalize you for this with a higher LCP (Largest Contentful Paint) score.
Images that should NOT be lazy loaded:
- Your store logo
- Hero/banner images at the top of the page
- The first 1-2 product images on category pages
- Any image visible in the initial viewport without scrolling
For these critical images, use eager loading with priority hints:
<img src="hero-banner.jpg"
loading="eager"
fetchpriority="high"
width="1200"
height="400"
alt="Summer Sale Banner">When You Need a Module: CSS Background Images
PrestaShop themes frequently use CSS background images for sliders, banners, category headers, and promotional blocks. The loading="lazy" attribute does not work for CSS backgrounds. You need JavaScript to handle these.
IntersectionObserver Approach
// Lazy load CSS background images
document.addEventListener('DOMContentLoaded', function() {
const lazyBackgrounds = document.querySelectorAll('[data-bg]');
const observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
const el = entry.target;
el.style.backgroundImage = 'url(' + el.dataset.bg + ')';
el.classList.add('bg-loaded');
observer.unobserve(el);
}
});
}, {
rootMargin: '200px 0px'
});
lazyBackgrounds.forEach(function(bg) {
observer.observe(bg);
});
});In your HTML/Smarty template:
{* Instead of inline background-image *}
<div class="category-banner" data-bg="{$category_image_url}"></div>When You Need a Module: Placeholder Effects
Native lazy loading shows nothing until the image loads, which can cause a jarring visual experience. Modules or libraries can add:
- Blur-up effect (LQIP) - Load a tiny, blurred version first, then replace with the full image. Creates a smooth perceived loading experience.
- Skeleton screens - Gray placeholder blocks that match the image dimensions, giving the user a sense of the page layout before images load.
- Dominant color placeholders - Extract the dominant color from the image and use it as the placeholder background. Pinterest popularized this approach.
When You Need a Module: Video Lazy Loading
Product videos and embedded YouTube/Vimeo players should be lazy loaded but cannot use the native attribute (except for iframes). For HTML5 <video> elements:
// Lazy load video elements
const lazyVideos = document.querySelectorAll('video[data-src]');
const videoObserver = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
const video = entry.target;
video.src = video.dataset.src;
video.load();
videoObserver.unobserve(video);
}
});
});
lazyVideos.forEach(function(video) {
videoObserver.observe(video);
});Impact on PrestaShop Performance and Core Web Vitals
Proper lazy loading directly impacts three Core Web Vitals metrics:
- LCP (Largest Contentful Paint) - Lazy loading above-the-fold images HURTS LCP. Only lazy load below-the-fold images.
- CLS (Cumulative Layout Shift) - Images without width/height attributes cause layout shifts when they load. Always specify dimensions.
- INP (Interaction to Next Paint) - Fewer resources loading simultaneously means the main thread is less congested, improving interactivity.
Must-Have: Width and Height Attributes
Without explicit width and height attributes, the browser does not know how much space to reserve for a lazy-loaded image. When the image finally loads, the page layout shifts, causing a high CLS score.
<!-- BAD - causes layout shift -->
<img src="product.jpg" loading="lazy" alt="Product">
<!-- GOOD - reserves space, no layout shift -->
<img src="product.jpg" loading="lazy"
width="400" height="400" alt="Product">
<!-- ALSO GOOD - CSS aspect-ratio -->
<img src="product.jpg" loading="lazy"
style="aspect-ratio: 1/1; width: 100%;" alt="Product">PrestaShop-Specific Lazy Loading Recommendations
Product Listing Pages (Category Pages)
Lazy load all product images except the first row (typically 3-4 products visible above the fold). Use native loading="lazy" for product images and apply fetchpriority="high" to the first row.
Product Detail Pages
The main product image should be loaded eagerly with fetchpriority="high". Thumbnail images in the gallery can be lazy loaded. Related/cross-sell product images at the bottom should be lazy loaded.
Homepage
Slider/carousel images above the fold should be eager loaded (at minimum the first slide). Module blocks below the fold (featured products, new products, etc.) should use lazy loading.
CMS Pages
Images embedded in CMS content are the hardest to optimize because they are typically stored as raw HTML in the database. A module or custom JavaScript is needed to add loading="lazy" to images within CMS content.
Quick Implementation Checklist
- Add
loading="lazy"to all<img>tags below the fold in your theme templates - Add
widthandheightattributes to ALL images (lazy or not) - Use
loading="eager"andfetchpriority="high"on above-the-fold hero images and the first row of products - If your theme uses CSS background images for sliders/banners, implement IntersectionObserver-based lazy loading
- Test with Google PageSpeed Insights to verify LCP and CLS improvements
- Test with real devices on slow connections (Chrome DevTools throttling) to ensure images load before users scroll to them
Summary: Module vs. Native
| Scenario | Solution |
|---|---|
| Standard product images | Native loading="lazy" - no module needed |
| CSS background images | Module or custom JS with IntersectionObserver |
| Blur-up / LQIP placeholders | Module or JS library (lazysizes, lozad) |
| Video lazy loading (HTML5) | Custom JS with IntersectionObserver |
| YouTube/Vimeo embeds | Native loading="lazy" on iframe - no module |
| CMS content images | Module to auto-add loading attribute to stored HTML |
| Third-party widget deferral | Custom JS implementation |
For more details, read our guides: PrestaShop Image Optimization: Alt Tags, Lazy Loading and Page Speed and Page Speed and SEO: How Slow Loading Kills Your Google Rankings.
PrestaShop Admin Performance: Why the Back Office Is Slow
A slow PrestaShop back office is one of the most frustrating problems for store administrators. Product editing takes forever, order management pages lag, and simple configuration changes become an exercise in patience. The worst part is that front office performance can be perfectly fine while the back office crawls. This guide identifies the most common causes of back office slowness and provides concrete fixes for each one.
The Most Common Causes
1. PrestaShop Addons API Connection
This is the number one cause of back office slowness that most store owners never discover. PrestaShop's back office makes HTTP requests to addons.prestashop.com on multiple pages to check for module updates, display notifications, and validate licenses. When PrestaShop's API is slow or unresponsive, your entire back office waits for these requests to time out.
Symptoms - The dashboard takes 10-20 seconds to load. The modules page is extremely slow. Other back office pages that load module information are affected.
Fix - Disconnect from PrestaShop Addons in your back office. Go to Modules > Module Manager and look for the option to sign out from your Addons account. Alternatively, disable the module update checking:
-- Disable addons API calls
UPDATE ps_configuration SET value = '0' WHERE name = 'PS_ADDONS_API_MODULE_CHANNEL';2. Debug Mode Left Enabled
When debug mode is enabled, PrestaShop disables all caching, recompiles Smarty templates on every request, and logs detailed error information. This is essential for development but catastrophic for performance.
Symptoms - Everything is slow, not just specific pages. Performance improved dramatically in the past and suddenly got worse.
Fix - Check config/defines.inc.php:
// Make sure these are set to false in production
define('_PS_MODE_DEV_', false);
define('_PS_DEBUG_PROFILING_', false);Also check Advanced Parameters > Performance:
- Template compilation - set to "Never recompile template files" in production
- Cache - set to "Yes"
- Cache type - "File system" is default, Redis or Memcached is better
3. Too Many Installed Modules
Every installed module adds overhead to the back office, even if it is disabled. Modules hook into back office pages, add menu items, load assets, and make database queries. A fresh PrestaShop installation has 50+ modules. Many stores accumulate 100-150 modules over time.
Fix - Audit your modules and uninstall (not just disable) anything you do not use. Pay special attention to:
- Statistics modules - Many stores have 5-10 statistics modules they never check. If you use Google Analytics, you probably do not need the built-in stats modules.
- Gamification module - Makes external API calls on every back office page load. Uninstall it.
- Welcome module (ps_welcome) - Displays a dashboard widget that loads external content. Uninstall after initial setup.
- Unused payment modules - Each loads configuration and validation code even when disabled.
4. Large Database Without Optimization
Over time, PrestaShop databases accumulate bloat - old cart data, expired guest sessions, search statistics, log entries, and abandoned cart records.
Fix - Clean up database bloat regularly:
-- Delete old carts (older than 30 days, not converted to orders)
DELETE FROM ps_cart WHERE id_cart NOT IN (
SELECT id_cart FROM ps_orders
) AND date_add < DATE_SUB(NOW(), INTERVAL 30 DAY);
-- Delete old connections/guest data
DELETE FROM ps_connections WHERE date_add < DATE_SUB(NOW(), INTERVAL 30 DAY);
DELETE FROM ps_guest WHERE id_guest NOT IN (
SELECT id_guest FROM ps_connections
);
-- Delete old search statistics
DELETE FROM ps_statssearch WHERE date_add < DATE_SUB(NOW(), INTERVAL 90 DAY);
-- Delete old mail logs
DELETE FROM ps_mail WHERE date_add < DATE_SUB(NOW(), INTERVAL 90 DAY);
-- Delete old page views
DELETE FROM ps_page_viewed WHERE date_add < DATE_SUB(NOW(), INTERVAL 30 DAY);
-- Optimize tables after cleanup
OPTIMIZE TABLE ps_cart, ps_connections, ps_guest, ps_statssearch, ps_mail, ps_page_viewed;5. Shared Hosting Limitations
Shared hosting environments have limited CPU, RAM, and I/O resources. When other accounts on the same server are busy, your PrestaShop back office suffers.
Symptoms - Performance varies throughout the day. Sometimes fast, sometimes extremely slow with no changes on your end.
Fix - Upgrade to VPS or dedicated hosting. Minimum recommended specifications for a PrestaShop back office to feel responsive:
- 2 CPU cores (4 recommended)
- 4 GB RAM (8 GB recommended)
- SSD storage
- PHP 8.1+ with OPcache enabled
- MySQL 8.0 with InnoDB buffer pool sized to fit your database in memory
6. OPcache Not Enabled or Misconfigured
OPcache caches compiled PHP code in memory, eliminating the need to reparse PHP files on every request. Without OPcache, every back office page load recompiles hundreds of PHP files.
Fix - Enable and configure OPcache:
opcache.enable = 1
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 32
opcache.max_accelerated_files = 16229
opcache.revalidate_freq = 60
opcache.fast_shutdown = 1
opcache.enable_cli = 07. Slow Dashboard Widgets
The PrestaShop dashboard loads multiple widgets that query the database for statistics, recent orders, best sellers, and more. With large databases, these queries can take several seconds each.
Fix - Simplify your dashboard. Remove widgets you do not use regularly. In the Dashboard, click the gear icon on each widget and disable those you do not need. Consider reducing the date range for dashboard statistics from "this year" to "this month."
8. Large Product Catalog
Stores with 10,000+ products experience slower product listing pages in the back office. The product list page loads all product data for display, including images, categories, and stock levels.
Fix - Adjust products per page in the back office to 20-50 instead of 100+. Use the search and filter features instead of browsing large product lists.
Performance Optimization Checklist
- Disable debug mode in
config/defines.inc.php - Set template compilation to "Never recompile" in Performance settings
- Enable caching (Redis or Memcached preferred over file system)
- Enable OPcache with adequate memory allocation
- Disconnect from PrestaShop Addons API
- Uninstall unused modules (especially statistics and gamification)
- Clean database bloat (old carts, connections, logs)
- Simplify dashboard widgets
- Upgrade to VPS/dedicated hosting with SSD
- Use PHP 8.1+ for significant performance gains
Measuring Back Office Performance
To quantify improvements, measure your back office page load times before and after each optimization:
# Time the dashboard load
curl -o /dev/null -s -w "Total: %{time_total}s\n" -b "cookie.txt" \
https://yourstore.com/admin-folder/index.php?controller=AdminDashboard
# Time the products page
curl -o /dev/null -s -w "Total: %{time_total}s\n" -b "cookie.txt" \
https://yourstore.com/admin-folder/index.php?controller=AdminProductsTarget times: Dashboard under 3 seconds, product listing under 2 seconds, product editing under 2 seconds.
For more details, read our guides: What Actually Makes PrestaShop Slow: Database, Modules and Hosting and Database Cleanup: Why Your PrestaShop Store Gets Slower Over Time.
Rate Limiting and Bot Protection for PrestaShop Without a WAF
Bots account for over 40% of all web traffic in 2026, and not all of them are benign search engine crawlers. Scraper bots steal your product data and pricing, credential-stuffing bots attack your login pages, and inventory-hoarding bots buy out limited stock before real customers can. A Web Application Firewall (WAF) like Cloudflare Pro is the ideal solution, but many PrestaShop store owners operate on budgets that do not include enterprise security tools. This guide shows you how to implement effective bot protection using only server configuration, .htaccess rules, and lightweight modules.
Understanding the Bot Threat Landscape
Types of Malicious Bots
- Scraper bots - Crawl your entire catalog to steal product data, descriptions, images, and prices for competitor sites or counterfeit marketplaces.
- Credential stuffing bots - Try stolen username/password combinations against your login page. They can test thousands of combinations per minute.
- Inventory hoarding bots - Add products to cart and hold them, preventing real customers from purchasing limited-stock items.
- Form spam bots - Submit contact forms, registration forms, and newsletter signups with spam content or phishing links.
- DDoS bots - Flood your server with requests to make your store unavailable.
- SEO spam bots - Inject spam links into your blog comments, product reviews, or contact forms.
Method 1 - Apache .htaccess Rate Limiting
If your server runs Apache with mod_evasive or mod_ratelimit, you can limit request rates at the server level.
Using mod_ratelimit
# Limit all connections to 10 requests per second
<IfModule mod_ratelimit.c>
SetOutputFilter RATE_LIMIT
SetEnv rate-limit 400
</IfModule>Block Known Bad User Agents
# Block common scraper and attack bots
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (SemrushBot|AhrefsBot|MJ12bot|DotBot|BLEXBot) [NC]
RewriteRule .* - [F,L]
# Block empty user agents (most legitimate browsers identify themselves)
RewriteCond %{HTTP_USER_AGENT} ^-?$
RewriteRule .* - [F,L]
# Block specific known bad IPs (update regularly)
# Deny from 192.168.1.100
# Deny from 10.0.0.0/8Protect Sensitive Endpoints
# Rate limit login page
<Location "/en/login">
<IfModule mod_evasive20.c>
DOSHashTableSize 3097
DOSPageCount 5
DOSSiteCount 50
DOSPageInterval 2
DOSSiteInterval 5
DOSBlockingPeriod 60
</IfModule>
</Location>Method 2 - Nginx Rate Limiting
If your PrestaShop runs behind Nginx (either as the web server or as a reverse proxy), Nginx has built-in rate limiting that is more powerful than Apache's.
# In nginx.conf or your site's server block
# Define rate limit zones
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/m;
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
server {
# Apply rate limit to login pages
location ~ /login$ {
limit_req zone=login burst=3 nodelay;
# ... your existing configuration
}
# Apply rate limit to API/webservice
location /api/ {
limit_req zone=api burst=10;
# ... your existing configuration
}
# General rate limit for all pages
location / {
limit_req zone=general burst=20;
# ... your existing configuration
}
}Method 3 - fail2ban for Brute Force Protection
fail2ban monitors your server logs and automatically bans IP addresses that show malicious behavior. It is available on most Linux servers and is free.
Install and Configure for PrestaShop
# Install fail2ban
sudo apt-get install fail2ban
# Create a PrestaShop login filter
sudo cat > /etc/fail2ban/filter.d/prestashop-login.conf << EOF
[Definition]
failregex = ^<HOST> .* "POST .*/login.*" (401|403)
datepattern = %%d/%%b/%%Y:%%H:%%M:%%S
EOF
# Create a jail for PrestaShop
sudo cat > /etc/fail2ban/jail.d/prestashop.conf << EOF
[prestashop-login]
enabled = true
port = http,https
filter = prestashop-login
logpath = /var/log/apache2/access.log
maxretry = 10
findtime = 300
bantime = 3600
EOF
# Restart fail2ban
sudo systemctl restart fail2banMethod 4 - PHP-Level Rate Limiting
For stores on shared hosting where you cannot modify server configuration, implement rate limiting in PHP. Create a simple rate limiter that uses PrestaShop's database or file system:
// Simple file-based rate limiter for PrestaShop
// Add to a custom module's hook on actionFrontControllerInitBefore
function rateLimitCheck($maxRequests = 60, $timeWindow = 60) {
$ip = Tools::getRemoteAddr();
$cacheDir = _PS_CACHE_DIR_ . 'ratelimit/';
if (!is_dir($cacheDir)) {
mkdir($cacheDir, 0755, true);
}
$file = $cacheDir . md5($ip) . '.json';
$now = time();
if (file_exists($file)) {
$data = json_decode(file_get_contents($file), true);
// Clean old entries
$data['requests'] = array_filter(
$data['requests'],
function($timestamp) use ($now, $timeWindow) {
return ($now - $timestamp) < $timeWindow;
}
);
if (count($data['requests']) >= $maxRequests) {
header('HTTP/1.1 429 Too Many Requests');
header('Retry-After: ' . $timeWindow);
die('Rate limit exceeded. Please wait and try again.');
}
} else {
$data = ['requests' => []];
}
$data['requests'][] = $now;
file_put_contents($file, json_encode($data));
}Method 5 - robots.txt and Crawl Control
While robots.txt does not stop malicious bots (they ignore it), it reduces the load from well-behaved crawlers:
# robots.txt for PrestaShop
User-agent: *
Disallow: /modules/
Disallow: /classes/
Disallow: /controllers/
Disallow: /translations/
Disallow: /var/
Disallow: /*?order=
Disallow: /*?orderby=
Disallow: /*?orderway=
Disallow: /*?tag=
Disallow: /*?id_currency=
Disallow: /*?search_query=
Disallow: /*?back=
Disallow: /*?n=
Disallow: /en/login
Disallow: /en/my-account
Disallow: /en/cart
Disallow: /en/order
# Limit crawl rate for aggressive bots
User-agent: SemrushBot
Crawl-delay: 10
User-agent: AhrefsBot
Crawl-delay: 10
User-agent: Googlebot
Allow: /
Sitemap: https://yourstore.com/1_index_sitemap.xmlMethod 6 - CAPTCHA on Critical Forms
Add Google reCAPTCHA or hCaptcha to your most targeted pages:
- Login page - Prevents credential stuffing attacks
- Registration page - Prevents fake account creation
- Contact form - Prevents spam submissions
- Newsletter signup - Prevents list pollution
PrestaShop has official reCAPTCHA modules available. For PrestaShop 8.x+, look for modules compatible with reCAPTCHA v3 (invisible) for the best user experience.
Method 7 - Cloudflare Free Tier
Even without Cloudflare Pro (which includes WAF), the free tier provides significant bot protection:
- Browser Integrity Check - Challenges requests with suspicious HTTP headers
- Bot Fight Mode - Automatically detects and challenges bots (available on free tier)
- Rate limiting - 1 free rule with 10,000 requests/month
- Under Attack Mode - JavaScript challenge for all visitors during active attacks
Monitoring and Detection
To know if bots are attacking your store, monitor your access logs:
# Find the top 20 IP addresses by request count
awk '{print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20
# Find IPs hitting login page excessively
grep "login" /var/log/apache2/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -20
# Find suspicious user agents
awk -F'"' '{print $6}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -30If you see a single IP making thousands of requests, or a user agent you do not recognize making hundreds of requests per minute, you have a bot problem.
Summary of Protection Layers
| Method | Protects Against | Difficulty | Cost |
|---|---|---|---|
| .htaccess user agent blocking | Known scrapers | Easy | Free |
| fail2ban | Brute force, credential stuffing | Medium | Free |
| Nginx rate limiting | All excessive requests | Medium | Free |
| PHP rate limiter | Targeted page abuse | Medium | Free |
| CAPTCHA | Form spam, fake accounts | Easy | Free |
| Cloudflare free tier | General bot traffic, DDoS | Easy | Free |
| robots.txt crawl-delay | Well-behaved crawlers | Easy | Free |
Further reading: Visitor Control: Blocking Bad Bots and Unwanted Traffic and reCAPTCHA for PrestaShop: Protecting Your Store from Spam and Bots.
When PrestaShop Combinations Kill Performance: Limits and Workarounds
PrestaShop's combination system allows you to create product variants - different sizes, colors, materials, and other attributes. It works perfectly for products with a handful of variants. But when products have hundreds or thousands of combinations, performance degrades dramatically. Product pages take 10-30 seconds to load, the back office becomes unusable, and category listing pages crawl. This guide explains exactly why combinations cause performance problems, where the practical limits are, and what you can do about it.
Why Combinations Cause Performance Problems
Database Architecture
PrestaShop stores combination data across multiple tables:
ps_product_attribute- One row per combination (e.g., Red-XL, Red-L, Blue-XL, Blue-L = 4 rows)ps_product_attribute_combination- Links each combination to its attribute valuesps_product_attribute_shop- Per-shop combination data (multistore)ps_stock_available- Stock level for each combinationps_specific_price- Price overrides per combinationps_product_attribute_image- Image assignments per combination
A product with 5 sizes and 10 colors creates 50 combinations. That means 50 rows in ps_product_attribute, 100 rows in ps_product_attribute_combination (2 attributes per combination), 50 rows in ps_stock_available, and potentially 50+ rows in ps_specific_price if you have custom pricing.
A product with 3 attributes (size: 10 options, color: 15 options, material: 4 options) creates 10 x 15 x 4 = 600 combinations. The database rows multiply accordingly.
The Exponential Growth Problem
| Attributes | Values per Attribute | Total Combinations | Approximate DB Rows |
|---|---|---|---|
| 2 | 5 x 5 | 25 | ~175 |
| 2 | 10 x 10 | 100 | ~700 |
| 3 | 5 x 10 x 4 | 200 | ~1,400 |
| 3 | 10 x 15 x 8 | 1,200 | ~8,400 |
| 4 | 5 x 10 x 4 x 3 | 600 | ~4,200 |
| 4 | 10 x 15 x 8 x 5 | 6,000 | ~42,000 |
With 6,000 combinations per product and 100 such products, you are looking at 4.2 million database rows just for combination data. This is where performance falls off a cliff.
Front Office Performance Impact
When a customer visits a product page with many combinations, PrestaShop must:
- Query all combinations from the database
- Calculate the price for each combination (applying tax rules, specific prices, group prices, cart rules)
- Check stock availability for each combination
- Generate the JSON data structure that powers the attribute selector
- Render the HTML for the attribute dropdowns or swatches
For a product with 1,000+ combinations, this process can take 5-30 seconds depending on server hardware.
Back Office Performance Impact
Editing a product with many combinations in the back office is often even worse than the front office. The combination tab loads all combinations at once, and saving changes triggers updates across multiple tables for every combination.
Practical Limits
| Combination Count | Front Office | Back Office | Verdict |
|---|---|---|---|
| 1-50 | Fast (< 1s) | Fast | No issues |
| 50-200 | Acceptable (1-3s) | Acceptable | Manageable |
| 200-500 | Slow (3-8s) | Slow | Needs optimization |
| 500-1000 | Very slow (8-15s) | Very slow | Consider restructuring |
| 1000+ | Unusable (15-30s+) | Often crashes | Restructure required |
These numbers assume a typical shared hosting environment. Dedicated servers with SSD storage, OPcache, and proper MySQL tuning can push the limits higher, but the underlying architecture still degrades linearly with combination count.
Workaround 1 - Restructure Your Product Catalog
The most effective solution is to reduce the number of combinations per product by restructuring how you organize products.
Split Products by Key Attribute
Instead of one product "T-Shirt" with combinations for every color and size, create separate products for each color:
- "T-Shirt - Red" (sizes: S, M, L, XL, XXL = 5 combinations)
- "T-Shirt - Blue" (sizes: S, M, L, XL, XXL = 5 combinations)
- "T-Shirt - Black" (sizes: S, M, L, XL, XXL = 5 combinations)
Instead of 1 product with 50 combinations (10 colors x 5 sizes), you have 10 products with 5 combinations each. The front office is fast, the back office is manageable, and you get better SEO because each color has its own indexed page.
Use PrestaShop's Product Pack Feature
For products that are genuinely different items sold together (like a furniture set with configurable pieces), consider using product packs instead of combinations.
Workaround 2 - Database and Server Optimization
Add Database Indexes
PrestaShop's default indexes may not be optimal for stores with many combinations. Add these indexes:
ALTER TABLE ps_product_attribute
ADD INDEX idx_product_default (id_product, default_on);
ALTER TABLE ps_product_attribute_combination
ADD INDEX idx_attribute (id_attribute);
ALTER TABLE ps_stock_available
ADD INDEX idx_product_attribute (id_product, id_product_attribute);
ALTER TABLE ps_specific_price
ADD INDEX idx_product_combo (id_product, id_product_attribute, id_shop);MySQL Configuration Tuning
# my.cnf optimizations for combination-heavy stores
innodb_buffer_pool_size = 2G # Adjust based on available RAM
innodb_log_file_size = 256M
query_cache_type = 1
query_cache_size = 128M
query_cache_limit = 4M
join_buffer_size = 4M
sort_buffer_size = 4M
tmp_table_size = 256M
max_heap_table_size = 256MEnable OPcache
opcache.enable = 1
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 32
opcache.max_accelerated_files = 16229
opcache.revalidate_freq = 60Workaround 3 - Lazy Loading Combinations
Instead of loading all combinations on page load, implement lazy loading that fetches combination data only when the customer selects an attribute. This requires custom module development or a module that overrides the default behavior.
The approach works like this:
- On initial page load, show only the first attribute group (e.g., Color)
- When the customer selects a color, make an AJAX request to fetch the available sizes for that color
- When the customer selects a size, fetch the price, stock, and image for that specific combination
This reduces the initial page load from loading all 1,000 combinations to loading only the first attribute group (perhaps 10-15 items), then incrementally loading data as needed.
Workaround 4 - Caching Strategies
Full Page Cache
Implement a full-page cache (Varnish, LiteSpeed Cache, or Nginx FastCGI Cache) for product pages. The first visitor triggers the slow combination load, but subsequent visitors get the cached version instantly. Limitations:
- Cart-specific information (logged-in customer prices, group prices) complicates caching
- Pages with customer-specific content cannot be fully cached
- Cache invalidation when prices or stock change
Redis or Memcached for Object Caching
Configure PrestaShop to use Redis or Memcached instead of file-based caching:
# In config/defines.inc.php or via Back Office
# Advanced Parameters > Performance > Caching
# Select Memcached or Redis as cache typeWorkaround 5 - Custom Combination Loading with Override
For developers, you can override the combination loading logic to paginate results or pre-compute combination data:
// Pre-compute combination data into a JSON file
// Run this via cron whenever products are updated
$products = Product::getProducts($id_lang, 0, 0, 'id_product', 'ASC');
foreach ($products as $product) {
$combinations = $product['id_product'];
$combData = Product::getProductProperties($id_lang, $product);
// Save to a JSON file per product
file_put_contents(
_PS_MODULE_DIR_ . 'yourcache/product_' . $product['id_product'] . '.json',
json_encode($combData)
);
}When to Avoid Combinations Entirely
Some use cases are fundamentally incompatible with PrestaShop's combination system:
- Configurable products with 4+ attributes and 10+ values each - Use a product configurator module instead
- Products with unique serial numbers - Use a stock management module with serial tracking
- Dimensional products (custom width x height x depth) - Use a custom dimensions module that calculates price on-the-fly
- Print-on-demand products with customer uploads - Use a product designer module
Monitoring Combination Performance
Use PrestaShop's built-in profiling to identify combination-related bottlenecks:
// In config/defines.inc.php
define('_PS_DEBUG_PROFILING_', true);This adds a profiling bar at the bottom of every page showing SQL query count, execution time, and memory usage. Look for:
- Pages with 500+ SQL queries (normal is 50-150)
- Single queries taking more than 100ms
- Total page generation time above 3 seconds
Summary of Recommendations
| Combination Count | Recommended Action |
|---|---|
| Under 100 | No action needed - PrestaShop handles this fine |
| 100-300 | Add database indexes, enable OPcache, use Redis caching |
| 300-1000 | Split products by primary attribute, add indexes, consider lazy loading |
| Over 1000 | Restructure catalog, use product configurator module, or implement custom lazy-load AJAX |
For more details, read our guides: Product Combinations and Variants: When Your Store Needs Them and What Actually Makes PrestaShop Slow: Database, Modules and Hosting.
PHP Version Compatibility Matrix for PrestaShop
Choosing the right PHP version for your PrestaShop store is one of the most critical infrastructure decisions you will make. Running an incompatible PHP version can cause white screens, broken checkout flows, module failures, and security vulnerabilities. This comprehensive guide covers every PrestaShop release from 1.6 through 9.x and maps each one to its supported PHP versions, recommended configurations, and upgrade considerations.
Why PHP Version Matters for PrestaShop
PHP is the server-side language that powers PrestaShop. Each major PHP release introduces performance improvements, new language features, and deprecates older functions. PrestaShop's codebase evolves alongside PHP, meaning that newer PrestaShop versions take advantage of modern PHP features while dropping support for outdated ones.
Running the wrong PHP version causes three categories of problems:
- Fatal errors - Functions removed in newer PHP versions (e.g.,
mysql_*functions removed in PHP 7.0,each()removed in PHP 8.0) cause immediate crashes. - Deprecation warnings - Deprecated functions generate warnings that can break AJAX responses, JSON output, and PDF generation when
display_errorsis enabled. - Security exposure - PHP versions that have reached end-of-life no longer receive security patches, leaving your store vulnerable.
Complete Compatibility Matrix
PrestaShop 1.6.x
| PrestaShop Version | PHP 5.4 | PHP 5.5 | PHP 5.6 | PHP 7.0 | PHP 7.1 | PHP 7.2+ |
|---|---|---|---|---|---|---|
| 1.6.0.x - 1.6.0.14 | Yes | Yes | Yes | No | No | No |
| 1.6.1.0 - 1.6.1.4 | Yes | Yes | Yes | Partial | No | No |
| 1.6.1.5 - 1.6.1.23 | Yes | Yes | Yes | Yes | Yes | No |
| 1.6.1.24+ | Yes | Yes | Yes | Yes | Yes | No |
Recommended PHP for 1.6.x - PHP 7.1. It offers the best balance of performance and compatibility. Running 1.6.x on PHP 7.2+ requires core file modifications that break the upgrade path and are not recommended.
PrestaShop 1.7.x
| PrestaShop Version | PHP 7.1 | PHP 7.2 | PHP 7.3 | PHP 7.4 | PHP 8.0+ |
|---|---|---|---|---|---|
| 1.7.0.x - 1.7.4.x | Yes (recommended) | No | No | No | No |
| 1.7.5.x | Yes | Yes (recommended) | No | No | No |
| 1.7.6.x | Yes | Yes (recommended) | Yes | No | No |
| 1.7.7.x | Yes | Yes | Yes (recommended) | Partial | No |
| 1.7.8.x | Yes | Yes | Yes | Yes (recommended) | No |
Critical warning - No version of PrestaShop 1.7 supports PHP 8.0 or later. If you run PS 1.7.6 on PHP 8, Smarty will crash immediately because the template engine uses functions that were removed in PHP 8.0. The each() function removal and changes to how array_key_exists() works with objects cause fatal errors.
PrestaShop 8.x
| PrestaShop Version | PHP 7.2 | PHP 7.3 | PHP 7.4 | PHP 8.0 | PHP 8.1 | PHP 8.2 | PHP 8.3 |
|---|---|---|---|---|---|---|---|
| 8.0.0 - 8.0.2 | Yes (min) | Yes | Yes | Yes | Partial | No | No |
| 8.0.3 - 8.0.5 | Yes (min) | Yes | Yes | Yes | Yes (recommended) | No | No |
| 8.1.0 - 8.1.2 | No | Yes (min) | Yes | Yes | Yes (recommended) | Partial | No |
| 8.1.3 - 8.1.7 | No | Yes (min) | Yes | Yes | Yes (recommended) | Yes | Partial |
Recommended PHP for 8.x - PHP 8.1. It is the sweet spot offering full compatibility, active security support, and excellent performance with JIT compilation. PHP 8.1 brings fibers, enums, readonly properties, and intersection types that PrestaShop 8 can leverage.
PrestaShop 9.x
| PrestaShop Version | PHP 8.1 | PHP 8.2 | PHP 8.3 | PHP 8.4 |
|---|---|---|---|---|
| 9.0.x | Yes (min) | Yes | Yes (recommended) | Yes |
Recommended PHP for 9.x - PHP 8.3 or 8.4. PrestaShop 9 runs on Symfony 6.4 LTS and requires PHP 8.1 as its minimum. PHP 8.4 brings property hooks and asymmetric visibility that future PrestaShop updates will leverage.
PHP End-of-Life Dates You Must Know
| PHP Version | Active Support Until | Security Fixes Until | Status (2026) |
|---|---|---|---|
| PHP 7.4 | Nov 2021 | Nov 2022 | EOL - Dangerous |
| PHP 8.0 | Nov 2022 | Nov 2023 | EOL - Dangerous |
| PHP 8.1 | Nov 2023 | Dec 2025 | EOL - Upgrade soon |
| PHP 8.2 | Dec 2024 | Dec 2026 | Security only |
| PHP 8.3 | Dec 2025 | Dec 2027 | Security only |
| PHP 8.4 | Dec 2026 | Dec 2028 | Active support |
If you are running PHP 7.4 or 8.0 in 2026, you are running on an unsupported version that no longer receives security patches. This is a critical risk for any e-commerce store handling payment data.
How to Check Your Current PHP Version
Method 1 - PrestaShop Back Office
Navigate to Advanced Parameters > Information. The Server Information section displays your PHP version, along with memory limit, max execution time, and other relevant settings.
Method 2 - PHP Info File
Create a file named phpinfo.php in your store's root directory with this content:
<?php phpinfo();Access it via your browser at https://yourstore.com/phpinfo.php. Delete this file immediately after checking - it exposes sensitive server configuration details.
Method 3 - Command Line
php -v
php -r "echo PHP_VERSION;"Note that the CLI PHP version may differ from the web server PHP version. Always verify through the web interface or phpinfo().
Common Issues When Running Wrong PHP Versions
White Screen of Death (WSOD)
The most common symptom of PHP incompatibility. Check your PHP error log (usually at /var/log/php-errors.log or accessible via your hosting panel). Typical errors include:
Fatal error: Uncaught Error: Call to undefined function mysql_connect()
Fatal error: Uncaught Error: Call to undefined function each()
Fatal error: Cannot use "parent" when current class scope has no parentDeprecation Warnings Breaking AJAX
When display_errors = On and you upgrade PHP, deprecation notices get prepended to AJAX responses. This breaks the JSON parsing in the back office, causing features like product search, customer lookup, and order creation to fail silently. The fix:
; php.ini
display_errors = Off
log_errors = On
error_log = /path/to/php-error.logModule Incompatibility
Third-party modules may not support your PHP version. Before upgrading PHP, check each installed module for compatibility. Common problem areas:
- Modules using
create_function()- removed in PHP 8.0 - Modules using
mysql_*functions - removed in PHP 7.0 - Modules using positional string access with curly braces
$str{0}- removed in PHP 8.0 - Modules not handling nullable return types - stricter in PHP 8.1+
How to Safely Upgrade PHP for PrestaShop
Step 1 - Audit Your Current Setup
Before changing anything, document your current environment:
php -v # Current PHP version
php -m # Loaded extensions
php -i | grep memory # Memory limit
php -i | grep max_exec # Execution time limitStep 2 - Check Module Compatibility
Review every installed module. Check the module developer's documentation for PHP version support. If a module has not been updated in over two years, it is likely incompatible with PHP 8.x.
Step 3 - Test on Staging First
Never upgrade PHP on your production server without testing. Create a staging copy of your store and test with the new PHP version. Check:
- Front office pages load correctly
- Product pages, category pages, CMS pages
- Cart and checkout process completes
- Payment modules process test transactions
- Back office functionality works (product editing, order management)
- All third-party modules function correctly
- Cron jobs execute without errors
Step 4 - Upgrade with Rollback Plan
Most hosting providers allow you to switch PHP versions from the control panel (cPanel, Plesk, DirectAdmin). Keep the previous PHP version available for quick rollback if issues arise.
Step 5 - Clear All Caches After Upgrade
After switching PHP versions, clear every cache layer:
# Clear PrestaShop cache
rm -rf var/cache/prod/* var/cache/dev/*
# Clear Smarty compiled templates
rm -rf var/cache/smarty/compile/* var/cache/smarty/cache/*
# If using OPcache, restart PHP-FPM
systemctl restart php8.3-fpm
# Clear any CDN cache (Cloudflare, etc.)PHP Configuration Best Practices for PrestaShop
Regardless of which PHP version you choose, these settings are essential for optimal PrestaShop performance:
; php.ini recommended settings
memory_limit = 512M
max_execution_time = 300
max_input_vars = 10000
post_max_size = 32M
upload_max_filesize = 32M
; OPcache settings (critical for performance)
opcache.enable = 1
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 32
opcache.max_accelerated_files = 16229
opcache.revalidate_freq = 60
opcache.fast_shutdown = 1
; Required extensions
extension = intl
extension = zip
extension = gd
extension = curl
extension = mbstring
extension = openssl
extension = pdo_mysql
extension = fileinfoModule Developer Considerations
If you develop PrestaShop modules, you need to consider PHP compatibility carefully:
- Minimum PHP version - Target PHP 7.2 as minimum for modules that should work on PrestaShop 8.0+, or PHP 8.1 for PrestaShop 9-only modules.
- Use PHPStan or Psalm - Static analysis tools catch PHP version incompatibilities before your users do.
- Avoid version-specific syntax - Features like match expressions (PHP 8.0), enums (PHP 8.1), and readonly properties (PHP 8.1) limit your module to those PHP versions and above.
- Test on multiple versions - Use Docker containers with different PHP versions to test your module across the compatibility range.
Frequently Asked Questions
Can I run PrestaShop 1.7 on PHP 8?
No. No version of PrestaShop 1.7 officially supports PHP 8.0 or later. While some users have applied patches to make it partially work, this is unsupported and will break with updates. The correct path is to upgrade to PrestaShop 8.x.
Should I use PHP 8.4 with PrestaShop 8.1?
Not recommended. PrestaShop 8.1 was developed and tested primarily with PHP 8.1. While PHP 8.2 has partial support in later 8.1.x releases, PHP 8.4 introduces changes that may cause issues with older Symfony components. Stick with PHP 8.1 for PrestaShop 8.x.
How much faster is PHP 8.x compared to 7.x?
Benchmarks show PHP 8.1 is approximately 20-30% faster than PHP 7.4 for typical PrestaShop workloads. The JIT compiler provides the most benefit for computational tasks. For I/O-bound operations (database queries, file reads), the improvement is smaller but still measurable.
Does upgrading PHP require upgrading PrestaShop?
Not necessarily, but they go hand in hand. You can upgrade PHP within the supported range for your PrestaShop version without upgrading PrestaShop itself. However, if you want to run a modern PHP version (8.3+), you will need PrestaShop 8.1 or 9.x.
For more details, read our guides: PrestaShop 1.7 vs 8 vs 9: Which Version Should You Be Running? and What PrestaShop 9 Changed and Why Module Compatibility Matters.
What Varnish Is and Why It Matters for PrestaShop
Varnish Cache is an HTTP reverse proxy that sits between your web server and the internet, serving cached copies of pages without ever touching PHP or MySQL. When a visitor requests a page that Varnish has cached, the response comes directly from memory in microseconds. PHP never executes. MySQL never receives a query. The web server barely notices the request happened.
This is fundamentally different from how PHP-based full page cache (FPC) modules work in PrestaShop. An FPC module still runs within PHP. The request hits Apache or Nginx, PHP boots, PrestaShop initializes (loading configuration, establishing database connections, parsing routes), and then the FPC module intercepts the request before the full controller logic runs, serving a cached HTML file. While this is significantly faster than rendering the page from scratch, it still involves starting PHP and loading the PrestaShop framework. That overhead, typically 50-200 milliseconds even for a cache hit, adds up under load.
Varnish eliminates that overhead entirely. A Varnish cache hit is served in 1-5 milliseconds. Under heavy traffic, the difference is dramatic. A PrestaShop store that struggles to handle 100 concurrent users with an FPC module can serve thousands of concurrent users with Varnish, because the vast majority of requests never reach the PHP backend at all.
When PHP Full Page Cache Modules Are Sufficient
Before investing in Varnish, it is worth understanding when a PHP-based FPC module is good enough. For many PrestaShop stores, it is.
If your store receives fewer than 50,000 daily page views, a well-configured FPC module will handle the load without problems. The additional complexity of Varnish is not justified when your server has spare capacity. If your server response times with FPC are consistently under 200 milliseconds, your visitors are already getting fast page loads. The bottleneck at that point is likely frontend rendering (CSS, JavaScript, images) rather than server response time.
FPC modules also handle some PrestaShop-specific scenarios more gracefully than Varnish because they run inside the application. They can check whether a user is logged in, whether the cart has items, and whether certain dynamic content needs to be personalized, all within the same PHP process. With Varnish, these checks must be handled through cookie inspection and cache variation rules, which adds configuration complexity.
Consider Varnish when your store regularly handles traffic spikes (flash sales, marketing campaigns, seasonal peaks) that overwhelm your PHP capacity, when you need sub-10ms response times for SEO or user experience reasons, when your hosting budget is limited and you need to serve more traffic from the same hardware, or when your store serves a high ratio of anonymous browsing traffic (category pages, product pages) relative to cart and checkout activity.
How Varnish Works: The Request Flow
Understanding the request flow through Varnish is essential for configuring it correctly with PrestaShop.
Request Arrives
When a visitor requests a page, the request hits Varnish first (Varnish listens on port 80 or 443 if terminated by a frontend proxy). Varnish examines the request: the URL, the HTTP method, the cookies, and the headers.
Cache Lookup
Varnish checks its cache for a stored response matching this request. The cache key is typically based on the URL and selected headers. If a matching response exists and has not expired, Varnish serves it directly. This is a cache hit. The response is sent to the visitor and the backend server is never contacted.
Cache Miss
If no matching cached response exists, Varnish forwards the request to the backend server (Apache or Nginx running PrestaShop). PrestaShop processes the request normally, generates the HTML response, and sends it back to Varnish. Varnish stores the response in its cache (if the response is cacheable) and forwards it to the visitor. Subsequent requests for the same page will be served from cache.
Cache Invalidation
When product data changes, prices update, or content is modified, the cached version becomes stale. Varnish needs to be told to discard the old cached version so it fetches a fresh one from the backend. This is cache invalidation, and it is the hardest part of any caching system to get right.
VCL Configuration for PrestaShop
Varnish Configuration Language (VCL) is a domain-specific language that controls how Varnish handles requests. A proper VCL configuration for PrestaShop must handle several PrestaShop-specific behaviors.
Backend Definition
The backend definition tells Varnish where to forward cache misses. For a typical PrestaShop setup where Apache or Nginx runs on the same server on port 8080:
backend default {
.host = "127.0.0.1";
.port = "8080";
.connect_timeout = 5s;
.first_byte_timeout = 60s;
.between_bytes_timeout = 10s;
}
The timeouts are important. PrestaShop pages can take several seconds to generate on a cold cache, especially category pages with many products. Setting first_byte_timeout too low causes Varnish to return a 503 error before PrestaShop finishes generating the page.
Handling Cookies and Sessions
Cookies are the biggest challenge when caching PrestaShop with Varnish. PrestaShop sets several cookies by default, and Varnish treats any request with cookies as uncacheable unless instructed otherwise. If you do not handle cookies in your VCL, Varnish will cache almost nothing.
PrestaShop sets these cookies on most requests: the session cookie (typically named PrestaShop-xxxx), the cart-related cookies, Google Analytics cookies (_ga, _gid, _gat), and various tracking cookies from marketing tools. Of these, only the PrestaShop session cookie matters for cache behavior. Analytics and tracking cookies should be stripped from the request before the cache lookup so they do not prevent caching.
In your VCL vcl_recv subroutine, strip non-essential cookies:
sub vcl_recv {
# Remove Google Analytics and other tracking cookies
set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_ga|_gid|_gat|__utm[a-z]+|_fbp|_gcl_[a-z]+)=[^;]*", "");
# Remove empty cookie header
if (req.http.Cookie ~ "^\s*$") {
unset req.http.Cookie;
}
}
Deciding What to Cache
Not every PrestaShop page should be cached. The VCL must distinguish between cacheable and non-cacheable requests.
Always cache: Product pages for anonymous visitors, category listing pages, CMS pages (about, terms, contact), the homepage, manufacturer and supplier pages, sitemap pages.
Never cache: The shopping cart page, checkout pages (all steps), the customer account area (orders, addresses, personal info), the login and registration pages, any page for a logged-in customer, POST requests, AJAX requests that modify state (add to cart, update quantity).
The VCL logic for this typically checks the URL path and the presence of session cookies:
sub vcl_recv {
# Do not cache POST requests
if (req.method == "POST") {
return (pass);
}
# Do not cache admin area
if (req.url ~ "^/admin") {
return (pass);
}
# Do not cache checkout and cart
if (req.url ~ "(cart|order|login|my-account|module/)" ) {
return (pass);
}
# Do not cache if customer has items in cart
if (req.http.Cookie ~ "PrestaShop-") {
return (pass);
}
return (hash);
}
Setting Cache Duration
In the vcl_backend_response subroutine, you control how long Varnish caches each response. PrestaShop sends Cache-Control headers that typically say no-cache or private because it assumes every response might contain personalized content. You need to override these for pages you know are safe to cache:
sub vcl_backend_response {
# Cache product and category pages for 1 hour
if (bereq.url ~ "^/([0-9]+-|[a-z]+-[0-9]+)") {
set beresp.ttl = 1h;
unset beresp.http.Set-Cookie;
}
# Cache static assets for 1 day
if (bereq.url ~ "\.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf)$") {
set beresp.ttl = 1d;
unset beresp.http.Set-Cookie;
}
}
Stripping Set-Cookie from cached responses is critical. If a cached response includes a Set-Cookie header, Varnish will not cache it by default, and even if forced to cache it, it would set the same session cookie for every visitor, causing session hijacking.
Cache Invalidation with PURGE Requests
When a product price changes, a new product is added, or content is updated, the cached version must be invalidated. Varnish supports PURGE requests: a special HTTP method that tells Varnish to remove a specific URL from its cache.
Configuring PURGE Support
Add PURGE handling to your VCL:
acl purge {
"127.0.0.1";
"localhost";
}
sub vcl_recv {
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return (synth(405, "Not allowed."));
}
return (purge);
}
}
The ACL restricts PURGE requests to localhost, preventing external users from flushing your cache.
Triggering Purges from PrestaShop
PrestaShop does not send PURGE requests natively. You need a module or custom hook that detects when cacheable content changes and sends a PURGE request to Varnish. The module hooks into PrestaShop events like actionProductUpdate, actionCategoryUpdate, and actionCMSPageUpdate. When these events fire, the module sends an HTTP PURGE request to the corresponding URL on the Varnish server.
For a product update, the module would purge the product URL, the category URLs the product belongs to (because category listing pages show product prices and availability), and potentially the homepage if it displays featured products. This cascade of purges is necessary to prevent stale data from appearing anywhere on the site.
Ban-Based Invalidation
For scenarios where many URLs need to be purged at once (a site-wide price update, a design change, a new promotion banner), individual PURGE requests are impractical. Varnish supports bans, which are pattern-based invalidation rules. A ban tells Varnish to discard any cached object matching a pattern:
sub vcl_recv {
if (req.method == "BAN") {
if (!client.ip ~ purge) {
return (synth(405, "Not allowed."));
}
ban("req.url ~ " + req.http.X-Ban-Pattern);
return (synth(200, "Banned."));
}
}
Sending a BAN request with the header X-Ban-Pattern: /category/ would invalidate all cached category pages in one operation.
Edge Side Includes (ESI) for Dynamic Blocks
Many PrestaShop pages contain a mix of static and dynamic content. The product listing on a category page is the same for every visitor, but the header showing the cart count is personalized. Without ESI, you cannot cache the page at all because the dynamic header makes the whole response visitor-specific.
Edge Side Includes solve this by allowing you to mark sections of the page as separately fetched fragments. Varnish assembles the final page from cached and uncached fragments.
How ESI Works
In your Smarty template, instead of rendering the cart widget directly, you include an ESI tag:
<esi:include src="/module/cartwidget/ajax" />
When Varnish processes the cached page, it encounters the ESI tag and makes a separate backend request for that fragment. The main page body is served from cache, while the cart widget is fetched fresh from PrestaShop. The assembled response includes both the cached body and the fresh cart widget.
Enable ESI processing in your VCL:
sub vcl_backend_response {
set beresp.do_esi = true;
}
ESI Considerations for PrestaShop
Implementing ESI requires modifying your PrestaShop templates to separate dynamic content into ESI-compatible fragments. Each fragment needs its own URL endpoint that returns just the HTML for that block. The fragments that are typically dynamic and need ESI treatment include the cart summary widget (item count, total), the customer greeting ("Hello, John"), any personalized product recommendations, the login/logout link, and recently viewed products.
The effort required to implement ESI properly is significant. Each dynamic fragment needs a dedicated controller, the templates need restructuring, and the caching rules for each fragment need individual tuning. This is one of the reasons Varnish is considered an advanced optimization, it works best when the application is designed with it in mind.
Backend Health Checks
Varnish can monitor the health of your backend server and take action when it becomes unavailable. This is configured in the backend definition:
backend default {
.host = "127.0.0.1";
.port = "8080";
.probe = {
.url = "/ping.php";
.timeout = 2s;
.interval = 5s;
.window = 5;
.threshold = 3;
}
}
Varnish sends a request to /ping.php every 5 seconds. If 3 out of the last 5 checks fail, Varnish marks the backend as sick. While the backend is sick, Varnish can serve stale cached content (grace mode) instead of returning errors to visitors. This means your store remains partially available even when the PHP backend crashes or restarts.
The grace mode configuration determines how long Varnish will serve stale content:
sub vcl_backend_response {
set beresp.grace = 6h;
}
With a 6-hour grace, if your backend goes down, visitors will see cached pages (even if they are up to 6 hours old) rather than error pages. Product prices might be slightly outdated, but the store remains functional while you fix the backend issue.
Performance Benchmarks
The performance difference between no cache, PHP FPC, and Varnish is substantial and measurable.
No cache (bare PrestaShop): A typical PrestaShop product page takes 200-800 milliseconds to generate, depending on server hardware, number of modules loaded, and database query count. Under load, response times increase because PHP workers are saturated. A single server might handle 20-50 concurrent users before response times become unacceptable.
PHP FPC module: Cache hits serve in 30-100 milliseconds because PHP still boots and the framework partially initializes. Under load, performance is much better because cached responses require minimal PHP processing time. A single server can handle 200-500 concurrent users depending on configuration. Cache misses still take the full rendering time.
Varnish: Cache hits serve in 1-5 milliseconds. Under load, Varnish itself can handle thousands of concurrent connections because it is written in C and designed specifically for this workload. The backend server only handles cache misses, which are a small fraction of total traffic on a properly configured system. The same hardware that struggles with 50 concurrent users without caching can handle 5,000 or more with Varnish.
These numbers illustrate why Varnish is worth the configuration complexity for high-traffic stores. The performance improvement is not incremental, it is an order of magnitude.
Hosting Requirements
Varnish has specific hosting requirements that not every PrestaShop hosting environment can accommodate.
Server Access
You need root access to install and configure Varnish. Shared hosting plans do not support Varnish because it requires its own process listening on a port and intercepting all HTTP traffic. You need a VPS, dedicated server, or cloud instance where you control the full server stack.
Memory
Varnish stores its cache in RAM. The amount of RAM you need depends on the number of unique pages in your catalog and the size of each cached response. A rough formula: number of cacheable pages multiplied by average page size gives you the minimum cache size. A store with 5,000 products, 200 categories, and an average page size of 50KB needs approximately 260MB of cache RAM. Add overhead for Varnish itself and you should allocate at least 512MB. For larger catalogs, 1-2GB is common.
Port Configuration
In a standard setup, Varnish listens on port 80 (the default HTTP port) and forwards cache misses to the web server on a different port (commonly 8080). This means you need to reconfigure Apache or Nginx to listen on port 8080 instead of 80. If you are using HTTPS (and you should be), you typically put Nginx in front of Varnish to handle SSL termination: Nginx on port 443 terminates SSL and forwards to Varnish on port 80, which forwards cache misses to Apache or PHP-FPM on port 8080.
Docker Setup Example
Running Varnish in Docker alongside a PrestaShop container is a clean way to add Varnish to an existing setup without modifying the host system.
Docker Compose Configuration
A basic Docker Compose setup with Varnish, Nginx for SSL, and PrestaShop:
services:
varnish:
image: varnish:7.4
ports:
- "80:80"
volumes:
- ./varnish/default.vcl:/etc/varnish/default.vcl:ro
environment:
- VARNISH_SIZE=512m
depends_on:
- prestashop
prestashop:
image: prestashop/prestashop:8
expose:
- "80"
environment:
- DB_SERVER=db
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=secretpassword
- MYSQL_DATABASE=prestashop
In this setup, Varnish is the entry point on port 80. The PrestaShop container does not expose its port to the host, only to the Docker network. The VCL backend host would be prestashop (the Docker service name) on port 80.
VCL for Docker
The VCL backend definition for Docker uses the service name instead of localhost:
backend default {
.host = "prestashop";
.port = "80";
}
Docker's internal DNS resolves the service name to the container IP. The rest of the VCL configuration remains the same as a non-Docker setup.
Cache Storage in Docker
By default, the Varnish Docker image uses in-memory storage (malloc), which is ideal for performance. The VARNISH_SIZE environment variable controls how much memory Varnish allocates for its cache. Set this to a value that fits within your container's memory limits while leaving room for the Varnish process itself.
For persistent cache that survives container restarts, you can use file-based storage by mounting a volume, but this is rarely necessary. The cache warms up quickly (within minutes of receiving traffic) and file-based storage is slower than memory-based storage.
Monitoring Varnish Performance
Varnish provides built-in tools for monitoring cache performance.
The varnishstat command shows real-time statistics including cache hit rate, backend connections, and memory usage. The most important metric is the hit rate, which should be 85% or higher for a well-configured setup. If your hit rate is below 70%, review your VCL rules because too many requests are passing through to the backend.
The varnishlog command shows detailed per-request logs, which are invaluable for debugging why specific requests are not being cached. You can filter by URL pattern, response code, or cache hit/miss status.
The varnishtop command shows a ranked list of the most frequent log entries, helping you identify patterns in cache misses or errors.
Common Pitfalls
Forgetting to Strip Cookies
The single most common Varnish misconfiguration with PrestaShop is not stripping analytics and tracking cookies. These cookies are present on virtually every request and make every request unique from Varnish's perspective, resulting in a 0% hit rate. Always strip cookies you do not need for cache variation.
Caching Personalized Content
If your VCL is too aggressive, it will cache pages that contain personalized content (logged-in user greeting, cart contents) and serve them to other visitors. This causes serious usability issues and potential privacy problems. Always pass requests that contain session cookies to the backend.
Not Invalidating on Content Changes
Without a proper purging mechanism, content changes in the back office will not be visible until cached pages expire naturally. For a store with active inventory changes, this means visitors might see out-of-stock products, wrong prices, or outdated descriptions. Implement PURGE or BAN support and integrate it with PrestaShop's update hooks.
Ignoring HTTPS
Varnish does not handle SSL natively. You must put an SSL-terminating proxy (Nginx, HAProxy, or a cloud load balancer) in front of Varnish. Failing to plan for this in your architecture leads to mixed content issues, redirect loops, or an inability to serve HTTPS traffic at all.
Is Varnish Right for Your Store
Varnish is a powerful tool, but it is not the right choice for every PrestaShop store. It adds operational complexity: another service to monitor, another configuration language to learn, another layer in your debugging process. The benefits are clear and measurable for stores that need them, but they come at a cost in setup time, maintenance, and troubleshooting difficulty.
If your store serves fewer than 50,000 page views per day and your server handles the load comfortably with an FPC module, Varnish is unnecessary complexity. If your store regularly faces traffic spikes that overwhelm your server, serves a high volume of anonymous browsing traffic, or needs the fastest possible response times for SEO or user experience, Varnish provides a level of performance that no PHP-based caching solution can match.
Start with proper PrestaShop optimization (query optimization, module audit, PHP OPcache, image optimization) and an FPC module. If those optimizations are not enough, Varnish is the next step in the performance scaling ladder.
For more details, read our guides: PrestaShop Cache: Full Page Cache Modules Explained and Redis Cache for PrestaShop: Setup and Performance Gains.
Ask a question
What customers say about us
Great work and support
Cross-device recently viewed sync for logged-in users
PlannedGrid layout option alongside existing carousel
ImplementedSuggest a Feature
No known issues
There are currently no open or resolved issues registered for this module.
- Addedadmin menu management via MenuInstaller for streamlined module setup
- AddedPS 9 / Hummingbird theme compatibility
- Addedgrid layout option alongside existing carousel
- Improvedcookie expiry configuration — adjustable from 1 to 90 days
- Fixedrecently viewed block appearing for products out of stock when hide_oos enabled
- Initialrelease: cookie-based recently viewed products for PrestaShop
- InitialConfigurable number of products to remember (up to 20)
- InitialHook-based widget placement — displayFooterProduct, displayLeftColumn, displayRightColumn
- InitialCompatible with PS 1.7.x and PS 8.x
Easy return - no questions asked
Install, set up and take profit
Priority Help & Satisfaction Over Sales
No reviews yet. Be the first to leave a review!
Write a Review