innhold/docs/newsletter-plugin.md
Ruben 36591e7438 Add per-form Listmonk list UUIDs to newsletter plugin
Add support for specifying Listmonk list UUIDs per form instance
Update petition form to use metadata-defined UUIDs
Add success confirmation message to newsletter forms
Update documentation with new functionality
2026-02-07 15:34:43 +01:00

98 lines
3.8 KiB
Markdown

# Newsletter Plugin Reference
For LLM agents working on the newsletter signup. Read when modifying newsletter functionality.
## Overview
Modular newsletter signup that can be embedded on any page. Uses Listmonk's public subscription API for double opt-in. Located in `custom/plugins/page/newsletter-signup.php`.
## How It Activates
Add to a page's `metadata.ini`:
```ini
plugins = "newsletter-signup"
```
Then call from PHP content files:
```php
<?= newsletter_signup('Your custom intro text here', 'hero') ?>
<?= newsletter_signup('Short text here', 'small') ?>
<?= newsletter_signup('Text', 'small', ['list-uuid-1', 'list-uuid-2']) ?>
```
## Themes
| Theme | Description | HTML Element |
|---|---|---|
| `hero` | Full-width gradient background section (green->blue). Centered form with pill-shaped inputs. | `<section>` |
| `small` | Compact inline box with green border. Fits between paragraphs. | `<aside>` |
## Function Signature
```php
newsletter_signup(string $introText, string $theme = 'hero', array $listUuids = [], string $formId = 'newsletter'): string
```
- `$introText` - Displayed above the form
- `$theme` - `'hero'` or `'small'`
- `$listUuids` - Listmonk list UUIDs for this form (empty = use global config)
- `$formId` - HTML id for the section (for anchor links)
## How It Works
1. Form submits via JavaScript `fetch()` (AJAX) - this is the ONE place JS is used on the site
2. Server validates: CSRF token, rate limit (30s), name/email
3. Calls Listmonk public subscription API
4. Returns JSON response
5. Button shows success/error state with animation
## Listmonk Integration
Config: `custom/listmonk-config.php` (not in repo, see `listmonk-config.example.php`)
```php
return [
'enabled' => true,
'url' => 'https://your-listmonk-instance.com',
'list_uuids' => ['uuid-1', 'uuid-2'],
];
```
Uses Listmonk's **public** subscription API (`/api/public/subscription`). No authentication needed. Listmonk handles its own double opt-in flow.
Per-form list UUIDs can be passed via `$listUuids` parameter. When empty, falls back to the global config's `list_uuids`.
## Anti-Spam
1. **CSRF token** - Separate from petition (`newsletter_csrf_token`)
2. **Rate limit** - 30 seconds between submissions (session-based)
3. **Input validation** - Name 2-100 chars, valid email, max 100 chars
## Translation Keys
All use `newsletter.*` prefix in language files:
- `newsletter.name_label`, `newsletter.name_placeholder`
- `newsletter.email_label`, `newsletter.email_placeholder`
- `newsletter.notice` (e.g., "We send about 12 emails per year")
- `newsletter.submit_button`
- `newsletter.success_message`, `newsletter.success_confirm`, `newsletter.error_message`
## Static Resources
CSS and JS are inlined in the output via static helper functions:
- `newsletterGetStyles()` - Included once per page (static flag)
- `newsletterGetScript()` - Included once per page (static flag)
This means multiple `newsletter_signup()` calls on one page share a single copy of CSS/JS.
## Critical: Do Not Break
1. **AJAX submission** - The form uses `fetch()` with JSON response. The `newsletterHandleSubmission()` function runs early (before any output) and calls `exit` after sending JSON.
2. **CSRF separate from petition** - Uses `newsletter_csrf_token` session key, not the petition's `csrf_token`.
3. **Static inclusion guards** - `$stylesIncluded` and `$scriptIncluded` static vars prevent duplicate CSS/JS. Do not reset these.
4. **Button states** - CSS classes `is-loading`, `is-success`, `is-error` control button feedback. The JS depends on these class names and `data-*` attributes.
5. **`escape` class on hero** - The hero section uses class `escape` to break out of the content container width. This is defined in `base.css`.
## Currently Used On
- Homepage (`content/index.php`) - hero theme with custom intro text