Retour du commanditaire après le premier envoi réel (juillet 2026) : des annonces à venir n'étaient pas proposées à la coche, et les dates affichées étaient les dates de publication. - Fenêtre « à venir » de 12 mois (FUTURE_HORIZON_MONTHS), démarrant à la fin du mois de la newsletter ou à aujourd'hui si ce mois est passé, en remplacement du plafond « début de fenêtre <= fin du mois ». Idem pour les séances (SEANCE_WINDOW_MARGIN_DAYS de 5 jours supprimée). Ces items sont regroupés dans un bloc « À venir », décochés par défaut. - event_date_label() centralise les libellés du thème (« Le X de H1 à H2 », « Du X au Y », « Jusqu'au X », « X à H ») sur la convention date_de_debut > datetime > post_date. Utilisée par l'export et par la pastille de la liste à cocher, qui affichent donc la même chose. - Tri par date d'événement (sql_event_date_order) et non par date de publication. - Fenêtres de fin « +35 j » et « +3 mois » recalées sur la date d'événement : un événement annoncé plus de 35 jours à l'avance sortait de la fenêtre avant d'avoir eu lieu et manquait dans la newsletter de son propre mois. - merge_selected_items() : une sélection déjà enregistrée est réinjectée dans la liste même si ses items sont sortis de la fenêtre — sans ça, rouvrir puis réenregistrer une ancienne newsletter l'amputait silencieusement. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011w7RzAHv4r1Yahnm2NwDDG
thalim-newsletter
Plugin WordPress qui compose les newsletters mensuelles du laboratoire THALIM à partir du contenu déjà publié sur le site, et les exporte en HTML prêt pour un envoi email.
- Version : 1.0.0
- Auteur : THALIM Dev
- Licence : GPL v2 or later
Installation
cd wp-content/plugins
git clone gitea@figureslibres.io:valentin_le_moign/thalim-plugin-newsletter.git thalim-newsletter
Puis activer depuis l'admin WordPress. Dans le cadre du projet THALIM, le clonage est automatisé par bootstrap.sh du repo thalim-stack.
Utilisation
Une fois activé, le plugin ajoute une page d'administration : Outils → Newsletter (capacité requise : edit_others_posts).
Le workflow :
- Sélection d'un mois (sélecteur année-mois)
- Chargement AJAX (
thalim_nl_load_month) des contenus éligibles, regroupés par catégorie parente - Cases à cocher pour inclure ou exclure chaque publication / séance. Pour un mois sans newsletter existante, tout est coché par défaut sauf le bloc « À venir » (voir plus bas). À l'ouverture d'une newsletter déjà enregistrée, c'est la sélection sauvegardée qui est restaurée — y compris les items qui ne seraient plus dans la fenêtre du mois, réintégrés par
merge_selected_items()pour qu'un réenregistrement ne les perde pas - Réordonnancement par glisser-déposer : chaque item porte une poignée (
⋮). Pour les catégories normales, on réordonne les annonces dans leur liste. Pour les séminaires, la poignée est sur le titre du séminaire : on réordonne les séminaires entre eux (les séances, elles, restent toujours triées par ordre chronologique). L'ordre choisi est repris tel quel dans le rendu HTML après sauvegarde — l'ordre de soumission des cases suit l'ordre du DOM, et l'export rend chaque section dans l'ordre stocké - Champs intro, conclusion, URL d'inscription, URL de désinscription
- Sauvegarde : crée un post WordPress dans la catégorie Newsletter (
20) avec le HTML email complet enpost_content - Bouton Exporter en HTML (
thalim_nl_export_html) → téléchargement du fichiernewsletter-THALIM-{mois}.html
Une liste des newsletters déjà sauvegardées permet de revenir éditer un mois passé.
Les catégories Vie du labo (intranet) (
9), Séance de séminaire (12), Newsletter (20) et Non classé (31) sont exclues de l'UI (EXCLUDED_CATSdansincludes/class-post-query.php). Les séances (cat 12) restent listées, mais imbriquées sous leur séminaire — voir plus bas.
Éligibilité : date d'événement, pas date de publication
Partout où il est question de « la date » d'un contenu, c'est la date de l'événement annoncé qui fait foi, dans l'ordre de priorité du thème : date_de_debut > datetime > post_date. Cet ordre gouverne l'éligibilité, le tri à l'intérieur de chaque section, et la date affichée dans le mail.
Un contenu est proposé pour le mois M s'il remplit l'une des deux conditions :
- Contenu du mois — sa date d'événement est antérieure ou égale à la fin de M, et sa fenêtre de fin (ci-dessous) ne s'est pas achevée avant le début de M ;
- Contenu à venir — sa date d'événement tombe entre la fin de M (ou aujourd'hui si M est déjà passé) et
FUTURE_HORIZON_MONTHS(12 mois). Ces items sont regroupés dans un bloc « À venir », décochés par défaut.
La fenêtre de fin, qui détermine combien de temps un contenu reste proposé après son événement, dépend de la catégorie (SPECIAL_WINDOW_TYPES dans includes/class-post-query.php) :
| Catégorie | Fin de fenêtre |
|---|---|
Appels (8), Soutenances (14) |
date_de_fin (date limite / date de soutenance) |
Colloques (10), Communications (13) |
date_de_fin, sinon date_de_debut |
Ouvrages (15), Articles (16) |
date d'événement + 3 mois |
| Toutes les autres | date d'événement + 35 jours |
Un appel à contribution reste donc proposé dans toutes les newsletters jusqu'à sa date limite, et un événement annoncé six mois à l'avance apparaît à la fois dans le bloc « À venir » des newsletters intermédiaires et dans la liste principale de la newsletter de son propre mois.
Cas particulier : Séminaires (11) → sélection par séance
Le séminaire n'est pas sélectionnable en tant que tel. À la place, le plugin liste ses séances (cat 12) individuellement, chacune avec sa propre case à cocher, regroupées sous le titre (non cliquable) de leur séminaire parent.
- Éligibilité : une séance apparaît si sa
date_de_debuttombe dans le mois, ou dans la fenêtre « à venir » (jusqu'à 12 mois). Un séminaire sans séance dans ces fenêtres n'apparaît pas. Les séances à venir sont décochées par défaut et signalées visuellement. - Découverte : on parcourt les séminaires publiés (cat 11) et on lit leur meta
seances(tableau d'IDs de séances). Le lien parent→séance vit donc sur le séminaire. - Sélection stockée :
_newsletter_sections[11]contient des IDs de séances, plus des IDs de séminaires. - Rendu HTML (
class-html-exporter.php) : les séances cochées sont regroupées par séminaire parent (lookup inverse viaThalim_NL_Post_Query::get_seminar_id_for_seance(), même requête que la redirection#seance-{ID}du thème). Le titre du séminaire est affiché une seule fois, suivi de la liste des séances sélectionnées (date · heure · lieu, lien vers#seance-{id}). - Ordre : les séminaires sont réordonnables entre eux par glisser-déposer (poignée sur le titre) — leur ordre de premier appartenance dans la sélection stockée donne l'ordre de rendu. Les séances d'un séminaire sont toujours triées par
date_de_debutcroissante, dans l'UI comme à l'export.
Catégories couvertes
La liste des catégories éligibles n'est pas codée en dur dans le plugin — elle est calculée dynamiquement via Thalim_NL_Post_Query::get_eligible_categories() (toutes les catégories WordPress, groupées par parent). Les constantes en haut de thalim-newsletter.php (THALIM_NL_CAT_APPELS = 8, etc.) ne servent qu'à associer les fenêtres temporelles spéciales aux catégories concernées :
| Constante | ID | Description |
|---|---|---|
THALIM_NL_CAT_APPELS |
8 | Appels |
THALIM_NL_CAT_COLLOQUES |
10 | Colloques |
THALIM_NL_CAT_SEMINAIRES |
11 | Séminaires |
THALIM_NL_CAT_COMMS |
13 | Communications |
THALIM_NL_CAT_SOUTENANCES |
14 | Soutenances |
THALIM_NL_CAT_OUVRAGES |
15 | Ouvrages |
THALIM_NL_CAT_ARTICLES |
16 | Articles |
THALIM_NL_CAT_NEWSLETTER |
20 | Newsletter (catégorie où sont sauvegardés les digests) |
IDs vérifiés en DB le 2026-03-20. À mettre à jour en cas de migration ou de réorganisation des taxonomies.
Dates affichées dans le mail
Le libellé est construit par Thalim_NL_Post_Query::event_date_label(), qui reprend les règles du thème (thalim_get_agenda_card_data()) :
| Champs renseignés | Rendu |
|---|---|
| début et fin le même jour, avec horaires | Le 9 octobre 2026 de 14:00 à 17:00 |
| début et fin sur plusieurs jours | Du 9 octobre 2026 au 11 octobre 2026 |
| début seul (+ heure éventuelle) | 9 octobre 2026 à 14:00 |
| fin seule — cas des appels à contribution | Jusqu'au 1 septembre 2026 |
datetime seul |
9 octobre 2026 |
| aucune date | date de publication, en dernier recours |
Les ouvrages (15) font exception : année seule, comme les cartes du site.
La même fonction alimente la pastille de date de la liste à cocher — ce que voit le rédacteur est ce qui partira dans le mail.
Format HTML email
includes/class-html-exporter.php génère un HTML compatible clients mail :
- Layout table-based, largeur 600 px
- Styles inline sur tous les éléments
- Polices : Gelasio (Google Fonts
@import, fallback Georgia) pour les titres, Arial/Helvetica pour le corps - Media queries pour le rendu mobile
- Preheader caché (texte d'aperçu dans les boîtes mail)
Le HTML complet est généré à la sauvegarde et stocké tel quel dans post_content — l'export se contente de le renvoyer.
Prérequis
- WordPress 6.0+
- PHP 7.4+
- Plugin Pods (le pod
postet son champ catégorie pour la triple écriture)
Structure
.
├── thalim-newsletter.php # point d'entrée, constantes, bootstrap
├── assets/
│ ├── admin.css # styles de la page admin
│ └── admin.js # interactions (sélecteur mois, cases, export)
└── includes/
├── class-post-query.php # requêtes SQL custom + fenêtres temporelles par catégorie
├── class-html-exporter.php # génération du HTML email (tables, inline styles)
└── class-admin-page.php # UI Tools > Newsletter + handlers AJAX + sauvegarde