- NEWSLETTER-RETOURS-2026-08-27.md : retour du commanditaire sur la newsletter de juillet (annonces à venir absentes, dates de publication affichées à la place des dates d'événement), vérification dans le code et implémentation. - NOTE-SLUG-NUMERIQUE-404-2026-08-27.md : annonces publiées répondant 404 (slug numérique incompatible avec /%category%/%postname%/), diagnostic et implémentation. - CLAUDE.md : nouveau module inc/post-slug-guard.php, piège du titre vide dans post-title-required.php, et bascule de la newsletter sur la date d'événement. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011w7RzAHv4r1Yahnm2NwDDG
203 lines
11 KiB
Markdown
203 lines
11 KiB
Markdown
# Newsletter — retour commanditaire du 27/08/2026
|
||
|
||
> Note de travail rédigée le 2026-08-27, **avant toute modification du code**.
|
||
> Contexte : la newsletter de juillet 2026 est la première réellement envoyée.
|
||
> Le commanditaire remonte deux bugs à corriger.
|
||
> Plugin concerné : `wp-data/wp-content/plugins/thalim-newsletter/`
|
||
> (état au commit `021f322`).
|
||
|
||
## 1. Le mail, en clair
|
||
|
||
Deux demandes :
|
||
|
||
1. **Les annonces futures n'apparaissent pas dans la liste à cocher du backoffice.**
|
||
Pour la NL de juillet, ils ont dû créer les newsletters d'août, septembre et
|
||
octobre uniquement pour aller y récupérer des portions de HTML et les recoller
|
||
à la main dans celle de juillet (ex. : la séance du séminaire Thalim du
|
||
9 octobre). Demande : **lister toutes les annonces à venir, sans limite
|
||
d'horizon**. Les filtres sur le passé, eux, leur conviennent.
|
||
|
||
2. **Les dates affichées sont les dates de publication, pas les dates de
|
||
l'événement annoncé.** Deux exemples cités :
|
||
- l'appel à contribution « La reconnaissance des modernes… » affiche
|
||
« 7 juillet » (sa date de publication) au lieu de « Jusqu'au 1 septembre 2026 » ;
|
||
- les événements culturels affichent la date de publication et non la date
|
||
prévue (ex. la visite insolite du 8 octobre).
|
||
|
||
Les deux points sont **confirmés dans le code** (vérifications ci-dessous, faites
|
||
sur le dump de dev daté du 2026-07-03).
|
||
|
||
## 2. Demande 1 — horizon futur
|
||
|
||
### Ce que fait le code
|
||
|
||
Chaque catégorie a une « fenêtre » `[début, fin]`
|
||
(`includes/class-post-query.php:21-38`). Un item n'est retenu pour le mois M que si :
|
||
|
||
```
|
||
début_fenêtre <= fin_du_mois ET fin_fenêtre >= début_du_mois
|
||
```
|
||
|
||
(`includes/class-post-query.php:303-304`)
|
||
|
||
C'est la condition **`début_fenêtre <= fin_du_mois`** qui coupe tout le futur.
|
||
|
||
| Catégories | Fenêtre | Horizon futur max (NL de juillet) |
|
||
|---|---|---|
|
||
| Colloques (10), Communications (13) | `date_de_debut − 35 j → date_de_fin` | ~**35 jours** |
|
||
| Séances de séminaire (sous 11) | `[1er du mois, fin du mois + 5 j]` | **5 jours** (`SEANCE_WINDOW_MARGIN_DAYS`, l. 38 et 203) |
|
||
| Appels (8), Soutenances (14) | `datetime → date_de_fin` | dépend de `datetime`, **vide en pratique** → retombe sur `post_date` |
|
||
| Ouvrages (15), Articles (16) | `datetime → +3 mois` | idem, piloté par la publication |
|
||
| **Toutes les autres** (dont Événements culturels 18, Médias 19, Captations 23…) | `datetime → +35 j` | idem, piloté par la publication |
|
||
|
||
La séance du 9 octobre citée dans le mail correspond exactement au cas
|
||
`SEANCE_WINDOW_MARGIN_DAYS = 5` : elle ne pouvait pas sortir dans la NL de juillet.
|
||
|
||
### Nuance importante
|
||
|
||
Pour les catégories où `datetime` n'est jamais renseigné (18, 19, 14…), la fenêtre
|
||
est en réalité calculée sur la **date de publication**. Conséquence : un événement
|
||
d'octobre publié en juin apparaît bien dans la NL de juin/juillet (mais avec la
|
||
mauvaise date), alors que le même événement publié en septembre n'apparaîtra jamais
|
||
dans celle de juillet. L'éligibilité est donc incohérente des deux côtés.
|
||
|
||
### Volume
|
||
|
||
Au 3 juillet 2026 (date du dump), seules **5 annonces** avaient une date
|
||
d'événement dans le futur. Ouvrir tout le futur ne fait donc pas exploser la liste,
|
||
mais le nombre grimpera en pleine saison (rentrée).
|
||
|
||
## 3. Demande 2 — dates affichées
|
||
|
||
### Ce que fait le code
|
||
|
||
`format_date_for_category()` (`includes/class-html-exporter.php:542`) ne lit
|
||
`date_de_debut` / `date_de_fin` **que** pour les catégories en fenêtre
|
||
`debut_minus35_to_fin` (colloques et communications). Pour toutes les autres, il lit
|
||
`datetime`, sinon `post_date`.
|
||
|
||
### Ce que dit la base (posts publiés depuis 2025)
|
||
|
||
| Catégorie | ont `datetime` | ont `date_de_debut` | ont `date_de_fin` |
|
||
|---|---|---|---|
|
||
| Événements culturels (18) | **0 / 73** | 69 / 73 | 67 / 73 |
|
||
| Soutenances (14) | 0 / 17 | 17 / 17 | 17 / 17 |
|
||
| Médias (19) | 0 / 48 | 21 / 48 | 21 / 48 |
|
||
| Appels à contribution (8) | 0 / 18 | 1 / 18 | 1 / 18 |
|
||
|
||
Donc pour les événements culturels, c'est **systématiquement** la date de
|
||
publication qui sort. Idem pour les soutenances. Sur les appels récents, `datetime`
|
||
vaut souvent littéralement `0000-00-00`, et la date limite est bien stockée dans
|
||
`date_de_fin` — champ utilisé pour l'éligibilité mais **jamais affiché**, et sans
|
||
préfixe « Jusqu'au ».
|
||
|
||
### Trois conséquences supplémentaires, non mentionnées dans le mail
|
||
|
||
- **Le tri interne à chaque section** utilise la même date fausse
|
||
(`ORDER BY`, `includes/class-post-query.php:305`) : les événements culturels sont
|
||
classés par date de publication.
|
||
- **Le backoffice affiche la bonne date, l'email la mauvaise** : la pastille de la
|
||
liste à cocher (`includes/class-admin-page.php:356`) lit bien `date_de_debut` en
|
||
premier. D'où la surprise à la lecture du mail réellement envoyé.
|
||
- **Le thème a déjà la logique attendue** : `thalim_get_agenda_card_data()`
|
||
(`wp-data/wp-content/themes/thalim/inc/ajax.php:180-215`) produit exactement
|
||
« Le X de H1 à H2 » / « Du X au Y » / « Jusqu'au X », sur la convention
|
||
`date_de_debut > datetime > post_date`. Le plugin ne la réutilise pas : il a
|
||
réimplémenté une version partielle.
|
||
|
||
## 4. Modifications à faire
|
||
|
||
1. **Requête — supprimer le plafond futur.**
|
||
Garder le critère de fin (ne pas ressortir ce qui est terminé avant le mois),
|
||
mais accepter n'importe quelle date de début à venir : lever la condition
|
||
`début_fenêtre <= fin_du_mois`, et pour les séances remplacer
|
||
`[début du mois, fin du mois + 5 j]` par `[début du mois, +∞[`.
|
||
|
||
2. **Dates — aligner sur la convention du thème.**
|
||
`date_de_debut > datetime > post_date` pour **toutes** les catégories, et
|
||
reprendre les libellés de `thalim_get_agenda_card_data()` : « Du … au … »,
|
||
« Jusqu'au … » quand seule `date_de_fin` existe (cas des appels), heures quand
|
||
elles sont renseignées. Le plus propre est de **factoriser** cette logique
|
||
plutôt que de la dupliquer une troisième fois (thème + exporter + hint admin).
|
||
|
||
3. **Tri** — trier par date d'événement réelle, pas par `datetime` / `post_date`.
|
||
|
||
## 5. Points à arbitrer avec le commanditaire
|
||
|
||
- **Cochage par défaut.** Aujourd'hui, sur un mois neuf, *tout est coché*
|
||
(`render_sections_html()`, `$check_all`). Si on injecte tout le futur, la NL de
|
||
juillet partirait pré-cochée avec des événements de mars suivant.
|
||
Proposition : passé et mois courant cochés par défaut, futur au-delà du mois
|
||
listé mais **décoché**, dans un sous-bloc « À venir » visuellement distinct.
|
||
C'est ce qui change le plus leur geste quotidien → à valider avant de coder.
|
||
|
||
- **« Jusqu'au » sur les appels** suppose que `date_de_fin` soit saisie côté
|
||
rédaction. Sur les appels publiés depuis janvier 2026, un seul sur sept l'a.
|
||
Sans ce champ, aucune date correcte n'est récupérable et on retombera sur la date
|
||
de publication → à leur signaler comme consigne de saisie.
|
||
|
||
## 6. Repères techniques
|
||
|
||
- Dump de dev utilisé pour les vérifications : contenu jusqu'au **2026-07-03**
|
||
(le post « La reconnaissance des modernes… » n'y est donc pas ; l'analyse porte
|
||
sur la logique, pas sur ce post précis).
|
||
- Newsletters enregistrées en base de dev : avril, mai, juin 2026.
|
||
- Conteneur de base : `thalim-dev-db-1` (`docker compose up -d db`).
|
||
- Catégories vérifiées en base le 2026-08-27 : les IDs historiques du README
|
||
(8, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20) sont toujours exacts.
|
||
À noter : `Séance de séminaire` (12) a pour parent `Séminaires` (11), pas 0.
|
||
|
||
## 7. Au passage (hors périmètre du retour)
|
||
|
||
- `PARENT_COLORS` (`includes/class-html-exporter.php:35-41`) est encore indexé sur
|
||
des term_ids en dur (1, 3, 4, 5, 6), contrairement à la convention du projet
|
||
(résolution par slug). À traiter si on repasse dans ce fichier.
|
||
|
||
## 8. Implémentation — 2026-08-27
|
||
|
||
Faite dans `thalim-plugin-newsletter`.
|
||
|
||
**Les trois modifications demandées :**
|
||
|
||
1. **Horizon futur ouvert** — le plafond « début de fenêtre ≤ fin du mois » est
|
||
remplacé par une fenêtre « à venir » de **12 mois**
|
||
(`FUTURE_HORIZON_MONTHS`), qui démarre à la fin du mois de la newsletter ou
|
||
à aujourd'hui si ce mois est déjà passé. Les séances suivent la même règle
|
||
(la marge de 5 jours, `SEANCE_WINDOW_MARGIN_DAYS`, est supprimée).
|
||
2. **Dates** — `Thalim_NL_Post_Query::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
|
||
désormais la même chose. Les ouvrages restent en année seule.
|
||
3. **Tri** — `sql_event_date_order()` remplace le tri par date de publication
|
||
dans toutes les catégories.
|
||
|
||
**Écarts et ajouts par rapport à la note, décidés en cours d'implémentation :**
|
||
|
||
- **Horizon borné plutôt qu'ouvert.** Un futur strictement illimité faisait
|
||
remonter tout l'historique postérieur au mois demandé : ouvrir la newsletter
|
||
de janvier 1999 saturait les 128 Mo de PHP (fatal). Le double plafond
|
||
(12 mois, et jamais avant aujourd'hui) borne la liste sans rien retirer des
|
||
cas réels — la séance du 13 novembre 2026 entre bien dans la newsletter de
|
||
juillet 2026.
|
||
- **Fenêtres de fin recalées sur la date d'événement.** Les fenêtres « +35 j »
|
||
et « +3 mois » partaient de la date de publication : 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. Vérifié sur quatre événements culturels
|
||
annoncés 36 à 137 jours à l'avance : tous absents avant, tous présents après.
|
||
C'est probablement l'autre moitié du « certains items du futur
|
||
n'apparaissaient pas » du commanditaire.
|
||
- **`merge_selected_items()`** — filet de sécurité : 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 (le formulaire ne soumet que ce qui est affiché).
|
||
Vérifié : la newsletter de juin restitue ses 54 items cochés.
|
||
|
||
**Point à valider par le commanditaire** (l'arbitrage du §5 n'avait pas été
|
||
tranché) : sur un mois neuf, tout est coché **sauf** le bloc « À venir », qui
|
||
est listé, visuellement distinct et décoché. Les séances à venir suivent la même
|
||
règle sans bloc séparé (elles restent groupées sous leur séminaire).
|
||
|
||
**Non traité** : la saisie de `date_de_fin` sur les appels à contribution reste
|
||
une consigne éditoriale — sans ce champ, aucun « Jusqu'au … » n'est possible.
|