# Shopware 6 Sales Counter: installation and configuration guide

> This guide covers the installation, configuration and customisation of the DfSalesCounter plugin, which displays on every product page how many times a product has already been sold, based on the…

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

This guide covers the installation, configuration and customisation of the **DfSalesCounter** plugin, which displays on every product page how many times a product has already been sold, based on the real orders of your Shopware 6 shop.

## Requirements

- Shopware 6.5.x, 6.6.x or 6.7.x in a self-hosted installation. Shopware Cloud (SaaS) does not accept server plugins.
- PHP 8.1 or higher.
- A storefront theme derived from the Shopware Storefront theme, or a custom theme that keeps the standard Twig blocks of the buy widget.
- Command line access is recommended for theme compilation, but installation through the administration works too.

## Installation

### ZIP upload from the administration

1. In the Shopware administration, open _Extensions_, then _My extensions_.
2. Click _Upload extension_ and select the `DfSalesCounter-1.0.0.zip` file.
3. Once the plugin is listed, click _Install_, then activate it with the toggle.
4. Recompile the theme from _Content_, _Themes_, selecting your theme and then _Recompile theme_. This step is needed only once, because the plugin ships a storefront stylesheet.

### Command line

Drop the `DfSalesCounter` folder into `custom/plugins/` of your installation, then run:

```
bin/console plugin:refresh
bin/console plugin:install --activate DfSalesCounter
bin/console theme:compile
bin/console cache:clear
```

On an environment with a deployment pipeline, theme compilation is usually already part of the standard steps.

## Configuration

The configuration page lives in _Extensions_, _My extensions_, the _..._ button on the right of DataFirefly Sales Counter, then _Configure_. The selector at the top of the page lets you pick the sales channel the configuration applies to: each channel can have its own threshold, its own wording and its own placement.

### General tab

- **Enable sales counter**: main switch. When off, no query runs and no badge is rendered.
- **Counting mode**: _Quantity sold_ adds up every ordered quantity of the product. _Number of orders_ counts the distinct orders that included the product. The first mode emphasises volume, the second one emphasises how many different customers were convinced.
- **Orders taken into account**: _All orders_ gives the raw figure. _Exclude cancelled orders_ drops those whose state machine state is `cancelled`. _Paid orders only_ keeps only orders with a transaction in `paid` or `paid_partially` state.
- **Minimum threshold before display**: below this value no badge appears. The default is 5. A threshold of 0 is treated as 1, the badge is never rendered for a product with no sales.
- **Period in days**: restricts counting to the last X days, based on the order date. The value 0 means a lifetime total.
- **Aggregate sales across all variants**: adds up the sales of the parent product and all of its variants. Recommended on a fashion or size-based catalogue, to be turned off when each variant matches a distinct use case.
- **Count only orders of the current sales channel**: prevents a B2B storefront or an export channel from inflating the figures shown on the consumer shop.

### Display tab

- **Position on the product page**: _Under the product name_, _Under the price_, or _Under the buy box_, meaning at the bottom of the box, below the add to cart button.
- **Visual style**: _Badge_ renders a bordered pill, _Simple text_ renders a line with no frame, _Banner_ renders a full width block with a coloured side bar.
- **Icon**: flame, cart, check, or none. Icons are inline SVG, no icon font is loaded.
- **Accent colour**: left empty, the primary colour of the theme is used. When filled, it feeds the `--df-sales-counter-accent` CSS variable on the badge element.
- **Thousands separator**: narrow space, comma, dot or none. Useful as soon as counters go past a thousand.
- **Custom text**: see the next section.
- **Cache lifetime in seconds**: 900 by default. The value 0 disables the cache and queries the database on every product page view.

## Customising the wording

### Global text from the configuration

The _Custom text_ field accepts a sentence with the `%count%` placeholder where the number should appear. Example: `This model has shipped %count% times this month`. That text is shared across every language of the sales channel. It is sanitised before rendering, which allows simple markup such as `` but blocks any script.

### Per-language wording through snippets

Leave the _Custom text_ field empty to drive the wording language by language. Open _Settings_, _Shop_, _Snippets_, then search for `dfSalesCounter`. Four keys are available:

- `dfSalesCounter.badge.quantitySingular` and `dfSalesCounter.badge.quantityPlural`, used in quantity sold mode.
- `dfSalesCounter.badge.ordersSingular` and `dfSalesCounter.badge.ordersPlural`, used in number of orders mode.

