Lo que exige la ley a partir del 19 de junio de 2026
La Directiva (UE) 2023/2673, que añade una función de desistimiento a la Directiva sobre los derechos de los consumidores, exige a toda tienda B2C de la UE un botón de desistimiento en dos pasos. El paso 1 dice «Desistir del contrato». El paso 2 dice «Confirmar el desistimiento». Entre ambos hay un formulario con el nombre y un medio de contacto como campos obligatorios, seguido de un acuse de recibo por correo electrónico en un soporte duradero.
Sin inicio de sesión, sin barrera de desplazamiento. Disponible durante todo el plazo de desistimiento. El riesgo de un requerimiento por incumplimiento suele situarse entre 500 y 2.000 EUR, más una prórroga automática del plazo de desistimiento a doce meses y catorce días.
Las dos vías para Shopware 6
Vía A: una extensión de plantilla Twig directamente en tu tema. Rápida, pero ligada a tu tema. Debes tener cuidado durante las actualizaciones del tema.
Vía B: tu propio plugin de storefront que registra un snippet de Twig. Limpia, segura ante actualizaciones y desactivable desde el admin. Es la vía de Shopware recomendada.
Vía A: extensión de plantilla Twig en el tema
Shopware 6 usa plantillas Twig basadas en bloques. Puedes sobrescribir o ampliar cualquier bloque. El pie de página se encuentra en @Storefront/storefront/layout/footer/footer.html.twig. Nos enganchamos al bloque base_footer_inner_container.
{# Resources/views/storefront/layout/footer/footer.html.twig #}
{% sw_extends '@Storefront/storefront/layout/footer/footer.html.twig' %}
{% block base_footer_inner_container %}
{{ parent() }}
<script
src="https://widerrufbutton.net/widget/v1/wh.js"
data-shop-id="{{ config('WiderrufButton.config.shopId') }}"
data-position="footer"
data-lang="de"
async
defer
></script>
{% endblock %}La llamada config(...) accede a la configuración del plugin. Si no quieres construir una configuración, también puedes escribir directamente la clave del widget en el snippet. Para una solución limpia, sin embargo, hace falta la vía B.
Vía B: tu propio plugin
Un plugin de Shopware 6 es esencialmente un bundle de Symfony con un composer.json, una clase de plugin y un services.xml para la inyección de dependencias.
La estructura mínima es así:
custom/plugins/WiderrufButton/
├── composer.json
├── src/
│ ├── WiderrufButton.php
│ ├── Resources/
│ │ ├── config/
│ │ │ ├── config.xml
│ │ │ └── services.xml
│ │ └── views/
│ │ └── storefront/
│ │ └── layout/
│ │ └── footer/
│ │ └── footer.html.twigEl config.xml define el campo de entrada para la clave del widget en el admin de Shopware:
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/shopware/platform/trunk/src/Core/System/SystemConfig/Schema/config.xsd">
<card>
<title>WiderrufButton</title>
<input-field>
<name>shopId</name>
<label>Widget-Key</label>
<helpText>Aus dem WiderrufButton-Dashboard</helpText>
</input-field>
</card>
</config>El services.xml queda vacío mientras no necesites tus propios servicios. La plantilla Twig sobrescribe el bloque del pie de página igual que en la vía A, pero llama a la configuración del plugin mediante config('WiderrufButton.config.shopId').
Activar y probar el plugin
Desde el directorio de Shopware, ejecuta los comandos en este orden:
bin/console plugin:refresh
bin/console plugin:install --activate WiderrufButton
bin/console theme:compile
bin/console cache:clearDespués el plugin aparece en el admin bajo Extensiones. Introduce ahí la clave del widget de tu panel de WiderrufButton. Guarda. Abre la tienda y comprueba el pie de página.
Ten en cuenta la caché HTTP y la CSP
Shopware 6 cachea de forma agresiva. Tras compilar el tema, vacía la caché HTTP, de lo contrario no verás el script de inmediato. En la configuración de Shopware eso es bin/console http:cache:clear.
Si tienes una Content Security Policy activa, widerrufbutton.net debe aparecer en las directivas script-src y connect-src. El navegador carga el script desde ahí y envía el desistimiento a la ruta de la API en el mismo dominio.
Por qué importa el Shadow DOM
Los temas de Shopware traen su propio CSS. Sin encapsulación, el estilo del botón chocaría con el tema, los colores se mostrarían mal, el modal aparecería en el lugar equivocado. Por eso el widget se ejecuta dentro del Shadow DOM. Su CSS está totalmente aislado, los estilos de Shopware no pueden sobrescribir nada y tu tema queda intacto.
Lo mismo ocurre en sentido contrario: el botón no puede hacer nada a tu tema. Sin estilos globales, sin nombres de clase que choquen, sin fuentes que se sobrescriban sin querer.
Multilingüe y sales channels
Shopware permite varios sales channels con dominios distintos. Para cada dominio necesitas una entrada de tienda separada en el panel de WiderrufButton, para que la comprobación CORS se ejecute sobre el origen correcto. Las claves de widget difieren, y debes vincular la clave correcta a la configuración del plugin por cada sales channel.
Encontrarás los detalles en la página de producto y en el tutorial.
Lista de verificación antes del go-live
- Clave del widget introducida y guardada en el admin
- Tema recompilado, caché HTTP vaciada
- Botón visible en el pie de página, accesible sin desplazarse
- Formulario enviado con datos de prueba, el correo llega en segundos
- La Content Security Policy permite el dominio del widget
- La entrada de prueba aparece en el panel bajo Desistimientos