DF Faceted SEO — Faceted Search & SEO for PrestaShop
Smart indexation of faceted URLs, SEO landing pages and a high-performance filter engine for PrestaShop 8 and 9.
DF Faceted SEO turns PrestaShop faceted search into a lasting SEO lever and accelerates your category pages 10 to 30 times thanks to a denormalised index. This documentation covers installation, configuration of indexation rules, creation of SEO landing pages and exploitation of popular combination statistics.
Overview
The native ps_facetedsearch module mechanically generates a URL for every possible filter combination. On a catalogue of a few thousand products with five facets, that means millions of URLs that Google crawls, diluting your crawl budget and PageRank between near-duplicate pages.
DF Faceted SEO solves the problem in two parallel ways:
- Smart indexation: business rules decide which combinations are indexable, which receive
noindex follow, and where the canonical points. - Dedicated SEO landing pages: for combinations with strong commercial potential (e.g. “red shoes size 42”), create landing pages with a clean URL, custom H1, custom meta and editorial content per language.
As a bonus, the search engine replaces the native engine with a system that is much faster thanks to a denormalised index and a two-layer cache.
Requirements
- PrestaShop 8.0 to 9.x
- PHP 8.1 or higher
- MySQL 5.7 or MariaDB 10.3 minimum
- Friendly URLs enabled (Preferences → SEO and URLs)
- Standard MySQL permissions to create tables
Installation
- Upload the ZIP archive via Modules → Module Manager → Upload a module.
- Click Install. The module automatically creates 10
ps_dffacetedseo_*tables and 5 tabs under Improve. - Go to Improve → DF Faceted SEO → Dashboard.
- Click Rebuild index. This step is mandatory the first time: without an index, the search engine has no data to work with.
- Clear the PrestaShop cache: Advanced parameters → Performance → Clear cache.
On a 50,000-product catalogue, the index rebuild typically takes 2 to 5 minutes. The module inserts rows in batches of 500.
Getting started — Dashboard
The dashboard (Improve → DF Faceted SEO) displays six statistic tiles:
- Active rules: number of enabled indexation rules
- Landing pages: number of SEO landing pages created
- Products in index: number of indexed products (should be close to your catalogue total)
- Rows in index: number of (product, filter value) pairs — the denormalised table
- Cache entries: number of cached queries
- Popular combinations: number of observed filter combinations
Under the tiles, two operation blocks:
- Rebuild index: useful after a major catalogue change (mass import, attribute structure change)
- Clear cache: useful after a rule or setting change
Indexation rules
Rules decide, for every visited filter combination, which robots tag and which canonical are sent to the browser and to Google. A rule has a scope (where it applies) and a policy (the decision).
Available scopes
- Global: applies to all faceted pages of the catalogue
- Specific category: applies only to pages of a given category
- Attribute group: applies to combinations containing a specific group (e.g. all pages where Colour is filtered)
- Feature: same, for a product feature
- Manufacturer: same, for a brand
- Price range: applies to pages filtered on a given price range
Available policies
- Index, follow: indexable page, canonical pointing to itself normalised
- Noindex, follow: page not indexed but links are followed (recommended for rare combinations)
- Canonical parent: page accessible but canonical points to the parent category (SEO value is transferred)
- Canonical self normalised: canonical on the page itself with filters sorted and grouped (eliminates URL duplicates for the same combination)
Priority chain
The module evaluates rules from most specific to most generic. Concretely, for a Shoes category page filtered by colour:
- The module first looks for a
category-scoped rule on Shoes - If it exists and matches, it is applied
- Otherwise it looks for an
attribute_group-scoped rule on Colour - Otherwise it falls back to the global rule
- If no rule matches, the dashboard default policy is applied
Advanced rule fields
- Maximum indexable filters: if the combination contains more filters than this limit, the policy automatically downgrades to
noindex follow. Example: 2 filters maximum on shoes (colour + size indexed, but not colour + size + material + season). - Value whitelist: allowed value IDs (comma-separated). A combination containing only whitelisted values is indexable. Example: whitelist colours red, black, white, blue — rare colours like “apple green” will not be indexed.
- Value blacklist: the opposite. Any combination containing a blacklisted value automatically falls to
noindex. - Minimum products: if the combination does not return at least this number of products, it goes to
noindex. Avoids indexing nearly empty pages. - Priority: integer. In case of conflict between two rules of the same scope, the highest priority wins.
Recommended starting strategy: create a global rule with canonical parent policy and maximum 1 indexable filter, then progressively add more specific rules to open indexation for high-potential combinations.
SEO landing pages
Landing pages are dedicated landing pages for strategic filter combinations. They have their own clean URL, their own H1, their own meta and editorial content per language.
Create a landing page
- Go to Improve → DF Faceted SEO → Landing pages
- Click Add
- Targeting section: pick the category and optionally the brand involved
- Display section: default sort, direction, active, indexable, priority
- Filter combination section: add the filters that compose the combination (attribute group and values, feature or brand). Example: Colour = Red AND Size = 42.
- Multilingual tabs: for each language fill in the internal name, URL slug, H1, meta title, meta description, intro content and outro content.
- Save
URL structure
A landing page URL follows the pattern:
https://your-domain.com/landing/your-slug
https://your-domain.com/en/landing/your-slug
https://your-domain.com/fr/landing/your-slug
The language prefix is automatically handled by the PrestaShop router as soon as friendly URLs are enabled and several languages are active on the shop.
If you get a 404 on a landing URL, check in this order: friendly URLs enabled, .htaccess regenerated (Save button at the bottom of SEO and URLs), cache cleared, landing active in the form, moduleRoutes hook properly attached to the module in Modules → Positions.
Editorial content
For each language you have two rich HTML blocks:
- Intro: displayed above the product grid. Ideal for a 150- to 300-word SEO introduction paragraph with your target keywords.
- Outro: displayed below the grid. Ideal for reassurance elements, buying guides, FAQs.
Automatic JSON-LD
Every landing page automatically injects two JSON-LD blocks into the page:
- BreadcrumbList: Home → Category → Landing
- Product: one Product block per displayed product (name, price, image, URL, availability)
You get Google rich snippets automatically without any additional configuration.
Popular combination statistics
The module automatically logs every filter combination actually visited by your customers in the ps_dffacetedseo_combination_log table: signature, hit count, last seen.
Exploit the statistics
- Go to Improve → DF Faceted SEO → Statistics
- Filter by category, minimum hits, display limit
- Sort by descending hits
- Identify combinations with more than 50 hits per week
- Click Promote in the action column
- The landing page form opens pre-filled with the filter combination
- You only need to fill in the editorial content and save
Maintenance
At the bottom of the Statistics page, a Purge old data button with a “days to keep” field. Recommended: purge every 90 days to avoid unlimited table growth.
Global settings
The dashboard offers 11 global settings grouped into 3 sections.
Indexation
- Default policy: policy applied when no rule matches
- Maximum indexable filters: global value (can be overridden per rule)
- Minimum products per combination: global threshold to consider a page indexable
Performance
- Cache TTL (seconds): lifetime of a cache entry. Default: 3600 (1 hour). Increase to 86400 (24 h) in stable production.
- Hide empty filters: if enabled, values with 0 results are hidden in the filter panel
- Results limit per page: product pagination
URLs
- Landings URL prefix: default
landing. The route pattern is defined hardcoded in themoduleRouteshook and uses this prefix.
Smart canonical
On every faceted page, the module computes the optimal canonical:
- Combination matching an existing landing: canonical = landing pretty URL
- Combination indexable according to rules: canonical = normalised self (filters sorted and grouped)
- Combination not indexable according to rules: canonical = parent category
- Category page without filter: canonical = standard self
Normalisation groups values by group and sorts groups by ID. Two visually different but semantically identical URLs (e.g. different GET parameter order) receive the same canonical.
High-performance filter engine
The engine relies on the ps_dffacetedseo_index table: one row per (product, filter type, value) tuple. The query becomes a simple set intersection of product IDs.
Two-layer cache
- Level 1: memory (in-process). Avoids repeating the same query twice within the same page.
- Level 2: database (
ps_dffacetedseo_cachetable). Persists results between requests with TTL.
Automatic invalidation
The module listens to the actionProductSave, actionProductDelete and actionCategoryUpdate hooks. Every time a product is saved, its index entry is regenerated and all cache entries linked to that product are invalidated.
AJAX and UX
The front filter panel is fully AJAX-driven:
- 250 ms debounce on filter changes
pushStateto update the URL without reloading the page- Real-time update of the
canonicalandrobotstags in the document head - Smooth scroll to the product grid after update
- Active filter chips clickable to remove a single filter
- Price slider with numeric fields and Apply button
- Colour swatches visible on Colour-type attributes
Multistore and multilingual
The module is natively multistore and multilingual:
- Every landing page has translations per language (
ps_dffacetedseo_landing_page_langtable) - Every landing can be restricted to one or more shops (
ps_dffacetedseo_landing_page_shoptable) - Indexation rules apply to all shops by default
- The index is partitioned by shop
- Interface translations are provided in French and English (XLIFF in
translations/)
Technical architecture
Hooks used
displayHeader: dynamic canonical and meta robotsactionFrontControllerSetMedia: frontend CSS and JSmoduleRoutes: clean route for landing pagesdisplayLeftColumn: filter panel injectiondisplayBeforeBodyClosingTag: JSON-LD on landingsactionProductSearchProviderRunQuery: integration with the PS engineactionProductSaveandactionProductDelete: incremental reindexationactionCategoryUpdate: category cache invalidationdisplayBackOfficeHeader: admin CSS and JS
Created tables
| Table | Role |
|---|---|
dffacetedseo_rule |
Indexation rules by scope |
dffacetedseo_landing_page |
Landings (business data) |
dffacetedseo_landing_page_lang |
Landing translations |
dffacetedseo_landing_page_shop |
Multistore links |
dffacetedseo_landing_filter |
Filters attached to landings |
dffacetedseo_combination_log |
Visit statistics |
dffacetedseo_cache |
Query result cache |
dffacetedseo_filter_template |
Reusable filter templates |
dffacetedseo_index |
Denormalised index (performance key) |
dffacetedseo_setting |
Internal settings |
Filter URL convention
?attribute_group__{id_group}=v1,v2&feature__{id_feature}=v3&manufacturer__0=5&price=10-50&s=needle
A stable SHA-1 signature is computed to compare combinations (landing matching, cache key, log).
Expected performance
Measurements on a reference catalogue (50,000 products, 8 active facets):
| Engine | Average time |
|---|---|
ps_facetedsearch native |
800 ms to 1.4 s per query |
| DF Faceted SEO without cache | 50 to 120 ms |
| DF Faceted SEO with cache | less than 10 ms |
Typical gain: ×10 to ×30
Technical FAQ
Do I need to uninstall ps_facetedsearch
No, the module integrates via the official hooks. You can test it in parallel. Once validated, uninstall ps_facetedsearch to avoid filter panel duplication.
Is the module HTTPS-compatible and does it use absolute canonical URLs
Yes. The module uses Context::getContext()->link->getPageLink() and getModuleLink() which respect the PrestaShop HTTPS configuration.
How do I add a new language on the module side
Copy the translations/fr-FR.xlf file to translations/xx-XX.xlf and translate the trans-unit entries. No other intervention required.
Does the module support combination attributes
Yes. The denormalised index indexes combinations via their attributes. The search engine filters on products for which at least one combination matches all active filters.
How do I debug a rule that does not apply
Enable PrestaShop logs (Advanced parameters → Logs) and check the dffacetedseo section. Each directive resolution logs the matched rule and the reason.
Troubleshooting
Fatal error on a getBySlug call
Symptom: Call to a member function getBySlug() on false. Cause: old get() helper returning false instead of the service object. Fixed in v1.0.1. Update the module.
404 on a landing page URL
Symptom: https://your-site/en/landing/your-slug returns 404. Typical cause: the moduleRoutes hook is not registered or the PrestaShop route cache is stale.
- Check that Preferences → SEO and URLs → Enable friendly URLs is set to YES
- Save this page (regenerates the
.htaccess) - Clear the PrestaShop cache twice
- Go to Modules → Positions, verify that
dffacetedseois attached tomoduleRoutes - Test fallback:
https://your-site/index.php?fc=module&module=dffacetedseo&controller=landing&slug=your-slug
The search engine returns no products
The index is probably empty. Go to the dashboard and click Rebuild index.
Filters do not show up in the column
Verify in Modules → Positions that dffacetedseo is attached to the displayLeftColumn hook. Depending on your theme, you can also attach it to displayRightColumn or displayHome.
Degraded performance after mass product import
Incremental invalidation works well for single modifications. After a mass import, it is faster to rebuild the entire index from the dashboard and clear the cache.
Updates
The module follows MAJOR.MINOR.PATCH versioning. Critical fixes (security, fatal errors) ship as patches; new features trigger a minor bump. Every major update ships an upgrade/upgrade-X.Y.Z.php script that runs automatically when installing the new version.
Support
For any question or bug report, contact support@datafirefly.com with the PrestaShop version, PHP version, module version and PHP/PrestaShop logs.