From a1d862328c385eea60c74c52ad4856c97dfc39c9 Mon Sep 17 00:00:00 2001 From: Valentin Le Moign Date: Wed, 10 Jun 2026 21:31:01 +0200 Subject: [PATCH] =?UTF-8?q?CLAUDE.md=20:=20mise=20=C3=A0=20jour=20apr?= =?UTF-8?q?=C3=A8s=20refactoring=20du=20th=C3=A8me=20et=20des=20plugins?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 49 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 522b6d2..0221f6f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -25,17 +25,19 @@ docker-compose down Timber/Twig. Chaque `*.php` charge un Twig de `templates/`. `base.twig` est le layout, les autres l'étendent. -- `functions.php` — gros (≈1400 lignes) : setup, i18n, contexte Twig, AJAX, filtres de requête, customisations admin -- `inc/` — helpers PHP par contexte (voir détails plus bas) +- `functions.php` — simple chargeur : init Timber + `require_once` des modules `inc/*` (l'ordre compte : `config.php` et `i18n.php` d'abord) +- `inc/` — toute la logique PHP, un module par responsabilité (voir détails plus bas) - `templates/` + `templates/partials/` — Twig - `scss/` → `css/` — SASS compilé **manuellement** par l'utilisateur (CSS commité) -- `js/` — scripts frontend et `adminDashboardMods.js` (admin) +- `js/` — scripts frontend ; `js/admin/` — scripts admin par contexte de page (voir « Customisations admin ») +- `assets/vendor/` — dépendances tierces auto-hébergées (Swiper 12.2.0, Iconoir 7.11.0) — plus aucun CDN - `vendor/` — Composer (Timber 2.x). `composer install` après clone +- `tests/run-tests.php` — tests des fonctions pures, à exécuter via `docker exec wordpress php /var/www/html/wp-content/themes/thalim/tests/run-tests.php` (idem dans chaque plugin) ### Plugins maison -- **`thalim-hal-importer/`** — import publications HAL (structure 254015). Admin : Outils → HAL Import. Voir le README du plugin pour le mapping doc types → catégories (10 types : ART, COUV, OUV, COMM, ISSUE, PROCEEDINGS, THESE, HDR, SON, VIDEO). -- **`thalim-newsletter/`** — composition et export HTML des digests mensuels. Admin : Outils → Newsletter. Voir le README du plugin pour les constantes de catégories. +- **`thalim-hal-importer/`** — import publications HAL (structure 254015). Admin : Outils → HAL Import. Voir le README du plugin pour le mapping doc types → catégories (10 types : ART, COUV, OUV, COMM, ISSUE, PROCEEDINGS, THESE, HDR, SON, VIDEO). Les catégories sont résolues **par slug** et les IDs Pods **par nom** ; toute écriture de relation Pods passe par `includes/class-pods-storage.php` (dépendance dure à Pods 3.x documentée dans le fichier — ne pas écrire `wp_podsrel` ailleurs). +- **`thalim-newsletter/`** — composition et export HTML des digests mensuels. Admin : Outils → Newsletter. Les constantes `THALIM_NL_CAT_*` sont résolues par slug au chargement (transient 1 j, fallback IDs historiques) ; le pod/champ `categorie` est résolu par nom dans `class-admin-page.php`. ### Plugins WP requis @@ -46,7 +48,7 @@ Timber/Twig. Chaque `*.php` charge un Twig de `templates/`. `base.twig` est le l ## Multilingue (système maison) -Polylang a été **remplacé** par un système custom. Toute la logique vit dans `functions.php`. +Polylang a été **remplacé** par un système custom. Toute la logique vit dans `inc/i18n.php`. - **Détection** : `thalim_current_language()` retourne `'en'` si `THALIM_ORIGINAL_URI` commence par `/en/`, sinon `'fr'`. Le préfixe `/en/` est strippé via `do_parse_request` avant la résolution d'URL WP, et `redirect_canonical` est désactivé sur les URLs `/en/` pour éviter que WP ne supprime le préfixe - **Champs texte bilingues** : convention `"FR // EN"` dans un même champ. `thalim_bilingual($value, $lang)` (exposé comme filtre Twig `|bilingual`) renvoie la bonne moitié. Utilisé partout : titres de posts, noms de termes de taxonomie, sous-titres, lieux, fonctions, types, etc. @@ -64,15 +66,26 @@ Les annonces ont une `date_de_debut` / `date_de_fin` (champ date Pods) ou un `da - **Activation** : ajouter `'thalim_event_date_order' => true` aux args d'un `WP_Query` (ou Timber) - **Filtre de plage** : `'thalim_event_date_filter' => ['from' => 'YYYY-MM-DD', 'to' => 'YYYY-MM-DD']` -- **Implémentation** : filtres `posts_join` + `posts_orderby` + `posts_where` dans `functions.php`. LEFT JOIN sur `postmeta` puis `CASE WHEN date_de_debut ELSE datetime ELSE post_date END DESC`. Les valeurs `0000-00-00...` sont traitées comme NULL -- **Format d'affichage** : `thalim_format_date($raw, $lang)` dans `inc/single-helpers.php` renvoie `date_i18n('j F Y', $ts)`. Les abréviations de mois (3-lettres) pour les vignettes agenda sont codées en dur dans `functions.php` (`thalim_get_agenda_card_data()`) et dans `inc/single-helpers.php` (séances) +- **Implémentation** : filtres `posts_join` + `posts_orderby` + `posts_where` dans `inc/event-dates.php`. LEFT JOIN sur `postmeta` puis `CASE WHEN date_de_debut ELSE datetime ELSE post_date END DESC`. Les valeurs `0000-00-00...` sont traitées comme NULL +- **Format d'affichage** : `thalim_format_date($raw, $lang)` dans `inc/single-helpers.php` renvoie `date_i18n('j F Y', $ts)`. Les abréviations de mois (3-lettres) pour les vignettes agenda sont codées en dur dans `inc/ajax.php` (`thalim_get_agenda_card_data()`) et dans `inc/single-helpers.php` (séances) - **Construction du `date_label`** : la logique « Le X de H1 à H2 / Du X au Y / Jusqu'au X / X à H » vit dans `thalim_get_agenda_card_data()` — à dupliquer prudemment si besoin ailleurs ## Helpers PHP (`inc/`) | Fichier | Rôle | |---|---| -| `single-helpers.php` | `thalim_get_single_data($post_id)` résout tous les champs Pods d'un post en tableau prêt pour Twig : dates formatées, images vs documents (split par mime-type), membres résolus en `{name, url}`, taxonomies (axes, étiquettes, programmes), séances triées en `seances_a_venir` / `seances_passees`, hiérarchie de catégorie, `type_label` et `fonction_label` dérivés des champs `type_*` / `fonction_*` ou (legacy) du `_pods_categorie`, liens externes (1–3), Canal-U / YouTube embeds. Inclut aussi `thalim_format_date()` (partagée). | +| `config.php` | **Identifiants centralisés** : `thalim_term_id_by_slug()` (slug → term_id, cache statique), `thalim_cat_id($cle)` (catégories structurelles par clé logique — attention, le slug de la cat 9 est `vie-du-labo-intranet`), `thalim_excluded_role_ids()`, `thalim_category_color_slug()` (seule map encore indexée sur term_id). **Ne jamais réintroduire d'ID numérique en dur** : passer par ces fonctions | +| `i18n.php` | Multilingue maison complet (cf. section dédiée) | +| `assets.php` | Enqueue front + admin (scripts admin conditionnels par écran via `get_current_screen()`) | +| `context.php` | `add_to_context()` (contexte Twig global) | +| `event-dates.php` | Filtres `posts_join/orderby/where` du tri par événement, `thalim_get_active_pinned_ids()`, `thalim_get_axes_filter_groups()` | +| `seance-helpers.php` | `thalim_get_seance_parent_id()` (mémoïsée — la seule résolution séance→séminaire, utilisée partout), `thalim_get_seance_link()`, redirection `template_redirect` séance→parent | +| `ajax.php` | Handlers `load_more_posts` / `load_more_agenda` + helpers partagés `thalim_ajax_read_filters()` / `thalim_ajax_build_query_args()`, `thalim_get_agenda_card_data()` | +| `archive-filters.php` | Helpers partagés des 4 contrôleurs d'archives (category/taxonomy/search/page-annonces) : exclusions, lecture des filtres GET, rubrique active, posts « directs », listes de filtres (liens injectés en closure par chaque contrôleur) | +| `access-control.php` | Restrictions contributeurs (`pre_get_posts`, `user_has_cap`, `wp_count_posts`), Vie du labo, redirections login/dashboard | +| `admin-tweaks.php` | Synchro `display_name`, Pods sur user-new, colonnes taxonomies, filtre catégorie exact, rewrite `/autres`, admin bar, `user_can_richedit` | +| `avatars.php` | `thalim_get_user_avatar_url()` (voir « Avatars ») | +| `single-helpers.php` | `thalim_get_single_data($post_id)` résout tous les champs Pods d'un post en tableau prêt pour Twig : dates formatées, images vs documents (split par mime-type), membres résolus en `{name, url}`, taxonomies (axes, étiquettes, programmes), séances triées en `seances_a_venir` / `seances_passees`, hiérarchie de catégorie, `type_label` et `fonction_label` dérivés des champs `type_*` / `fonction_*` ou (legacy) du `_pods_categorie`, liens externes (1–3), Canal-U / YouTube embeds. Inclut aussi `thalim_format_date()` (partagée). **Champs profil/HTML passés par `wp_kses_post`** (autoescape Twig désactivé) | | `author-helpers.php` | `thalim_get_author_data($user_id)` (profil membre) et `thalim_get_author_posts_by_category($user_id)` (posts liés au membre, groupés par catégorie primaire, plus un groupe spécial « séances de séminaire » via cat 12). Tri inter-groupes par `ordre_profil` (term meta) puis par nombre de posts | | `membres-helpers.php` | Page `/membres` : `thalim_get_membres_groups()` regroupe par slugs de rôle taxonomy (mapping codé en dur dans `$group_definitions` — voir « Page membres » plus bas) | | `post-card-helpers.php` | `thalim_get_card_data($post_id)` / `thalim_get_cards_data($posts)` : données pour `partials/post-card.twig`. Inclut la résolution catégorie parente pour le code couleur (`parent_slug`), la première image (medium), la `card_event_date`, et la redirection `#seance-{ID}` pour les séances de séminaire | @@ -83,10 +96,10 @@ Les annonces ont une `date_de_debut` / `date_de_fin` (champ date Pods) ou un `da ### Avatars (chaîne de fallback) -`thalim_get_user_avatar_url($user_id)` dans `functions.php` : +`thalim_get_user_avatar_url($user_id)` dans `inc/avatars.php` : 1. Simple Local Avatar (`simple_local_avatar` user meta) — résolu via `media_id` quand dispo (pour survivre aux changements de domaine), sinon URL réécrite -2. Gravatar (HEAD request avec `d=404`) — résultat (positif ou négatif) caché 1 semaine en transient `thalim_gravatar_{ID}` +2. Gravatar — lu **uniquement** depuis le transient `thalim_gravatar_{ID}` (1 semaine). Aucune requête réseau dans le rendu : le HEAD `d=404` est fait par le cron quotidien `thalim_warm_gravatar_cache` (+ réchauffage unitaire `thalim_warm_gravatar_user` planifié à la volée en cas de cache manquant) 3. Chaîne vide → templates fallback initiales ## Pages spécifiques @@ -140,7 +153,19 @@ Sur les pages de taxonomie/tag, les **séances de séminaire (cat 12)** sont exc ## Customisations admin -`js/adminDashboardMods.js` (≈900 lignes) + `css/admin.css`. L'admin est très modifié. +`js/admin/*` + `css/admin.css`. L'admin est très modifié. Les scripts sont découpés +par contexte de page et enqueués conditionnellement (`inc/assets.php`, via +`get_current_screen()`) : + +- `admin-base.js` — toutes pages : namespace `window.ThalimAdmin` (table `CONFIG` + des sélecteurs/IDs Pods, `safeRun()` pour isoler chaque module dans un try/catch, + `ensureVisualMode`, `reinitEditor`, `updatePostboxVisibility`, `INFO_TIPS` + + `initInfoPopovers`, `markReady` + fallback reveal 2 s) +- `admin-rename.js` — toutes pages : rename « Article » → « Annonce » +- `admin-post-edit.js` — `post.php`/`post-new.php` (reçoit `thalimAxesGroups`) +- `admin-profile.js` — profil / user-edit / user-new +- `admin-taxonomy-list.js` — `edit-tags.php`/`term.php` (popovers FR//EN, filtre type de programme, mode visuel) +- `admin-pods-modal.js` — iframe `?pods_modal` (verrou catégorie séance) ### Patterns transversaux