Alexander 68b347a61f Add tree-home block; merge birthday/anniversary timeline
- New "Upcoming family events" block for the tree home page,
  rendering the same card + timeline visualisation as the
  newsletter email but adapted for web context: avatars resolve
  to media-file URLs (no CID), the silhouette placeholder reuses
  BockenTheme's .person-card .photo-placeholder rules so the
  Nord-mixed shades and dark-mode handling stay in sync with the
  full-diagram plugin, and per-viewer relationship labels surface
  when the signed-in user is linked to an Individual on the tree.
- Default window 30 days, configurable via the standard block
  config UI. Wide-screen wrapper caps at 760 px with a small
  right-side breathing margin.
- Block renders via AJAX and caches its HTML for 5 minutes per
  (tree, window, viewer, locale), so the tree home page paints
  instantly and repeat visits skip the heavy event/query +
  relationship-BFS work.
- Living-kin section is now a single date-sorted timeline that
  mixes birthdays and intact-couple anniversaries. Each row's
  icon + label key off the fact's tag, so a mixed run shares
  one rail. Applies to both block and email.
- Newsletter subscription menu entry removed from the header;
  the form is still reachable on the standard /my-account page
  via the registerCustomView override.
2026-05-15 17:16:51 +02:00

webtrees Email Newsletter

A webtrees 2.2+ custom module that sends recurring email newsletters with:

  • Upcoming birthdays of still-living individuals (formatted as ordinal age — "45th birthday" / "45. Geburtstag").
  • Upcoming marriage anniversaries of intact couples (admin toggle, per tree). Marriages with a divorce or annulment fact are excluded automatically.
  • Historical events — births and deaths of deceased individuals whose anniversary falls in the upcoming window.

The look-ahead window and the send cadence are the same number: one "every N days" setting (default 14) drives both the cron interval and how far each issue looks ahead. Issues with nothing to report are silently skipped.

Each recipient gets a per-recipient render — language, relationship labels, detail filter, cadence, and personalisation tokens are all resolved against their webtrees account.

Highlights

  • Editorial layout with embedded circular avatars, a left-side timeline rail, and event-type icons (birth / death / marriage).
  • BockenTheme light-mode skin — Open Sans, cream background, Nord accent palette. The newsletter and the website read as one product.
  • Per-recipient localisation — German for users whose webtrees language starts with de, English otherwise. Subject line, body, date strings, and (optionally) a custom subject prefix are all localised. Subject dates use IntlDateFormatter for the recipient's locale.
  • Per-recipient relationship labels"your mother", "4th great- grandfather", "first cousin twice removed". Uses webtrees' own RelationshipService so the labels match the site.
  • Kin-distance detail filter — close family get the full card (avatar + timeline + icon); distant kin appear as a single-line bullet at the foot of each section. The "distance" radius is an admin setting (default 3); spouses inherit their partner's distance; recipients with no linked tree record always see the full detailed view.
  • Per-recipient cadence — each subscriber can pick weekly, biweekly, monthly, every-two-months, quarterly, or "use site default" on their /my-account/{tree} page.
  • One-shot intro paragraph — admins can attach a Markdown intro (bilingual, EN/DE) to the next issue. Supports {{first_name}}, {{last_name}}, {{username}}, {{email}} personalisation tokens. Rendered alongside the tree-contact user's avatar as an editorial column. Cleared automatically after a successful send.
  • Cron-only dispatch — the "is it due?" decision is made server- side against stored timestamps. Calling the trigger more often than the cadence is harmless and idempotent.

Requirements

  • webtrees ≥ 2.2.0
  • PHP ≥ 8.2 with ext-intl (for locale-aware subject dates) and either ext-imagick or ext-gd (for avatar resizing — falls back to original-size embeds if neither is present).
  • A working SMTP / sendmail configuration in Control panel → Sending email. This module reuses webtrees' standard mailer and signs with the site's DKIM keys if configured.
  • An external scheduler on the host (system cron, systemd timer, Kubernetes CronJob, …) that can fire an HTTP request at a fixed interval. Newsletter dispatch never runs on visitor page loads.

