Newsletter ListMonk

Newsletter / ListMonk Contract

The shared footer newsletter form renders through:

  • layouts/partials/footer.html
  • layouts/partials/form/newsletter-inner.html
  • layouts/partials/helpers/newsletter-listmonk-config.html

The intent is to keep the newsletter surface shared in generator while letting each client website point at its own ListMonk node through site config. Do not fork the newsletter partial per site just to change endpoints.

Required Site Params

Example:

params:
  subscribe:
    title: Newsletter
    subtext: New essays, releases, and event announcements.
    checkboxes:
      - label: Essays
        moto: New posts and long-form writing
        value: "1"
        checked: true
      - label: Events
        moto: Talks, launches, and workshops
        value: "4"
    listmonk:
      baseUrl: "https://newsletter.client-example.com"

checkboxes[*].value must match list IDs that exist on the configured ListMonk node.

Supported ListMonk Params

Recommended key:

  • params.subscribe.listmonk.baseUrl

Optional overrides:

  • params.subscribe.listmonk.formAction
  • params.subscribe.listmonk.captcha.enabled
  • params.subscribe.listmonk.captcha.challengeUrl
  • params.subscribe.listmonk.captcha.scriptSrc
  • params.subscribe.listmonk.ajaxSubmit

Snake_case variants are also accepted for these keys so site configs can stay consistent with their existing style.

Submit Behavior

The shared form uses AJAX by default so the footer can show an inline thank-you state without leaving the page.

If the website domain is different from the ListMonk node, that node must allow cross-origin form POSTs for AJAX to succeed. If it does not, either:

  • set params.subscribe.listmonk.ajaxSubmit: false to use normal browser form submission
  • or configure CORS on the ListMonk node

When AJAX submission fails at runtime, the shared form now falls back to a normal browser form submit instead of silently failing in place.

Defaults

If no params.subscribe.listmonk.baseUrl is provided, the shared partial still falls back to the legacy QuantaLumin node at https://newsletter.quantalumin.com for backward compatibility.

Authored Newsletter and Unlock Metadata

Newsletter bodies and member sequence steps should stay in Hugo markdown. Do not copy article bodies into ListMonk, Postiz, or another CMS. Use front matter to tell downstream services how a page participates in newsletter, sequence, and unlock workflows.

Example article metadata:

canonical_id: biology-week-001
summary: Cells, microscopes, and the first practical habits.
streams: [biology]
newsletter:
  include: true
  lists: [tutorlumin-news]
  subject: Biology week 1 is ready
  preheader: The first member lesson is now available.
access:
  visibility: member
  groups: [tutorlumin-biology-week-001]
recommended_next:
  - biology-week-002

Example newsletter issue wrapper:

type: newsletter
newsletter:
  subject: TutorLumin notes for this week
  preheader: New biology notes and the next study step.
items:
  - ref: /courses/biology/week-1/
    role: lead

Example member sequence wrapper:

type: sequence
sequence:
  id: biology-foundations
  audience: tutorlumin-biology
  trigger:
    event: membership.created
  steps:
    - id: welcome
      offset: P0D
      source: /courses/biology/week-1/
    - id: second-week
      offset: P7D
      source: /courses/biology/week-2/

Newsletter Manifest Output

Sites can expose a machine-readable newsletter/unlock manifest by adding a Hugo content file such as:

---
title: Newsletter manifest
layout: newslettermanifest
url: "/.well-known/quantalumin-newsletter/index.json"
outputs: [json]
build:
  render: always
  list: never
---

The generated JSON contains:

  • site_id
  • article canonical_id, path, title, summary, and weight
  • streams
  • newsletter
  • sequence
  • access
  • recommended_next

The Datacentre newsletter-unlock service imports this manifest and projects it into ListMonk campaign drafts, Postiz schedule entries, rota recommendations, and LDAP-backed unlock groups. Hugo remains the authoring source of truth; ListMonk and Postiz only receive delivery/scheduling projections.

Page-Level Modal Trigger

Pages can opt into the shared newsletter popup with front matter newsletterModal. The value may be either a boolean or a config object.

Example:

params:
  newsletterModal:
    triggerEvent: timeout
    timeoutDelay: 5000

Supported popup keys are:

  • triggerEvent: scroll or timeout
  • scrollThreshold: percent of page scroll before opening when using scroll
  • timeoutDelay: delay in milliseconds before opening when using timeout
  • moveInsteadOfClone: move the footer newsletter node into the modal instead of cloning it

Both top-level newsletterModal / NewsletterModal and nested params.newsletterModal / params.NewsletterModal front matter are accepted.

Pages that opt into newsletterModal can also open the shared modal on demand from authored content. Two supported triggers are available:

  • a link to #newsletter-modal
  • any element with data-ql-open-newsletter

That lets sites keep newsletter CTAs in markdown/content while still using the shared footer newsletter form rendered by the generator modal wrapper.