# DataFirefly All in One SEO — Complete documentation

> Complete documentation of the DataFirefly All in One SEO module for PrestaShop 8 and 9: installation, meta templates, JSON-LD schemas, XML sitemap, redirects, 404 monitoring, robots.txt, GA4/GTM tracking, content analyzer.

- Page: <https://www.datafirefly.com/en/documentation/dfallinoneseo/>
- Language: en
- Last updated: 2026-08-05
- Other languages: [fr](https://www.datafirefly.com/documentation/dfallinoneseo/index.md), [es](https://www.datafirefly.com/es/documentation/dfallinoneseo/index.md), [de](https://www.datafirefly.com/de/documentation/dfallinoneseo/index.md), [it](https://www.datafirefly.com/it/documentation/dfallinoneseo/index.md), [pl](https://www.datafirefly.com/pl/documentation/dfallinoneseo/index.md), [pt](https://www.datafirefly.com/pt/documentation/dfallinoneseo/index.md), [nl](https://www.datafirefly.com/nl/documentation/dfallinoneseo/index.md)
- Index: <https://www.datafirefly.com/en/documentation/llms.txt>

Premium all-in-one SEO suite for PrestaShop 8 and 9: dynamic meta templates, full JSON-LD schemas, multilingual XML sitemap, redirects, 404 monitoring, Open Graph and Twitter Cards, GA4 and GTM, intelligent robots.txt with AI crawler blocking and content analyzer — all in a single module.

## Requirements

- **PrestaShop**: 8.0 to 9.x
- **PHP**: 8.1 or higher (8.2 and 8.3 recommended)
- **MySQL**: 5.7+ or MariaDB 10.3+
- **productcomments module** (official PrestaShop): optional, required only for AggregateRating on products
- **mod_rewrite** enabled on Apache (or Nginx equivalent) for rewritten URLs

The module is multi-shop aware natively: all tables are scoped by `id_shop`. You can have completely different configurations per shop.

## Installation

1. Download `dfallinoneseo-vX.Y.Z.zip` from your DataFirefly client area.
2. Log in to your PrestaShop back-office.
3. Go to **Modules → Module Manager**.
4. Click **Upload a module** in the top right.
5. Drag-and-drop the ZIP file or click **Select a file**.
6. Installation automatically creates the 11 SQL tables, registers the hooks and adds the **Improve → DataFirefly SEO** menu.

After installation, open the module **Dashboard** for an overview of the global SEO score and the priority issues to fix.

## 10-minute first-time setup

This quick walkthrough lets you configure the essentials before the first Google crawl.

1. **Settings → General**: enable the module, set the site name and the "Home" label for the breadcrumb.
2. **Meta & templates**: define at least a _Product_ template and a _Category_ template (see dedicated section).
3. **Schema → Organization identity**: fill in logo, phone, email, address and social network URLs (`sameAs`).
4. **Sitemap**: enable the sitemap and click **Regenerate now**.
5. **Tracking**: add your GA4 Measurement ID and/or GTM ID.
6. **Tracking → Verifications**: paste the Google Search Console verification value.
7. **Robots.txt**: click **Load defaults (PS + AI blocking)** to start from a healthy baseline.

## Meta templates

The module replaces manual `meta_title` and `meta_description` entry with dynamic templates per entity type. When a record with empty metas is saved, the matching template is applied automatically.

### Supported entity types

- **Product**: product pages (all types including virtual and pack)
- **Category**: category pages
- **CMS Page**: static content pages
- **Brand / Manufacturer**: manufacturer pages
- **Supplier**: supplier pages
- **Home**: shop home page
- **Generic pages**: `/contact`, `/sitemap`, etc.

### Available tokens

Tokens are replaced with actual values at page render time. Not all tokens are available for every entity type.

- `{shop_name}` — shop name
- `{sep}` — separator (default `|`)
- `{product_name}` — product name (current language)
- `{product_reference}` — internal reference
- `{product_sku}` — alias for reference
- `{product_ean13}` — EAN13 barcode
- `{product_brand}`, `{brand}` — manufacturer/brand
- `{category}` — default category (product) or category name (category page)
- `{category_parent}` — parent category name
- `{category_description}` — short description (160 char max)
- `{short_description}` — product short description (160 char max)
- `{price}` — VAT-incl. price formatted with currency
- `{price_tax_excl}` — VAT-excl. price formatted
- `{title}` — CMS page title
- `{summary}` — CMS content excerpt (160 char max)

### Conditional blocks

To avoid rendering an empty token, use the conditional syntax:

```
{?product_brand}{product_brand} | {/?}{product_name} - {shop_name}
```

If `product_brand` is empty (product without brand), the entire block between `{?token}` and `{/?}` is removed. Otherwise, its content is rendered and tokens inside are replaced normally.

### Recommended template examples

**Product**:

```
Title: {?product_brand}{product_brand} {/?}{product_name} - {category} | {shop_name}
Description: Discover {product_name}{?product_brand} by {product_brand}{/?}. {short_description} Fast shipping on {shop_name}.
```

**Category**:

```
Title: {category} - {?category_parent}{category_parent} - {/?}{shop_name}
Description: All products in the {category} category on {shop_name}. {category_description}
```

**Home**:

```
Title: {shop_name} - Online store
Description: Welcome to {shop_name}. Discover our catalog, fast shipping, secure payment.
```

### Per-entity override

To override a specific page (e.g. a flagship product), click the **Meta override** icon from the **Bulk edit** menu or use the URL:

```
?controller=AdminDfSeoMeta&entity=product&entity_id=42
```

The override page lets you set `meta_title`, `meta_description`, the robots directive (e.g. `noindex,follow`) and a custom canonical per language.

The robots directive defined on a specific entity takes priority over global indexation settings. Use it sparingly to avoid accidentally deindexing your best pages.

## JSON-LD schemas

The module generates a single `@graph` block aggregating all schemas for the current page, validated by Google Rich Results Test.

### Automatically generated schemas

- **Organization** — on all pages, company identity
- **WebSite** — on the home, with `SearchAction` for sitelinks search box
- **LocalBusiness** — if a physical address is set
- **BreadcrumbList** — breadcrumb
- **Product** — on product pages, with `offers`, `priceValidUntil`, `gtin13`/`isbn`/`mpn`
- **AggregateRating** — aggregated from the official productcomments module
- **Article** — on CMS pages
- **FAQPage** — from product or page FAQ blocks

### Organization identity

**Schema → Organization identity** tab. Fields to fill in:

- **Type**: Organization, Corporation, LocalBusiness, Store, OnlineStore, OnlineBusiness
- **Logo**: absolute URL (recommended 600x60 minimum, square or landscape ratio)
- **Phone**, **Email**: used in `contactPoint`
- **Postal address**: street, postal code, city, country (ISO-2)
- **sameAs**: one URL per line (Facebook, Instagram, LinkedIn, Twitter/X, etc.)

### Product offer validity

The _Product offer validity (days)_ field controls the value of `priceValidUntil` in `Product.offers`. Default: 60 days. Google requires this field to display the price in rich results.

### Custom schemas

**Schema → Custom schemas** tab. Allows adding tailored JSON-LD blocks (HowTo, Recipe, Event, JobPosting, VideoObject, Course, etc.) with a precise scope:

- **global**: all pages
- **home**: home only
- **product**: all product pages
- **product_id**: a specific product (uses the ID field)
- **category**, **category_id**: same for categories
- **cms**, **cms_id**: same for CMS pages

Variables available in custom JSON: `{shop_name}`, `{base_url}`, `{entity_id}`, `{entity_type}`.

Custom JSON-LD is inserted as-is in the `@graph`. Validate it with the [Rich Results Test](https://search.google.com/test/rich-results) before publication. Invalid JSON is silently rejected.

## XML sitemap

The module generates an XML sitemap compliant with the [sitemaps.org specification](https://www.sitemaps.org/protocol.html), with hreflang on every URL and image support. Architecture: one _sitemap index_ per shop, then one sitemap per entity type × language, split into chunks.

### Configuration

**Sitemap** tab. Enable the sitemap then check the content to include:

- Products (default all active products)
- Categories
- CMS pages
- Brands / Manufacturers
- Suppliers
- Images (adds `image:image` to each product URL)
- Videos (if present in pages)

Additional options:

- **Exclude out-of-stock**: removes out-of-stock products
- **Gzip**: also generates `.xml.gz` variants (reduces 5-10x the size downloaded by crawlers)
- **URLs per file**: chunk size (recommended 5000-10000, max 50000 per XML spec)

### Regeneration

Regeneration is manual from the admin to avoid unexpected server load. Click **Regenerate now**.

To automate, schedule a cron that calls the following script (every 6 or 12 hours depending on your catalog update frequency):

```
0 */6 * * * php /var/www/html/index.php fc=module&module=dfallinoneseo&controller=sitemap&action=rebuild
```

### Submission to search engines

Click **Ping search engines** to notify Google and Bing (legacy but still active endpoints). For Google Search Console, submit the sitemap index URL once in GSC → Sitemaps. GSC will re-crawl automatically on every change.

Sitemap index URL: `https://your-shop.com/sitemap.xml`

## Public HTML sitemap

A human-readable HTML sitemap is automatically generated at `/plan-du-site`. It aggregates categories (tree), CMS pages, brands, suppliers and the 200 most recent products. Useful for internal linking and accessibility.

## Redirects

The module handles HTTP 301 (permanent), 302 (temporary), 307, 308 and 410 (Gone) redirects with three match types.

### Match types

- **Exact**: the source URL must match exactly (without query string)
- **Prefix**: the source URL is a prefix of the requested URL. The suffix is kept in the destination if _Keep query string_ is checked. Useful for migrating entire folders (`/old-folder/` → `/new-folder/`).
- **Regex**: PHP regular expression (mode `~...~i` case-sensitive/insensitive). Capture groups are available in the destination via `$1`, `$2`, etc.

### Manual creation

**Redirects → New redirect** tab. Fields:

- **Source URL**: path without domain (e.g. `/old-page`)
- **Destination URL**: path or absolute URL. Leave empty for a 410 code.
- **Match type**, **HTTP code**, **Keep query string**

### CSV import / export

Expected CSV format (with header):

```
source,destination,type,code
/old-product,/new-product,exact,301
/old-folder/,/new-folder/,prefix,301
/old-(.*),/new-$1,regex,301
```

CSV export reuses the redirects currently filtered in the list.

### Automatic redirect on slug change

If **Settings → Monitoring → Auto 301 redirect on URL change** is checked, the module creates a 301 automatically when you change the slug of a product, category, CMS page, brand or supplier. The `created_by` is then marked `auto:urlchange` for distinction.

This option avoids the majority of SEO 404s related to content refactoring. Enable it from installation.

## 404 monitoring

**404 Monitor** tab. Captures all 404 error URLs served by PrestaShop, with deduplication, hit counting, bot detection and IP hashing (PrestaShop's `COOKIE_KEY` salt for GDPR compliance).

### Available filters

- **Unresolved**: URLs without a covering redirect (default view)
- **Resolved**: URLs for which a redirect was created afterwards
- **Bots**: hits from user-agents identified as bots
- **All**

### Create a redirect in one click

On each row, the **Redirect** button opens an inline form that pre-fills the source. Enter the destination, choose the HTTP code, validate. The 404 is automatically marked as resolved.

### Purge and maintenance

The **Settings → Monitoring** menu exposes a threshold _Maximum number of 404 entries kept_ (default 5000). Beyond, the **Purge old 404s** button removes the oldest unresolved entries.

## Dynamic robots.txt

The module serves a `/robots.txt` file dynamically generated on each request, based on the rules defined in **Robots.txt**.

### PrestaShop + AI blocking presets

The **Load defaults (PS + AI blocking)** button overwrites all current rules and loads a healthy preset that:

- Blocks sensitive PrestaShop directories (`/admin*/`, `/cache/`, `/classes/`, etc.)
- Blocks technical pages (`/cart`, `/order`, `/my-account`, etc.)
- Blocks the main non-respectful AI crawlers: **GPTBot**, **ClaudeBot**, **CCBot**, **Google-Extended**, **anthropic-ai**
- Points to the sitemap (`Sitemap: /sitemap.xml`)

### Custom rules

Each rule has a user-agent, a directive (`Allow`, `Disallow`, `Crawl-delay`), a value and a position (order in the file). Enable/disable a rule without deleting it via the ON/OFF pill.

### Live preview

The **Generated file preview** block at the bottom of the page renders the robots.txt as it will be served, before publication.

## Native llms.txt file

The module serves an `/llms.txt` file compliant with the [llmstxt.org specification](https://llmstxt.org/). This file lists, in markdown, the main sections of the site for respectful AI crawlers that want a structured view rather than scraping the entire HTML.

No configuration is required — the module automatically generates the file from your tree of categories, CMS pages and brands.

## Open Graph and Twitter Cards

**Social** tab. The module injects `og:*` and `twitter:*` tags on all pages.

### Settings

- **Enable Open Graph and Twitter Cards**: master switch
- **Automatic og:locale**: computed from the context language (e.g. `en_US`)
- **Default OG image**: absolute URL of a 1200×630 image (used when the page has no dedicated image)
- **og:site_name**, default **og:type**
- **Twitter @handle** and card type (`summary` or `summary_large_image`)
- **fb:app_id**: Facebook App ID

For product pages, the module automatically uses the main image of the product. For other pages, the default OG image is used if no image is defined.

## Tracking: GA4, GTM, pixels

### GA4 and Enhanced Ecommerce

**GA4 Measurement ID** field: format `G-XXXXXXXXXX`. Automatic format validation.

Check **Enhanced Ecommerce** to enable `view_item`, `view_item_list`, `add_to_cart`, `remove_from_cart`, `begin_checkout`, `add_payment_info`, `purchase` events.

Check **Respect Consent Mode v2** to anonymize hits until explicit consent (compatible with standard CMPs).

### Google Tag Manager

**GTM ID** field: format `GTM-XXXXXXX`. The module injects the GTM snippet in the `head` and the `noscript` fallback right after the opening `body`.

### Advertising pixels

- **Facebook Pixel ID**: 15 digits
- **TikTok Pixel ID**: alphanumeric

If Consent Mode v2 is active, these pixels only fire after consent.

### Ownership verifications

Paste the verification tag values (without the full `meta` tag, only the `content` attribute value):

- Google Search Console
- Bing Webmaster Tools
- Yandex Webmaster
- Pinterest
- Baidu

### Custom head and body-end code

Two free fields accept arbitrary HTML/JS:

- **Code injected in head**: for third-party scripts, additional meta tags
- **Code injected just before body closing**: ideal for chat widgets, late retargeting, async scripts

These fields perform no validation. An HTML syntax error can break the page rendering. Test in pre-production before publication.

## Content analyzer

**Analyzer** tab. Submit a product, a category, a CMS page or raw HTML to the analyzer to get a global SEO score and a detailed metrics breakdown.

### Computed metrics

- **Global SEO score** (0-100) — weighted pondering of checks
- **Flesch readability** — multilingual approximation (vowel-group syllable count)
- **Word count**, **sentence count**
- **Primary keyword density** (in %)
- **Internal / external / nofollow links**
- **Images without alt attribute**
- **H1 to H6 heading structure**
- Presence of the keyword in **slug** and **first paragraph**

### Checks

The analyzer returns a list of checks with `good` / `warn` / `bad` status:

- Title length (50-60 characters)
- Meta description length (140-160 characters)
- Slug presence and length
- Body length (minimum 300 words)
- Presence of at least one image with alt
- Keyword in title, in first paragraph, in slug
- Keyword density between 0.5% and 2.5%
- At least one H1 and several H2/H3

The analyzer is a guide, not an absolute truth. A score of 80+ is excellent. Below 50, review structure and wording. Never sacrifice editorial quality for a score.

## Bulk edit

**Bulk edit** tab. Paginated grid (30 entries/page) with filters to quickly modify `meta_title`, `meta_description` and `link_rewrite` on products, categories or CMS pages.

### Available filters

- **All**
- **Without title**: only entries with empty meta_title
- **Without description**: only entries with empty meta_description
- **Search by name**

### Bulk apply templates

The **Apply templates** button automatically applies the template defined for the current entity type to the entries matching the filters. Check **Apply only to empty fields** to avoid overwriting already-filled metas.

## SEO metabox on the product page

On a product edit page in the back-office, a **DataFirefly SEO** box is added with:

- A **live SEO score** (7 checks: title length, description, slug, body, image, EAN13, brand)
- A faithfully rendered **Google SERP preview**
- The detected primary keyword

## Advanced settings

### Indexation

**Settings → Indexation** tab:

- **Multilingual hreflang**: generates `link rel="alternate"` tags on all pages
- **x-default strategy**: _Default language_ (recommended), _English_, or _Disabled_
- **Canonical URL**: injects `link rel="canonical"`
- **Canonical on pagination**: _On current page_ (recommended), _Always on page 1_, or _No canonical_
- **Automatic noindex**: /search, cart, my account, new products, best sales, prices drop, faceted
- **Canonical to parent page on faceted**: avoids duplicate content of faceted navigation

### Images

- **Automatic alt attribute generation**: on saving an image without alt, applies the template
- **Alt template**: default `{product_name} - {shop_name}`
- **Native image lazyload**: adds `loading="lazy"` and `decoding="async"` to all images, with IntersectionObserver fallback for `data-src` images

### Maintenance

- **Clear cache**: purges Smarty + PrestaShop caches
- **Purge old 404s**: applies the configured threshold
- **Export all data (JSON)**: downloads a JSON file with all SEO tables of the current shop (useful for migration between environments or backup before uninstallation)

## Multi-shop

All features are scoped by `id_shop`. By switching from one shop to another via the PrestaShop context selector, you see and modify only that shop's data.

Special cases to know:

- **Templates**: one template per (entity type, shop) pair. Define templates explicitly for each shop.
- **Sitemap**: a distinct sitemap_index per shop, accessible at `https://shop-1.com/sitemap.xml`, `https://shop-2.com/sitemap.xml`, etc.
- **Robots.txt**: rules per shop, served on the corresponding domain
- **Redirects**: per shop
- **Custom schemas**: per shop

## Troubleshooting

### The sitemap is not generated

- Check that the `modules/dfallinoneseo/sitemaps/` folder is writable by PHP
- Check permissions: `chmod 755 modules/dfallinoneseo/sitemaps/`
- Increase `max_execution_time` in php.ini if you have more than 50,000 products

### JSON-LD schemas don't appear

- Check that the module is enabled (**Settings → General**)
- Check that the relevant schema type is enabled (**Schema → Generated schema types**)
- Clear the PrestaShop cache
- Inspect the HTML source: schemas are injected in a `script type="application/ld+json"` block

### 301 redirects don't work

- Check that the module is installed and enabled
- Check that redirects are marked **active** (ON pill)
- For regex, test your expression on [regex101.com](https://regex101.com/) in PCRE mode
- Priority order is: exact → prefix → regex (by descending `hit_count`)

### GA4 / GTM doesn't inject

- Check the ID format (`G-XXXXXXX` or `GTM-XXXXXXX`)
- If Consent Mode v2 is active, the snippet is in "denied" mode by default until consent. Check the CMP layer.
- Inspect the page `head`: the GA4/GTM snippet is injected just before closing

### robots.txt doesn't change

- Check that no static `robots.txt` file exists at the site root (it would take priority over the module). Delete it.
- The module serves robots.txt via a PrestaShop route — check that _Friendly URL_ is enabled

### Error creating SQL tables on installation

- Check that the MySQL user has `CREATE` and `ALTER` rights
- Check the encoding: MySQL must support `utf8mb4` with `utf8mb4_unicode_ci` collation
- If PrestaShop's custom table prefix exceeds 5 characters, some index names may exceed MySQL's 64-character limit. Contact support.

## Technical reference

### Hooks used

The module registers 18 hooks:

- `displayHeader` — injection of meta tags, canonical, hreflang, OG, Twitter, JSON-LD, GA4/GTM, verifications
- `displayBeforeBodyClosingTag` — GTM noscript, FB Pixel noscript, custom body-end code injection
- `displayBackOfficeHeader` — back-office CSS/JS
- `displayAdminProductsExtra` — SEO metabox on product page
- `actionDispatcherBefore`, `actionDispatcherAfter` — redirect routing and 404 capture
- `actionObjectProductAddAfter`, `actionObjectProductUpdateAfter` — meta auto-fill + auto-301
- `actionObjectCategoryAddAfter`, `actionObjectCategoryUpdateAfter` — same for categories
- `actionObjectCmsAddAfter`, `actionObjectCmsUpdateAfter` — same for CMS
- `actionObjectManufacturerUpdateAfter`, `actionObjectSupplierUpdateAfter` — auto-301 on slug change
- `actionAdminControllerSetMedia`, `actionFrontControllerSetMedia` — CSS/JS assets
- `displayProductExtraContent` — reserved for future use
- `moduleRoutes` — `/sitemap.xml`, `/plan-du-site`, `/robots.txt`, `/llms.txt` routes

### Added SQL tables

All tables use the `df_seo_` prefix, `utf8mb4` charset, `utf8mb4_unicode_ci` collation:

- `df_seo_meta`, `df_seo_meta_lang` — meta overrides per entity
- `df_seo_template`, `df_seo_template_lang` — templates per type
- `df_seo_redirect` — 301/302/307/308/410 redirects
- `df_seo_404` — 404 journal
- `df_seo_score` — score snapshots (analyzer)
- `df_seo_keyword` — focus keywords
- `df_seo_robots_rule` — robots.txt rules
- `df_seo_schema_custom` — custom JSON-LD schemas
- `df_seo_log` — internal diagnostic log

### Uninstallation

Uninstallation removes the hooks and back-office tabs, but **keeps the SQL tables and data**. To fully purge:

```
DROP TABLE ps_df_seo_meta, ps_df_seo_meta_lang, ps_df_seo_template, ps_df_seo_template_lang,
           ps_df_seo_redirect, ps_df_seo_404, ps_df_seo_score, ps_df_seo_keyword,
           ps_df_seo_robots_rule, ps_df_seo_schema_custom, ps_df_seo_log;
DELETE FROM ps_configuration WHERE name LIKE 'DFSEO_%';
```

Before uninstallation, use **Settings → Maintenance → Export all data (JSON)** to keep a complete archive. The JSON format lets you re-import redirects, templates and schemas on another installation.

## Updates and support

- **Updates**: 12 months included from purchase. Optional annual renewal at €49.
- **Support**: 12 months by email, response within 48 business hours.
- **Changelog** and downloads of the latest versions on [your DataFirefly client account](https://www.datafirefly.com/en/product/dfallinoneseo/).
