Troubleshooting
44 answersThis topic helps you diagnose and fix common PrestaShop problems: white screen after installing a module, 500 Internal Server Errors, settings that won't save, a broken .htaccess, CSS changes that don't appear, translations stuck in English, wrong hook positions, and images that break after a server move.
It's for merchants and developers who need a clear next step when something stops working. Where to look, how to turn on debug mode, and how to tell a module conflict from a server issue.
Browse the questions below, or start with our PrestaShop troubleshooting guide.
Questions
A PrestaShop white screen (the blank "white screen of death") after installing a module almost always means a fatal PHP error that PrestaShop is hiding. Here is how to see it and recover, in order.
- Turn on debug mode to read the error. Edit
config/defines.inc.phpand setdefine('_PS_MODE_DEV_', true);, then reload the page. Instead of a blank screen you'll see the actual PHP error and the file and line it came from. - Can't reach the back office? Disable the module over FTP. Rename the module's folder, for example
/modules/modulename/to/modules/modulename_disabled/. PrestaShop stops loading it and your back office returns, no admin login needed. - Send us the error. Once you can read the message, share it with us and we'll tell you what's wrong and how to fix it.
Remember to switch debug mode back off once you're done, since it exposes internal paths. For the wider list of causes and fixes, see our PrestaShop troubleshooting guide.
PrestaShop debug mode shows PHP errors and detailed exception output, which is useful while diagnosing a problem but unsafe to leave enabled on a live shop. It can expose paths, configuration details, SQL errors, and customer-facing stack traces.

From the back office, the normal path is Advanced Parameters > Performance > Debug mode. On the filesystem, the same setting is controlled by _PS_MODE_DEV_ in config/defines.inc.php:
// config/defines.inc.php
define('_PS_MODE_DEV_', true);
// switch back after debugging
define('_PS_MODE_DEV_', false);If you must debug production briefly, enable it for the shortest possible time, reproduce the issue, save the error details, and turn it off again. A safer developer-only pattern is to gate debug mode behind a private condition, for example a temporary cookie check:
define('_PS_MODE_DEV_', isset($_COOKIE['debug']) && $_COOKIE['debug'] === 'secret');After changing debug mode, clear PrestaShop cache if the behavior does not change immediately. Also check server logs, because fatal errors may be logged there even when the browser only shows a generic 500 page.
If you use MPR Performance Revolution, there is a safer production pattern than editing the core define directly: Employee Debug Mode writes a small bootstrap file and sets a short-lived MPRPSDEV cookie for logged-in back-office employees, so regular visitors stay in production mode. The cookie is HTTP-only, secure when HTTPS is in use, same-site Lax, and expires after four hours of inactivity. That is still debugging on a live shop, so use it narrowly, but it is less risky than showing stack traces to every visitor.
Never leave _PS_MODE_DEV_ enabled after the incident is reproduced. Capture the exception message, stack trace and the request URL, then disable debug mode and work from logs. If the error appears only during checkout or payment callbacks, prefer server logs and module logs over exposing debug output on public payment return URLs.
This is almost always an environment difference between the two servers, not the module itself. Check these first:
- PHP version. Confirm test and production run the same major/minor PHP.
- OPcache, production often caches the old code; clear OPcache after deploying (the most common gotcha).
- File permissions. The module needs write access to its own directories.
- Conflicting module. Another module on production may clash; disable suspects one at a time.
- Different configuration, compare key PrestaShop and server settings across both.
Comparing phpinfo() from each environment is the fastest way to spot the discrepancy. For a full walkthrough, see our PrestaShop troubleshooting guide.
A PrestaShop 500 Internal Server Error means something crashed on the server side, so the fix starts with finding the real error message. Check these in order:
- Your server's PHP error log. The most important one; it holds the actual fatal error. Ask your host where it lives if you are not sure.
- PrestaShop's own logs in
var/logs/. - The Apache or Nginx error log.
- Debug mode. Turn it on temporarily to see the error in the browser, then turn it back off.
If you get a 500 but no error details anywhere, it is usually an .htaccess problem or a mod_security rule blocking the request. For the full walkthrough, see our PrestaShop troubleshooting guide.
Work through these checks in order. Configuration save problems are usually caused by a blocked POST request, a stale admin token, missing permissions, server limits or a module table/config problem.

- JavaScript errors. Open browser Developer Tools and check the Console and Network tabs. A JavaScript error can stop the submit handler, and a 403/500 response tells you the request reached the server but failed there.
- Expired security token. PrestaShop admin controllers use tokens on URLs and forms. Open the module configuration page fresh from Modules > Module Manager, do not submit from an old browser tab, then try again. If you use a proxy or cache in front of the back office, make sure admin pages are never cached.
- Employee permissions. Check that the employee profile can view and configure modules. A profile without the right module permission may see the page but fail on save or redirect back without changes.
- Too many form fields. Large multilingual or multistore forms can exceed PHP's
max_input_vars, so fields at the end of the POST are silently dropped. Raise it to3000or5000for large forms. - POST/body limits. If the form includes image uploads, long HTML fields or many serialized options, also check
post_max_size,upload_max_filesize,max_execution_timeandmemory_limit. - Server security rules. ModSecurity, a host WAF or a CDN rule can block HTML, JavaScript snippets, iframe code or SQL-looking text in module settings. Check the HTTP status and ask the host for the matching rule ID.
- Missing database table or failed upgrade. Some modules store settings in their own tables. If installation or upgrade did not create those tables, saving may fail even though the form renders.
- File permissions. Most module settings are database-backed, but some modules also write generated files, cache files or config exports. Make sure the web-server user can write the module's documented writable paths.
; Useful PHP starting points for large module forms
max_input_vars = 5000
post_max_size = 32M
upload_max_filesize = 32M
max_execution_time = 300
memory_limit = 256MIf it still will not save, contact our support team with the module name, PrestaShop version, PHP version, the full Network response for the save request, and a screenshot of the Console. That gives us enough to tell the difference between a browser problem, a PrestaShop token problem, a server limit and a module schema issue.
Keep the cache enabled on a production store. Caching is one of the main things keeping PrestaShop fast, and switching it off permanently slows every page for every visitor without fixing the underlying fault.
Disabling a cache layer is still a legitimate diagnostic step. Turn one layer off temporarily when you need to confirm whether a symptom is cache-related, typical cases:
- template or design changes that do not show up on the front office;
- stale prices, stock or blocks that survive a normal refresh;
- a module setting that seems to have no effect after saving.
Do it in a controlled way: change one layer at a time, prefer a staging copy or a quiet moment, note what you switched, and re-enable it as soon as the test is done. If the symptom disappears with a layer off, you have found where the stale data lives. The fix is to clear or repair that layer, or to correct the module or template that caches wrongly, not to leave caching off.
In most cases the problem is simply stale cache, and a proper clear resolves it. Follow the steps in How do I clear PrestaShop cache properly? before considering anything more drastic.
A broken .htaccess file can break friendly URLs, redirects, static asset handling or even back-office access. PrestaShop can regenerate its own rewrite rules, but custom server rules should be backed up first.

