tenbruggencate/newsletter-lite

Shopware 6 newsletter signup: GDPR-safe with double opt-in, opaque-token unsubscribe with email erasure, per-IP rate limit.

Maintainers

Package info

bitbucket.org/Bruggencate/sw-plugin-newsletter-lite

Homepage

Issues

Documentation

Type:shopware-platform-plugin

pkg:composer/tenbruggencate/newsletter-lite

Statistics

Installs: 10

Dependents: 0

Suggesters: 0

1.11.0 2026-05-18 00:17 UTC

README

Ten Bruggencate Development

Newsletter Lite

Newsletter Lite

Own a clean, GDPR-safe subscriber list. Newsletter Lite is the genuine free tool for capturing and managing newsletter subscribers in Shopware 6: a standalone subscriber table, opaque-token unsubscribe with one-click email erasure, double opt-in by default, and a searchable admin list with CSV export. No third-party dependencies. None of Shopware's built-in newsletter UX-customisation pain.

It does one thing, and does it well — get consent-clean subscribers into a list you control, and let you get them back out again (CSV export) for whatever you send them with.

▲ Newsletter Pro adds campaigns, lifecycle automations (abandoned-cart, back-in-stock, win-back) and native-data segmentation built on your shop's own order data. Pro requires this plugin and installs it automatically — see Part of a Lite/Pro family below.

License: MIT · Shopware: 6.7.x · PHP: 8.1 / 8.2

🇬🇧 English · 🇳🇱 Nederlands · 🇩🇪 Deutsch

📖 More context: Why we built this · How it compares

Screenshots

Newsletter landing page on desktop — branded hero, three-bullet promise, signup form card, subscriber-count transparency footer.

Landing page — desktop

Newsletter landing page on mobile — fully stacked, full-width form fields, 24×24 minimum touch targets.

Landing page — mobile (responsive)

Admin Newsletter subscribers module — searchable subscriber list with Export CSV, showing Confirmed, Pending confirmation, and Unsubscribed status badges.

Admin — subscriber management — searchable list, CSV export, double-opt-in status badges

What it does

Shopware ships a newsletter module, but customising its UX fights the built-in flow. This plugin is deliberately smaller:

  • tenbruggencate_nl_subscriber table — plain id, email, source, brand_name (server-derived — see below), consent_given + audit trail, confirmed + DOI token columns, unsubscribe_token, locale, subscribed_at, unsubscribed_at
  • Signup form partial — drop-in Twig include with compact (footer) and full (landing) variants
  • Landing page at /newsletter — SEO-safe, standalone, no theme dependency
  • Opaque-token unsubscribe — URL carries a CSPRNG token, not the email address. One click: email gets scrubbed to erased-<id>@newsletter.invalid, the row stays for stats
  • Three locales out of the box — nl-NL, en-GB, de-DE
  • Double opt-in by default (v1.6+) — new signups receive a confirmation email; rows only flip to confirmed=1 after the visitor clicks the link. 24h token expiry. Existing pre-DOI subscribers grandfathered as already confirmed. Single-opt-in remains available via the requireDoubleOptIn config toggle if you have a deliberate reason to use it
  • Origin / volume / consent triple-defence on the subscribe endpoint — cross-origin POSTs rejected (v1.4.1), per-IP rate limit (v1.5.0, 5 attempts / 10 min), and DOI for proof-of-consent (v1.6.0)
  • Admin subscriber list (v1.10.0) — a "Newsletter subscribers" module under the Marketing menu: search by email, sortable columns, a per-row confirmed / pending / unsubscribed status, and one-click CSV export. Backed by a read-only DAL entity — the opaque tokens and consent IP hash are never exposed through the admin API

Install

composer require tenbruggencate/newsletter-lite
bin/console plugin:refresh
bin/console plugin:install --activate TenBruggencateNewsletterLite
bin/console database:migrate --all TenBruggencateNewsletterLite
bin/console cache:clear

Configuration

Configurable per sales channel from Extensions → TenBruggencateNewsletterLite.

FieldDefaultPurpose
enabledtrueKill switch — signup form renders nothing when off
brandName(empty)Shown in headings (e.g. "Schatkistjes Club"); leave blank for generic wording
consentText(snippet)Checkbox label; HTML allowed
privacyPageUrl/about/privacyLink target in the fineprint
landingPageEnabledtrueToggle the /newsletter landing page route

Routes

RouteMethodPurpose
/newsletterGETLanding page with signup form
/newsletter/subscribePOSTHandles the signup form submit
/newsletter/unsubscribe/{token}GETOpaque-token unsubscribe + email scrub

Usage

Embed the signup form anywhere via Twig:

{# Compact variant — for footers #}
{% include '@TenBruggencateNewsletterLite/storefront/newsletter/_signup.html.twig' with { variant: 'compact' } %}

{# Default variant — for landing pages #}
{% include '@TenBruggencateNewsletterLite/storefront/newsletter/_signup.html.twig' %}

Standards

  • Performance — no JS dependency; plain POST with a 302 redirect on success. Async submission via fetch() is a ~20-line enhancement you ship in your theme if desired.
  • SEO — add /newsletter/unsubscribe/* to your theme's robots.txt disallow list (the landing page is indexable, the unsubscribe endpoint should not be).
  • GDPR — the opaque-token pattern means the unsubscribe URL leaks nothing. One click also erases the email address from storage; the row stays for stats, PII is gone. Satisfies right-to-erasure without a manual request. Every signup writes a consent audit trail (consent_given_at, consent_text_version, consent_ip_hash) for Article-7 supervisory audits. Full data-flow + subject-rights documentation in GDPR.md.
  • WCAG 2.2 AA — semantic <form>, <label for>, <input type=email required>, keyboard-accessible by construction. Focus state inherited from your theme. Live axe-core audit output + desktop + mobile screenshots + localised-copy evidence: docs/ACCESSIBILITY.md.
  • Security — CSRF-protected via Shopware's default handler; unsubscribe_token is 32 bytes random_bytes(). No user-controllable input in the unsubscribe SQL (token is looked up with a prepared statement).
  • Uninstallplugin:uninstall --keep-user-data preserves the tenbruggencate_nl_subscriber table AND every TenBruggencateNewsletterLite.config.* row (default, recommended path when you might reinstall). plugin:uninstall without the flag drops the subscriber table entirely + clears config — use this only when you genuinely want to discard all subscribers. There is no middle ground; exports happen before, not during, uninstall.

Production-readiness checklist

A deliberately short list of things to verify before enabling the plugin on a customer-facing storefront. Not legal cover — the MIT license already disclaims warranty — but practical guidance an experienced operator would want anyway.

  • [ ] Database backup before upgrading or uninstalling. The plugin owns one table; a backup makes the destructive uninstall path reversible.
  • [ ] SMTP wired up before flipping requireDoubleOptIn on. v1.6.0+ defaults DOI to on; without working mail transport, visitors submit the form, get the "check your inbox" page, and never receive a confirmation email — they're stuck in confirmed=0 forever. If you can't configure SMTP yet, set requireDoubleOptIn=false until you can.
  • [ ] Privacy policy URL set in the plugin config. The form's fineprint links to it; an empty URL routes to a 404 and trains visitors to ignore privacy notices.
  • [ ] Test on staging before production. Especially the unsubscribe + DOI confirm flows — both rely on per-row tokens that depend on random_bytes() being available (always is, on any modern PHP, but verify).
  • [ ] Trusted proxies configured if you're behind a CDN / load balancer. v1.5.0+ rate-limits per client IP; without trusted_proxies set, every visitor shares the same proxy IP and the limit fires too aggressively.

Compatibility

Core platform

ShopwarePHPStatus
6.7.x — tested against 6.7.8, 6.7.98.1, 8.2Stable
6.6.xNot supported
6.5.x and earlierNot supported

Database

EngineVersionNotes
MySQL8.0+Primary target; JSON functions used for config-row manipulation in migrations
MariaDB10.11+Tested end-to-end; earlier versions lack some JSON operator support

Browsers (storefront)

Evergreen browsers only — the two most recent stable releases of each:

BrowserDesktopMobile
Chrome / Chromium
Firefox
Safari✅ (macOS)✅ (iOS 16+)
Edge

Internet Explorer and legacy Edge are not supported. The plugin emits no runtime JS (where applicable) so graceful degradation on older browsers usually still renders content, just without progressive enhancements.

Admin browsers

Same evergreen matrix — the Shopware admin is Vue-based and has its own compatibility baseline that this plugin doesn't extend or narrow.

Development

ToolVersionScope
PHP≥ 8.1Runtime + test suite
Composer2.xDependency management
Node.js≥ 18Only needed if you edit SCSS and re-run the theme compile
Python≥ 3.9Only needed for the repo's asset-pipeline scripts (scripts/*.py)

Accessibility

WCAG 2.2 level A + AA — see docs/ACCESSIBILITY.md for axe-core audit output and per-page violations.

What we test before each release

  • Full PHPUnit unit suite against PHP 8.1 + 8.2 (source-inspection tests don't need a kernel)
  • PHPStan level 8 + PHP-CS-Fixer (@PSR12 + @Symfony)
  • Composer validate on every plugin
  • Live-DB smoke tests (plugin install → activate → route render → uninstall cycle)
  • axe-core audit on the primary storefront surfaces (see ACCESSIBILITY.md)

Part of a Lite/Pro family

Newsletter Lite is the free tier of a Lite/Pro plugin family. It is a complete, standalone tool — capturing and managing a clean subscriber list is the whole job, and nothing here is gated or crippled to push an upsell.

Newsletter Pro (sold separately) builds on the list Lite gives you and adds the sending side: campaign composition, lifecycle automations (abandoned-cart, back-in-stock, win-back, post-purchase) and behavioural segmentation built on your shop's own order data. Pro requires this plugin and installs it automatically. It is brand-new and still in development — if all you need today is a consent-clean subscriber list, Newsletter Lite on its own is the right tool.

Related plugins

Part of the TenBruggencate Suite — small, focused plugins that play well together:

  • MultiBrand — recommended: when MultiBrand is active, brand_name is populated automatically from the resolved brand (priority: MultiBrand resolver → SalesChannelContext → configured brandName → empty). Never read from the form, so tampering is impossible. Per-SC segmentation without separate sales channels.
  • Analytics — signup conversions tracked automatically when Analytics is active and consent is given.
  • LegalPages — provides the /legal/privacy page that privacyPageUrl typically points at.
  • Maintenance — branded maintenance page that cooperates with this plugin's privacy / consent posture.

More from Ten Bruggencate Development

Focused, privacy-first Shopware 6 plugins — free to start, upgrade when you grow:

  • NewsletterLite: GDPR-safe signup & subscriber-list management · Pro: campaigns, lifecycle automations, native-data segmentation
  • Legal PagesLite: localized legal-page templates · Pro: the compliance toolkit (maintained templates, cookie policy, accessibility statement)
  • Analytics — multi-backend (Matomo / Plausible), GDPR-first, cookieless-capable
  • Maintenance — a branded, SEO-correct maintenance page
  • Multi-Brand — serve multiple brands from one Shopware, by hostname
  • Product Encyclopedia — structured educational content pages linked to products
  • Seasons — scheduled theme-config variants

Support

License

MIT © Ten Bruggencate Development