PS PrestaShop Intermediate

SEO Link Obfuscation for PrestaShop

Installation, preset configuration, writing CSS selectors and verifying what crawlers actually receive.

Updated Module version 1.0.0

This guide covers installation, configuration and verification of the dfobfuscator module on PrestaShop 8 and 9.

Installation

  1. Go to Modules and Services, Upload a module in your back office.
  2. Drop the dfobfuscator.zip file and confirm.
  3. Click Configure once installation completes.

The module registers itself on two hooks: actionOutputHTMLBefore for HTML rewriting and actionFrontControllerSetMedia for loading front-end assets. No core file override is created.

The PHP DOM extension must be enabled. It is on by default on nearly all hosting. Without it, the module stays installed but leaves the HTML unchanged.

Configuration

Enable obfuscation

The main switch disables all rewriting without uninstalling the module. Useful to compare source code before and after, or to isolate the module during diagnostics.

The three presets

Preset What it targets Default
Faceted navigation Filter blocks and the active filter list On
Product sorting The sort dropdown On
Pagination Links to page 2, 3 and beyond Off

Only enable pagination if your XML sitemap and internal linking make every product page reachable another way. Otherwise you cut the only crawl path to part of your catalog.

Custom CSS selectors

One selector per line. Commas on a single line are also accepted. Every link matching a selector is obfuscated.

#footer .account-links a
.block-tags a
.my-custom-block a[data-filter]

The built-in converter supports tag, id, class, attributes (presence or exact value), the descendant combinator and the direct child combinator. If your shop ships symfony/css-selector in its vendor directory, the module uses it first and you get the full CSS syntax.

XPath lines

For selections CSS cannot express, prefix the line with xpath::

xpath://div[@id='js-product-list']//a[contains(@href,'?order=')]

Excluded controllers

A comma-separated list of front controller names. On those pages no rewriting happens and the assets are not loaded. Default value: order,cart. Add any controller whose flow must not depend on JavaScript.

How the rewriting works

On the actionOutputHTMLBefore hook, the module receives the complete page HTML. It first checks that this is a full HTML document, which rules out AJAX and JSON responses. It then loads the document into DOMDocument, converts each selector into an XPath query, and replaces the matched links with span elements.

Each obfuscated element receives:

  • a data-o attribute holding the URL in reversed base64;
  • the df-obf class alongside its original classes;
  • tabindex="0" and role="link" for accessibility;
  • data-t when the original link carried a target attribute.

Links whose URL starts with #, mailto:, tel: or javascript: are skipped. The rel attribute is stripped, the target attribute is kept as data-t.

Automatic fallback

If document parsing fails, or if no selector matches a link, the original HTML is returned unmodified. The module therefore cannot break a page because of unexpected markup.

AJAX-loaded content

Filter refreshes and infinite scroll reinject links after the initial render. The front.js file installs a MutationObserver that applies the same selectors to those new links, browser side. Selectors are passed to the front end through Media::addJsDef. XPath lines are excluded from this mechanism, since the browser does not evaluate them.

Verifying that it works

  1. Open a category page with filters, then view the page source (Ctrl+U, not the element inspector).
  2. Search for df-obf: you should find span elements where the filter links used to be.
  3. Search for a filter URL, for example ?q=: it should no longer appear in an href attribute.

The element inspector shows the DOM after JavaScript execution, not the served HTML. To judge the result from a crawler’s point of view, always use view source or a tool such as curl.

On the navigation side, test left click, middle click, ctrl+click (cmd+click on macOS) and the Enter key after reaching a filter by tabbing.

Troubleshooting

Nothing is obfuscated

Check in order: the main switch is on, at least one preset or selector is set, the current controller is not in the exclusion list, the PHP DOM extension is available. Then clear the PrestaShop cache.

A custom theme is not covered

Presets target Classic theme selectors. On a bespoke theme, inspect the filter block to note its container id or class, then add a custom selector line.

Narrow the selector scope by targeting a more specific container, or remove the preset involved and replace it with tighter custom selectors.

Some third-party modules rebuild their filter block entirely. If behaviour differs between the first display and a refresh, check that your custom selector applies to the rebuilt container rather than to an element destroyed on every update.

Frequently asked questions

Is this cloaking?

No. The served HTML is identical for everyone: no user-agent test, no page variant. The link exists for nobody in the source code, and the browser reconstructs it at interaction time.

Do already indexed URLs disappear?

No. Obfuscation acts on the discovery of new URLs. For URLs already in the index, keep your noindex directives or redirects until Google revisits them.

What is the performance impact?

A DOM parse of the final page, in the range of a few milliseconds on a standard category page. On the front end, 5 KB of JavaScript and 0.2 KB of CSS.

Should I disable the module during an SEO audit?

No, quite the opposite: the audit should reflect what crawlers see. If your audit tool reports a drop in internal link count on category pages, that is the expected result.

Was this page helpful?

Still stuck? Contact support