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
98 lines
3.8 KiB
Markdown
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
|