# Verificación de Edad PrestaShop – Modal Bloqueante para CBD, Alcohol, Vapeo y Profesionales Sanitarios

> El módulo dfagegate añade una modal de verificación de edad bloqueante a su tienda PrestaShop 8 o 9. Cubre dos mercados distintos: el modo estándar para productos regulados por edad…

- Página: <https://www.datafirefly.com/es/documentation/verification-age-prestashop-modal-cbd-alcool-vape-medical/>
- Idioma: es
- Actualizado el: 2026-09-28
- Otros idiomas: [fr](https://www.datafirefly.com/documentation/verification-age-prestashop-modal-cbd-alcool-vape-medical/index.md), [en](https://www.datafirefly.com/en/documentation/verification-age-prestashop-modal-cbd-alcool-vape-medical/index.md), [de](https://www.datafirefly.com/de/documentation/verification-age-prestashop-modal-cbd-alcool-vape-medical/index.md), [it](https://www.datafirefly.com/it/documentation/verification-age-prestashop-modal-cbd-alcool-vape-medical/index.md), [pl](https://www.datafirefly.com/pl/documentation/verification-age-prestashop-modal-cbd-alcool-vape-medical/index.md), [pt](https://www.datafirefly.com/pt/documentation/verification-age-prestashop-modal-cbd-alcool-vape-medical/index.md), [nl](https://www.datafirefly.com/nl/documentation/verification-age-prestashop-modal-cbd-alcool-vape-medical/index.md)
- Índice: <https://www.datafirefly.com/es/documentation/llms.txt>

El módulo **dfagegate** añade una modal de verificación de edad **bloqueante** a su tienda PrestaShop 8 o 9. Cubre dos mercados distintos: el **modo estándar** para productos regulados por edad (CBD, alcohol, vapeo, armería, mecheros, productos 18+), y el **modo médico** para dispositivos médicos reservados a profesionales sanitarios (en Francia, en el sentido del artículo L5122-9 del Código de Salud Pública).

**Compatibilidad** — PrestaShop 1.7.7+, 8.x y 9.0. PHP 7.4 mínimo, 8.1+ recomendado. Multitienda y multilingüe (FR/EN/ES/DE precargados en la instalación).

## Instalación

La instalación sigue el flujo estándar de PrestaShop. Tras la compra en DataFirefly, recibirá un archivo ZIP `dfagegate-X.Y.Z.zip`.

### Desde el back-office (recomendado)

1. Inicie sesión en su back-office PrestaShop
2. Vaya a **Módulos → Catálogo de módulos**
3. Haga clic en **Subir un módulo** arriba a la derecha
4. Seleccione el ZIP `dfagegate-X.Y.Z.zip`
5. Una vez subido, haga clic en **Instalar**

### Vía FTP

1. Descomprima el archivo localmente
2. Suba la carpeta `dfagegate/` al directorio `modules/` de su PrestaShop
3. Vaya a **Módulos → Catálogo de módulos**
4. Busque «DataFirefly Age Gate» y haga clic en **Instalar**

**Importante** — Tras la instalación, **el módulo está desactivado por defecto**. Es intencional: le permite configurar los textos y el modo antes de bloquear su tienda. Vaya a la configuración del módulo y active el interruptor en la pestaña _General_ una vez todo esté configurado.

## Configuración inicial

Acceda a la configuración: **Módulos → Módulos instalados → DataFirefly Age Gate → Configurar**.

La configuración se organiza en 6 pestañas:

- **General** — activación, modo, tipo de verificación, edad mínima, ámbito de visualización
- **Contenido** — textos multilingües (título, mensaje, botones, avisos legales)
- **Apariencia** — logo, colores, desenfoque de fondo
- **Comportamiento** — cookie, redirección, reglas de bypass
- **Modo médico** — profesiones y número de colegiado (solo aplica en modo médico)
- **Registros y RGPD** — registro, estadísticas y diagnóstico

### Pestaña General

- **Activar el módulo** — interruptor Sí/No, controla la visualización global de la modal
- **Modo** — _Estándar_ (CBD, alcohol, vapeo, armería) o _Médico_ (profesionales sanitarios)
- **Tipo de verificación** — _Botón sí/no_, _Fecha de nacimiento_, o _Declaración de profesión_
- **Edad mínima** — 18 por defecto, 21 en algunos mercados
- **Ámbito de visualización** — toda la tienda, categorías seleccionadas o productos seleccionados (ver más abajo)
- **Probar la modal** — botón que abre la tienda en modo de vista previa (ver la sección Diagnóstico)

**¿Qué tipo de verificación elegir?** El _botón sí/no_ es adecuado para la mayoría de los casos (CBD, alcohol general, vapeo): rápido, baja fricción, disuasión suficiente para una inspección regulatoria. La _fecha de nacimiento_ es más estricta y se recomienda para armerías o líquidos con nicotina. La _declaración de profesión_ está reservada al modo médico.

### Ámbito de visualización: seleccionar categorías o productos

Desde la versión 1.1.0, el ajuste **Ámbito de visualización** de la pestaña General ofrece tres modos:

- **Toda la tienda** — la modal se muestra en todas las páginas. Es el comportamiento histórico y el valor por defecto
- **Solo categorías seleccionadas** — la modal se muestra en las páginas de las categorías marcadas y en las fichas de los productos que les pertenecen. La selección se hace en un árbol de categorías con casillas, filtro de búsqueda instantáneo y contador de selección
- **Solo productos seleccionados** — la modal solo se muestra en las fichas de los productos elegidos. Busque por nombre o referencia, las sugerencias aparecen mientras escribe y cada producto retenido se convierte en una etiqueta eliminable

En el modo de categorías, la opción **Incluir las subcategorías** (activada por defecto) cubre automáticamente toda la descendencia de las categorías marcadas: marque «CBD» y sus subcategorías «Aceites», «Flores» o «Resinas» quedan cubiertas sin marcarlas una a una. La expansión se apoya en los nested sets de PrestaShop, en una sola consulta.

**¿Tienda mixta?** Es el caso de uso típico de la selección: una tienda gourmet que también vende licores, una parafarmacia con una sección de material profesional. Seleccione la sección regulada por categoría: queda protegida, y el resto de la tienda permanece sin modal.

**Modo productos y páginas de listado** — En el modo de productos seleccionados, las páginas de listado (categoría, búsqueda, novedades) no activan la modal: solo lo hacen las fichas de los productos elegidos. Para cubrir una sección entera, listados incluidos, prefiera la selección por categoría.

La decisión de visualización se toma **en el servidor**, no en JavaScript. El comentario de diagnóstico de la etiqueta head indica el ámbito activo: `scope=all`, `scope=categories` o `scope=products`. Al guardar, un ámbito seleccionado con una selección vacía se rechaza con un mensaje de error, para evitar dejar la configuración en un estado incoherente.

### Pestaña Contenido

Cada idioma activado en su PrestaShop dispone de su propio bloque de textos. Los valores por defecto vienen precargados en **FR, EN, ES y DE**. Para cada idioma puede configurar:

- **Título** — se muestra en grande en la parte superior de la modal (por defecto: «Verificación de edad»)
- **Mensaje** — texto explicativo principal, los saltos de línea se conservan
- **Botón confirmar** — etiqueta del botón positivo (por defecto: «Tengo 18 años o más»)
- **Botón rechazar** — etiqueta del botón negativo
- **Aviso legal** — texto al pie de la modal (p. ej. «El consumo abusivo de alcohol es peligroso para la salud.»)
- **Mensaje de rechazo** — pantalla mostrada cuando el usuario rechaza, antes de la redirección

**HTML** — El contenido se sanea al guardar (solo texto plano). Los saltos de línea se convierten en etiquetas de salto al renderizar mediante un filtro `nl2br` automático.

### Pestaña Apariencia

- **Logo** — PNG, JPG, SVG o WEBP, 2 MB máx., mostrado en la parte superior de la modal
- **Color de fondo** — color de la tarjeta principal (blanco por defecto)
- **Color primario** — título y botón principal (negro #111111 por defecto)
- **Color del texto** — cuerpo del mensaje
- **Color del overlay** — velo detrás de la modal, acepta formatos CSS `rgba()` y hex (por defecto: `rgba(15,15,20,0.85)`)
- **Desenfoque de fondo** — efecto moderno, funciona en todos los navegadores actuales

### Pestaña Comportamiento

- **Duración de la cookie** — en días (90 por defecto). Ponga `0` para una cookie de sesión (eliminada al cerrar el navegador)
- **URL de redirección al rechazar** — deje vacío para mostrar solo el mensaje de rechazo, o indique una URL externa
- **Bypass de IPs** — lista de IPs (una por línea) para las que la modal nunca se muestra. Ideal para usted y su equipo durante las pruebas
- **Bypass de URLs** — rutas parciales excluidas. Precargado con `/legal`, `/contact` y otras páginas legales
- **Bypass de clientes conectados** — si se activa, los clientes ya autenticados nunca ven la modal

### Pestaña Modo médico

Esta pestaña solo aplica cuando el **modo** es _Médico_ y el **tipo de verificación** es _Declaración de profesión_.

- **Lista de profesiones** — una por línea. Por defecto: Médico, Farmacéutico, Enfermero/a, Fisioterapeuta, Dentista, Veterinario, Otro profesional sanitario. Totalmente personalizable
- **Número de colegiado obligatorio** — si se activa, aparece un campo en la modal. Validación por regex que acepta de 9 a 11 dígitos. **El número no se almacena**, solo se valida en el servidor

**Cumplimiento legal** — El modo médico materializa una declaración jurada en el espíritu del artículo francés L5122-9 del Código de Salud Pública, que reserva la publicidad de ciertos dispositivos médicos a los profesionales sanitarios autorizados. **Este módulo no sustituye una revisión jurídica de su catálogo por un abogado especializado**. Consulte a su asesor para validar su configuración y verificar las normas equivalentes en su jurisdicción.

### Pestaña Registros y RGPD

- **Registrar los rechazos** — guarda cada rechazo en la tabla `ps_dfagegate_log` con IP hasheada SHA-256 (nunca en claro), fecha, motivo
- **Retención de los registros** — duración de conservación en días (365 por defecto, `0` para ilimitada). Los rechazos más antiguos que esta duración se eliminan automáticamente cada vez que se abre la página de configuración

Desde la versión 1.1.0, esta pestaña también muestra las **estadísticas de rechazos**: total de los últimos 30 días, reparto por motivo, y los 15 últimos rechazos con fecha, motivo, edad declarada y profesión cuando aplica. Un botón **Purgar todos los registros de rechazo** (con confirmación) vacía la tabla para la tienda actual.

Esta pestaña también muestra un resumen RGPD:

- **Cookie depositada** — `dfagegate_ok`
- **Categoría** — estrictamente necesaria (cumplimiento legal de acceso)
- **Datos** — valor «1», duración configurable, SameSite=Lax, Secure en HTTPS

## Configurar según su mercado

### Tienda CBD general

- Modo: **Estándar**
- Tipo de verificación: **Botón sí/no**
- Edad mínima: **18**
- Duración de la cookie: **90 días**
- URL de redirección: _vacía_ (solo mensaje de rechazo)

### Tienda de licores / alcohol premium

- Modo: **Estándar**
- Tipo de verificación: **Fecha de nacimiento** (control más estricto)
- Edad mínima: **18** (o 21 en mercados US)
- URL de redirección: cualquier página de información oficial

### Tienda de vapeo / e-líquidos con nicotina

- Modo: **Estándar**
- Tipo de verificación: **Fecha de nacimiento** (muy recomendado para nicotina)
- Edad mínima: **18**
- Registrar rechazos: **Sí** (útil en caso de inspección)

### Armería

- Modo: **Estándar**
- Tipo de verificación: **Fecha de nacimiento** (obligatorio)
- Edad mínima: **18**
- Bypass de URLs: añadir `/normativa`, `/licencia-de-caza`
- Registrar rechazos: **Sí**

### Tienda gourmet con sección de licores (tienda mixta)

- Modo: **Estándar**
- Tipo de verificación: **Botón sí/no**
- Ámbito de visualización: **Categorías seleccionadas**, con la categoría Licores marcada y las subcategorías incluidas
- Resultado: la modal solo se muestra en la sección de licores y sus fichas de producto, el resto de la tienda permanece sin fricción

### Tienda de material médico (dispositivos profesionales)

- Modo: **Médico**
- Tipo de verificación: **Declaración de profesión**
- Lista de profesiones: Médico, Farmacéutico, Fisioterapeuta, Osteópata (adaptar a su catálogo)
- Número de colegiado obligatorio: **Sí**
- Bypass de clientes conectados: **Sí** (si ya valida la profesión al registrarse)

## Cómo funciona la verificación por fecha de nacimiento

A diferencia de un simple botón, la verificación por fecha de nacimiento realiza el cálculo **en el servidor**, no en el navegador:

1. El visitante introduce día, mes y año en la modal
2. JavaScript envía estos valores al controlador AJAX `DfagegateAjaxModuleFrontController`
3. PHP valida la fecha con `checkdate()` y calcula la edad mediante `DateTimeImmutable::diff()`
4. Si la edad es inferior al umbral configurado, el servidor devuelve una respuesta JSON con `success=false, denied=true` y el mensaje de error
5. La modal muestra el mensaje de rechazo y redirige tras 2 segundos
6. Si la edad alcanza el umbral, se deposita la cookie `dfagegate_ok` y la modal se cierra

**¿Por qué en el servidor?** Un control puramente JavaScript puede eludirse mediante DevTools en menos de 10 segundos. El cálculo en servidor garantiza que un usuario menor de edad no pueda acceder al sitio, incluso con conocimientos técnicos. Es esencial para superar una inspección regulatoria.

Tenga en cuenta que **la fecha de nacimiento nunca se almacena** — se usa para un solo cálculo y luego se olvida. Solo se retiene la validación binaria (aceptado / rechazado) a través de la cookie.

## Cómo funciona el modo médico

1. La modal muestra un desplegable de profesiones (configurable) y opcionalmente un campo de número de colegiado
2. Hay una casilla obligatoria de **declaración jurada**
3. El controlador AJAX valida que se ha seleccionado una profesión
4. Si el número de colegiado es obligatorio, el servidor valida el formato mediante una expresión regular que acepta de 9 a 11 dígitos consecutivos
5. Sin almacenamiento: ni la profesión ni el número se conservan en la base de datos — la cookie `dfagegate_ok` solo materializa el paso exitoso

**Elección de diseño** — La regulación exige materializar la declaración, no necesariamente una verificación en tiempo real contra un registro nacional. Nuestro enfoque es _cumplimiento mínimo viable_: pedimos la declaración, la validamos formalmente, registramos el rechazo si está activado, pero no recopilamos datos personales innecesarios.

## Multitienda

El módulo es **100% compatible con multitienda**. Todas las configuraciones (modo, tipo de verificación, textos multilingües, colores, reglas de bypass, ámbito de visualización) se almacenan por contexto de tienda mediante `id_shop_group` e `id_shop`. Esto significa que un mismo PrestaShop puede alojar:

- Una tienda **CBD FR** en modo estándar a 18 años con textos en francés
- Una tienda **vapeo UK** en modo estándar a 18 años con textos en inglés
- Una tienda **material médico DE** en modo médico con número de colegiado obligatorio y textos en alemán

Para configurar una subtienda específica:

1. En el selector de contexto en la parte superior del back-office, elija la subtienda objetivo
2. Abra la configuración del módulo
3. Modifique los valores — se persistirán solo para esa tienda

Los **hooks se registran en todas las tiendas** en el momento de la instalación mediante `Shop::getCompleteListOfShopsID()`, evitando el problema clásico del módulo que solo funciona en la tienda actual.

## Compatibilidad con temas personalizados

El módulo utiliza el hook estándar `displayBeforeBodyClosingTag` para inyectar la modal justo antes del cierre de la etiqueta body. Este hook debería ser universal en PrestaShop 1.7.5+.

Desafortunadamente, **algunos temas personalizados no llaman a este hook** en su layout. Para este caso, dfagegate incluye un **fallback de inyección JavaScript**:

1. PHP pre-renderiza el HTML completo de la modal y lo pasa al JS mediante `Media::addJsDef`
2. En el `DOMContentLoaded`, el script comprueba si el elemento con ID `dfagegate-modal` existe en el DOM
3. Si existe, todo bien — el hook funcionó
4. Si no, el script inyecta la modal por sí mismo mediante `insertAdjacentHTML('beforeend', ...)`
5. Un mensaje `console.info` confirma la activación del fallback

**Resultado práctico** — El módulo funciona en cualquier tema PrestaShop 1.7.5+, incluidos los temas personalizados incompletos, **sin tocar el layout**. Puede desplegarlo sin coordinarse con su agencia de temas.

## Diagnóstico y depuración

Una vez activado, dfagegate añade un **comentario HTML en la etiqueta head** de cada página del front, con la forma «dfagegate v1.1.0 enabled=1 scope=all should_display=1».

Este comentario es su primer punto de diagnóstico. Consulte el código fuente de una página (Ctrl+U o Cmd+U) y busque «dfagegate».

| Comentario | Interpretación |
| --- | --- |
| Sin comentario | El hook `displayHeader` no está registrado — verifique que el módulo esté instalado y activo |
| `enabled=0` | El interruptor «Activar el módulo» está en No en la pestaña General |
| `enabled=1 should_display=0` | Un bypass está activo (su IP está en la lista blanca, la URL actual coincide con una ruta excluida, o es un cliente conectado con el bypass activado), o la página actual está fuera del ámbito seleccionado — compruebe el valor `scope=` |
| `enabled=1 should_display=1` | Todo correcto en el servidor. Si la modal no aparece, revise la consola del navegador |

### ¿La modal sigue sin aparecer?

1. ¿Está presente el comentario de diagnóstico con `should_display=1`? Si no, corrija la configuración
2. Abra la tienda en **navegación privada**. La cookie `dfagegate_ok` puede haberse depositado en una sesión anterior
3. Verifique su IP en los bypass de la pestaña _Comportamiento_
4. Con un ámbito seleccionado, compruebe que la página probada pertenece a las categorías o productos elegidos
5. Abra la consola del navegador (F12). Busque mensajes `[dfagegate]`
6. Consulte los registros de PrestaShop en **Parámetros avanzados → Registros**, filtre por «dfagegate»
7. **Vacíe la caché de PrestaShop** tras cada cambio de configuración: _Parámetros avanzados → Rendimiento → Vaciar la caché_

### Probar con el modo de vista previa

Desde la versión 1.1.0, el botón **Probar la modal** de la pestaña General abre la tienda en una nueva pestaña con el parámetro `?dfagegate_preview=1`. En este modo:

- La modal se muestra **aunque la cookie dfagegate_ok ya esté depositada**
- Confirmar no deposita **ninguna cookie**: la prueba es repetible a voluntad, sin navegación privada ni borrado manual

Con un ámbito seleccionado, navegue hasta una página cubierta conservando el parámetro en la URL para ver la modal.

### Restablecer la cookie en su navegador

1. Abra las DevTools (F12)
2. Pestaña **Application** (Chrome) o **Storage** (Firefox)
3. Sección **Cookies** → su dominio
4. Elimine la fila `dfagegate_ok`
5. Recargue la página

## Cumplimiento RGPD

### La cookie `dfagegate_ok`

- **Tipo** — estrictamente necesaria para cumplir una obligación legal de acceso
- **Base legal** — exenta de consentimiento previo (existen exenciones similares en el marco ePrivacy europeo)
- **Valor** — binario (`1` = confirmado)
- **Duración** — configurable (90 días por defecto), o sesión si se pone 0
- **Atributos** — `SameSite=Lax`, `Secure` automático en HTTPS, `Path=/`

**En la práctica** — **No** necesita añadir esta cookie a su banner de consentimiento. Entra en la misma categoría que la cookie de sesión de PrestaShop o la cookie CSRF: necesaria para el funcionamiento legal del sitio, por tanto exenta.

### Los registros de rechazo

Si activa _Registrar los rechazos_, cada rechazo se guarda en la tabla `ps_dfagegate_log` con:

- `id_shop` — subtienda afectada
- `reason` — motivo del rechazo (`user_refused` o `dob_under_age`)
- `age` — edad declarada si aplica
- `profession` — profesión declarada si aplica
- `ip_hash` — **SHA-256 de la IP**, nunca la IP en claro
- `date_add` — marca de tiempo

El hash SHA-256 hace la IP **no reversible** a la vez que permite deduplicar los intentos (una misma IP siempre produce el mismo hash). Es el compromiso recomendado por las autoridades de protección de datos para las estadísticas de acceso.

La **retención es automática** desde la 1.1.0: las entradas más antiguas que la duración configurada (365 días por defecto) se purgan cada vez que se abre la página de configuración. Una conservación limitada en el tiempo es exactamente lo que el principio de minimización del RGPD espera de un registro de este tipo. Las estadísticas de la pestaña Registros (total de 30 días, reparto por motivo, últimos rechazos) se basan en estos mismos datos hasheados.

### Los datos de verificación

- La **fecha de nacimiento** transita por AJAX para el cálculo pero **nunca se almacena**
- El **número de colegiado** se valida en el servidor y luego se **olvida**, nunca se almacena
- Solo se conserva la **validación binaria**, a través de la cookie

## Estructura técnica e integración

### Hooks utilizados

- `displayHeader` — inyecta el comentario de diagnóstico
- `actionFrontControllerSetMedia` — registra CSS y JS, pasa la configuración y el HTML pre-renderizado de la modal al JS
- `displayBeforeBodyClosingTag` — renderiza la modal en el servidor (fallback JS si el tema no lo incluye)

### Puntos de entrada AJAX

El controlador AJAX responde en `/module/dfagegate/ajax` y acepta dos acciones:

- `action=confirm` — con parámetros según el tipo de verificación (nada para sí/no, día/mes/año para fecha de nacimiento, profesión/número para médico)
- `action=refuse` — registra el rechazo y devuelve la URL de redirección

Las respuestas son JSON. Una confirmación devuelve `success=true`. Un rechazo por edad insuficiente devuelve `success=false`, `denied=true` y el mensaje de error correspondiente. Un error de validación devuelve `success=false` con el mensaje. Un rechazo del usuario devuelve `success=true` y `redirect_url` con la URL de redirección configurada.

### Esquema de base de datos

Se crea una sola tabla: `ps_dfagegate_log`. Contiene las columnas `id_log` (clave primaria autoincremental), `id_shop`, `reason` (varchar 64), `age` (nullable), `profession` (varchar 128 nullable), `ip_hash` (char 64 para el SHA-256) y `date_add` (datetime). Dos índices secundarios optimizan las consultas de informes: `idx_shop_date` sobre (id_shop, date_add) e `idx_reason` sobre reason.

## Desinstalación

### Desactivar sin eliminar

**Módulos → Módulos instalados → DataFirefly Age Gate → Desactivar**. La configuración y la tabla de registros se conservan. Puede reactivarlo en cualquier momento sin reconfigurar.

### Desinstalación completa

**Módulos → Módulos instalados → DataFirefly Age Gate → Desinstalar**. Esta acción:

- Elimina la tabla `ps_dfagegate_log`
- Elimina todas las entradas de configuración (23 claves escalares + 6 claves multilingües)
- Desregistra los hooks
- Retira el módulo del sistema

**Atención** — La desinstalación es **irreversible**. Si desea conservar el historial de registros de rechazo (por ejemplo para una auditoría de protección de datos), exporte la tabla antes.

## Soporte y actualizaciones

Cada licencia incluye:

- **12 meses de actualizaciones** — compatibilidad PrestaShop, correcciones, mejoras
- **Soporte técnico por email** — respuesta en 24h laborables, FR/EN
- **Reembolso de 30 días** sin preguntas
- **Código fuente sin cifrar** — libre de adaptar el módulo a sus necesidades específicas

Para cualquier consulta técnica o informe de error, contáctenos desde su cuenta DataFirefly. Indique su versión de PrestaShop, versión de PHP, versión del módulo (visible en la parte superior de la pantalla de configuración) y, si es posible, el comentario de diagnóstico presente en la etiqueta head de su tienda.
