# DF Samples: product sample ordering (PrestaShop 8 & 9)

> Overview DF Samples adds an "Order a sample" button to your product pages. The sample can be free or cost a few euros, for the product or for the combination…

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

## Overview

DF Samples adds an "Order a sample" button to your product pages. The sample can be free or cost a few euros, for the product or for the combination the customer selected. The module creates a hidden sample product for each enrolled product, locks the quantity to 1, enforces per-customer limits on the cart content, tracks sample-to-purchase conversion and sends a follow-up email with an optional discount voucher.

The module supports PrestaShop 8.0 to 9.x, multistore and multiple languages, and uses no core override. This documentation covers version 1.1.0.

## Installation

1. In the back office, go to **Modules > Module Manager**.
2. Click **Upload a module** and drop the `dfsamples.zip` file.
3. Open **Catalog > Samples (DF)**: the product list, the dashboard and the settings are on this page.

On installation, the module creates:

- three tables: `dfsamples_product`, `dfsamples_order` and `dfsamples_cart`;
- a disabled **Samples** category under Home, open to all customer groups, which will hold the sample products;
- its default settings and a security token for the cron job;
- the **Catalog > Samples (DF)** admin tab;
- a copy of the English email template for each installed language that has none.

It registers 12 hooks, including displayProductActions, displayProductAdditionalInfo, displayDfSamplesButton, actionCartSave, actionCartUpdateQuantityBefore, actionValidateOrder and actionOrderStatusPostUpdate.

## Upgrading from version 1.0.0

Upload the new ZIP over the old one from the Module Manager. The upgrade script:

- adds the `dfsamples_cart` table and the new columns;
- registers the new hooks;
- creates the Samples category and moves your existing sample products into it;
- renames them to the new format and adds missing images (on PrestaShop 9, version 1.0.0 did not copy the image);
- keeps your enrolled products, statistics and follow-up history.

If a step fails, the **Resync sample products** button at the top of the module page runs the synchronization again for all sample products.

## Adding a product to the sample program

1. Open **Catalog > Samples (DF)** and click **Add a product**.
2. Search for the product by name or reference, then select it. Products already enrolled and sample products are excluded from the results.
3. Enter the **Sample price (tax incl.)**. Enter 0.00 for a free sample.
4. Set **Max per customer** for this product within the rolling window (0 = unlimited).
5. Turn on **Sample per option** if the product has combinations and the customer should pick one (see below).
6. Save.

### What the module does on save

The module creates a hidden sample product, or updates the existing one:

- translated name in the format "Sample: Product name" (Échantillon, Muestra, Muster, Campione in the other languages);
- reference in the format SMPL followed by the source product ID;
- price excluding tax computed from the price you entered and the tax rule of the source product;
- cover image of the source product copied to every image format;
- default category: the Samples category;
- visibility "nowhere": the product appears neither in listings nor in search;
- orders allowed when out of stock, so a request is never blocked;
- weight taken from the global setting, used by carriers.

If you later change the price, the option setting, the global weight or the active status, the sample product is synchronized again. If it was deleted manually from the catalog, it is recreated on the next save.

## Sample per option

With **Sample per option** turned on, the customer selects a combination on the product page as for a normal purchase, then clicks the button, which reads "Order a sample of this option".

- The combination is recorded on the sample line, for example "Size: A4, Paper: Coated 300 g". It is shown in an "Option" field in the cart, the order, the invoice and the follow-up email.
- Each combination gets its own line. The same combination cannot be added twice.
- The product's per-customer maximum is counted per combination.
- The sample price is the same for all combinations of the product.

The sample product stays a simple product, with no combinations and no stock of its own. The combination is a customization text added by the module, so your combinations are not duplicated.

## Settings

The settings are below the product list on the **Catalog > Samples (DF)** page.

### General settings