Each value accepts the `%count%` placeholder. English, French, Spanish, German and Italian translations ship with the plugin. A value edited in the snippet manager takes precedence over the plugin one, including after an update.

## How the figure is computed

The plugin reads product-type order line items, joined to the order and its state. The computation runs as a single aggregated query, with no background job and no dedicated table.

- In quantity mode, the query sums the quantity column of the order line items.
- In order mode, it counts distinct order identifiers.
- Only the live version of orders is taken into account, working versions created during a credit note or an order edit are ignored.
- With variant aggregation enabled, the plugin first resolves the family of the displayed product, parent product and variants, then filters on the whole set of identifiers.

If the result is below the configured threshold, no extension is added to the product and the template renders nothing. The badge therefore does not exist in the HTML, which avoids any leftover display through a theme CSS rule.

## Cache and freshness

The result is stored in the Symfony application cache pool, under a key combining the product identifier, the sales channel and a signature of the options that influence the computation. Changing the counting mode, the order scope, the period or the aggregation options changes that signature and therefore invalidates previous values automatically.

On every order placed, the plugin purges the cache of the products contained in that order, along with that of their parent product. The counter therefore reflects the sale without waiting for the configured lifetime to expire.

On a modest catalogue the cache lifetime can be set to 0 with no noticeable consequence: the query hits indexed columns. On a large catalogue with heavy traffic, keep a lifetime of several minutes.

## Advanced rendering customisation

The plugin extends the product page buy widget and adds its badge in three standard Twig blocks, depending on the chosen placement: the product name block, the price container block and the buy container block. The badge itself is rendered by a dedicated component template, `storefront/component/df-sales-counter/badge.html.twig`, which exposes two overridable blocks, one for the icon and one for the text.

From a theme or a plugin, the extension is accessible in Twig on the page product under the name `dfSalesCounter`. It exposes the raw number, the formatted number, the placement, the style, the icon, the accent colour, the custom text and the counting mode. You can therefore render the counter somewhere other than the buy box, for instance in a product information tab, by fetching the extension and including the component.

Styles are defined in `Resources/app/storefront/src/scss/base.scss` around the `df-sales-counter`, `df-sales-counter__icon` and `df-sales-counter__text` classes, with one modifier per visual style. Any rule of your theme compiled after the plugin one takes precedence, without having to modify the plugin.

## Troubleshooting

### No badge appears

Check in order: the plugin is activated, the enable switch is on for the right sales channel, the product has reached the configured threshold, and the selected order scope does not exclude all your orders. A threshold of 5 with a _Paid orders only_ scope on a test shop whose orders are never marked as paid will never produce any display.

### The badge appears unstyled

The theme was not recompiled after activation. Run `bin/console theme:compile` or use the recompile button in the administration.

### The figure seems frozen

The cache lifetime has not elapsed yet. Clear the application cache with `bin/console cache:pool:clear cache.app`, or temporarily set the lifetime to 0 to validate the computation.

### The badge is not in the right place

A heavily customised theme may have removed or renamed the Twig blocks of the buy widget. Try another placement in the configuration, or include the component manually in your template by fetching the product extension.

## Update and uninstall

An update is performed by uploading the new ZIP then clicking _Update_, followed by a theme recompilation if the version contains style changes. The configuration is kept.

On uninstall, a checkbox offers to keep user data. Unchecked, every configuration key of the plugin is removed. The plugin creates no table and runs no migration, so uninstalling leaves nothing in the database beyond its configuration.

## Configuration key reference

Every key is prefixed with `DfSalesCounter.config.` and can be handled through the Admin API or the `system:config:set` command:

- `active`, boolean
- `countMode`, values `quantity` or `orders`
- `orderScope`, values `all`, `notCancelled` or `paid`
- `minThreshold`, integer
- `periodDays`, integer
- `aggregateVariants`, boolean
- `scopeToSalesChannel`, boolean
- `position`, values `afterName`, `afterPrice` or `afterBuy`
- `style`, values `badge`, `inline` or `banner`
- `icon`, values `none`, `flame`, `cart` or `check`
- `accentColor`, hexadecimal string
- `thousandSeparator`, values `space`, `comma`, `dot` or `none`
- `customText`, string
- `cacheTtl`, integer in seconds
