# DataFirefly Live Counters: guia completo

> O DataFirefly Live Counters mostra na sua loja PrestaShop um widget de contadores animados alimentado em parte automaticamente pela sua base de dados (clientes ativos, encomendas expedidas, produtos, países servidos)…

- Página: <https://www.datafirefly.com/pt/documentation/dflivecounters/>
- Idioma: pt
- Atualizado em: 2026-09-02
- Outros idiomas: [fr](https://www.datafirefly.com/documentation/dflivecounters/index.md), [en](https://www.datafirefly.com/en/documentation/dflivecounters/index.md), [es](https://www.datafirefly.com/es/documentation/dflivecounters/index.md), [de](https://www.datafirefly.com/de/documentation/dflivecounters/index.md), [it](https://www.datafirefly.com/it/documentation/dflivecounters/index.md), [pl](https://www.datafirefly.com/pl/documentation/dflivecounters/index.md), [nl](https://www.datafirefly.com/nl/documentation/dflivecounters/index.md)
- Índice: <https://www.datafirefly.com/pt/documentation/llms.txt>

O DataFirefly Live Counters mostra na sua loja PrestaShop um widget de contadores animados alimentado em parte automaticamente pela sua base de dados (clientes ativos, encomendas expedidas, produtos, países servidos) e em parte por valores que introduz (avaliações, satisfação, seguidores nas redes sociais…). O widget posiciona-se nativamente em vários hooks (página inicial, rodapé, carrinho, colunas) ou em qualquer sítio do seu tema através da tag Smarty `widget name="dflivecounters"`. Esta documentação cobre a instalação, a configuração dos 17 contadores disponíveis, os 5 temas visuais, a estratégia de cache, a ligação às APIs do Facebook e do Instagram, a atualização AJAX em direto e a resolução dos principais problemas.

## Instalação

1. Transfira o arquivo `dflivecounters.zip` a partir da sua conta DataFirefly.
2. Back-office PrestaShop → **Módulos** → **Carregar um módulo** → envie o ZIP.
3. Na instalação, o módulo regista 7 hooks de apresentação e inicializa uma dezena de variáveis de configuração. **Não é criada nenhuma tabela SQL**: todas as definições são guardadas em `ps_configuration`.
4. O módulo carrega o seu autoloader PSR-4 autónomo: não é necessário nenhum `composer install` no servidor.

Compatível com PrestaShop 8.0 a 9.x, PHP 8.1+. Multiloja nativo, multilingue através do sistema nativo do PrestaShop. Compatível com o modo de demonstração.

## Aspeto do widget

Abra **Módulos → DataFirefly Live Counters → Configurar**. A primeira secção reúne as definições de aspeto global.

### Tema visual

Cinco temas prontos a usar:

- **Minimal**: sobriedade máxima, fundo branco, ideal para temas minimalistas.
- **Glassmorphism**: vidro fosco com `backdrop-blur`, fundo ligeiramente tingido com a cor primária. Muito atual.
- **Gradient**: fundo em gradiente de largura total, da cor primária para um tom escuro. Forte impacto visual, texto branco.
- **Card**: cartões brancos elevados com sombra suave e hover. Clássico premium.
- **Flat**: fundo ligeiramente tingido com a cor primária, valores coloridos na cor primária.

### Título e subtítulo

Apresentados acima da grelha de contadores. Deixe vazios para ocultar o cabeçalho (útil no rodapé, onde o contexto já é dado pelo ambiente).

### Cores

Três cores principais comandam todo o widget através de variáveis CSS (`--dflc-primary`, `--dflc-text`, `--dflc-bg`):

- **Cor principal**: ícones por defeito, destaque do tema Flat, gradiente do tema Gradient.
- **Cor do texto**: título, subtítulo, valores e etiquetas.
- **Cor de fundo**: fundo da secção (ignorada nos temas Glassmorphism e Gradient, que aplicam o seu próprio fundo).

Cada contador pode também ter **a sua própria cor de ícone** (campo «Icon color» na linha do contador), o que permite por exemplo manter os ícones do Facebook e do Instagram nas cores da marca respetiva, conservando a coerência do resto.

### Colunas

Duas definições independentes:

- **Colunas desktop**: 1 a 6 (por defeito 4).
- **Colunas mobile**: 1 a 3 (por defeito 2). O breakpoint é 768 px.

### Duração da animação CountUp

Duração em milissegundos durante a qual os números correm de 0 até ao valor alvo (por defeito 2 000 ms). É aplicada uma curva de ease-out cúbica para uma desaceleração suave. Coloque `0` para desativar a animação e mostrar o valor final de imediato.

Nos dispositivos com `prefers-reduced-motion: reduce`, a animação é automaticamente desativada, qualquer que seja a duração configurada.

### Atualização AJAX em direto (opcional)

Quando ativada, o widget consulta periodicamente um endpoint JSON para atualizar os valores sem recarregar a página. Dois parâmetros:

- **Live refresh**: ON/OFF.
- **Intervalo**: em segundos, mínimo 30 (por defeito 60). Definição forçada a 30 se introduzir menos.

O endpoint responde com um `Cache-Control: public, max-age=30` que permite ao seu CDN absorver o tráfego. A animação de transição de um valor para outro arranca a partir do valor anteriormente apresentado, não a partir de zero: o efeito visual é mais natural.

### «Date from»

Data de referência usada por dois contadores:

- **Encomendas expedidas**: contabiliza apenas as encomendas criadas depois desta data (filtro `WHERE date_add >= ?`).
- **Anos de experiência**: calcula automaticamente o número de anos decorridos desde essa data até hoje.

## Catálogo dos contadores

Estão disponíveis 17 contadores, distribuídos por três grupos consoante o modo de cálculo.

### Contadores automáticos (5)

Estes contadores leem em tempo real os dados do seu PrestaShop. Nenhuma introdução necessária.

- **Clientes**: clientes ativos (`active = 1 AND deleted = 0`), delimitados ao contexto da loja. TTL 15 min.
- **Encomendas expedidas**: encomendas com pelo menos um histórico de estado entre os estados selecionados (campo «Order states counted as shipped»). Se nenhum estado estiver selecionado, o módulo usa automaticamente o flag `shipped = 1` da tabela `ps_order_state`. TTL 15 min.
- **Encomendas tratadas**: todas as encomendas cujo estado atual tem o flag `logable = 1` (o flag canónico do PrestaShop para as encomendas que contam nas estatísticas). Exclui portanto anulações e reembolsos. TTL 15 min.
- **Produtos**: produtos ativos e visíveis do catálogo, delimitados ao contexto da loja. TTL 30 min.
- **Países servidos**: número de países distintos que receberam pelo menos uma encomenda (`COUNT(DISTINCT id_country)` na tabela `ps_address` em join com `ps_orders`). TTL 1 h.

### Contadores híbridos (4)

Estes contadores tentam primeiro um cálculo automático e recorrem depois ao valor manual que introduziu como reserva.

- **Anos de experiência**: calculado a partir da data «Date from»; valor manual se preferir fixar um número arredondado (ex.: «12» em vez de «11»). TTL 24 h.
- **Artigos publicados**: deteção automática das tabelas dos principais módulos de blogue PrestaShop (`smart_blog_post`, `prestablog_news`, `psblog_post`, `ph_simpleblog_post`) através de `INFORMATION_SCHEMA`. Se não houver correspondência, use o valor manual. TTL 24 h.
- **Seguidores Facebook**: chamada à Graph API do Facebook com um Page Access Token de longa duração. Reserva manual se não estiver configurado ou se a API falhar. TTL 1 h.
- **Seguidores Instagram**: chamada à Graph API do Instagram (conta Business ou Creator obrigatória). Reserva manual. TTL 1 h.

### Contadores manuais (8)

Estes contadores mostram simplesmente o valor que introduz. Ideais para as métricas que o PrestaShop não consegue calcular ou que quer controlar totalmente.

- **Avaliações de clientes**: número de avaliações (Trustpilot, Google, plataformas de avaliações certificadas, etc.).
- **Satisfação**: taxa de satisfação. Dica: use um sufixo «%» e um valor 0–100.
- **CO₂ poupado**: kg de emissões evitadas. Dica: sufixo «kg».
- **Prémios**: prémios, certificações, distinções.
- **Horas de suporte**: sufixo «h».
- **Seguidores TikTok**: a Display API do TikTok exige um OAuth por utilizador, impraticável para um widget público. Introdução manual.
- **Seguidores X (Twitter)**: a API X v2 é paga. Introdução manual.
- **Seguidores LinkedIn**: o LinkedIn Organization Followers exige aprovação na Marketing Developer Platform. Introdução manual.

## Configuração por contador

Cada linha de contador na administração propõe as mesmas definições:

- **Ativo** (ON/OFF): só os contadores ativos aparecem no widget. A ordem de apresentação segue a da administração.
- **Etiqueta personalizada**: substitui a etiqueta por defeito. Deixe vazio para usar a etiqueta nativa traduzida no idioma do visitante.
- **Valor (manual)**: para os contadores manuais e a reserva dos híbridos.
- **Offset**: inteiro adicionado ao valor calculado. Prático para partir de um número mais favorável sem tocar na base de dados. Nos contadores «Clientes» e «Encomendas expedidas», por exemplo, pode adicionar respetivamente +500 e +2 000 se a sua loja acabou de ser migrada. A etiqueta «Current live» ao lado do campo Offset indica o valor bruto calculado pelo PrestaShop, sem offset.
- **Prefixo / Sufixo**: 4 e 6 caracteres respetivamente. O prefixo e o sufixo permanecem fixos mesmo durante a animação.
- **Casas decimais**: 0 a 3. A formatação usa `Intl.NumberFormat` com a localidade do visitante (separadores de milhares e vírgula decimal localizados).
- **Cor do ícone**: substitui a cor primária apenas para esse ícone.

As etiquetas personalizadas são guardadas na configuração **por loja e por idioma** através do sistema nativo do PrestaShop. Pode assim ter «Clientes satisfeitos» em português e «Happy customers» em inglês, ou mesmo uma etiqueta diferente por loja em multiloja.

## Estados de encomenda «expedidos»

O contador «Encomendas expedidas» baseia-se por defeito no histórico dos estados. A definição **Order states counted as shipped** permite escolher com precisão os estados que contam. Numa instalação PrestaShop padrão, são os estados ID 4 (Expedida) e 5 (Entregue) que estão pré-configurados.

Se a sua loja usa estados personalizados (ex.: «Entrega em mão», «Click & Collect levantado»), lembre-se de os adicionar à seleção, caso contrário essas encomendas não serão contabilizadas.

Se nenhum estado estiver selecionado, o módulo recorre a uma reserva que consulta o flag `shipped = 1` da tabela `ps_order_state`. Esta abordagem é mais permissiva e abrange a maioria das configurações correntes.

## Configurar o Facebook

1. Aceda a [developers.facebook.com](https://developers.facebook.com/) e crie uma App de tipo «Business».
2. Na secção **Graph API Explorer**, selecione a sua App e depois a sua Página Facebook.
3. Gere um **Page Access Token** com os scopes `pages_read_engagement` e `pages_show_list`.
4. Troque esse token curto (1 h) por um **token de longa duração** (60 dias) através do endpoint `/oauth/access_token?grant_type=fb_exchange_token`.
5. Obtenha o seu **Page ID** nas definições da sua Página (secção «Transparência da Página» ou diretamente no Graph API Explorer).
6. Preencha os dois campos na configuração do Live Counters e guarde. O contador Facebook é atualizado ao guardar.

O token de longa duração expira ao fim de 60 dias. Depois disso, o contador recorre à reserva manual. Crie um lembrete para renovar o token antes da expiração.

## Configurar o Instagram

1. A sua conta Instagram tem de estar em modo **Business** ou **Creator**. As contas pessoais não são suportadas pela Graph API.
2. Associe a sua conta Instagram a uma Página Facebook (definições da Página → Instagram).
3. No Graph API Explorer, consulte `/me/accounts` com o seu Page Access Token para obter o **Instagram User ID** associado (campo `instagram_business_account`).
4. Use o mesmo token Facebook de longa duração para a API do Instagram.
5. Preencha o IG User ID e o token na configuração do Live Counters.

## Estratégia de cache

A cache funciona a dois níveis para garantir um TTFB constante mesmo sob tráfego.

### Cache por contador

Cada contador tem o seu próprio TTL:

- 15 minutos: Clientes, Encomendas expedidas, Encomendas tratadas.
- 30 minutos: Produtos.
- 1 hora: Países servidos, Facebook, Instagram.
- 24 horas: Anos de experiência, Artigos publicados e todos os contadores manuais.

A cache usa primeiro a camada `Cache` nativa do PrestaShop (memcached, APCu ou Redis, se configurados no seu servidor), e depois uma reserva em sistema de ficheiros em `var/cache/dflivecounters/`. Isso garante que os TTL são respeitados mesmo que a camada nativa esteja em modo «no-cache».

### Cache do widget renderizado

O HTML completo do widget é ele próprio colocado em cache durante **60 segundos** por idioma e por hook (`dflc_widget_LANG_HASH`). Esta segunda camada absorve a maioria do tráfego mesmo quando os contadores internos já estão atualizados.

### Limpeza automática

- Guardar a configuração limpa automaticamente todas as caches do módulo.
- Um botão **Limpar a cache** está disponível no painel de administração para invalidação manual.
- A desinstalação do módulo limpa a cache automaticamente.

O painel de administração mostra as estatísticas em direto: número de entradas em cache, tamanho em KB, caminho da pasta. Útil para verificar que a cache em sistema de ficheiros está ativa.

## Posicionar o widget no seu tema

O módulo regista 7 hooks na instalação:

- `displayHome`: página inicial
- `displayFooter`: rodapé
- `displayFooterBefore`: imediatamente antes do rodapé (PS 8+)
- `displayLeftColumn` / `displayRightColumn`: colunas laterais
- `displayShoppingCartFooter`: página do carrinho, por baixo do resumo
- `actionFrontControllerSetMedia`: regista os recursos CSS/JS

Pode adicionar ou remover hooks em **Design → Posições** no back-office.

### Posicionamento livre através do Smarty

Para posicionar o widget num sítio preciso do seu tema (ex.: na página de produto, por baixo do título de uma categoria), use a tag widget Smarty:

```
{widget name="dflivecounters"}
```

O widget implementa a interface `WidgetInterface` nativa do PrestaShop, o que o torna chamável a partir de qualquer template `.tpl` do seu tema.

## Personalizar o template do widget

O template Smarty principal é `views/templates/hook/widget.tpl`. Para o substituir sem modificar o módulo (de forma a preservar as atualizações), copie-o para o seu tema, na pasta `themes/o-seu-tema/modules/dflivecounters/views/templates/hook/widget.tpl`.

Variáveis Smarty expostas:

- `{$dflc.counters}`: array de cada contador com as chaves `key`, `label`, `value`, `icon`, `prefix`, `suffix`, `decimals`, `icon_color`
- `{$dflc.theme}`: slug do tema (`minimal`, `glassmorphism`, `gradient`, `card`, `flat`)
- `{$dflc.title}`, `{$dflc.subtitle}`
- `{$dflc.primary_color}`, `{$dflc.text_color}`, `{$dflc.bg_color}`
- `{$dflc.cols_desktop}`, `{$dflc.cols_mobile}`
- `{$dflc.hook}`: nome do hook de origem (útil para adaptar a renderização consoante o posicionamento)

## Endpoint AJAX

O controlador front-office `refresh` expõe um URL JSON utilizável pela atualização em direto ou por qualquer integração de terceiros:

```
index.php?fc=module&module=dflivecounters&controller=refresh
```

A resposta JSON contém um booleano `success`, um `timestamp` Unix e um objeto `counters` em que cada chave é o identificador do contador (customers, shipped_orders, facebook, instagram, etc.) e cada valor é o número atual. O conteúdo reflete os contadores ativos no momento da chamada, com os offsets aplicados. A resposta é servida com `Cache-Control: public, max-age=30`.

## Acessibilidade

O widget é concebido para respeitar as recomendações WCAG 2.2 AA:

- Estrutura semântica: `section`, `header`, `ul role="list"`, `li`.
- Todos os ícones SVG têm `aria-hidden="true"` (decorativos).
- Respeito estrito de `prefers-reduced-motion: reduce`: animação desativada, valor final apresentado de imediato.
- Contrastes: as cores por defeito respeitam um rácio superior a 4.5:1 nos temas Minimal e Card. Verifique as suas cores personalizadas com uma ferramenta como o axe DevTools.
- Formato dos números: `font-variant-numeric: tabular-nums` para uma largura de dígito constante (evita o «salto» visual durante a animação).

## RGPD

O widget é concebido para não exigir nenhuma menção de consentimento:

- Nenhum cookie colocado do lado do visitante.
- Nenhum script de terceiros carregado (sem Facebook Pixel, sem Google Tag Manager).
- As chamadas às APIs do Facebook e do Instagram são feitas **do lado do servidor em PHP**, nunca a partir do navegador. Nenhum dado do visitante é transmitido à Meta.
- Nenhum dado pessoal recolhido ou guardado pelo módulo.

## Compatibilidade e notas técnicas

- PrestaShop 8.0 a 9.x, PHP 8.1+.
- Multiloja nativo: todas as consultas SQL são delimitadas ao `Shop::getContextListShopID()`.
- Multilingue: sistema multilingue nativo do PrestaShop.
- Nenhuma tabela SQL criada: configuração guardada em `ps_configuration`.
- Autoloader PSR-4 autónomo (sem `composer install` no servidor).
- WidgetInterface nativa do PrestaShop: utilizável através de `{widget name="dflivecounters"}`.
- Peso dos recursos: 3 KB JS, 2 KB CSS. Nenhum pedido externo por defeito.
- Conforme às convenções AJAX do PrestaShop 9: `$this->module->l()` em vez de `$this->l()`, controlador front-office dedicado para a atualização, nunca uma substituição de `ajaxRender`.

## FAQ e resolução de problemas

**O widget não aparece na página inicial.** Verifique que o módulo está ligado ao hook `displayHome` em **Design → Posições**. Verifique também que pelo menos um contador está ativo: sem contador ativo, o widget não devolve nada (silenciosamente).

**O contador Facebook fica a zero.** Várias causas possíveis: Page ID incorreto, token expirado (validade de 60 dias), scope em falta (`pages_read_engagement` é obrigatório). Limpe a cache do módulo e recarregue a configuração: o valor devolvido pela Graph API aparecerá ao lado da etiqueta «Current live».

**O contador Encomendas expedidas está demasiado baixo.** Verifique a seleção «Order states counted as shipped»: só os estados selecionados são contados. Se quiser incluir estados personalizados (ex.: «Click & Collect levantado»), adicione-os à seleção.

**Os números parecem congelados e não refletem o meu tráfego real.** É a cache a fazer o seu trabalho. O TTL por defeito vai de 15 minutos (clientes, encomendas) a 24 horas (contadores estáticos). Use o botão **Limpar a cache** para invalidar manualmente. Para uma atualização automática, ative o modo **Live refresh**.

**A animação CountUp não arranca.** O widget usa IntersectionObserver e dispara no momento em que entra no viewport. Se o widget já estiver visível no carregamento da página (ex.: colocado mesmo no topo), a animação arranca de imediato. Se ficar congelada a zero: verifique a consola JavaScript do seu navegador, outro módulo pode estar a quebrar o bundle JS.

**O widget prejudica o meu Lighthouse / Core Web Vitals.** Com um posicionamento no fundo da página (rodapé) e a cache de 60 s no HTML renderizado, o impacto CLS / LCP é negligenciável. Se constatar um problema, verifique que não ativou o **Live refresh** com um intervalo demasiado curto (o AJAX dispara enquanto o Lighthouse mede). Para uma auditoria limpa, desative a atualização em direto.

**Em multiloja, os contadores são delimitados por loja?** Sim. Todas as consultas SQL usam `Shop::getContextListShopID()`. Em modo «todas as lojas», os contadores acumulam; em modo «uma loja», contam apenas essa. As etiquetas e o valor manual são igualmente por loja e por idioma.

**Como adicionar um novo contador personalizado?** Crie uma classe que estenda `Df/LiveCounters/Counter/AbstractCounter` (ou `ManualCounter` para um contador 100% manual), implemente `getKey()`, `getDefaultLabel()` e `getValue()`, e adicione depois a instância ao array de instâncias do `CounterRegistry`. Para não perder o seu código na próxima atualização, crie um mini-módulo complementar que injete o seu contador no registry através de um hook personalizado. Contacte-nos para obter um exemplo.