- **Button position**: below add-to-cart (displayProductActions), in the additional info block (displayProductAdditionalInfo), or custom placement only (displayDfSamplesButton, see the next section).
- **Default sample price (tax incl.)**: value suggested when you add a sample.
- **Sample weight**: in kilograms, applied to all sample products, used for shipping costs.
- **Require customer account**: on by default. Per-customer limits can only be enforced reliably on identified customers.
- **Customer group discounts on samples**: apply (PrestaShop default) or do not apply. See "Prices and group discounts".
- **Samples category**: default category of all sample products. Keep it disabled. If you pick another category, existing samples are moved to it.
- **Redirect sample pages**: on by default. A visitor landing on a sample product page gets a 301 redirect to the source product.
- **Conversion counted on**: purchase of the sampled product only, or any subsequent purchase.

### Limits

- **Max samples per cart**: 0 = unlimited.
- **Max samples per customer per window**: all sample products combined, 0 = unlimited.
- **Rolling window**: in days, 30 by default. With 0, the customer limits apply to all past orders, with no time limit.

### Automatic follow-up

- **Enable follow-up emails**.
- **Delay after sample order**: in days, 14 by default.
- **Only customers subscribed to the newsletter**: turn it on if your legal basis for commercial emails is consent.
- **Include a discount voucher**: a single-use voucher restricted to the customer is generated for each follow-up.
- **Voucher amount**: percentage, 10 by default.
- **Voucher validity**: in days, 30 by default.

The cron URL is shown in this section and in the dashboard.

## Showing the button with Creative Elements or a custom theme

When the product page is built with a page builder, native hooks are not always rendered, or not where you want them. The module provides a dedicated hook, `displayDfSamplesButton`.

1. In the settings, set **Button position** to **Custom placement only (displayDfSamplesButton)**. The button is then no longer added to the native hooks, which avoids showing it twice.
2. With **Creative Elements**: in the product page template, add the **Module** widget where you want the button, select the DF Samples module and the `displayDfSamplesButton` hook.
3. In a **custom theme**: add `{hook h='displayDfSamplesButton'}` to the product page template, for example `templates/catalog/product.tpl`.

Wherever it is placed, the button follows the selected combination and updates when the customer changes it.

## Prices and group discounts

The sample price is independent of the source product: tiered prices, specific prices and the minimum quantity of the source product do not apply. Only a catalog price rule targeting all products without distinction would also apply to samples.

A customer group discount (**Customers > Groups**, for example -15% for resellers) applies by default to all products, samples included. With **Do not apply: samples keep their price**, the module excludes sample products from each group's discount: your resellers pay the set sample price, and the discount still applies to the rest of the catalog. Groups created later are handled automatically.

The button shows the price the logged-in customer will pay, group discount and tax included.

## Limits and cart enforcement

The rules are checked every time the cart is saved, not only when the button is clicked. Adding through the + and - buttons on the cart page, a direct add-to-cart URL, "Reorder" or the cart merge at login goes through the same checks:

1. lines of disabled samples are removed;
2. duplicates are removed (same sample, or same combination in option mode);
3. the quantity of each line is set back to 1;
4. the per-cart maximum is applied;
5. the per-product maximum and the global per-customer maximum are applied over the rolling window.

When a line has to go, the most recent one is removed. The customer sees a message on the cart or checkout page. Cancelled, refunded or payment-error orders do not count toward the limits. Carts built by an employee in the back office are not subject to the limits.

## Setting up the cron job

Follow-ups are sent by a cron job. Schedule the URL shown in the settings every hour. Crontab example:

```
0 * * * * wget -q -O /dev/null "https://your-shop.com/module/dfsamples/cron?token=YOUR_TOKEN"
```

Each run processes up to 50 orders and returns a JSON summary: `processed`, `sent`, `skipped`, `waiting` and `retry`.

### Rules applied by the cron job

- One email per order, even when it contains several samples. It lists the tested products and holds at most one voucher.
- Only samples that are not converted and not yet followed up are considered, once the delay has passed.
- The sample order must have reached a paid, shipped or delivered status. An order still awaiting payment is checked again later, then dropped if it is still unpaid 60 days after the follow-up due date.
- Cancelled, refunded or payment-error orders are ignored.
- A sample whose product was bought in the same order gets no follow-up.
- With the newsletter option on, customers who are not subscribed get no follow-up.
- If sending fails, the module retries on later runs, up to three times and at least six hours apart. The voucher generated for an email that was not sent is deleted.
- Two simultaneous runs cannot send the same email: each order is claimed before processing.