PrestaShop writes its generated rules inside its managed markers and preserves custom code outside that block. If the file is badly broken, rename the current file, create a fresh empty .htaccess, then regenerate friendly URL rules from the back office by saving the SEO & URLs / friendly URL settings. Clear cache afterwards.
# Temporary minimal Apache rewrite block - not a full PrestaShop .htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
</IfModule>That snippet is only a recovery aid. A real PrestaShop .htaccess includes generated dispatcher, image, asset and redirect rules for the shop's base URI. If the shop is in a subdirectory, the regenerated RewriteBase must match that path. If the file breaks again immediately after regeneration, look for custom rules from a theme, module, CDN, security plugin or hosting panel.
Before regenerating, save the broken file as a dated backup so you can recover any custom redirects, CDN rules or security headers that were outside PrestaShop's managed block. After regeneration, compare the backup and restore only the custom rules you understand. Put custom redirects above or below the generated block according to their purpose, but avoid editing inside PrestaShop's markers because the back office can overwrite that section again.
If regeneration fails, check Apache has mod_rewrite enabled and that the web-server user can write the shop root. On Nginx, .htaccess is ignored entirely, so the fix belongs in the Nginx server block instead of in this file. Always test a product URL, category URL, image URL, CSS/JS asset and back-office login after the repair, because a rewrite file can look fine while one class of URLs is still broken.
If CSS changes do not appear in PrestaShop, work through the cache layers in order instead of changing random files.

