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
This commit is contained in:
parent
15a8f97cb2
commit
36591e7438
5 changed files with 47 additions and 17 deletions
|
|
@ -2,6 +2,7 @@ date = "2026-01-15"
|
|||
plugins = "petition-form"
|
||||
thank_you_page = "takk"
|
||||
hide_list = true
|
||||
newsletter_list_uuids = "dfcf73f4-c86a-43a1-9ddb-31309f7392a9,c4849164-d5e7-4aca-9721-423282773fa1"
|
||||
title = "Underskriftskampanje: Ja til medisinsk cannabis på resept!"
|
||||
|
||||
[en]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
return [
|
||||
'enabled' => true,
|
||||
'url' => 'https://newsletter.example.com', // Your Listmonk URL (no trailing slash)
|
||||
'list_uuids' => [
|
||||
'list_uuids' => [ // Default lists (used when no per-form UUIDs are specified)
|
||||
'UUID1',
|
||||
'UUID2'
|
||||
]
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
* Then in your PHP content file, call the function with your custom text and theme:
|
||||
* <?= newsletter_signup('Your custom intro text here', 'hero') ?>
|
||||
* <?= newsletter_signup('Short text here', 'small') ?>
|
||||
* <?= newsletter_signup('Text', 'small', ['list-uuid-here']) ?>
|
||||
*
|
||||
* Available themes:
|
||||
* - 'hero': Full-width gradient background section (like CTA sections)
|
||||
|
|
@ -57,7 +58,7 @@ function newsletterT(string $key): string {
|
|||
/**
|
||||
* Subscribe to newsletter via Listmonk public API
|
||||
*/
|
||||
function newsletterSubscribe(string $email, string $name): array {
|
||||
function newsletterSubscribe(string $email, string $name, array $listUuids = []): array {
|
||||
$configPath = dirname(__DIR__, 2) . '/listmonk-config.php';
|
||||
if (!file_exists($configPath)) {
|
||||
return ['success' => false, 'error' => 'config_missing'];
|
||||
|
|
@ -71,7 +72,7 @@ function newsletterSubscribe(string $email, string $name): array {
|
|||
$payload = json_encode([
|
||||
'email' => $email,
|
||||
'name' => $name,
|
||||
'list_uuids' => $config['list_uuids']
|
||||
'list_uuids' => !empty($listUuids) ? $listUuids : $config['list_uuids']
|
||||
]);
|
||||
|
||||
$url = $config['url'] . '/api/public/subscription';
|
||||
|
|
@ -210,12 +211,15 @@ SCRIPT;
|
|||
/**
|
||||
* Render the "hero" theme - full-width gradient background section
|
||||
*/
|
||||
function newsletterRenderHero(string $introText, string $formId): string {
|
||||
function newsletterRenderHero(string $introText, string $formId, array $listUuids = []): string {
|
||||
$csrfToken = $_SESSION['newsletter_csrf_token'];
|
||||
$nonce = bin2hex(random_bytes(8));
|
||||
$escapedIntro = htmlspecialchars($introText, ENT_QUOTES, 'UTF-8');
|
||||
$escapedFormId = htmlspecialchars($formId, ENT_QUOTES, 'UTF-8');
|
||||
$t = newsletterGetTranslations();
|
||||
$listUuidsField = !empty($listUuids)
|
||||
? "\n" . ' <input type="hidden" name="newsletter_list_uuids" value="' . htmlspecialchars(implode(',', $listUuids), ENT_QUOTES, 'UTF-8') . '">'
|
||||
: '';
|
||||
|
||||
$html = <<<HTML
|
||||
<section class="newsletter-section newsletter-hero escape" id="{$escapedFormId}">
|
||||
|
|
@ -223,7 +227,7 @@ function newsletterRenderHero(string $introText, string $formId): string {
|
|||
<p class="newsletter-intro">{$escapedIntro}</p>
|
||||
<form class="newsletter-form" method="post" data-newsletter-form data-success-message="{$t['successMessage']}" data-error-message="{$t['errorMessage']}">
|
||||
<input type="hidden" name="newsletter_csrf" value="{$csrfToken}">
|
||||
<input type="hidden" name="newsletter_form_id" value="{$escapedFormId}">
|
||||
<input type="hidden" name="newsletter_form_id" value="{$escapedFormId}">{$listUuidsField}
|
||||
<div class="newsletter-fields">
|
||||
<div class="newsletter-field">
|
||||
<label for="newsletter_name_{$nonce}" class="visually-hidden">{$t['nameLabel']}</label>
|
||||
|
|
@ -252,19 +256,22 @@ HTML;
|
|||
/**
|
||||
* Render the "small" theme - compact inline notice with border
|
||||
*/
|
||||
function newsletterRenderSmall(string $introText, string $formId): string {
|
||||
function newsletterRenderSmall(string $introText, string $formId, array $listUuids = []): string {
|
||||
$csrfToken = $_SESSION['newsletter_csrf_token'];
|
||||
$nonce = bin2hex(random_bytes(8));
|
||||
$escapedIntro = htmlspecialchars($introText, ENT_QUOTES, 'UTF-8');
|
||||
$escapedFormId = htmlspecialchars($formId, ENT_QUOTES, 'UTF-8');
|
||||
$t = newsletterGetTranslations();
|
||||
$listUuidsField = !empty($listUuids)
|
||||
? "\n" . ' <input type="hidden" name="newsletter_list_uuids" value="' . htmlspecialchars(implode(',', $listUuids), ENT_QUOTES, 'UTF-8') . '">'
|
||||
: '';
|
||||
|
||||
$html = <<<HTML
|
||||
<aside class="newsletter-section newsletter-small" id="{$escapedFormId}">
|
||||
<p class="newsletter-intro">{$escapedIntro}</p>
|
||||
<form class="newsletter-form" method="post" data-newsletter-form data-success-message="{$t['successMessage']}" data-success-confirm="{$t['successConfirm']}" data-error-message="{$t['errorMessage']}">
|
||||
<input type="hidden" name="newsletter_csrf" value="{$csrfToken}">
|
||||
<input type="hidden" name="newsletter_form_id" value="{$escapedFormId}">
|
||||
<input type="hidden" name="newsletter_form_id" value="{$escapedFormId}">{$listUuidsField}
|
||||
<div class="newsletter-fields">
|
||||
<div class="newsletter-field">
|
||||
<label for="newsletter_email_{$nonce}" class="visually-hidden">{$t['emailLabel']}</label>
|
||||
|
|
@ -464,19 +471,20 @@ STYLES;
|
|||
*
|
||||
* @param string $introText Custom intro text to display above the form
|
||||
* @param string $theme Theme to use: 'hero' (default) or 'small'
|
||||
* @param array $listUuids Optional Listmonk list UUIDs for this form (default: uses global config)
|
||||
* @param string $formId Optional form ID for the section (default: 'newsletter')
|
||||
* @return string The complete HTML for the newsletter signup section
|
||||
*/
|
||||
function newsletter_signup(string $introText, string $theme = 'hero', string $formId = 'newsletter'): string {
|
||||
function newsletter_signup(string $introText, string $theme = 'hero', array $listUuids = [], string $formId = 'newsletter'): string {
|
||||
$html = newsletterGetStyles();
|
||||
|
||||
switch ($theme) {
|
||||
case 'small':
|
||||
$html .= newsletterRenderSmall($introText, $formId);
|
||||
$html .= newsletterRenderSmall($introText, $formId, $listUuids);
|
||||
break;
|
||||
case 'hero':
|
||||
default:
|
||||
$html .= newsletterRenderHero($introText, $formId);
|
||||
$html .= newsletterRenderHero($introText, $formId, $listUuids);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -522,8 +530,20 @@ function newsletterHandleSubmission(): void {
|
|||
exit;
|
||||
}
|
||||
|
||||
// Parse per-form list UUIDs (if provided)
|
||||
$listUuids = [];
|
||||
if (!empty($_POST['newsletter_list_uuids'])) {
|
||||
$raw = explode(',', $_POST['newsletter_list_uuids']);
|
||||
foreach ($raw as $uuid) {
|
||||
$uuid = trim($uuid);
|
||||
if (preg_match('/^[0-9a-f\-]{36}$/i', $uuid)) {
|
||||
$listUuids[] = $uuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Subscribe
|
||||
$result = newsletterSubscribe($email, $name);
|
||||
$result = newsletterSubscribe($email, $name, $listUuids);
|
||||
|
||||
if ($result['success']) {
|
||||
$_SESSION['newsletter_last_submit'] = time();
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ function petitionSanitizeCSV(string $value): string {
|
|||
* Subscribe email to Listmonk newsletter lists via public API
|
||||
* Listmonk handles double opt-in (sends its own confirmation email)
|
||||
*/
|
||||
function petitionSubscribeToNewsletter(string $email, string $name): bool {
|
||||
function petitionSubscribeToNewsletter(string $email, string $name, array $listUuids = []): bool {
|
||||
$configPath = dirname(__DIR__, 2) . '/listmonk-config.php';
|
||||
if (!file_exists($configPath)) {
|
||||
error_log("Listmonk config not found: {$configPath}");
|
||||
|
|
@ -59,13 +59,15 @@ function petitionSubscribeToNewsletter(string $email, string $name): bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
$uuids = !empty($listUuids) ? $listUuids : $config['list_uuids'];
|
||||
|
||||
// Log the UUIDs being used
|
||||
error_log("Listmonk attempting subscription with UUIDs: " . implode(', ', $config['list_uuids']));
|
||||
error_log("Listmonk attempting subscription with UUIDs: " . implode(', ', $uuids));
|
||||
|
||||
$payload = json_encode([
|
||||
'email' => $email,
|
||||
'name' => $name,
|
||||
'list_uuids' => $config['list_uuids']
|
||||
'list_uuids' => $uuids
|
||||
]);
|
||||
|
||||
$url = $config['url'] . '/api/public/subscription';
|
||||
|
|
@ -1238,6 +1240,9 @@ function petitionGetPageData(?Context $ctx): ?array {
|
|||
// Use petition_title if set (for subpages), otherwise fall back to page title
|
||||
$petitionTitle = $metadata['petition_title'] ?? $metadata['title'] ?? $petitionId;
|
||||
$thankYouPage = $metadata['thank_you_page'] ?? 'takk';
|
||||
$newsletterListUuids = !empty($metadata['newsletter_list_uuids'])
|
||||
? array_map('trim', explode(',', $metadata['newsletter_list_uuids']))
|
||||
: [];
|
||||
|
||||
$formErrors = [];
|
||||
$formData = ['firstname' => '', 'surname' => '', 'email' => '', 'region' => '', 'display' => 'semi'];
|
||||
|
|
@ -1472,7 +1477,7 @@ function petitionGetPageData(?Context $ctx): ?array {
|
|||
error_log("Newsletter checkbox: " . ($newsletterOptIn ? 'checked' : 'not checked'));
|
||||
if ($newsletterOptIn) {
|
||||
$fullName = $formData['firstname'] . ' ' . $formData['surname'];
|
||||
petitionSubscribeToNewsletter($formData['email'], $fullName);
|
||||
petitionSubscribeToNewsletter($formData['email'], $fullName, $newsletterListUuids);
|
||||
}
|
||||
|
||||
$_SESSION['last_petition_submit'] = time();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ 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
|
||||
|
|
@ -29,11 +30,12 @@ Then call from PHP content files:
|
|||
## Function Signature
|
||||
|
||||
```php
|
||||
newsletter_signup(string $introText, string $theme = 'hero', string $formId = 'newsletter'): string
|
||||
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
|
||||
|
|
@ -58,6 +60,8 @@ return [
|
|||
|
||||
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`)
|
||||
|
|
@ -71,7 +75,7 @@ All use `newsletter.*` prefix in language files:
|
|||
- `newsletter.email_label`, `newsletter.email_placeholder`
|
||||
- `newsletter.notice` (e.g., "We send about 12 emails per year")
|
||||
- `newsletter.submit_button`
|
||||
- `newsletter.success_message`, `newsletter.error_message`
|
||||
- `newsletter.success_message`, `newsletter.success_confirm`, `newsletter.error_message`
|
||||
|
||||
## Static Resources
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue