# 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 ```bash 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`](https://figureslibres.io/valentin_le_moign/thalim-stack). ## Utilisation Une fois activé, le plugin ajoute une page d'administration : **Outils → Newsletter** (capacité requise : `edit_others_posts`). Le workflow : 1. Sélection d'un mois (sélecteur année-mois) 2. Chargement AJAX (`thalim_nl_load_month`) des contenus éligibles, regroupés par catégorie parente 3. 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 4. **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é 5. Champs **intro**, **conclusion**, **URL d'inscription**, **URL de désinscription** 6. Sauvegarde : crée un post WordPress dans la catégorie **Newsletter** (`20`) avec le HTML email complet en `post_content` 7. Bouton **Exporter en HTML** (`thalim_nl_export_html`) → téléchargement du fichier `newsletter-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_CATS` dans `includes/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 : 1. **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 ; 2. **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_debut` tombe 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 via `Thalim_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_debut` croissante, 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 `post` et 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 ```