Installation

  1. Copy this directory into the webtrees modules_v4/ folder, renaming it to email_newsletter:

    cp -r webtrees_email_newsletter /var/www/webtrees/modules_v4/email_newsletter
    
  2. In the webtrees control panel, go to Modules → All modules and enable Email Newsletter.

  3. Open Control panel → Modules → Email Newsletter → Preferences and, for each tree:

    • Tick Enable newsletter for this tree.
    • Set the send-cadence (default 14 days). This same number is the look-ahead window for the next issue.
    • Toggle Include marriage anniversaries if desired.
    • Set Detailed view distance (default 3). Lower values produce a terser email focused tightly on close kin.
    • Optional: set per-locale Subject prefix and a Generic fallback (e.g. [Bocken family] ).
    • Optional: tick existing webtrees users in Subscribed users to subscribe them. Users can still adjust their own subscription and cadence on /my-account/{tree}.
    • Optional: add external (non-user) addresses in Extra recipient email addresses.
  4. Copy the Cron URL at the bottom and wire it into your scheduler (see below).

Setting up the scheduler

Why no built-in scheduler? PHP has no daemon, and frameworks like Laravel rely on a once-per-minute system cron to fire their internal scheduler. This module follows the same convention: the host OS owns the timer, the module owns the "is it actually due?" decision.

System cron

# Run every 15 minutes. The module itself decides whether sending is due.
*/15 * * * *  curl -fsS --max-time 60 'https://example.com/module/_email_newsletter_/Cron?token=YOUR_TOKEN' > /dev/null

systemd timer

/etc/systemd/system/webtrees-newsletter.service:

[Unit]
Description=webtrees newsletter trigger

[Service]
Type=oneshot
ExecStart=/usr/bin/curl -fsS --max-time 60 "https://example.com/module/_email_newsletter_/Cron?token=YOUR_TOKEN"

/etc/systemd/system/webtrees-newsletter.timer:

[Unit]
Description=Trigger webtrees newsletter dispatch

[Timer]
OnCalendar=*-*-* *:00/15
Persistent=true

[Install]
WantedBy=timers.target

Then systemctl enable --now webtrees-newsletter.timer.

Forcing a one-off send

The admin Preferences page has a Send now button for testing. For an unattended forced send (bypassing the per-recipient "is it due?" check), append &force=1 to the cron URL.

Subscribers

Three sources, combined and de-duplicated by email:

  1. Webtrees users who opt in themselves via the per-tree Newsletter subscription menu entry on /my-account/{tree} — visible only to logged-in users on trees where the module is enabled.
  2. Webtrees users an admin subscribes from the preferences page.
  3. External addresses the admin lists in Extra recipient email addresses.

Only approved and email-verified webtrees accounts will receive the newsletter. External addresses always receive on every run (they have no per-user cadence timer).

Sender identity

To match webtrees' own convention for system-generated email (registration, password resets, "new version available"), the From: header is SiteUserControl panel → Sending email → Sender name / Sender email (SMTP_FROM_NAME / SMTP_DISP_NAME). The tree's contact user becomes the Reply-To:, so replies still reach a human admin.

If SMTP_FROM_NAME isn't set the dispatcher falls back to the tree contact for From: as well, so the message always has a valid sender envelope.

Privacy

The dispatch service does not impersonate a webtrees user, so it sees the tree from the visitor access level. Records and facts that your tree settings hide from visitors will be omitted from the newsletter even if a recipient has higher in-app access. This is the safest default for an outbound email — if you need to expose more information, relax the tree's visitor-access settings or hand-curate the Extra recipient list.

License

AGPL-3.0-or-later. See LICENSE for the full text.

S
Description
An email newsletter plugin for upcoming birthdays and marriage anniversaries of living tree members as well as birth and death days for deceased.
Readme 257 KiB
Languages
PHP 50.8%
HTML 49.2%