- Browser cache: hard refresh, test in private mode, or disable cache in the browser network panel.
- PrestaShop cache: clear cache from Advanced Parameters > Performance, especially after editing templates, theme assets, or module views.
- CCC and asset optimization: temporarily disable combine/minify/cache CSS and JavaScript while testing. If the change appears with CCC off, regenerate the optimized assets before turning it back on.
- Correct theme path: confirm you edited the active theme or child theme, not an old theme directory. In the network panel, open the loaded CSS file and verify that your rule is actually present.
- CDN or reverse proxy: purge Cloudflare, Varnish, host cache, or any external CDN that serves static assets.
- Server cache: if CSS is generated by PHP or a module, OPcache/PHP-FPM and module cache can delay changes until cleared or restarted.
The quickest proof is the browser network panel: find the CSS URL, confirm it returns 200, check the response content, and compare the timestamp or query string. If the response does not contain your rule, PrestaShop is not serving the file you edited. If it does contain the rule but the style is not visible, the issue is selector specificity, order, media queries, or another rule overriding it.
Confirm the active theme in Design > Theme & Logo. For a normal theme the file is often under themes/active_theme/assets/css/; for a child theme, edit the child theme path, for example themes/child_theme/assets/css/custom.css, not the parent theme unless the child imports it.
While testing, go to Advanced Parameters > Performance and disable Smart cache for CSS, Smart cache for JavaScript, Minify HTML, Compress inline JavaScript in HTML and Move JavaScript to the end if they affect the asset you are checking. Also use Force compilation and temporarily disable Smarty cache until the right file is confirmed.
css='https://example.com/themes/classic/assets/css/theme.css'
rule='.my-test-rule'
curl -sI "$css?v=$(date +%s)" | sed -n '1,12p'
curl -fsSL "$css?v=$(date +%s)" | grep -nF "$rule" || echo 'rule not in served CSS'
rm -rf var/cache/dev/* var/cache/prod/*If Performance Revolution or another optimization module is active, also clear its asset/cache layer or temporarily disable its asset optimization while confirming the change.
When a PrestaShop module translation stays in English, the strings have usually not been translated yet, or the old version is still cached. Work through these in order:

- Translate the strings. Go to International → Translations → Translate modules, pick the module and your language, and fill in the translations.
- Clear the cache. Smarty may still be serving the old template, clear the cache from Advanced Parameters → Performance.
- Check which system the module uses. Some modules ship their own translation files instead of PrestaShop's; the documentation will say which.
- Match the right file. If templates use
{l s='...' mod='modulename'}, the translation has to live in the module's own translation file, not the global PrestaShop translations.
More fixes: PrestaShop troubleshooting guide.
After editing translations, clear both PrestaShop cache and any server/CDN cache that could hold compiled templates. Also make sure you are translating in the right shop and language context on multistore, because a string can be translated for one shop or locale while another still falls back to English.
From the module side, Smarty templates normally call PrestaShop's translator with a module name, for example {l s='Related Products' mod='mprblogrevolution'}. That mod value has to match the module directory, and old modules may still rely on files under their own translations/ folder. If a specific phrase never appears in the back-office translation screen, it may be built dynamically in PHP or JavaScript, so search the module source for the exact English text and confirm it is wrapped in the translation function.
On older or legacy-style modules, translations usually come from modules/modulename/translations/xx.php and Smarty calls such as {l s='Text' mod='modulename'}. On newer PrestaShop 1.7/8/9 code, Symfony translation domains may be used instead, commonly with catalogue files such as translations/fr-FR/Modules.Modulename.Admin.xlf or Modules.Modulename.Shop.xlf. Translating the legacy file will not fix a string rendered through a Symfony domain.
JavaScript is a separate case: strings printed into JS variables can be translated server-side, but strings hard-coded in .js files need the module's JavaScript translation mechanism or must be exposed from PHP/templates first. If only buttons or alerts in the browser stay English, search the module's views/js/ files as well as PHP and Smarty templates.
{l s='Table Optimization' mod='mprcleanuprevolution'}
$_MODULE['<{mprcleanuprevolution}prestashop>db_optimize_e48edafb7a762aa641253a1475eb1933'] = 'Optimisation des tables';
$_MODULE['<{mprcleanuprevolution}mypresta-rocks>db_optimize_e48edafb7a762aa641253a1475eb1933'] = 'Optimisation des tables';To move a module that is showing in the wrong place, open Design > Positions in the back office. That page is the live hook list for PrestaShop, every hook your theme exposes, with the modules attached to each one, in render order. Find your module there and you have two levers: reorder it within its current hook by dragging it up or down, or unhook it and transplant it to a different hook entirely.
The usual gotcha: a module only appears where its hook is actually displayed. If you transplant to a hook your theme doesn't render, nothing shows up, the placement isn't broken, the hook just isn't on the page. Use the "Transplant a module" button to see which hooks are available, and check your theme's docs for the ones it supports. Reordering takes effect immediately; you don't need to clear the cache for a position change.
If you want to understand how hooks fire and where each one renders, our PrestaShop hooks guide walks through the full hook list and the override system.
After you migrate PrestaShop to a new server, broken product images almost always come down to one of three things: the thumbnails weren't regenerated, the /img/ folder isn't writable, or the shop's domain still points at the old host.

Work through these in order:
- Regenerate thumbnails. Go to Design → Image Settings and run Regenerate thumbnails. A copied database keeps image records, but the resized files have to be rebuilt on the new disk.
- Check folder permissions. The
/img/directory (and its subfolders) must be writable by the web server, or PrestaShop can't write the regenerated files. File ownership often changes during a copy between servers. - Fix the shop domain. If images 404 with the old hostname, update the domain in Shop Parameters → Traffic & SEO and regenerate the
.htaccessfrom SEO & URLs. If you use a CDN, repoint it at the new server too.
This is one slice of a larger move. For the full server/domain checklist, URLs, redirects, SSL and database, see our PrestaShop migration guide; for other post-move symptoms, the troubleshooting guide covers white screens and 500 errors.
Use the browser network panel to separate URL problems from file problems. If the image URL still contains the old domain, fix Shop Parameters > Traffic & SEO > Set shop URL, including the SSL domain and base URI, then regenerate .htaccess. If the hostname is correct but the response is 404, check whether the original file exists under img/p/ and whether image rewrite rules are active.
If the image works directly from the new server but not through the public URL, purge the CDN/reverse proxy and check that it points to the new origin. Mixed http/https image URLs after migration usually mean SSL or base URL settings are inconsistent, not that the product image records are broken.
find img -maxdepth 2 -type d ! -writable -print | head
find img/p -type f -name '*.jpg' | head
image_url='https://example.com/1-home_default/product.jpg'
curl -sI "$image_url" | sed -n '1,12p'No. Database Cleanup is a manual, back-office tool. You open the cleanup screen, see a live count for each task, old abandoned carts, old search statistics, expired specific prices, old logs, connection and guest data, mail logs, and run one task or all of them on demand. There's no cron endpoint, so nothing runs on a schedule by itself.

That's deliberate: it lets you review exactly what will be deleted and how much before you commit, which is what you want for one-off cleanups and after big imports. The common mistake is expecting it to keep the database tidy on its own. It won't; you have to come back and run it.
If you want cleanups to run automatically on a schedule, that's Cleanup Revolution instead, it includes cron automation (for example a daily database cleanup and a weekly table optimize) plus audit logging. So: pick Database Cleanup for hands-on manual runs, and Cleanup Revolution when you want it scheduled and hands-off.
In code, Cleanup Revolution registers three cron tasks: db_cleanup daily at 03:00, file_cleanup daily at 03:30, and table_optimize weekly at 04:00. Database Cleanup does not register those tasks and does not expose a cron URL, so copying a Cleanup Revolution cron command into Database Cleanup will not make the manual module scheduled.
For setup details, use the Cleanup Revolution cron setup documentation from the Cleanup Revolution product/support page: Cleanup Revolution.
When PrestaShop mail isn't going out, start in Advanced Parameters → E-mail: if you use SMTP, confirm the server, port, username and password, then click Send a test email to reproduce the failure.
The usual culprits:
- Your host blocks outgoing SMTP connections (common on shared hosting).
- SPF/DKIM records aren't set up, so mail is delivered but lands in spam.
- The PHP
mail()function is disabled on the server.
For dependable delivery, send through an external SMTP service (Mailgun, SendGrid, or even Gmail SMTP) rather than the local mail function. The same working mail setup is what powers ticket notifications in MPR Support Revolution, it's a helpdesk module, not a mail fixer, so get core delivery healthy first and its notifications follow.
A slow PrestaShop back office almost always comes down to a handful of usual suspects. Work through them in order: (1) Too many modules hooking into admin pages. Each one that loads on displayBackOfficeHeader adds work to every screen. (2) Debug mode left enabled in production, which adds heavy overhead. (3) Slow MySQL queries, open the Symfony profiler to see which ones. (4) A large catalogue with many combinations dragging down product lists. (5) The server simply running out of RAM.
Quick wins: turn debug mode off, make sure OPcache is enabled, and review which modules load on every admin page under Design → Positions → displayBackOfficeHeader, disabling any you don't need. If the front office is slow too, the cause is usually shared (caching, server resources, query load).
For the full checklist, see our PrestaShop performance guide.
This almost always means PrestaShop or Composer cannot load a PHP class that the module expects. Read the exact missing class in the fatal error first; the namespace usually tells you whether the missing file belongs to the module itself, a bundled vendor/ dependency, a shared package, or a stale cache entry.

- Incomplete module files. Re-upload the original ZIP. Do not copy only the main module PHP file, and do not merge a new version over a half-deleted old folder.
- Missing Composer autoload. If the module has
vendor/autoload.php, that file and the wholevendor/tree must be present. PrestaShop loads active module autoloaders during Symfony/container boot on modern branches, so a missing vendor folder can break pages beyond the module configuration screen. - Wrong case on Linux.
MyClass.phpandmyclass.phpare different files on Linux. A module that worked on a case-insensitive local machine can fail after upload. - Stale class cache. Clear
var/cache/prodandvar/cache/dev. On older installations, also remove the generated legacy class index under the active cache directory if it exists. - OPcache still serving old code. Reload PHP-FPM or Apache after replacing module files. Clearing PrestaShop cache does not reset web OPcache.
- Wrong PHP version. Composer dependencies can require a newer PHP version than the server is running, or a module may use syntax unsupported by your PHP branch.
- Unreadable files. Make sure the module directory and vendor files are readable by the web-server user.
# From the PrestaShop root
test -f modules/examplemodule/vendor/autoload.php && echo 'module autoload exists'
find var/cache/prod -mindepth 1 -maxdepth 1 -exec rm -rf -- {} +
find var/cache/dev -mindepth 1 -maxdepth 1 -exec rm -rf -- {} +
sudo systemctl reload php8.2-fpmThe reliable reset is: back up the current folder, delete the broken module folder, extract the original ZIP cleanly, restore only documented uploads or exports, clear PrestaShop cache, reset OPcache and reload the page. If the fatal names a shared library class, include the exact class name and stack trace when contacting support.
For related white-screen and 500-error checks, see our PrestaShop troubleshooting guide.
Try these in order: (1) Clear your browser cookies for the domain. (2) Try a different browser or an incognito window. (3) Delete the contents of var/cache/. (4) Check that PS_SHOP_DOMAIN matches the exact domain you are visiting. (5) If you use SSL, confirm PS_SSL_ENABLED is set correctly. (6) Inspect .htaccess for stray redirect rules. As a last resort, temporarily disable overrides by setting define('_PS_DISABLE_OVERRIDES_', true); in config/defines.inc.php to rule out a faulty override.
More fixes in our PrestaShop troubleshooting guide.
This happens when an update changes something your theme wasn't prepared for. Work through it in order:
- Confirm it's the theme. Switch temporarily to a default theme (Classic or Hummingbird). If the storefront renders fine, the problem is your theme.
- Check for a theme update. See whether your theme developer has released a version compatible with the PrestaShop version you just installed.
- Look at your overrides. If you're on a child theme, check which template files reference blocks or markup that changed; if you edited the parent theme directly, those edits may have been wiped or now conflict.
- If the theme is abandoned, migrating to a maintained theme may be the only durable option.
The recurring cause is editing the parent theme directly, so every update overwrites your work. Moving your CSS, JS and template tweaks into a child theme keeps them isolated and update-safe. You can scaffold one in seconds with our free Child Theme Generator, then drop your overrides into its assets/css/custom.css. Always check theme compatibility on a staging copy before updating live. More detail: our PrestaShop child themes guide.
The systematic approach: (1) disable all third-party modules (not PrestaShop's built-in ones); (2) check whether the problem disappears; (3) re-enable modules one by one, testing after each; (4) when the problem returns, you have found the culprit. It is tedious but reliable. For performance-specific issues, the Symfony profiler (available in debug mode) shows which hooks and modules take the longest to execute.
Learn more: our troubleshooting guide.
If a PrestaShop template override is ignored, clear cache and check that the override is in the active theme path with the exact module/template structure. For module templates, the usual path is themes/your_theme/modules/module_name/.... Also disable Smarty cache/force compilation while testing, because PrestaShop may keep rendering the compiled old template.

modules/mprolark/views/templates/hook/displayBeforeBodyClosingTag.tpl
# override in:
themes/your_theme/modules/mprolark/views/templates/hook/displayBeforeBodyClosingTag.tpl
modules/mprfacebookpixel/views/templates/hook/order-confirmation.tpl
# override in:
themes/your_theme/modules/mprfacebookpixel/views/templates/hook/order-confirmation.tplCheck the exact source template path in the module before choosing the override path. A template from views/templates/hook, views/templates/front, or views/templates/admin may need that subpath mirrored, depending on how the module renders it. If the shop uses a child theme, multishop, or a different theme for the current shop context, the override must be placed in the theme that is actually active for that shop.
- Hook templates:
modules/modulename/views/templates/hook/file.tplbecomesthemes/your_theme/modules/modulename/views/templates/hook/file.tpl. - Front templates:
modules/modulename/views/templates/front/file.tplbecomesthemes/your_theme/modules/modulename/views/templates/front/file.tpl. - Admin templates: theme overrides normally do not apply to back-office module templates; those are rendered from the module/admin context, so changing the front-office theme path will not affect them.
With a child theme, put the override in the child theme that is active for the current shop, not in the parent theme. If the child does not override the file, PrestaShop can still fall back to the parent/module template, which makes it look as if your edited file is being ignored.
If the file is in the right place and cache is cleared, confirm that the page is really using the template you edited. Some modules render a different template for AJAX, mobile layouts, checkout steps, hooks, or modern Symfony controllers. Temporarily add a harmless HTML comment to the override, reload with force compile enabled, and inspect the page source. If the comment is absent, the issue is path, theme context, or template selection rather than the content of the override.
Product imports usually fail for one of four reasons: the CSV is too large for the web request, PHP upload limits are too low, the server times out while processing rows or images, or a specific row contains invalid data.

Start by reducing the import size. Split large CSV files into smaller batches, import images separately if possible, and test with 10 to 50 rows before retrying thousands. If the small file works, the mapping is probably correct and the problem is capacity or timeout related.
Check the relevant PHP and server limits:
upload_max_filesize
post_max_size
memory_limit
max_execution_time
max_input_time
max_file_uploads
PHP-FPM request_terminate_timeout
Nginx or Apache proxy/read timeout
CDN timeout, for example Cloudflare request limitsPrestaShop reports upload-size errors when the file exceeds upload_max_filesize or the form limit, but timeouts can appear as a blank page, 500 error, or partially imported catalog. For very large catalogs, use a CLI importer, cron-based importer, or dedicated import module rather than relying on one long browser request.
The native importer is under Advanced Parameters > Import in PrestaShop 1.7/8/9. After a blank page or 500 error, check var/logs/prod.log, var/logs/dev.log, the PHP-FPM log and the web server error log before retrying, because the visible import page often loses the real exception when the request dies.
For a partial import, do not immediately rerun the full file with destructive options such as deleting existing products unless that was planned. Identify the last successfully imported reference or ID, split the remaining CSV from the next row, fix any products left disabled or without images, then rebuild search and faceted indexes after the final batch.
If the import stops on the same row each time, inspect that row for bad delimiters, unescaped quotes, invalid encoding, broken image URLs, impossible category references, duplicate references, or values that do not match the selected import mapping. Use UTF-8, keep the delimiter consistent, and rebuild search/faceted indexes after a successful large import if product visibility or filters look wrong.
This is a file-permissions problem, not a corrupted store. After a server migration the new server often runs PHP under a different user, while the copied files still belong to the old account or to root. PrestaShop then cannot write compiled Smarty templates or Symfony cache files.

Clear stale cache files first, then fix ownership and permissions for the writable cache/log paths. Replace www-data:www-data with the user and group your PHP-FPM or web server actually uses, such as nginx:nginx or your hosting account user.
Before running chown, identify the user PHP is actually running as. On a shell with the shop files, useful checks are ps -eo user,group,comm | grep -E 'php-fpm|apache|nginx', grep -R '^user\|^group' /etc/php*/fpm/pool.d 2>/dev/null, or a temporary phpinfo() page checked through the browser. Use that user/group instead of guessing www-data.
cd /path/to/prestashop
# Remove generated cache contents, not the parent directories
find var/cache/prod -mindepth 1 -maxdepth 1 -exec rm -rf -- {} +
find var/cache/dev -mindepth 1 -maxdepth 1 -exec rm -rf -- {} +
# Fix common PS 1.7/8/9 writable paths
sudo chown -R www-data:www-data var 2>/dev/null || true
find var -type d -exec chmod 775 {} +
find var -type f -exec chmod 664 {} +
# Older PS 1.6-style Smarty paths, if they exist
sudo chown -R www-data:www-data cache/smarty 2>/dev/null || true
find cache/smarty -type d -exec chmod 775 {} + 2>/dev/null
find cache/smarty -type f -exec chmod 664 {} + 2>/dev/nullAvoid chmod -R 777. It may hide the error temporarily, but it leaves the shop writable by everyone on the server. If permissions look correct and the error remains, check disk space, inode exhaustion, SELinux/AppArmor policies and whether PHP-FPM is chrooted into a different path.
Our PrestaShop migration guide covers the full move, and the troubleshooting guide covers related white-screen and 500 errors.
Duplicate order confirmation emails are usually caused by duplicate send paths, not by the order_conf template itself. PrestaShop's native order confirmation is sent during PaymentModule::validateOrder(), and hooks around order validation can also trigger email modules.