## Conversion tracking

When an order containing a sample is validated, the module records the customer, their email, the source product, the combination, the language and the shop.

When this customer places a later order, the matching samples are marked as converted:

- in **product** mode (default): if the order contains the product they sampled;
- in **any purchase** mode: as soon as the order contains a real product.

A conversion is only counted once the purchase order reaches a validated status (payment accepted, for example). An order paid by bank transfer is therefore counted when the payment is received. A purchase in the same order as the sample is not a conversion.

## Dashboard

The panel above the product list shows:

- **Samples ordered**: number of recorded sample lines;
- **Conversions**: number of samples followed by a purchase, and the conversion rate;
- **Revenue from conversions**: total tax-incl. amount of the conversion orders, converted to the default currency;
- **Pending follow-ups**.

The product list also shows, per product, the number of samples ordered, the number of conversions and whether option mode is on.

## Follow-up emails

The templates are in the module's `mails` folder, in French, English, Spanish, German and Italian, as HTML and text (`dfsamples_followup`). For other installed languages, the English template is copied on installation: translate it in the `mails/` folder followed by the language code, for example `mails/nl/`.

Available variables:

- `{firstname}` and `{lastname}`;
- `{product_name}`: the tested product or products, comma-separated;
- `{product_link}`: link to the first product's page;
- `{voucher_block}`: formatted voucher for the HTML version, empty when the voucher is off;
- `{voucher_text}`: same content for the text version;
- `{shop_name}`.

## Discount vouchers

When the option is on, each follow-up creates a PrestaShop cart rule:

- code in the format SMPL followed by eight random characters;
- restricted to the recipient, usable once;
- percentage discount, configurable validity.

Vouchers are listed in **Catalog > Discounts > Cart Rules**.

## Catalog, sitemap and product feeds

Sample products have the "nowhere" visibility and sit in the disabled Samples category. They do not appear in listings, search or featured blocks, and their page redirects to the source product. Most sitemap and feed modules skip these products. If yours includes them, exclude the Samples category or references starting with SMPL in its settings.

## Checkout compatibility

The module does not touch the checkout: a sample is a regular product line. It works with the native checkout and with one-page checkouts that reuse the native PrestaShop steps. The sample removal message is shown on the cart and checkout pages.

## Uninstalling

Uninstalling removes the module's tables, settings and tab. Sample products are **disabled, not deleted**, and the Samples category is kept, so your order history stays consistent. A reinstall reuses this category. You can delete these products and the category manually if you no longer need them.

## Troubleshooting

### The button does not appear on the product page

Check that the product is enrolled and active in **Catalog > Samples (DF)**. Then change the button position: some themes do not render displayProductActions. With a page builder, use the displayDfSamplesButton hook.

### A message is shown instead of the button

"You have reached the sample limit for this product": the customer reached their maximum within the rolling window. "Your cart already contains the maximum of N samples per order": the per-cart maximum is reached. Adjust the limits if needed.

### Sample products have no image

This affected samples created by version 1.0.0 on PrestaShop 9. Click **Resync sample products**: missing images are added.

### The displayed price is not the expected one

The price is entered tax included and converted using the source product's tax rule. For a customer in a discounted group, check the "Customer group discounts on samples" setting. A global catalog price rule also applies to samples.

### Follow-ups are not sent

Open the cron URL in a browser and read the JSON summary. `enabled: false` means follow-ups are turned off. `waiting` counts sample orders not yet paid. Also check the delay, the newsletter option and the shop's email configuration (**Advanced Parameters > E-mail**).

### A sample disappears from the cart

This is the cart enforcement: duplicate, per-cart maximum or customer limit reached. The customer sees a message on the cart page.