- Payment module: check whether the payment module calls order validation twice, for example once from the customer return URL and once from a webhook/IPN callback. Payment module logs and PrestaShop logs usually show this clearly.
- Mail Alerts or email modules: disable extra notification modules temporarily to see whether the second email is actually a separate alert that looks like an order confirmation.
- Duplicate hook registrations: check whether a custom module is hooked twice to
actionValidateOrder,actionValidateOrderAfteror order confirmation hooks and sending its own customer email. - Overrides/custom code: inspect overrides of
PaymentModule,OrderHistoryorMail, plus any custom module that callsMail::Send()after order creation. - SMTP/provider retries: compare message IDs and timestamps in the SMTP log. Two different PrestaShop sends are a code/configuration issue; one send delivered twice is a mail transport issue.
Start by comparing the two emails. If the subject, template and timestamps are identical, investigate duplicate order validation or duplicate hooks first. If the content differs, identify which module owns the second template.
First decide whether you have one order with two emails or two separate orders. Compare the order reference and id_order in the email/back office: the same reference points to duplicate mail sending, while two different references or two order rows point to duplicate payment validation or a customer/browser retry that created another order.
If two orders exist for the same cart or payment transaction, investigate the payment callback/webhook path before mail templates. If only one order exists, focus on duplicate hooks, mail modules, overrides and SMTP/provider retries.
SELECT h.name AS hook_name, m.name AS module_name, hm.position
FROM ps_hook_module hm
JOIN ps_hook h ON h.id_hook = hm.id_hook
JOIN ps_module m ON m.id_module = hm.id_module
WHERE h.name IN (
'actionValidateOrder',
'actionValidateOrderAfter',
'displayOrderConfirmation',
'displayPaymentReturn'
)
ORDER BY h.name, hm.position;Module text is translated per language, so this is a missing translation, not a bug. If a module shows English while your admin language is French, the French strings for that module simply are not installed yet.
Fix it in International → Translations → Translate modules: pick the module and your language, then fill in the missing strings. Some modules also ship a translation file you import the same way, check the module's documentation.
More fixes: our PrestaShop troubleshooting guide.
You can stop a module loading its CSS or JavaScript without removing the module itself. You keep its hooks, tables, settings and back-office features, and only strip the front-office assets you do not want. Here are the practical ways, simplest first.
1. Remove assets in theme.yml
The cleanest, update-safe method. In your theme's theme.yml, under assets, set the offending asset ID to false under css: all or js: all. The ID is what the module passes to registerStylesheet / registerJavascript (visible in the page source). Clear the cache from Advanced Parameters → Performance afterwards. This removes the asset on every page and survives module updates.
2. Media::unregister in a hook
For page-by-page control, use a small custom module that calls Media::unregisterStylesheet() / Media::unregisterJavascript() inside hookActionFrontControllerSetMedia, wrapped in your own conditions (for example, keep a slider's assets only on the homepage). Your module must run after the target module on that hook. Set the order in Design → Positions.
3. Unhook the module from displayHeader
In Design → Positions you can remove a module from the hook where it registers assets. This kills its CSS/JS everywhere while its other hooks keep working, handy when you plan to restyle it entirely with your own CSS. Riskier for JavaScript, and a module update can re-add the hook, so re-check after updates.
Test before you trust it
Removing CSS can break a module's layout; removing JavaScript can break clicks, forms or AJAX. Screenshot the affected pages first, make the change, then verify every page type and feature still works. For the safe, update-proof way to add your own styles and scripts, see our custom CSS and JavaScript guide.
The Allowed memory size of X bytes exhausted error means a single PHP request tried to use more memory than memory_limit allows, and PHP killed it. The fix is partly raising the limit and partly finding what consumed the memory.
Check the active limit
In the back office, Advanced Parameters > Information shows the web PHP value. Over SSH, php -i | grep memory_limit shows the CLI value, which can be different from PHP-FPM. When debugging a front-office or back-office fatal, trust the web value and the PHP-FPM/Apache error log.
Common causes
- Large CSV imports: split files into chunks, import images separately and disable non-essential modules during the import.
- Products with hundreds of combinations: the product page and stock/combinations logic can load a lot of data at once.
- Poorly coded modules: look for the file and line in the fatal error. Whole-table reads, large object logging and unbounded exports are common causes.
- Large catalogs with layered navigation: filtered category pages can hold many products, facets and combinations in memory.
- Image generation: regenerating thumbnails for large catalogs can exhaust memory if image dimensions are huge.
Raise the limit safely
; php.ini or PHP-FPM pool
memory_limit = 512M
; .user.ini in the PrestaShop root, if your host supports it
memory_limit = 512M
# Apache + mod_php only
php_value memory_limit 512M
# PrestaShop fallback in config/defines.inc.php, limited by the server ceiling
@ini_set('memory_limit', '512M');Where to find the fatal
# PHP-FPM / web server logs vary by distribution
tail -f /var/log/php8.2-fpm.log
tail -f /var/log/apache2/error.log
tail -f /var/log/nginx/error.log
# PrestaShop logs
tail -f var/logs/prod.log
tail -f var/logs/dev.logDo not keep raising memory blindly. memory_limit is per PHP process. A 512 MB limit across many PHP-FPM workers can exhaust a small server under load. If normal page views need 512 MB or more, use the fatal line, slow logs and module profiling to find the root cause.
For server sizing see our PrestaShop hosting guide; for OPcache, Redis and cache tooling that reduce repeated work, see Performance Revolution.
If a product with lots of combinations saves only partially, loses combinations, or fails silently, the cause is almost always PHP's max_input_vars limit. It caps how many form fields PHP accepts in one POST request, and when a product form exceeds it, every field past the limit is silently discarded, with no error.
Why it happens
Each combination adds many fields (price impact, weight, quantity, reference, EAN-13, MPN, minimum quantity, and more), and every text field is multiplied by the number of languages. A product with dozens of combinations across several languages easily blows past the common default of 1000 fields.
Check your current value
In the back office, open Advanced Parameters → Information and read the PHP configuration section, which lists max_input_vars. (You can also load a temporary phpinfo() file, then delete it.)
Raise the limit
- php.ini (cleanest, if you have access): set
max_input_vars = 10000and restart PHP-FPM or your web server. 10000 covers most stores; very large catalogues can go higher. - .user.ini (PHP-FPM/CGI): add the same line in your store root; it can take a few minutes to apply.
- .htaccess (only on Apache mod_php):
php_value max_input_vars 10000, remove it if it triggers a 500 error, which means your server ignores it. - Hosting panel: cPanel's MultiPHP INI Editor or Plesk's PHP settings expose the value directly.
While you're there
Also raise post_max_size (at least 32M), memory_limit (256M+), and max_execution_time (300s) so large product saves don't fail for a different reason.
If it still won't save
For products with hundreds of combinations, bypass the form entirely: import combinations via CSV (Advanced Parameters → Import) or the webservice API. Neither is subject to max_input_vars. Also check that a host-level override, a web-server body limit, or a security firewall isn't capping the request.
See our PrestaShop troubleshooting guide.
A blank PrestaShop admin page after a core update, the White Screen of Death, almost always means PHP hit a fatal error that production mode is hiding. The fix is to make the error visible, then clear what the update left stale.
1. Turn on debug mode to see the real error
Edit /config/defines.inc.php and set define('_PS_MODE_DEV_', true);. On Symfony-based versions you can instead set APP_DEBUG=1 (and the dev environment) in the root .env. Reload. You should now get a file path, line number and stack trace instead of a blank screen.
2. Clear caches and the class index
Delete the contents of the Symfony cache (var/cache/prod and var/cache/dev) and the Smarty caches (cache/smarty/compile, cache/smarty/cache), and remove the class index file so PrestaShop regenerates it. On PHP-FPM, also reset OPcache (restart PHP-FPM or call opcache_reset()). Stale bytecode is a very common cause.
3. Rule out modules and overrides
Incompatible third-party modules and stale files in /override/ are the usual culprits. If the error names a module, disable it: rename its folder under /modules/, or set active = 0 in ps_module. To test overrides, move /override/ aside, delete the class index again, and reload.
4. Check PHP and logs
Confirm your server's PHP version matches the range your PrestaShop version requires (check the release notes), a hosting PHP switch alongside the update often triggers fatal errors. If debug mode still shows nothing, read the web server and PHP-FPM error logs, plus PrestaShop's own log directory.
Always work from a backup: before any core update, back up both files and database, disable third-party modules, and re-enable them one at a time afterwards. For deeper diagnosis, see our guide on PrestaShop troubleshooting.
If PrestaShop add to cart is not working. The button does nothing, spins forever, or the cart shows the wrong total. The cause is almost always one of three things: a JavaScript error, a stale cache, or a module conflict. Work through them in that order.

Start in the browser
Add to cart is an AJAX request, so open Developer Tools (F12). On the Console tab, reload the product page and look for red errors like $ is not defined or a SyntaxError, a single broken script (often from one module) halts all page JavaScript, including the cart. The file path in the error points to the culprit module; disable it to confirm.
If the button spins but never finishes, switch to the Network tab, filter to XHR, and click Add to Cart. The cart request should return status 200 with valid JSON. A 500 means a server error; HTML mixed into the response means a module printed a warning before the JSON, breaking it; a 403 points to a security module or WAF.
rm -rf var/cache/dev/* var/cache/prod/*
base='https://example.com/index.php'
curl -sS "$base?controller=cart&add=1&ajax=true&id_product=1&qty=1&token=STATIC_TOKEN" \
-H 'X-Requested-With: XMLHttpRequest' | jq .Clear every cache layer
If the cart updates but shows stale quantities or prices, a cache is serving old data. Test in an incognito window first to rule out the browser. Then clear the Smarty compile and cache folders under var/cache (or use Advanced Parameters > Performance > Clear cache). If you use CCC (Combine, Compress, Cache), one module's JS syntax error can break the whole combined bundle, disable CCC to test. If a CDN like Cloudflare fronts your store, make sure "Cache Everything" rules never cover the cart endpoint; cart responses are customer-specific and must not be cached.
Cookies, sessions and module conflicts
A cart that empties on every page load is usually a cookie problem, a mismatched domain (www vs non-www), a wrong SameSite or Secure flag, or sessions not shared across load-balanced servers. To find a conflicting module, disable third-party modules in groups and re-enable in batches of five; pay attention to anything hooked into actionCartSave, actionCartUpdate or actionFrontControllerSetMedia.
For a wider diagnostic walkthrough, see our PrestaShop troubleshooting guide.
When something breaks, the answer is almost always sitting in your PrestaShop logs. You just need to know which file to open. Here is the fast version that solves most problems.
Where the logs live:
- Application log.
var/logs/prod.log(live) andvar/logs/dev.log(debug mode). Check this first for PrestaShop and module errors. Filter forERRORandCRITICAL. - PHP error log. Catches fatal errors before PrestaShop's logger starts. Location varies by host; run
php -i | grep error_logto find it. - Web-server log, Apache (
/var/log/apache2/error.log) or Nginx (/var/log/nginx/error.log). This is where a bare 500 error with no PHP detail shows up. - Back office, Advanced Parameters > Logs shows events PrestaShop records itself (failed logins, email failures), but not fatal PHP errors.
The workflow that finds the cause: enable debug mode (set _PS_MODE_DEV_ to true in config/defines.inc.php), then run tail -f var/logs/prod.log in one terminal and reproduce the error in your browser. Watch the line that appears at the exact moment it breaks, and read the stack trace top-down for the first frame pointing at /modules/ or /themes/, that is usually your culprit. Turn debug mode back off afterwards; it exposes internal paths.
For the full developer walkthrough, stack traces, grep recipes and common error patterns, see our PrestaShop troubleshooting guide.
Security Scan is built to run across PrestaShop 1.7, 8 and 9 and PHP 7.1 and newer. Deprecated PrestaShop APIs are wrapped so the module behaves correctly on every supported branch.
Yes. Our free public PrestaShop Security Scanner passively fingerprints any store you own straight from its URL, PrestaShop and PHP version, end-of-life risk and HTTPS security headers, in seconds, with nothing to install. It reads only what any visitor already sees. Install the module when you want the deep, private scan of your modules, files and permissions.
Security Scan is free and detection-only: it finds problems, scores your store 0–100 and shows you manual fix steps. Security Revolution acts on the same findings, one-click fixes, store hardening, core-file integrity monitoring, change alerts and fleet management from one dashboard. Start with Security Scan; upgrade when you want the fixes and monitoring automated.
No. A standalone dashboard or CLI scan stays entirely on your server. The report is generated locally and the only outbound requests are self-checks to your own public URLs, which are guarded against internal-address (SSRF) access. Nothing is sent to us. If you explicitly enrol the optional fleet connector, scan results are sent, over a signed channel, only to the hub you configured.
Yes. Security Scan is detection-only: it reads your files, configuration, database and your own public URLs, and the only thing it ever writes is its own scan-history record. It never modifies shop files, settings, products, orders or customers, so you can run it on a production store at any time without risk.
These four HTTP errors are the ones PrestaShop store owners hit most often. Here's what each means and where to look first.
403 Forbidden, the server refuses the request, almost always a permissions or access-rule problem. Reset file permissions (755 for directories, 644 for files), review .htaccess for over-broad Deny rules, and check any WAF/ModSecurity logs for false positives.
404 Not Found, the URL points to nothing. Most often friendly URLs are on but .htaccess/mod_rewrite isn't generating the rewrites: go to Shop Parameters → Traffic & SEO, confirm friendly URLs are enabled and save to regenerate. Deleting a product or category without a 301 redirect (e.g. an old /example-product.html) also leaves 404s.
500 Internal Server Error, a server-side fault, usually a PHP fatal error, a bad .htaccess, a wrong PHP version for your build, a database-connection failure, or a faulty module. Fastest diagnosis: set _PS_MODE_DEV_ to true in config/defines.inc.php to see the real error (turn it back off afterwards), then check the PHP log and PrestaShop's logs in var/logs/. Disable a recently added module by renaming its folder over FTP.
503 Service Unavailable, the server can't handle the request right now. Usual causes: maintenance mode left on (Shop Parameters → General → Maintenance), a leftover maintenance flag after an upgrade, or server overload during a traffic spike.
For persistent 500/503 issues, our Performance Revolution module reduces backend load through caching and OPcache handling. For the deeper walkthrough, see our PrestaShop debugging guide.
No. This module is detection-only by design. It catches common, well-known risks fast and tells you exactly how to fix each one by hand. Automatic one-click fixes, hardening and monitoring live in Security Revolution.
Most random logout, empty-cart and admin login-loop reports come down to cookie/session configuration. PrestaShop stores important state such as customer, cart, language and login data in an encrypted cookie, while PHP may also keep server-side session data. If the cookie cannot be read, is scoped to the wrong host, is rejected by the browser, or becomes too large, the shop loses state between page loads.
Fast browser check
Browser DevTools > Application/Storage > Cookies
Domain: should match the canonical host, e.g. www.example.com or .example.com
Secure: true when the shop is HTTPS
HttpOnly: true for the main PrestaShop cookie
SameSite: Lax is common, but payment POST/3-D Secure returns may need None; Secure
Size: keep the main cookie below the browser 4096-byte limit
Host: do not mix www and non-www in the same checkoutWhy customers get logged out
- The cookie key changed: if
_COOKIE_KEY_or the newer cookie encryption key was overwritten during a deploy, old cookies become unreadable and everyone is logged out. Restore the key from backup. - Domain mismatch: cookies set for
example.commay not behave the same onwww.example.com. Pick one canonical host and redirect the other before PrestaShop handles the request. - SSL mismatch: if the shop switches between HTTP and HTTPS, secure cookies may not be sent. Force HTTPS consistently.
- Cookie too large: PrestaShop rejects oversized cookie payloads because browsers cap cookies around 4096 bytes. Modules should not store large arrays or debug data in the cookie.
- Session storage mismatch: on multiple web nodes, file-based sessions need sticky sessions or shared storage such as Redis.
Empty cart after payment
If the cart disappears only after returning from a payment provider, test the full payment redirect with DevTools open. Cross-site POST returns and 3-D Secure flows can be affected by SameSite. For those flows, the cookie may need SameSite=None; Secure. Keep HttpOnly and Secure enabled.
Cache checks
After changing domain, SSL, cookie or redirect settings, clear PrestaShop cache, OPcache and any CDN/full-page cache. Cached pages generated under the old host or protocol can keep sending customers through the wrong domain and make a cookie issue look random.
GDPR
The PrestaShop session/cart cookie is essential and does not need marketing consent. Analytics, ad, chat and tracking cookies do. Use a cookie-consent module or CMP that actually blocks non-essential scripts until consent is given; a banner that loads tracking anyway does not solve compliance. See our GDPR and cookie compliance guide.
When PrestaShop is slow, MySQL is usually the first place to look: a single product or category page can fire well over a hundred SQL queries, and one unindexed query drags the whole page down. The fastest way to find it is to make the slow queries visible.
The classic server-side tool is the MySQL slow query log. Set slow_query_log = 1 and a long_query_time threshold (start around 1 second, then lower it), and MySQL records every query that runs too long, with how many rows it examined versus returned. Run EXPLAIN on the worst offenders: a type: ALL full table scan on a large table is your culprit, and a targeted index usually fixes it.
If you would rather not touch the server config, MPR Performance Revolution can profile from inside PrestaShop, but the coverage depends on the instrumentation path. The built-in instrumentation installs a Doctrine DBAL SQL logger for Symfony/Doctrine components; full classic PrestaShop Db query coverage requires installing the optional database profiling override. With the relevant instrumentation active, the profiler can show query count, total query time, slowest queries with call counts and SQL text, and slow module hooks.
The module's own slow-query threshold is separate from MySQL's server log threshold. Its default threshold is 0.1 seconds, so it can catch PrestaShop-level slow queries that may never appear in a server slow log set to 1 second. It stores slow queries in its own table by query hash, increments occurrence count for repeats, and keeps controller and stack-trace context so you can see where the query came from.
The built-in analyzer runs EXPLAIN and flags common problems: type = ALL full table scans, filesort, temporary tables, possible keys not being used, row estimates over 10000, SELECT *, leading-wildcard LIKE searches and broad OR conditions. Those warnings are not automatic fixes, but they tell you whether to add an index, rewrite a query, reduce a module's data load, or archive old data.
Server slow log: best for database-wide slow SQL across everything using MySQL.
Performance Revolution built-in profiler: best for Doctrine/Symfony DBAL queries and module timing.
Performance Revolution optional Db override: needed for full classic PrestaShop Db query coverage.Large numbers of product combinations can slow both the front office and the back office because each combination creates extra rows for attributes, stock, prices, images, and shop associations. The real cost is multiplicative: 6 sizes x 8 colors x 5 finishes is already 240 combinations for one product.
Start by finding the products with the largest combination sets:
SELECT id_product, COUNT(*) AS combinations
FROM ps_product_attribute
GROUP BY id_product
HAVING combinations > 200
ORDER BY combinations DESC;Then check stock rows for combination-heavy products:
SELECT id_product, COUNT(*) AS stock_rows
FROM ps_stock_available
WHERE id_product_attribute <> 0
GROUP BY id_product
ORDER BY stock_rows DESC;Common fixes include reducing unnecessary attribute dimensions, splitting very large configurable products into separate products, avoiding combinations for options that do not affect price or stock, and using a configurator module for made-to-order options instead of generating every possible combination.
Also check operational limits. Saving huge combination forms can hit max_input_vars, post_max_size, memory_limit, or web-server request timeouts. Stock sync jobs and imports can also become slow if they update thousands of combination stock rows one by one.
After large changes, rebuild search and faceted-search indexes, clear cache, and check slow query logs. If Performance Revolution is installed, its query profiler can help identify whether combination, stock, or layered-navigation queries are the bottleneck.
A slow PrestaShop back office usually has a different cause than a slow front office, so profile it separately. Start with one slow admin URL, measure whether the delay is server time or browser assets in DevTools Network, then work through modules, dashboard widgets, database, cache and server limits.
What to profile first
- Modules: the Module Manager, dashboard and configuration pages can load module metadata, hooks, autoloaders and external notifications. Sign out of Addons, uninstall unused modules, and test whether the slow page improves with non-essential admin modules disabled on staging.
- Dashboard widgets: if only the dashboard is slow, disable statistics, welcome/gamification and external-feed widgets first. Widgets are often slower than the core admin shell.
- Database: check slow queries and bloated tables such as carts, guests, connections, logs, mail logs and abandoned sessions. Clean old rows on a schedule, then optimize large tables during maintenance.
- Cache: make sure debug mode is off, Smarty compilation is not forced on every request,
var/cacheis writable, and OPcache is enabled for web PHP. Clear and warm admin cache after upgrades, but do not leave the back office rebuilding cache on every request. - Server limits: check CPU steal, disk I/O wait, memory pressure, PHP-FPM
pm.max_children, MySQL buffer pool size and whether the server is swapping. Shared hosting often gets slow at busy times even when PrestaShop did not change.
The most common causes
- The Addons connection: some back-office pages contact
addons.prestashop.comfor module and notification data. When that service is slow, the admin can wait for timeouts. Signing out of Addons in Module Manager often removes the worst lag. - Debug mode left on: production should not run with
_PS_MODE_DEV_enabled. Debug mode disables or weakens caching and makes every admin request heavier. - Too many modules: disabled modules can still leave files, hooks, tabs or autoload overhead. Uninstall what you do not use after taking a backup.
- No OPcache: without OPcache, PHP recompiles many files for each back-office request.
- Database bloat: old operational data makes admin grids, statistics and search slower.
Quick commands to ask your host for
# PHP-FPM pressure
systemctl status php8.2-fpm
grep 'server reached pm.max_children' /var/log/php8.2-fpm.log
# Disk and memory pressure
free -m
vmstat 1 5
iostat -xz 1 5
# MySQL slow query log, if enabled
tail -f /var/log/mysql/mysql-slow.logPerformance Revolution helps with Redis caching, fragment/query caching, cache warming and CDN purge workflows, but an admin-only slowdown still needs profiling. If the dashboard alone is slow, remove widgets. If every admin page is slow, focus on OPcache, PHP-FPM capacity, database latency and module overhead first.
Security Revolution is a PrestaShop security module that adds a store-level protection and monitoring layer on top of your shop: it stops unauthorised access, shows you what changed, hardens responses, and keeps an evidence trail for after-incident review.
Access & identity
- Two-factor authentication (TOTP / Google Authenticator) for back-office employees, with per-user session monitoring and the ability to end a suspicious session.
- Brute-force protection: failed-login tracking, IP scoring and automated blocking with thresholds you set.
- Configurable firewall with allow / block rules, including country blocking; every block records the reason, score and country, with one-click unblock.
Integrity & visibility
- File-integrity monitoring with baseline comparison and drift detection.
- Audit log linking sensitive actions to IP, country and the employee or customer responsible.
- Vulnerability scanner that flags risky settings, debug mode left on in production, an exposed
install/folder, exposed backup files, the PHP version leaking in headers.
Hardening & operations
- Security-headers manager (CSP, HSTS, X-Frame-Options, Referrer-Policy, Permissions-Policy) editable from the Back Office.
- Scheduled local backups.
- Email anti-abuse: disposable/throwaway-email blocking and email rate limits.
- Traffic monitor with country and bot/crawler analytics.
What it does not replace: server-level hardening (host firewall, fail2ban, OS patches), HTTPS, secure hosting, strong passwords or off-site backups. It complements those and makes risky activity visible inside PrestaShop. Which is exactly where most attacks land once perimeter defences are bypassed. Compatible with current PrestaShop versions.
Full feature list on the Security Revolution product page.
No. Database Cleanup never fires an open-ended DELETE. Every task ends with a LIMIT clause, so a single query can only touch a bounded number of rows - that is what keeps a cleanup from locking your tables for minutes on a busy shop.
When you run a task, the module repeats the bounded delete in batches and stops at a hard safety cap of 50,000 rows per run. If a table has more than that to clear, the workspace simply tells you to run the task again - you stay in control instead of one giant query grinding the database. The per-task limits are 5,000 rows for carts and expired prices, and 10,000 for search stats, logs, connections, guest records and mail logs.
Before anything is deleted you see the exact row count for each task, and a confirmation prompt appears on every action (the run all button warns explicitly that the data cannot be recovered). The tasks it covers are non-order data only: abandoned carts older than 30 days that never became an order, search statistics and logs older than 90 days, expired specific-price rules, old connection and orphan guest records, and mail-log entries older than 30 days.
The abandoned-cart cleanup explicitly left-joins orders and only removes carts where no order exists. Search statistics use statssearch, logs use log, visitor history uses connections, orphan visitors use guest, mail logs use mail, and expired discounts use specific_price where the end date is not the open-ended 0000-00-00 00:00:00 value and is already in the past.
The integrity screen uses warning thresholds rather than deleting automatically: for example, abandoned carts warn after 1,000 rows, guests after 5,000, logs after 10,000, connections after 20,000, mail after 2,000 and search stats after 50,000. Repairs call the same bounded cleanup tasks, so the integrity repair path follows the same safety limits as the workspace.
It is far safer than running raw SQL by hand, but the standard rule still holds: back up your database before any cleanup on a live store. For a wider maintenance suite that also covers images, cache and module leftovers, see Cleanup Revolution.
reCAPTCHA & hCaptcha Protection adds CAPTCHA validation to the PrestaShop front-office forms that bots actually target, so spam submissions and automated account creation get stopped before they reach you. Each form has its own on/off toggle, so you can protect login but leave the contact form open, or the other way round.
Protected forms (per-form toggle):
- Contact form
- Customer login
- Customer registration / account creation
- Newsletter subscription
The registration widget is rendered through the customer account form hook. The GDPR consent placement is contact-form specific: it is limited to the contact controller/contactform module and renders the contact CAPTCHA widget there.
Providers (one active at a time, switchable without reinstalling):
- Google reCAPTCHA v2 - the classic I am not a robot checkbox.
- Google reCAPTCHA v3 - invisible; it scores each interaction and you set the score threshold (default 0.5; higher is stricter) below which a request is rejected.
- hCaptcha - a privacy-minded alternative for stores that prefer not to send traffic data to Google.
Set-up is all in the Back Office: provider dropdown, site key and secret key fields, per-form toggles, the v3 threshold, and configuration checks that warn you when keys are missing so protection is not silently off. Compatible with current PrestaShop versions.
The install defaults are intentionally inactive until configured: ENABLED=0, provider recaptcha_v2, empty site and secret keys, protected forms set to contact,registration, v3 threshold 0.5, v3-to-v2 fallback off, and conditional script loading off. After you add keys and enable the module, validation runs server-side before the relevant form action continues.
For v3, the module posts the token to Google's verification endpoint and compares the returned score with your threshold. If optional v2 fallback is enabled and fallback keys are present, a low v3 score stores a short-lived fallback flag and asks the visitor to complete a v2 checkbox challenge instead of failing immediately. hCaptcha uses the hCaptcha verification endpoint and reads h-captcha-response; Google providers read g-recaptcha-response.
Theme coverage has two layers. The module uses normal PrestaShop form hooks where they exist, and a footer injector can place a widget before submit buttons for common legacy selectors when a theme does not expose the ideal hook. Conditional script loading can keep provider scripts off pages without protected forms, but it defaults off for legacy theme compatibility.
See the full walkthrough on the reCAPTCHA & hCaptcha Protection product page.
Yes, and in Cleanup Revolution that is the default. When the image cleanup removes an orphaned file (an image on disk with no matching record in the database), trash mode moves it into a dated trash folder under your image directory (img/_cleanup_trash/YYYY-MM-DD/) instead of deleting it. Files are renamed on collision so nothing is overwritten.
This gives you a recovery window: if a scan flags an image you actually still need, it is sitting in the trash folder and can be restored by moving it back. The retention period is a configurable setting (30 days by default), and you clear out the trash folder yourself when you no longer need the files. If you would rather skip the safety net, you can turn trash mode off, and the cleanup deletes the files outright.
The image scan covers product, category, manufacturer and supplier image folders, and every run is written to the action log with the file count, space freed and who triggered it. That trash-and-restore behaviour is specific to image files; database deletions are handled separately, with a dry-run preview and double confirmation, and those are not reversible, so for the database side the rule is still to back up first.
Cleanup Revolution is the broader maintenance suite: alongside images it handles database tasks, cache and temporary files, duplicate detection (products, categories, features, attributes) and leftover folders from removed modules, with cron automation and an audit log. It is multistore-aware. For database-only cleanup there is the simpler Database Cleanup module.
Other categories
Still have questions?
Can't find what you're looking for? Send us your question and we'll get back to you.