feat: thème WordPress sur mesure Union Locale CGT Foix Haute-Ariège (v1.2.0)

This commit is contained in:
Union Locale CGT Foix Haute-Ariège 2026-11-12 21:27:56 +01:00
commit 4c51761c75
30 changed files with 5215 additions and 0 deletions

26
.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
# Système
.DS_Store
Thumbs.db
desktop.ini
ehthumbs.db
# Éditeurs & IDE
.vscode/
.idea/
*.sublime-workspace
*.sublime-project
*.swp
*.swo
*~
# Logs & temporaires
*.log
*.tmp
*.bak
.env
.env.local
# Dépendances locales éventuelles (non requises par le thème)
node_modules/
vendor/
composer.phar

41
404.php Normal file
View File

@ -0,0 +1,41 @@
<?php
/**
* Gabarit de page d'erreur 404 utile avec recherche et liens directs vers l'UL (404.php).
*
* @package CGT_FHA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
get_header();
$opts = cgt_fha_get_options();
?>
<section class="cgt-section cgt-section--white cgt-404">
<div class="cgt-container--narrow">
<span class="cgt-404__code">404</span>
<h1><?php esc_html_e( 'Cette page est introuvable', 'cgt-fha' ); ?></h1>
<p style="color:var(--text-muted); max-width:560px; margin-inline:auto;">
<?php esc_html_e( 'Le lien que vous avez suivi a peut-être été déplacé ou n\'existe plus. Effectuez une recherche ou accédez directement aux services de l\'Union Locale CGT Foix Haute-Ariège.', 'cgt-fha' ); ?>
</p>
<form role="search" method="get" class="cgt-search-form" action="<?php echo esc_url( home_url( '/' ) ); ?>">
<label for="cgt-404-search" class="screen-reader-text"><?php esc_html_e( 'Rechercher sur le site', 'cgt-fha' ); ?></label>
<input type="search" id="cgt-404-search" name="s" placeholder="<?php esc_attr_e( 'Rechercher une actualité, un droit…', 'cgt-fha' ); ?>" />
<button type="submit" class="cgt-btn cgt-btn--primary"><?php esc_html_e( 'Rechercher', 'cgt-fha' ); ?></button>
</form>
<div class="cgt-network-strip">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>" class="cgt-network-link">Accueil</a>
<a href="<?php echo esc_url( cgt_fha_get_local_news_archive_url() ); ?>" class="cgt-network-link">Actualités locales</a>
<a href="<?php echo esc_url( (string) $opts['calendar_url'] ); ?>" class="cgt-network-link">Calendrier</a>
<a href="<?php echo esc_url( (string) $opts['contact_url'] ); ?>" class="cgt-network-link">Urgence salarié / Contact</a>
<a href="<?php echo esc_url( (string) $opts['join_url'] ); ?>" class="cgt-network-link">Rejoindre la CGT</a>
</div>
</div>
</section>
<?php
get_footer();

211
AGENTS.md Normal file
View File

@ -0,0 +1,211 @@
# AGENTS.md — CAHIER DES CHARGES COMPLET : THÈME WORDPRESS `cgt-wp-theme`
**Projet :** Site officiel de l'Union Locale CGT Foix Haute-Ariège (`https://cgt-fha.fr/`)
**Dépôt Gitea officiel :** `https://git.cgt-fha.fr/Union_Locale_CGT_Foix_Haute-Ariege/cgt-wp-theme.git`
**Chemin de déploiement VPS :** `/var/www/fastuser/data/www/cgt-fha.fr/wp-content/themes/cgt-fha/`
**Ressource Skills locale :** `../skills/` (`../skills/wp-performance/SKILL.md` et `../skills/wp-block-themes/SKILL.md`)
**Ressource graphique locale :** `../ressources/banniere union locale noir.png` (à copier dans `assets/img/banniere-ul-noir.png` et utiliser comme logo par défaut de l'en-tête)
**Maquette de référence visuelle :** L'utilisateur fournit l'image de maquette validée en pièce jointe. Respecte fidèlement sa hiérarchie visuelle, ses proportions, ses espacements et son style graphique.
---
## 1. PHILOSOPHIE TECHNIQUE, SKILLS & RÈGLES D'ARCHITECTURE
Tu es l'unique développeur de ce thème WordPress sur mesure. Ce thème remplace un thème généraliste bridé (*Neve*) pour offrir une souveraineté totale, une vitesse de chargement maximale et une ergonomie pensée pour les salariés et militants de Haute-Ariège[cite: 6].
- **Utilisation des Skills (`../skills/`) :**
- Lis et applique les bonnes pratiques définies dans `../skills/wp-performance/SKILL.md` (optimisation des requêtes, cache Transients, WP-Cron) et `../skills/wp-block-themes/SKILL.md` (uniquement pour la structure propre de `theme.json`)[cite: 6].
- **Restriction stricte :** Ne génère **jamais** de blocs Gutenberg personnalisés en React (`@wordpress/scripts`, `block.json` compilés) ni de Full Site Editing complet[cite: 6].
- **Architecture : Thème PHP Classique / Hybride Moderne :**
- Utilise des gabarits PHP 8.x propres, typés et sécurisés (`header.php`, `footer.php`, `front-page.php`, `home.php`, `single.php`, `page.php`, `archive.php`, `404.php`)[cite: 6].
- Utilise `theme.json` uniquement pour déclarer la palette de couleurs CGT et les typographies dans l'éditeur d'articles[cite: 6].
- **Zéro dépendance externe lourde (RGPD & Performance) :**
- CSS moderne natif (`CSS Custom Properties`, `CSS Grid`, `Flexbox`, mobile-first). Aucune bibliothèque CSS externe (pas de Bootstrap ni Tailwind CDN)[cite: 6].
- JavaScript *Vanilla* ES6 minimaliste uniquement pour le menu mobile accessible et les onglets de l'admin (pas de jQuery)[cite: 6].
- Aucune police Google Fonts chargée via CDN tiers : utilise des polices système modernes (`system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`) ou des fichiers hébergés localement[cite: 6].
- **100 % Modifiable sans toucher au code :**
- En dehors des articles locaux (publiés dans WordPress) et des actualités confédérales extraites automatiquement depuis `cgt.fr`, **tous les textes, images, icônes, liens, boutons et coordonnées du thème doivent être modifiables depuis l'administration WordPress** (*Apparence > Réglages UL CGT* + *Apparence > Menus* + *Médiathèque*).
- **Pré-remplissage obligatoire par défaut :** Toutes les options doivent posséder des valeurs par défaut complètes (définies via `wp_parse_args()`) afin que le site soit immédiatement fonctionnel et complet dès l'activation du thème, sans aucune zone vide.
- **Intégration propre avec les extensions sœurs (Gitea) :**
- Le thème gère le visuel, le SEO/OpenGraph de base, le bandeau de mobilisation et l'encart d'actualités confédérales[cite: 6].
- Il prévoit des hooks/emplacements propres (`do_action(...)` / support de shortcodes) pour accueillir les sorties des extensions `cgt-wp-calendar` (Agenda) et `cgt-wp-forms` (Formulaires Défense, Adhésion, Formation), tout en affichant un rendu cohérent même si ces extensions ne sont pas encore activées[cite: 6].
---
## 2. IDENTITÉ VISUELLE & CHARTE GRAPHIQUE
- **Couleur primaire (Rouge CGT) :** `--cgt-red: #d20012;` (hover : `--cgt-red-dark: #a8000e;`)[cite: 7]
- **Couleurs neutres & surfaces :**
- Fond principal : `--bg-main: #ffffff;`
- Fond alterné (section Confédérale / Formation / Footer) : `--bg-soft: #f1f3f5;`
- Barre supérieure contact : `--bg-topbar: #1c1e21;`
- Texte principal : `--text-main: #1a1a1a;`
- Texte secondaire : `--text-muted: #4a5568;`
- Bordures des cartes : `--border-card: #cbd5e1;`
- Rayons d'arrondi : `--radius-card: 12px;` à `14px`, boutons pilules `--radius-pill: 999px;`.
---
## 3. EN-TÊTE (`header.php`) & NAVIGATION
Respecte exactement le haut de la maquette de référence :
1. **Barre supérieure (`topbar`) :**
- Fond sombre (`#1c1e21`), texte blanc fin (`13px`).
- À gauche : icône téléphone + lien `tel:` (`07 60 49 64 69` par défaut) et icône enveloppe + lien `mailto:` (`union-locale@cgt-fha.fr` par défaut)[cite: 7].
- À droite : icônes réseaux sociaux (Facebook officiel de l'UL `https://www.facebook.com/profile.php?id=61552410568856`, etc., éditables dans les réglages)[cite: 7].
2. **Bandeau d'Alerte Mobilisation Auto-Expirant :**
- Bandeau pleine largeur sur fond rouge CGT (`#d20012`), texte blanc centré en gras (ex. : `MOBILISATION : Grève et manifestation à Foix - Allées de Villote`), cliquable si une URL est renseignée[cite: 6].
- **Condition stricte d'affichage :** S'affiche uniquement si la case *Activer le bandeau* est cochée **ET** que l'horodatage actuel (`current_time('timestamp')`) est strictement inférieur à la *Date et heure d'expiration* configurée dans l'admin[cite: 6]. Passé ce délai, le bandeau disparaît automatiquement[cite: 6].
3. **Barre de Navigation Principale (`<header>`) :**
- Fond blanc, hauteur confortable, ombre légère au défilement.
- À gauche : Logo officiel de l'Union Locale CGT Foix Haute-Ariège (modifiable via `custom_logo` dans WordPress, avec fallback SVG/PNG local propre).
- À droite : Menu principal horizontal (`wp_nav_menu` : **Accueil**, **Actualités**, **Calendrier**, **Contact**), avec soulignement rouge sur l'élément actif.
- **IMPORTANT :** Ne mets **PAS** de bouton rouge « Syndiquez-vous » dans cette barre de navigation (pour éviter la répétition avec le Hero juste en dessous).
- Sur mobile (`< 768px`) : bouton menu hamburger accessible (`aria-expanded="false"`, contrôle clavier `Escape`).
---
## 4. PAGE D'ACCUEIL (`front-page.php`) — STRUCTURE COMPLÈTE
La page d'accueil s'articule en **7 sections verticales** dans cet ordre exact :
### Section 1 : Bannière Hero Plein Écran (Ancrage Territorial & Action)
- **Visuel de fond :** Image panoramique des montagnes d'Ariège / territoire (configurable dans l'admin avec une image par défaut intégrée dans `assets/img/hero-ariege.jpg`), recouverte d'un voile sombre dégradé (`rgba(15, 18, 22, 0.62)`) assurant une lisibilité parfaite du texte blanc.
- **Contenu centré verticalement et horizontalement :**
- Titre principal (`<h1>`, blanc, grand, gras, 2 lignes) :
`Union Locale CGT Foix Haute-Ariège`
`Votre syndicat de proximité !`
- Citation centrée en dessous (blanc doux, italique, éditable dans l'admin) :
`« La régression sociale ne se négocie pas, elle se combat ! » — Henri Krasucki, Secrétaire Général de la CGT de 1982 à 1992`
- **Deux boutons d'action centrés côte à côte** (`display: flex; justify-content: center; gap: 1rem; flex-wrap: wrap;`) :
1. Bouton gauche (fond blanc `#ffffff`, texte noir `#1a1a1a`, coins arrondis `8px`, gras) : **« J'ai besoin d'aide »** (lien configurable, par défaut vers la page Contact / Urgence salarié)[cite: 6].
2. Bouton droit (fond sombre translucide ou rouge foncé, bordure blanche/rouge, texte blanc, coins arrondis `8px`, gras) : **« Rejoindre la CGT »** (lien configurable, par défaut vers la page Syndiquez-vous)[cite: 6].
### Section 2 : Module « À QUOI NOUS SERVONS ? » (3 Cartes de Mission)
Placé **immédiatement sous le Hero et avant les actualités** (fond blanc `#ffffff`) :
- **Titre de section :** `À QUOI NOUS SERVONS ?` centré en majuscules (`<h2>`).
- **Grille 3 colonnes** (`grid-template-columns: repeat(3, 1fr); gap: 1.5rem;`, 1 colonne sur mobile) :
- Chaque carte possède un fond blanc, une bordure fine (`1px solid #cbd5e1`), des coins arrondis (`border-radius: 12px`), un padding généreux (`1.75rem`) et un contenu centré :
1. **Carte 1 :** Icône poing levé / collectif (SVG propre) • Titre `S'ORGANISER` • Texte par défaut : *« Construire le syndicat dans votre entreprise, préparer les élections CSE et ne plus rester isolé face à l'employeur. »*
2. **Carte 2 :** Icône bouclier (SVG propre) • Titre `SE DÉFENDRE` • Texte par défaut : *« Faire respecter vos droits, vos salaires et vos conditions de travail, avec l'appui de nos conseillers du salarié et juristes. »*
3. **Carte 3 :** Icône bulles d'échange / livre (SVG propre) • Titre `S'INFORMER & SE FORMER` • Texte par défaut : *« Connaître les actualités des luttes en Haute-Ariège et bénéficier de vos droits à la formation syndicale (CFESES). »*
- *Note :* Les icônes (sélecteur parmi une bibliothèque SVG intégrée), titres et textes de ces 3 cartes sont modifiables dans l'admin WordPress.
### Section 3 : Vitrine 1 — « SUR LE TERRAIN EN HAUTE-ARIÈGE » (Actualités Locales)
- **Priorité éditoriale locale :** Affiche automatiquement les **3 derniers articles publiés** dans le WordPress de l'UL (`WP_Query` sur `post_type => 'post'`, `posts_per_page => 3`)[cite: 6].
- **Titre de section :** `SUR LE TERRAIN EN HAUTE-ARIÈGE` centré en majuscules (`<h2>`).
- **Mise en page des 3 cartes** (fidèle à la maquette) :
- Grille 3 colonnes (`gap: 1.5rem`).
- Image à la une en haut avec coins arrondis (`border-radius: 12px; height: 190px; object-fit: cover; width: 100%;`), avec fallback SVG propre si un article n'a pas d'image.
- Juste sous l'image : une pilule rouge CGT (`background: #d20012; color: #fff; border-radius: 999px; font-size: 12px; padding: 2px 10px;`) affichant la catégorie principale (ex. *Mobilisation*, *Vie syndicale*) suivie de la date de publication (`d.m.Y`).
- Titre de l'article en gras (`18px`) cliquable vers `single.php`.
- Extrait nettoyé (`wp_trim_words`, ~20 mots).
- **Pied de section :** Bouton lien discret centré *« Voir toutes les actualités locales → »* vers la page des articles (`get_permalink(get_option('page_for_posts'))`), suivi du hook `do_action('cgt_fha_after_local_news');` permettant d'injecter les prochains rendez-vous de `cgt-wp-calendar`[cite: 6].
### Section 4 : Vitrine 2 — « ACTUALITÉ CONFÉDÉRALE » (Récupération automatique `cgt.fr`)
- **Fond de section :** Gris très doux (`#f1f3f5`) pour bien la distinguer des actualités locales.
- **Titre de section :** `ACTUALITÉ CONFÉDÉRALE` centré en majuscules (`<h2>`).
- **Moteur PHP (`inc/class-cgt-confederal-feed.php`) :**
- Interroge `https://www.cgt.fr/` via `wp_remote_get()` (timeout 10s, User-Agent propre) et parse le HTML avec `DOMDocument` + `DOMXPath` (sans polluer `wp_posts`) :
- **1 article `featured` (« À la une ») :** extrait depuis la section *"à la une de la cgt"* (`title`, `summary`, `image_url` convertie en URL absolue `https://www.cgt.fr/...`, `category`, `url`).
- **3 articles `latest` (`ARTICLE 1`, `ARTICLE 2`, `ARTICLE 3`) :** extraits depuis les 3 premiers articles de la section suivante *"mais aussi..."* (complétés via `https://www.cgt.fr/actualites` si un résumé est manquant).
- **Fallback de sécurité :** Si la page d'accueil `cgt.fr` échoue ou change de structure DOM, bascule automatiquement sur les 4 premiers articles de `https://www.cgt.fr/actualites` (le 1er devient `featured`, les 3 suivants deviennent `latest`).
- **Cache & WP-Cron :** Stockage dans le transient `cgt_fha_confederal_feed` (expiration 3h) + sauvegarde de secours `cgt_fha_confederal_feed_backup` conservée en cas d'indisponibilité réseau. Événement `WP-Cron` toutes les 2 heures + bouton *"Actualiser les actus confédérales"* dans la barre d'admin WordPress (`admin_bar_menu`).
- **Rendu HTML/CSS fidèle à la maquette :**
- **Bloc supérieur « À LA UNE » :**
- Conteneur centré (`max-width: 880px; margin: 0 auto 2.5rem auto;`), disposition horizontale Flexbox (`align-items: center`).
- À gauche (`flex: 0 0 58%`) : Image de l'article (`border-radius: 14px; height: 290px; object-fit: cover;`) avec un badge overlay discret en bas à droite `À LA UNE`.
- À droite (`flex: 1; margin-left: -40px; position: relative; z-index: 2;`) : **Boîte blanche arrondie chevauchant le bord droit de l'image** (`background: #fff; border: 1px solid #cbd5e1; border-radius: 14px; padding: 1.75rem; box-shadow: 0 10px 25px rgba(0,0,0,0.06); text-align: center;`) contenant :
- Le titre de l'article (ou surtitre `À LA UNE` + titre).
- La description / chapô nettoyé.
- Le bouton pilule encadré (`border: 1.5px solid #1a1a1a; border-radius: 999px; padding: 6px 28px; font-weight: 700;`) : **« LIRE SUR CGT.FR ↗ »** (`target="_blank" rel="noopener noreferrer"`).
- *Responsive mobile (`< 768px`) :* `flex-direction: column`, `margin-left: 0`, `margin-top: -24px`.
- **Grille inférieure (3 colonnes : ARTICLE 1, ARTICLE 2, ARTICLE 3) :**
- Grille CSS `grid-template-columns: repeat(3, 1fr); gap: 1.5rem;` (1 colonne sous `768px`).
- Chaque carte affiche l'image en haut (`height: 190px; width: 100%; object-fit: cover; border-radius: 14px;`), puis une **boîte blanche arrondie qui remonte par-dessus le bas de l'image** (`margin-top: -24px; position: relative; z-index: 2; background: #fff; border: 1px solid #cbd5e1; border-radius: 14px; padding: 1.25rem; box-shadow: 0 6px 18px rgba(0,0,0,0.05); display: flex; flex-direction: column; text-align: center; flex: 1;`) contenant :
- Le titre de l'article en gras.
- La description courte (~120 caractères).
- En bas (`margin-top: auto; padding-top: 1rem;`), le bouton pilule encadré **« LIEN ↗ »** (`target="_blank" rel="noopener noreferrer"`).
### Section 5 : Parcours « SALARIÉS ISOLÉS & TPE : VOUS N'ÊTES PAS SEULS »
- **Fond :** Blanc (`#ffffff`).
- **Contenu (entièrement éditable dans l'admin) :**
- Bloc pédagogique destiné aux salariés des petites entreprises (< 11 salariés), commerces, artisanat ou chantiers sans CSE[cite: 6].
- Met en avant la **confidentialité absolue** de toute démarche vis-à-vis de l'employeur, le rôle du syndicat **Multipros**, et l'accompagnement par les **Conseillers du Salarié** lors des entretiens préalables[cite: 6].
- Bouton d'action rouge CGT : *« Contacter l'UL en toute confidentialité »*[cite: 6].
### Section 6 : Vie Militante, Formation Syndicale (CFESES) & Appli Mobile
- **Fond :** Gris doux (`#f1f3f5`).
- **Grille 2 colonnes (`grid-template-columns: 1fr 1fr; gap: 2rem;`) :**
1. **Colonne gauche — Formation Syndicale (CFESES) :** Rappelle le droit légal de chaque salarié au **Congé de Formation Économique, Sociale, Environnementale et Syndicale** (maintien de salaire, demande à remettre à l'employeur 30 jours avant) et l'aide à la vie syndicale[cite: 6, 8].
2. **Colonne droite — L'Application Mobile UL CGT Foix Haute-Ariège :** Présente l'application Android/KMP (actualités locales, alertes mobilisation Push, carte de syndiqué virtuelle & 13 timbres 100 % hors-ligne) avec emplacement pour le lien de téléchargement direct (`.apk` / Play Store) et l'image QR Code (configurables dans l'admin)[cite: 8].
### Section 7 : Réseau Syndical CGT
- **Fond :** Blanc (`#ffffff`).
- Bandeau de liens structurés vers l'écosystème confédéral et départemental : **UD CGT 09**, **Confédération CGT (`cgt.fr`)**, **La NVO (`nvo.fr`)**, **IHS CGT**, **INDECOSA-CGT**[cite: 6].
---
## 5. PIED DE PAGE (`footer.php`) — SOUVERAIN & PRATIQUE
- **Aucune mention** *"Propulsé par WordPress"* ou *"Thème..."*[cite: 6].
- **Fond sombre (`#1c1e21`), texte blanc/gris clair, grille 3 colonnes :**
1. **Union Locale CGT Foix Haute-Ariège :** Logo (version claire/monochrome), courte présentation, et appel militant : *« Une lutte dans votre entreprise, une info à partager ? Contactez l'UL »*.
2. **Nos Locaux & Permanences (visible sur 100 % des pages) :**[cite: 6]
- Adresse : `Espace Sabart, 10 Av. de l'Ayroule, 09400 Tarascon-sur-Ariège` (modifiable dans l'admin)[cite: 7].
- Téléphone cliquable : `07 60 49 64 69`[cite: 7]
- Email cliquable : `union-locale@cgt-fha.fr`[cite: 7]
- Horaires des permanences d'accueil et juridiques (éditables)[cite: 6].
- Lien vers la page Facebook officielle de l'UL[cite: 7].
3. **Accès rapides & Mentions :** Liens vers *Actualités*, *Calendrier*, *Se syndiquer*, *Urgence salarié*, *Mentions légales & Confidentialité*.
---
## 6. PANNEAU D'ADMINISTRATION WORDPRESS (`inc/theme-options.php`)
Crée une page de réglages complète et intuitive dans **Apparence > Réglages UL CGT** (organisée en onglets propres sans dépendance JS externe) permettant de modifier sans coder :
1. **Onglet 1 — Identité & Coordonnées :** Téléphone, E-mail, Adresse des locaux, Horaires des permanences, URL Facebook, URL page *Syndiquez-vous*, URL page *Besoin d'aide / Contact*.
2. **Onglet 2 — Bandeau Mobilisation :** Case *Activer*, Texte du mot d'ordre & lieu, Lien URL optionnel, Champ `datetime-local` d'expiration automatique[cite: 6].
3. **Onglet 3 — Page d'accueil (Hero & Blocs statiques) :**
- Sélecteur d'image de fond du Hero (via la Médiathèque WP `wp_enqueue_media()`), Titre H1, Citation, Libellés et liens des 2 boutons du Hero.
- Champs pour les 3 cartes *« À quoi nous servons ? »* (choix d'icône SVG, titre, description pour chaque carte).
- Champs pour les blocs *Salariés isolés / TPE*, *Formation CFESES* et *Application Mobile* (URL APK/Store + sélecteur image QR Code + cases pour afficher/masquer chaque bloc)[cite: 6, 8].
4. **Onglet 4 — Flux Confédéral (`cgt.fr`) :** État du cache actuel (date de dernière synchronisation, aperçu de l'article *À la une* en cache) et bouton de rafraîchissement manuel immédiat.
---
## 7. SEO LOCAL, OPENGRAPH & PERFORMANCE (`inc/seo-performance.php`)
1. **Balises `<title>` et `<meta name="description">` :**
- Sur la page d'accueil : `Union Locale CGT Foix Haute-Ariège | Défense des salariés et action syndicale`[cite: 6].
- Sur les articles et pages : `[Titre] | Union Locale CGT Foix Haute-Ariège` + meta description extraite automatiquement du contenu nettoyé[cite: 6].
2. **Balises OpenGraph :** Injection automatique de `og:title`, `og:description`, `og:url`, `og:type`, `og:locale` (`fr_FR`) et `og:image` (image à la une ou image Hero par défaut) pour des aperçus propres sur Facebook, WhatsApp et SMS[cite: 6].
3. **Alerte Indexation Admin :** Si `get_option('blog_public') == '0'`, affiche une alerte rouge dans le tableau de bord WordPress invitant à autoriser l'indexation dans *Réglages > Lecture*[cite: 6].
4. **Optimisation & Nettoyage :** Suppression de `wp-emoji` et `wp-embed`, ajout de `loading="lazy"` sur les images hors ligne de flottaison, échappement systématique (`esc_html`, `esc_url`, `esc_attr`, `wp_kses_post`)[cite: 6].
---
## 8. GESTION DE VERSIONS & PUBLICATION GITEA
- **Dépôt distant :** `https://git.cgt-fha.fr/Union_Locale_CGT_Foix_Haute-Ariege/cgt-wp-theme.git` (branche principale : `main`).
- **Fichier `.gitignore` :** Crée un fichier `.gitignore` propre à la racine pour exclure les fichiers système (`.DS_Store`, `Thumbs.db`), les éditeurs (`.vscode/`, `.idea/`), et d'éventuels dossiers temporaires, tout en conservant le code source du thème et le fichier `AGENTS.md`.
- **Compatibilité déploiement VPS :** Assure-toi que tous les chemins dans le thème utilisent exclusivement les fonctions natives WordPress (`get_template_directory()`, `get_template_directory_uri()`) afin que le déploiement automatisé vers `/var/www/fastuser/data/www/cgt-fha.fr/wp-content/themes/cgt-fha/` fonctionne sans aucune dépendance de chemin en dur[cite: 6].
---
## 9. ARBORESCENCE DES FICHIERS À GÉNÉRER
```text
/
├── AGENTS.md # Ce cahier des charges
├── .gitignore # Exclusions propres pour Gitea
├── style.css # En-tête thème WP + Variables CSS + Design System complet
├── theme.json # Palette couleurs CGT (#d20012) & réglages éditeur
├── functions.php # Chargement des modules, supports WP, menus, enqueues
├── header.php # Topbar, Bandeau Mobilisation auto-expirant, Nav responsive
├── footer.php # Footer 3 colonnes avec coordonnées Espace Sabart & liens CGT
├── front-page.php # Page d'accueil complète (7 sections fidèles à la maquette)
├── home.php # Liste paginée des actualités locales de l'UL
├── single.php # Gabarit d'article local (partage social, catégorie, navigation)
├── page.php # Gabarit de page standard (Contact, Calendrier, Syndiquez-vous...)
├── archive.php # Archives par catégorie/étiquette locale
├── 404.php # Page d'erreur 404 utile avec recherche et liens vers l'UL
├── inc/
│ ├── class-cgt-confederal-feed.php # Scraper cgt.fr + cache Transients + WP-Cron + rendu wireframe
│ ├── theme-options.php # Page d'admin WP : Réglages UL CGT (onglets + médias WP)
│ └── seo-performance.php # Titres SEO locaux, OpenGraph, alerte indexation, nettoyage WP
└── assets/
├── js/main.js # Menu mobile accessible & onglets admin (Vanilla JS)
└── img/ # Visuels par défaut (hero-ariege.jpg/svg, logo-ul.svg, placeholder.svg)

61
archive.php Normal file
View File

@ -0,0 +1,61 @@
<?php
/**
* Gabarit d'archives par catégorie, étiquette, date ou recherche (archive.php).
*
* @package CGT_FHA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
get_header();
?>
<section class="cgt-page-hero">
<div class="cgt-container">
<nav class="cgt-breadcrumb" aria-label="<?php esc_attr_e( 'Fil d\'Ariane', 'cgt-fha' ); ?>">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php esc_html_e( 'Accueil', 'cgt-fha' ); ?></a>
<span aria-hidden="true">/</span>
<a href="<?php echo esc_url( cgt_fha_get_local_news_archive_url() ); ?>"><?php esc_html_e( 'Actualités', 'cgt-fha' ); ?></a>
<span aria-hidden="true">/</span>
<span><?php echo esc_html( wp_strip_all_tags( get_the_archive_title() ) ); ?></span>
</nav>
<h1 class="cgt-page-hero__title"><?php the_archive_title(); ?></h1>
<?php if ( get_the_archive_description() ) : ?>
<div class="cgt-page-hero__desc"><?php the_archive_description(); ?></div>
<?php endif; ?>
</div>
</section>
<section class="cgt-section cgt-section--white">
<div class="cgt-container">
<?php if ( have_posts() ) : ?>
<div class="cgt-news-grid">
<?php
while ( have_posts() ) :
the_post();
cgt_fha_render_local_post_card();
endwhile;
?>
</div>
<div class="cgt-pagination">
<?php
the_posts_pagination(
array(
'mid_size' => 2,
'prev_text' => '← Précédent',
'next_text' => 'Suivant →',
)
);
?>
</div>
<?php else : ?>
<p><?php esc_html_e( 'Aucun article trouvé dans cette rubrique.', 'cgt-fha' ); ?></p>
<?php endif; ?>
</div>
</section>
<?php
get_footer();

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
assets/img/hero-ariege.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
assets/img/logo-cgt-09.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
assets/img/logo-cgt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
assets/img/logo-ihs.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
assets/img/logo-nvo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360 72" width="360" height="72" role="img" aria-label="Union Locale CGT Foix Haute-Ariège">
<rect x="0" y="2" width="68" height="68" rx="4" fill="#d20012"/>
<text x="16" y="27" fill="#ffe600" font-family="Georgia, serif" font-style="italic" font-weight="700" font-size="22">la</text>
<text x="5" y="61" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-weight="900" font-size="36" letter-spacing="-1.5">cgt</text>
<text x="84" y="31" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-weight="800" font-size="21" letter-spacing="0.4">UNION LOCALE</text>
<text x="84" y="59" fill="#e2e8f0" font-family="system-ui, -apple-system, sans-serif" font-weight="800" font-size="21" letter-spacing="0.4">FOIX HAUTE-ARIÈGE</text>
</svg>

After

Width:  |  Height:  |  Size: 832 B

7
assets/img/logo-ul.svg Normal file
View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360 72" width="360" height="72" role="img" aria-label="Union Locale CGT Foix Haute-Ariège">
<rect x="0" y="2" width="68" height="68" fill="#d20012"/>
<text x="16" y="27" fill="#ffe600" font-family="Georgia, serif" font-style="italic" font-weight="700" font-size="22">la</text>
<text x="5" y="61" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-weight="900" font-size="36" letter-spacing="-1.5">cgt</text>
<text x="84" y="31" fill="#1a1a1a" font-family="system-ui, -apple-system, sans-serif" font-weight="900" font-size="21" letter-spacing="0.4">UNION LOCALE</text>
<text x="84" y="59" fill="#1a1a1a" font-family="system-ui, -apple-system, sans-serif" font-weight="900" font-size="21" letter-spacing="0.4">FOIX HAUTE-ARIÈGE</text>
</svg>

After

Width:  |  Height:  |  Size: 825 B

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 480" width="800" height="480" role="img" aria-label="Union Locale CGT Foix Haute-Ariège">
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#1c1e21"/>
<stop offset="100%" stop-color="#2d333b"/>
</linearGradient>
<linearGradient id="accent" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#d20012"/>
<stop offset="100%" stop-color="#a8000e"/>
</linearGradient>
</defs>
<rect width="800" height="480" fill="url(#bg)"/>
<path d="M0 360 L140 245 L270 325 L430 190 L585 305 L700 235 L800 315 L800 480 L0 480 Z" fill="#252a30"/>
<path d="M0 400 L180 310 L350 375 L540 285 L720 355 L800 330 L800 480 L0 480 Z" fill="#181b1f"/>
<rect x="330" y="135" width="140" height="140" rx="12" fill="url(#accent)"/>
<text x="400" y="192" text-anchor="middle" fill="#ffe600" font-family="Georgia, serif" font-style="italic" font-weight="700" font-size="34">la</text>
<text x="400" y="248" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-weight="900" font-size="60" letter-spacing="-2">cgt</text>
<text x="400" y="330" text-anchor="middle" fill="#f1f5f9" font-family="system-ui, -apple-system, sans-serif" font-weight="700" font-size="22" letter-spacing="1.5">UNION LOCALE FOIX HAUTE-ARIÈGE</text>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,34 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180" width="180" height="180" role="img" aria-label="Emplacement QR Code application mobile CGT">
<rect width="180" height="180" rx="12" fill="#ffffff" stroke="#cbd5e1" stroke-width="2"/>
<g fill="#1a1a1a">
<rect x="18" y="18" width="42" height="42" rx="4"/>
<rect x="25" y="25" width="28" height="28" fill="#ffffff"/>
<rect x="32" y="32" width="14" height="14"/>
<rect x="120" y="18" width="42" height="42" rx="4"/>
<rect x="127" y="25" width="28" height="28" fill="#ffffff"/>
<rect x="134" y="32" width="14" height="14"/>
<rect x="18" y="120" width="42" height="42" rx="4"/>
<rect x="25" y="127" width="28" height="28" fill="#ffffff"/>
<rect x="32" y="134" width="14" height="14"/>
<rect x="72" y="22" width="10" height="10"/>
<rect x="94" y="22" width="12" height="10"/>
<rect x="72" y="42" width="18" height="10"/>
<rect x="98" y="42" width="10" height="18"/>
<rect x="22" y="74" width="14" height="10"/>
<rect x="44" y="74" width="16" height="12"/>
<rect x="22" y="96" width="10" height="14"/>
<rect x="40" y="96" width="20" height="10"/>
<rect x="72" y="120" width="12" height="12"/>
<rect x="96" y="120" width="14" height="10"/>
<rect x="122" y="120" width="18" height="12"/>
<rect x="148" y="120" width="14" height="18"/>
<rect x="72" y="144" width="24" height="14"/>
<rect x="108" y="142" width="16" height="16"/>
<rect x="134" y="146" width="26" height="12"/>
<rect x="124" y="74" width="16" height="14"/>
<rect x="148" y="74" width="14" height="26"/>
<rect x="120" y="96" width="20" height="14"/>
</g>
<rect x="68" y="68" width="44" height="44" rx="8" fill="#d20012"/>
<text x="90" y="97" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-weight="900" font-size="18">cgt</text>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

177
assets/js/main.js Normal file
View File

@ -0,0 +1,177 @@
/**
* Scripts Vanilla ES6 — Union Locale CGT Foix Haute-Ariège
* Menu mobile accessible + ombre header + partage + onglets & médias admin WP.
*/
(function () {
'use strict';
/* -------------------------------------------------------------------------
* 1. Navigation mobile accessible & sticky header
* ---------------------------------------------------------------------- */
const header = document.querySelector('.cgt-header');
const navToggle = document.querySelector('.cgt-nav-toggle');
const navMenu = document.getElementById('cgt-primary-nav');
if (header) {
const onScroll = () => {
header.classList.toggle('is-scrolled', window.scrollY > 10);
};
onScroll();
window.addEventListener('scroll', onScroll, { passive: true });
}
if (navToggle && navMenu) {
const setOpen = (isOpen) => {
navToggle.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
navToggle.setAttribute(
'aria-label',
isOpen ? 'Fermer le menu principal' : 'Ouvrir le menu principal'
);
navMenu.classList.toggle('is-open', isOpen);
};
navToggle.addEventListener('click', () => {
const expanded = navToggle.getAttribute('aria-expanded') === 'true';
setOpen(!expanded);
});
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape' && navMenu.classList.contains('is-open')) {
setOpen(false);
navToggle.focus();
}
});
document.addEventListener('click', (event) => {
if (
navMenu.classList.contains('is-open') &&
!navMenu.contains(event.target) &&
!navToggle.contains(event.target)
) {
setOpen(false);
}
});
}
/* -------------------------------------------------------------------------
* 2. Bouton copier le lien sur les articles
* ---------------------------------------------------------------------- */
const copyBtns = document.querySelectorAll('[data-cgt-copy-url]');
copyBtns.forEach((btn) => {
btn.addEventListener('click', async () => {
const url = btn.getAttribute('data-cgt-copy-url');
if (!url || !navigator.clipboard) {
return;
}
try {
await navigator.clipboard.writeText(url);
const original = btn.textContent;
btn.textContent = 'Lien copié !';
setTimeout(() => {
btn.textContent = original;
}, 2200);
} catch (e) {
// Ignore silencieusement si l'API clipboard est restreinte
}
});
});
/* -------------------------------------------------------------------------
* 3. Interface d'administration : onglets + sélecteur média WP
* ---------------------------------------------------------------------- */
const adminWrap = document.querySelector('.cgt-admin-wrap');
if (!adminWrap) {
return;
}
const tabButtons = adminWrap.querySelectorAll('[data-cgt-tab]');
const tabPanels = adminWrap.querySelectorAll('[data-cgt-panel]');
const activeTabInput = adminWrap.querySelector('input[name="cgt_fha_active_tab"]');
const refererInput = adminWrap.querySelector('input[name="_wp_http_referer"]');
const activateTab = (tabId) => {
tabButtons.forEach((btn) => {
const match = btn.getAttribute('data-cgt-tab') === tabId;
btn.classList.toggle('nav-tab-active', match);
btn.setAttribute('aria-selected', match ? 'true' : 'false');
});
tabPanels.forEach((panel) => {
const match = panel.getAttribute('data-cgt-panel') === tabId;
panel.hidden = !match;
});
if (activeTabInput) {
activeTabInput.value = tabId;
}
if (refererInput) {
try {
const url = new URL(refererInput.value, window.location.origin);
url.searchParams.set('tab', tabId);
refererInput.value = url.pathname + url.search;
} catch (e) {
// Ignore si l'URL est invalide
}
}
};
tabButtons.forEach((btn) => {
btn.addEventListener('click', (event) => {
event.preventDefault();
activateTab(btn.getAttribute('data-cgt-tab'));
});
});
// Sélecteurs de médias WordPress (wp.media)
if (typeof wp !== 'undefined' && wp.media) {
adminWrap.querySelectorAll('[data-cgt-media-select]').forEach((selectBtn) => {
selectBtn.addEventListener('click', (event) => {
event.preventDefault();
const targetId = selectBtn.getAttribute('data-cgt-media-select');
const inputEl = document.getElementById(targetId);
const previewEl = document.getElementById(targetId + '_preview');
const frame = wp.media({
title: 'Choisir une image',
button: { text: 'Utiliser cette image' },
library: { type: 'image' },
multiple: false,
});
frame.on('select', () => {
const attachment = frame.state().get('selection').first().toJSON();
if (inputEl && attachment.url) {
inputEl.value = attachment.url;
}
if (previewEl && attachment.url) {
previewEl.src = attachment.url;
previewEl.hidden = false;
}
});
frame.open();
});
});
adminWrap.querySelectorAll('[data-cgt-media-clear]').forEach((clearBtn) => {
clearBtn.addEventListener('click', (event) => {
event.preventDefault();
const targetId = clearBtn.getAttribute('data-cgt-media-clear');
const defaultUrl = clearBtn.getAttribute('data-cgt-default-url') || '';
const inputEl = document.getElementById(targetId);
const previewEl = document.getElementById(targetId + '_preview');
if (inputEl) {
inputEl.value = defaultUrl;
}
if (previewEl) {
if (defaultUrl) {
previewEl.src = defaultUrl;
previewEl.hidden = false;
} else {
previewEl.src = '';
previewEl.hidden = true;
}
}
});
});
}
})();

112
footer.php Normal file
View File

@ -0,0 +1,112 @@
<?php
/**
* Pied de page souverain (3 colonnes) — Union Locale CGT Foix Haute-Ariège.
* Aucune mention "Propulsé par WordPress".
*
* @package CGT_FHA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$opts = cgt_fha_get_options();
$phone_raw = (string) $opts['phone'];
$phone_href = preg_replace( '/[^0-9+]/', '', $phone_raw );
$email = (string) $opts['email'];
$logo_url = cgt_fha_get_footer_logo_url();
?>
</main>
<footer class="cgt-footer" role="contentinfo">
<div class="cgt-container">
<div class="cgt-footer__grid">
<!-- Colonne 1 : Identité & appel militant -->
<div>
<a href="<?php echo esc_url( home_url( '/' ) ); ?>" aria-label="<?php esc_attr_e( 'Retour à l\'accueil', 'cgt-fha' ); ?>">
<img
src="<?php echo esc_url( $logo_url ); ?>"
alt="Union Locale CGT Foix Haute-Ariège"
class="cgt-footer__logo"
loading="lazy"
decoding="async"
/>
</a>
<?php if ( ! empty( $opts['footer_desc'] ) ) : ?>
<p class="cgt-footer__text"><?php echo esc_html( (string) $opts['footer_desc'] ); ?></p>
<?php endif; ?>
<?php if ( ! empty( $opts['footer_call'] ) ) : ?>
<p class="cgt-footer__call"><?php echo esc_html( (string) $opts['footer_call'] ); ?></p>
<?php endif; ?>
</div>
<!-- Colonne 2 : Nos Locaux & Permanences (visible sur 100 % des pages) -->
<div>
<h2 class="cgt-footer__title"><?php esc_html_e( 'Nos Locaux & Permanences', 'cgt-fha' ); ?></h2>
<ul class="cgt-footer__list">
<?php if ( ! empty( $opts['address'] ) ) : ?>
<li>
<?php echo cgt_fha_render_icon( 'map-pin', 17 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<span><?php echo esc_html( (string) $opts['address'] ); ?></span>
</li>
<?php endif; ?>
<?php if ( '' !== $phone_raw ) : ?>
<li>
<?php echo cgt_fha_render_icon( 'phone', 17 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<a href="<?php echo esc_url( 'tel:' . $phone_href ); ?>"><?php echo esc_html( $phone_raw ); ?></a>
</li>
<?php endif; ?>
<?php if ( '' !== $email ) : ?>
<li>
<?php echo cgt_fha_render_icon( 'mail', 17 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<a href="<?php echo esc_url( 'mailto:' . $email ); ?>"><?php echo esc_html( $email ); ?></a>
</li>
<?php endif; ?>
<?php if ( ! empty( $opts['hours'] ) ) : ?>
<li>
<?php echo cgt_fha_render_icon( 'clock', 17 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<span><?php echo esc_html( (string) $opts['hours'] ); ?></span>
</li>
<?php endif; ?>
<?php if ( ! empty( $opts['facebook_url'] ) ) : ?>
<li>
<?php echo cgt_fha_render_icon( 'facebook', 17 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<a href="<?php echo esc_url( (string) $opts['facebook_url'] ); ?>" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Page Facebook officielle de l\'UL', 'cgt-fha' ); ?>
</a>
</li>
<?php endif; ?>
</ul>
</div>
<!-- Colonne 3 : Accès rapides & Mentions -->
<div>
<h2 class="cgt-footer__title"><?php esc_html_e( 'Accès rapides & Mentions', 'cgt-fha' ); ?></h2>
<?php
wp_nav_menu(
array(
'theme_location' => 'footer',
'container' => false,
'menu_class' => 'cgt-footer__list',
'depth' => 1,
'fallback_cb' => 'cgt_fha_default_footer_menu',
)
);
?>
</div>
</div>
<div class="cgt-footer__bottom">
<span>&copy; <?php echo esc_html( wp_date( 'Y' ) ); ?> Union Locale CGT Foix Haute-Ariège — Tous droits réservés.</span>
<span><?php esc_html_e( 'Union des syndicats CGT — Foix & Haute-Ariège (09)', 'cgt-fha' ); ?></span>
</div>
</div>
</footer>
<?php wp_footer(); ?>
</body>
</html>

271
front-page.php Normal file
View File

@ -0,0 +1,271 @@
<?php
/**
* Gabarit de la Page d'Accueil — 7 sections verticales fidèles à la maquette.
*
* @package CGT_FHA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
get_header();
$opts = cgt_fha_get_options();
?>
<!-- =========================================================================
SECTION 1 : BANNIÈRE HERO PLEIN ÉCRAN
========================================================================= -->
<section class="cgt-hero" aria-label="<?php esc_attr_e( 'Présentation de l\'Union Locale CGT Foix Haute-Ariège', 'cgt-fha' ); ?>">
<img
src="<?php echo esc_url( (string) $opts['hero_bg_url'] ); ?>"
alt=""
class="cgt-hero__bg"
fetchpriority="high"
decoding="async"
/>
<div class="cgt-hero__overlay" aria-hidden="true"></div>
<div class="cgt-hero__content">
<h1 class="cgt-hero__title">
<span><?php echo esc_html( (string) $opts['hero_title_line1'] ); ?></span>
<?php if ( '' !== trim( (string) $opts['hero_title_line2'] ) ) : ?>
<span><?php echo esc_html( (string) $opts['hero_title_line2'] ); ?></span>
<?php endif; ?>
</h1>
<?php if ( '' !== trim( (string) $opts['hero_quote'] ) ) : ?>
<p class="cgt-hero__quote"><?php echo esc_html( (string) $opts['hero_quote'] ); ?></p>
<?php endif; ?>
<div class="cgt-hero__actions">
<a href="<?php echo esc_url( (string) $opts['hero_btn1_url'] ); ?>" class="cgt-btn cgt-btn--white">
<?php echo esc_html( (string) $opts['hero_btn1_label'] ); ?>
</a>
<a href="<?php echo esc_url( (string) $opts['hero_btn2_url'] ); ?>" class="cgt-btn cgt-btn--hero-dark">
<?php echo esc_html( (string) $opts['hero_btn2_label'] ); ?>
</a>
</div>
</div>
</section>
<!-- =========================================================================
SECTION 2 : À QUOI NOUS SERVONS ? (3 Cartes de Mission)
========================================================================= -->
<section class="cgt-section cgt-section--white cgt-missions-section" aria-labelledby="cgt-missions-heading">
<div class="cgt-container">
<h2 id="cgt-missions-heading" class="cgt-section__title"><?php echo esc_html( (string) $opts['missions_title'] ); ?></h2>
<?php if ( ! empty( $opts['missions_subtitle'] ) ) : ?>
<p class="cgt-section__subtitle"><?php echo esc_html( (string) $opts['missions_subtitle'] ); ?></p>
<?php endif; ?>
<div class="cgt-missions-grid">
<?php for ( $i = 1; $i <= 3; $i++ ) : ?>
<article class="cgt-mission-card">
<div class="cgt-mission-card__icon" aria-hidden="true">
<?php echo cgt_fha_render_icon( (string) $opts[ 'mission_' . $i . '_icon' ], 40 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</div>
<h3 class="cgt-mission-card__title"><?php echo esc_html( (string) $opts[ 'mission_' . $i . '_title' ] ); ?></h3>
<p class="cgt-mission-card__text"><?php echo esc_html( (string) $opts[ 'mission_' . $i . '_text' ] ); ?></p>
</article>
<?php endfor; ?>
</div>
</div>
</section>
<!-- =========================================================================
SECTION 3 : SUR LE TERRAIN EN HAUTE-ARIÈGE (3 derniers articles locaux)
========================================================================= -->
<section class="cgt-section cgt-section--white cgt-local-section" aria-labelledby="cgt-local-news-heading">
<div class="cgt-container">
<h2 id="cgt-local-news-heading" class="cgt-section__title"><?php echo esc_html( (string) $opts['local_news_title'] ); ?></h2>
<?php
$local_query = new WP_Query(
array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => 3,
'ignore_sticky_posts' => true,
'no_found_rows' => true,
'update_post_meta_cache' => false,
)
);
?>
<?php if ( $local_query->have_posts() ) : ?>
<div class="cgt-news-grid">
<?php
while ( $local_query->have_posts() ) :
$local_query->the_post();
cgt_fha_render_local_post_card();
endwhile;
wp_reset_postdata();
?>
</div>
<?php else : ?>
<p class="cgt-section__subtitle">
<?php esc_html_e( 'Les prochaines actualités locales et comptes-rendus de luttes à Foix et en Haute-Ariège seront publiés ici très prochainement.', 'cgt-fha' ); ?>
</p>
<?php endif; ?>
<div class="cgt-section__footer">
<a href="<?php echo esc_url( cgt_fha_get_local_news_archive_url() ); ?>" class="cgt-btn cgt-btn--subtle">
<?php echo esc_html( (string) $opts['local_news_more'] ); ?>
</a>
</div>
<?php
// Hook pour injecter les prochains rendez-vous de l'extension cgt-wp-calendar.
do_action( 'cgt_fha_after_local_news' );
?>
</div>
</section>
<!-- =========================================================================
SECTION 4 : ACTUALITÉ CONFÉDÉRALE (cgt.fr)
========================================================================= -->
<?php CGT_FHA_Confederal_Feed::render_section( (string) $opts['confederal_title'] ); ?>
<!-- =========================================================================
SECTION 5 : SALARIÉS ISOLÉS & TPE : VOUS N'ÊTES PAS SEULS
========================================================================= -->
<?php if ( ! empty( $opts['tpe_enabled'] ) ) : ?>
<section class="cgt-section cgt-section--white" aria-labelledby="cgt-tpe-heading">
<div class="cgt-container">
<div class="cgt-tpe-box">
<div>
<?php if ( ! empty( $opts['tpe_badge'] ) ) : ?>
<span class="cgt-tpe-box__badge"><?php echo esc_html( (string) $opts['tpe_badge'] ); ?></span>
<?php endif; ?>
<h2 id="cgt-tpe-heading" class="cgt-tpe-box__title"><?php echo esc_html( (string) $opts['tpe_title'] ); ?></h2>
<p class="cgt-tpe-box__text"><?php echo esc_html( (string) $opts['tpe_text'] ); ?></p>
<a href="<?php echo esc_url( (string) $opts['tpe_btn_url'] ); ?>" class="cgt-btn cgt-btn--primary">
<?php echo esc_html( (string) $opts['tpe_btn_label'] ); ?>
</a>
</div>
<ul class="cgt-tpe-points">
<?php for ( $p = 1; $p <= 3; $p++ ) : ?>
<?php if ( ! empty( $opts[ 'tpe_point_' . $p ] ) ) : ?>
<li>
<span class="cgt-tpe-points__icon">
<?php echo cgt_fha_render_icon( 'check', 18 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</span>
<span><?php echo esc_html( (string) $opts[ 'tpe_point_' . $p ] ); ?></span>
</li>
<?php endif; ?>
<?php endfor; ?>
</ul>
</div>
<?php do_action( 'cgt_fha_tpe_section_after' ); ?>
</div>
</section>
<?php endif; ?>
<!-- =========================================================================
SECTION 6 : FORMATION SYNDICALE (CFESES) & APPLICATION MOBILE
========================================================================= -->
<?php
$split_count = ( ! empty( $opts['cfeses_enabled'] ) ? 1 : 0 ) + ( ! empty( $opts['app_enabled'] ) ? 1 : 0 );
if ( $split_count > 0 ) :
$split_class = 1 === $split_count ? 'cgt-split-grid cgt-split-grid--single' : 'cgt-split-grid';
?>
<section class="cgt-section cgt-section--soft" aria-label="<?php esc_attr_e( 'Formation syndicale et application mobile', 'cgt-fha' ); ?>">
<div class="cgt-container">
<div class="<?php echo esc_attr( $split_class ); ?>">
<?php if ( ! empty( $opts['cfeses_enabled'] ) ) : ?>
<article class="cgt-feature-card">
<span class="cgt-feature-card__eyebrow"><?php echo esc_html( (string) $opts['cfeses_eyebrow'] ); ?></span>
<h2 class="cgt-feature-card__title"><?php echo esc_html( (string) $opts['cfeses_title'] ); ?></h2>
<p class="cgt-feature-card__text"><?php echo esc_html( (string) $opts['cfeses_text'] ); ?></p>
<div class="cgt-feature-card__footer">
<a href="<?php echo esc_url( (string) $opts['cfeses_btn_url'] ); ?>" class="cgt-btn cgt-btn--primary">
<?php echo esc_html( (string) $opts['cfeses_btn_label'] ); ?>
</a>
</div>
</article>
<?php endif; ?>
<?php if ( ! empty( $opts['app_enabled'] ) ) : ?>
<article class="cgt-feature-card">
<span class="cgt-feature-card__eyebrow"><?php echo esc_html( (string) $opts['app_eyebrow'] ); ?></span>
<h2 class="cgt-feature-card__title"><?php echo esc_html( (string) $opts['app_title'] ); ?></h2>
<div class="cgt-app-layout">
<div>
<p class="cgt-feature-card__text"><?php echo esc_html( (string) $opts['app_text'] ); ?></p>
</div>
<?php if ( ! empty( $opts['app_qr_url'] ) ) : ?>
<img
src="<?php echo esc_url( (string) $opts['app_qr_url'] ); ?>"
alt="<?php esc_attr_e( 'QR Code pour télécharger l\'application mobile UL CGT Foix Haute-Ariège', 'cgt-fha' ); ?>"
class="cgt-app-qr"
loading="lazy"
decoding="async"
/>
<?php endif; ?>
</div>
<div class="cgt-feature-card__footer">
<a href="<?php echo esc_url( (string) $opts['app_download_url'] ); ?>" class="cgt-btn cgt-btn--outline-dark" target="_blank" rel="noopener noreferrer">
<?php echo esc_html( (string) $opts['app_btn_label'] ); ?>
</a>
</div>
</article>
<?php endif; ?>
</div>
</div>
</section>
<?php endif; ?>
<!-- =========================================================================
SECTION 7 : RÉSEAU SYNDICAL CGT
========================================================================= -->
<?php if ( ! empty( $opts['network_enabled'] ) ) : ?>
<section class="cgt-section cgt-section--white" aria-labelledby="cgt-network-heading">
<div class="cgt-container">
<h2 id="cgt-network-heading" class="cgt-section__title"><?php echo esc_html( (string) $opts['network_title'] ); ?></h2>
<div class="cgt-network-grid">
<?php for ( $n = 1; $n <= 5; $n++ ) : ?>
<?php
if ( empty( $opts[ 'network_' . $n . '_enabled' ] ) ) {
continue;
}
$n_logo = (string) ( $opts[ 'network_' . $n . '_logo' ] ?? '' );
$n_label = (string) ( $opts[ 'network_' . $n . '_label' ] ?? '' );
$n_desc = (string) ( $opts[ 'network_' . $n . '_desc' ] ?? '' );
$n_btn = (string) ( $opts[ 'network_' . $n . '_btn' ] ?? 'Visiter le site ↗' );
$n_url = (string) ( $opts[ 'network_' . $n . '_url' ] ?? '' );
if ( '' === $n_label || '' === $n_url ) {
continue;
}
?>
<article class="cgt-network-card">
<?php if ( '' !== $n_logo ) : ?>
<div class="cgt-network-card__logo-wrap">
<img
src="<?php echo esc_url( $n_logo ); ?>"
alt="<?php echo esc_attr( $n_label ); ?>"
class="cgt-network-card__logo"
loading="lazy"
decoding="async"
/>
</div>
<?php endif; ?>
<h3 class="cgt-network-card__title"><?php echo esc_html( $n_label ); ?></h3>
<?php if ( '' !== $n_desc ) : ?>
<p class="cgt-network-card__desc"><?php echo esc_html( $n_desc ); ?></p>
<?php endif; ?>
<div class="cgt-network-card__cta">
<a href="<?php echo esc_url( $n_url ); ?>" class="cgt-network-card__btn" target="_blank" rel="noopener noreferrer">
<?php echo esc_html( $n_btn ); ?>
</a>
</div>
</article>
<?php endfor; ?>
</div>
</div>
</section>
<?php endif; ?>
<?php
get_footer();

303
functions.php Normal file
View File

@ -0,0 +1,303 @@
<?php
/**
* Fonctions principales du thème Union Locale CGT Foix Haute-Ariège.
*
* @package CGT_FHA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
define( 'CGT_FHA_VERSION', '1.2.0' );
define( 'CGT_FHA_DIR', get_template_directory() );
define( 'CGT_FHA_URI', get_template_directory_uri() );
/**
* Chargement des modules du thème.
*/
require_once CGT_FHA_DIR . '/inc/theme-options.php';
require_once CGT_FHA_DIR . '/inc/class-cgt-confederal-feed.php';
require_once CGT_FHA_DIR . '/inc/seo-performance.php';
/**
* Configuration des supports WordPress et menus.
*/
add_action( 'after_setup_theme', 'cgt_fha_setup' );
function cgt_fha_setup(): void {
load_theme_textdomain( 'cgt-fha', CGT_FHA_DIR . '/languages' );
add_theme_support( 'title-tag' );
add_theme_support( 'post-thumbnails' );
add_image_size( 'cgt-card', 640, 380, true );
add_image_size( 'cgt-featured', 960, 560, true );
add_theme_support(
'custom-logo',
array(
'height' => 120,
'width' => 520,
'flex-height' => true,
'flex-width' => true,
)
);
add_theme_support(
'html5',
array(
'search-form',
'comment-form',
'comment-list',
'gallery',
'caption',
'style',
'script',
'navigation-widgets',
)
);
add_theme_support( 'responsive-embeds' );
add_theme_support( 'align-wide' );
register_nav_menus(
array(
'primary' => __( 'Menu principal (En-tête)', 'cgt-fha' ),
'footer' => __( 'Accès rapides (Pied de page)', 'cgt-fha' ),
)
);
}
/**
* Chargement des styles et scripts frontend (zéro dépendance externe).
*/
add_action( 'wp_enqueue_scripts', 'cgt_fha_enqueue_assets' );
function cgt_fha_enqueue_assets(): void {
$style_ver = file_exists( CGT_FHA_DIR . '/style.css' ) ? (string) filemtime( CGT_FHA_DIR . '/style.css' ) : CGT_FHA_VERSION;
$js_ver = file_exists( CGT_FHA_DIR . '/assets/js/main.js' ) ? (string) filemtime( CGT_FHA_DIR . '/assets/js/main.js' ) : CGT_FHA_VERSION;
wp_enqueue_style( 'cgt-fha-style', get_stylesheet_uri(), array(), $style_ver );
wp_enqueue_script(
'cgt-fha-main',
CGT_FHA_URI . '/assets/js/main.js',
array(),
$js_ver,
array(
'in_footer' => true,
'strategy' => 'defer',
)
);
}
/**
* Chargement des scripts admin uniquement sur la page de réglages du thème.
*/
add_action( 'admin_enqueue_scripts', 'cgt_fha_admin_enqueue_assets' );
function cgt_fha_admin_enqueue_assets( string $hook_suffix ): void {
if ( 'appearance_page_cgt-fha-settings' !== $hook_suffix ) {
return;
}
wp_enqueue_media();
$js_ver = file_exists( CGT_FHA_DIR . '/assets/js/main.js' ) ? (string) filemtime( CGT_FHA_DIR . '/assets/js/main.js' ) : CGT_FHA_VERSION;
wp_enqueue_script( 'cgt-fha-admin', CGT_FHA_URI . '/assets/js/main.js', array(), $js_ver, true );
}
/**
* URL du logo d'en-tête (Personnaliser > Logo personnalisé ou Réglages UL CGT ou bannière par défaut).
*/
function cgt_fha_get_header_logo_url(): string {
$custom_logo_id = (int) get_theme_mod( 'custom_logo' );
if ( $custom_logo_id > 0 ) {
$src = wp_get_attachment_image_url( $custom_logo_id, 'full' );
if ( $src ) {
return $src;
}
}
$opts = cgt_fha_get_options();
return ! empty( $opts['header_logo_url'] )
? (string) $opts['header_logo_url']
: CGT_FHA_URI . '/assets/img/banniere-ul-noir.png';
}
/**
* URL du logo clair du pied de page.
*/
function cgt_fha_get_footer_logo_url(): string {
$opts = cgt_fha_get_options();
return ! empty( $opts['footer_logo_url'] )
? (string) $opts['footer_logo_url']
: CGT_FHA_URI . '/assets/img/banniere-ul-blanc.png';
}
/**
* Retourne l'URL de la page listant toutes les actualités locales.
*/
function cgt_fha_get_local_news_archive_url(): string {
$posts_page_id = (int) get_option( 'page_for_posts' );
if ( $posts_page_id > 0 ) {
$link = get_permalink( $posts_page_id );
if ( $link ) {
return $link;
}
}
$opts = cgt_fha_get_options();
return ! empty( $opts['news_url'] ) ? (string) $opts['news_url'] : home_url( '/actualites/' );
}
/**
* Menu de secours pour la navigation principale si aucun menu n'est encore assigné dans Apparence > Menus.
*/
function cgt_fha_default_primary_menu(): void {
$opts = cgt_fha_get_options();
$items = array(
array(
'label' => 'Accueil',
'url' => home_url( '/' ),
'active' => is_front_page(),
),
array(
'label' => 'Actualités',
'url' => cgt_fha_get_local_news_archive_url(),
'active' => is_home() || is_singular( 'post' ) || is_category() || is_tag(),
),
array(
'label' => 'Calendrier',
'url' => (string) $opts['calendar_url'],
'active' => is_page( 'calendrier' ),
),
array(
'label' => 'Contact',
'url' => (string) $opts['contact_url'],
'active' => is_page( 'contact' ),
),
);
echo '<ul class="cgt-nav__list">';
foreach ( $items as $item ) {
$classes = $item['active'] ? 'menu-item current-menu-item' : 'menu-item';
$aria = $item['active'] ? ' aria-current="page"' : '';
printf(
'<li class="%s"><a href="%s"%s>%s</a></li>',
esc_attr( $classes ),
esc_url( $item['url'] ),
$aria,
esc_html( $item['label'] )
);
}
echo '</ul>';
}
/**
* Menu de secours pour les accès rapides du pied de page.
*/
function cgt_fha_default_footer_menu(): void {
$opts = cgt_fha_get_options();
$items = array(
'Actualités' => cgt_fha_get_local_news_archive_url(),
'Calendrier' => (string) $opts['calendar_url'],
'Se syndiquer' => (string) $opts['join_url'],
'Urgence salarié' => (string) $opts['contact_url'],
'Mentions légales & Confidentialité' => (string) $opts['legal_url'],
);
echo '<ul class="cgt-footer__list">';
foreach ( $items as $label => $url ) {
printf(
'<li><a href="%s">%s</a></li>',
esc_url( $url ),
esc_html( $label )
);
}
echo '</ul>';
}
/**
* Icônes SVG propres intégrées (zéro police d'icônes externe).
*/
function cgt_fha_render_icon( string $name, int $size = 24 ): string {
$s = (int) $size;
$icons = array(
'phone' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 22 16.92z"/></svg>',
'mail' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>',
'map-pin' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="3"/></svg>',
'clock' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>',
'facebook' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M13.5 22v-8h2.7l.4-3h-3.1V9.1c0-.9.3-1.5 1.6-1.5h1.7V4.9c-.3 0-1.3-.1-2.4-.1-2.4 0-4 1.4-4 4.1V11H8v3h2.9v8h2.6Z"/></svg>',
'instagram' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="2" width="20" height="20" rx="5"/><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"/><line x1="17.5" y1="6.5" x2="17.51" y2="6.5"/></svg>',
'youtube' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M21.8 8s-.2-1.4-.8-2c-.8-.8-1.6-.8-2-.9C16.2 5 12 5 12 5h0s-4.2 0-7 .1c-.4.1-1.2.1-2 .9-.6.6-.8 2-.8 2S2 9.6 2 11.2v1.5C2 14.4 2.2 16 2.2 16s.2 1.4.8 2c.8.8 1.8.8 2.2.9 1.6.1 6.8.1 6.8.1s4.2 0 7-.1c.4-.1 1.2-.1 2-.9.6-.6.8-2 .8-2s.2-1.6.2-3.2v-1.5c0-1.7-.2-3.3-.2-3.3ZM9.9 14.6V9.2l5.4 2.7-5.4 2.7Z"/></svg>',
'menu' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>',
'check' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg>',
// Icônes des 3 cartes de mission.
'fist' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 11V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2"/><path d="M14 10V4a2 2 0 0 0-2-2a2 2 0 0 0-2 2v2"/><path d="M10 10.5V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2v8"/><path d="M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15"/></svg>',
'shield' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>',
'chat' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 9a2 2 0 0 1-2 2H6l-4 4V4c0-1.1.9-2 2-2h8a2 2 0 0 1 2 2v5Z"/><path d="M18 9h2a2 2 0 0 1 2 2v11l-4-4h-6a2 2 0 0 1-2-2v-1"/></svg>',
'megaphone' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m3 11 18-5v12L3 14v-3z"/><path d="M11.6 16.8a3 3 0 1 1-5.8-1.6"/></svg>',
'scale' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m16 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z"/><path d="m2 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z"/><path d="M7 21h10"/><path d="M12 3v18"/><path d="M3 7h2c2 0 5-1 7-2 2 1 5 2 7 2h2"/></svg>',
'users' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>',
'book' => '<svg xmlns="http://www.w3.org/2000/svg" width="' . $s . '" height="' . $s . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1 0-5H20"/></svg>',
);
return $icons[ $name ] ?? $icons['fist'];
}
/**
* Rendu réutilisable d'une carte d'article local (front-page, home, archive).
*/
function cgt_fha_render_local_post_card(): void {
$cats = get_the_category();
$cat_name = 'Vie syndicale';
if ( ! empty( $cats ) ) {
foreach ( $cats as $cat ) {
if ( ! in_array( $cat->slug, array( 'uncategorized', 'non-classe' ), true ) && 'Uncategorized' !== $cat->name ) {
$cat_name = $cat->name;
break;
}
}
}
$placeholder = CGT_FHA_URI . '/assets/img/placeholder.svg';
?>
<article id="post-<?php the_ID(); ?>" <?php post_class( 'cgt-news-card' ); ?>>
<a href="<?php the_permalink(); ?>" class="cgt-news-card__thumb-link" aria-hidden="true" tabindex="-1">
<?php if ( has_post_thumbnail() ) : ?>
<?php
the_post_thumbnail(
'cgt-card',
array(
'class' => 'cgt-news-card__thumb',
'loading' => 'lazy',
'alt' => esc_attr( get_the_title() ),
)
);
?>
<?php else : ?>
<img
src="<?php echo esc_url( $placeholder ); ?>"
alt="<?php echo esc_attr( get_the_title() ); ?>"
class="cgt-news-card__thumb"
loading="lazy"
decoding="async"
/>
<?php endif; ?>
</a>
<div class="cgt-news-card__body">
<div class="cgt-news-card__meta">
<span class="cgt-pill-cat"><?php echo esc_html( $cat_name ); ?></span>
<time datetime="<?php echo esc_attr( get_the_date( 'c' ) ); ?>" class="cgt-news-card__date">
<?php echo esc_html( get_the_date( 'd.m.Y' ) ); ?>
</time>
</div>
<h3 class="cgt-news-card__title">
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</h3>
<p class="cgt-news-card__excerpt">
<?php echo esc_html( wp_trim_words( get_the_excerpt(), 20, '…' ) ); ?>
</p>
</div>
</article>
<?php
}

133
header.php Normal file
View File

@ -0,0 +1,133 @@
<?php
/**
* En-tête du thème Union Locale CGT Foix Haute-Ariège.
*
* 1. Topbar sombre (#1c1e21) avec téléphone, e-mail et réseaux sociaux
* 2. Bandeau d'alerte mobilisation auto-expirant (#d20012)
* 3. Barre de navigation blanche (logo à gauche, menu horizontal à droite)
*
* @package CGT_FHA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$opts = cgt_fha_get_options();
$phone_raw = (string) $opts['phone'];
$phone_href = preg_replace( '/[^0-9+]/', '', $phone_raw );
$email = (string) $opts['email'];
$logo_url = cgt_fha_get_header_logo_url();
?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<?php wp_body_open(); ?>
<a class="skip-link" href="#cgt-main-content"><?php esc_html_e( 'Aller au contenu principal', 'cgt-fha' ); ?></a>
<!-- 1. Topbar sombre -->
<div class="cgt-topbar" role="region" aria-label="<?php esc_attr_e( 'Coordonnées rapides et réseaux sociaux', 'cgt-fha' ); ?>">
<div class="cgt-container cgt-topbar__inner">
<div class="cgt-topbar__contacts">
<?php if ( '' !== $phone_raw ) : ?>
<a href="<?php echo esc_url( 'tel:' . $phone_href ); ?>" class="cgt-topbar__link">
<?php echo cgt_fha_render_icon( 'phone', 14 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<span><?php echo esc_html( $phone_raw ); ?></span>
</a>
<?php endif; ?>
<?php if ( '' !== $phone_raw && '' !== $email ) : ?>
<span class="cgt-topbar__sep" aria-hidden="true">/</span>
<?php endif; ?>
<?php if ( '' !== $email ) : ?>
<a href="<?php echo esc_url( 'mailto:' . $email ); ?>" class="cgt-topbar__link">
<?php echo cgt_fha_render_icon( 'mail', 14 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<span><?php echo esc_html( $email ); ?></span>
</a>
<?php endif; ?>
</div>
<div class="cgt-topbar__socials">
<?php if ( ! empty( $opts['facebook_url'] ) ) : ?>
<a href="<?php echo esc_url( (string) $opts['facebook_url'] ); ?>" class="cgt-topbar__social" target="_blank" rel="noopener noreferrer" aria-label="Facebook Union Locale CGT Foix Haute-Ariège">
<?php echo cgt_fha_render_icon( 'facebook', 16 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</a>
<?php endif; ?>
<?php if ( ! empty( $opts['instagram_url'] ) ) : ?>
<a href="<?php echo esc_url( (string) $opts['instagram_url'] ); ?>" class="cgt-topbar__social" target="_blank" rel="noopener noreferrer" aria-label="Instagram Union Locale CGT Foix Haute-Ariège">
<?php echo cgt_fha_render_icon( 'instagram', 16 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</a>
<?php endif; ?>
<?php if ( ! empty( $opts['youtube_url'] ) ) : ?>
<a href="<?php echo esc_url( (string) $opts['youtube_url'] ); ?>" class="cgt-topbar__social" target="_blank" rel="noopener noreferrer" aria-label="YouTube Union Locale CGT Foix Haute-Ariège">
<?php echo cgt_fha_render_icon( 'youtube', 16 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</a>
<?php endif; ?>
</div>
</div>
</div>
<!-- 2. Bandeau d'Alerte Mobilisation Auto-Expirant -->
<?php if ( cgt_fha_is_banner_active() ) : ?>
<div class="cgt-mob-banner" role="alert">
<?php if ( ! empty( $opts['banner_url'] ) ) : ?>
<a href="<?php echo esc_url( (string) $opts['banner_url'] ); ?>" class="cgt-mob-banner__inner">
<span><?php echo esc_html( (string) $opts['banner_text'] ); ?></span>
</a>
<?php else : ?>
<div class="cgt-mob-banner__inner">
<span><?php echo esc_html( (string) $opts['banner_text'] ); ?></span>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
<!-- 3. Barre de Navigation Principale -->
<header class="cgt-header" role="banner">
<div class="cgt-container cgt-header__inner">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>" class="cgt-brand" rel="home">
<img
src="<?php echo esc_url( $logo_url ); ?>"
alt="<?php echo esc_attr( get_bloginfo( 'name' ) ?: 'Union Locale CGT Foix Haute-Ariège' ); ?>"
class="cgt-brand__logo"
decoding="async"
fetchpriority="high"
/>
</a>
<button
type="button"
class="cgt-nav-toggle"
aria-controls="cgt-primary-nav"
aria-expanded="false"
aria-label="<?php esc_attr_e( 'Ouvrir le menu principal', 'cgt-fha' ); ?>"
>
<?php echo cgt_fha_render_icon( 'menu', 22 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</button>
<nav id="cgt-primary-nav" class="cgt-nav" aria-label="<?php esc_attr_e( 'Navigation principale', 'cgt-fha' ); ?>">
<?php
wp_nav_menu(
array(
'theme_location' => 'primary',
'container' => false,
'menu_class' => 'cgt-nav__list',
'depth' => 1,
'fallback_cb' => 'cgt_fha_default_primary_menu',
)
);
?>
</nav>
</div>
</header>
<main id="cgt-main-content" tabindex="-1">
<?php
// Hook pour extensions éventuelles juste après l'ouverture du contenu principal.
do_action( 'cgt_fha_main_open' );

61
home.php Normal file
View File

@ -0,0 +1,61 @@
<?php
/**
* Gabarit de la liste paginée des actualités locales de l'UL (home.php).
*
* @package CGT_FHA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
get_header();
$posts_page_id = (int) get_option( 'page_for_posts' );
$page_title = $posts_page_id > 0 ? get_the_title( $posts_page_id ) : 'Actualités locales — Foix & Haute-Ariège';
?>
<section class="cgt-page-hero">
<div class="cgt-container">
<nav class="cgt-breadcrumb" aria-label="<?php esc_attr_e( 'Fil d\'Ariane', 'cgt-fha' ); ?>">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php esc_html_e( 'Accueil', 'cgt-fha' ); ?></a>
<span aria-hidden="true">/</span>
<span><?php echo esc_html( $page_title ); ?></span>
</nav>
<h1 class="cgt-page-hero__title"><?php echo esc_html( $page_title ); ?></h1>
<p class="cgt-page-hero__desc">
<?php esc_html_e( 'Retrouvez les communiqués, mobilisations, tracts et comptes-rendus des syndicats CGT de Foix et de la Haute-Ariège.', 'cgt-fha' ); ?>
</p>
</div>
</section>
<section class="cgt-section cgt-section--white">
<div class="cgt-container">
<?php if ( have_posts() ) : ?>
<div class="cgt-news-grid">
<?php
while ( have_posts() ) :
the_post();
cgt_fha_render_local_post_card();
endwhile;
?>
</div>
<div class="cgt-pagination">
<?php
the_posts_pagination(
array(
'mid_size' => 2,
'prev_text' => '← Précédent',
'next_text' => 'Suivant →',
)
);
?>
</div>
<?php else : ?>
<p><?php esc_html_e( 'Aucun article local publié pour le moment.', 'cgt-fha' ); ?></p>
<?php endif; ?>
</div>
</section>
<?php
get_footer();

View File

@ -0,0 +1,840 @@
<?php
/**
* Moteur de récupération et rendu de l'actualité confédérale depuis https://www.cgt.fr/
*
* - Interroge cgt.fr via wp_remote_get() (timeout 10s, User-Agent propre)
* - Parse le HTML Drupal via DOMDocument + DOMXPath sans polluer wp_posts
* - Extrait 1 article "À la une" + 3 articles "mais aussi..."
* - Enrichit les résumés via https://www.cgt.fr/actualites et, si besoin, depuis la page article
* - Cache Transient (3h) + sauvegarde de secours (autoload = false) + WP-Cron (2h)
*
* @package CGT_FHA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class CGT_FHA_Confederal_Feed {
public const TRANSIENT_KEY = 'cgt_fha_confederal_feed';
public const BACKUP_OPTION = 'cgt_fha_confederal_feed_backup';
public const LOCK_TRANSIENT = 'cgt_fha_confederal_feed_lock';
public const CRON_HOOK = 'cgt_fha_refresh_confederal_feed';
public const CRON_INTERVAL = 'cgt_fha_two_hours';
/**
* Enregistre les hooks WP-Cron, Admin Bar et rafraîchissement manuel.
*/
public static function init(): void {
add_filter( 'cron_schedules', array( __CLASS__, 'register_cron_interval' ) );
add_action( 'init', array( __CLASS__, 'ensure_cron_scheduled' ) );
add_action( self::CRON_HOOK, array( __CLASS__, 'cron_refresh' ) );
add_action( 'switch_theme', array( __CLASS__, 'clear_cron' ) );
add_action( 'admin_bar_menu', array( __CLASS__, 'add_admin_bar_button' ), 95 );
add_action( 'admin_post_cgt_fha_refresh_feed', array( __CLASS__, 'handle_manual_refresh' ) );
}
/**
* Ajoute un intervalle WP-Cron de 2 heures.
*
* @param array<string, array<string, mixed>> $schedules Planifications existantes.
* @return array<string, array<string, mixed>>
*/
public static function register_cron_interval( array $schedules ): array {
if ( ! isset( $schedules[ self::CRON_INTERVAL ] ) ) {
$schedules[ self::CRON_INTERVAL ] = array(
'interval' => 2 * HOUR_IN_SECONDS,
'display' => 'Toutes les 2 heures (Actus Confédérales CGT)',
);
}
return $schedules;
}
/**
* Planifie la tâche WP-Cron si elle n'est pas déjà active.
*/
public static function ensure_cron_scheduled(): void {
if ( ! wp_next_scheduled( self::CRON_HOOK ) ) {
wp_schedule_event( time() + 300, self::CRON_INTERVAL, self::CRON_HOOK );
}
}
/**
* Supprime la tâche WP-Cron lors du changement de thème.
*/
public static function clear_cron(): void {
$timestamp = wp_next_scheduled( self::CRON_HOOK );
while ( $timestamp ) {
wp_unschedule_event( $timestamp, self::CRON_HOOK );
$timestamp = wp_next_scheduled( self::CRON_HOOK );
}
}
/**
* Callback exécuté par WP-Cron toutes les 2 heures.
*/
public static function cron_refresh(): void {
self::get_feed( true );
}
/**
* Bouton « Actualiser les actus confédérales » dans la barre d'admin WordPress.
*/
public static function add_admin_bar_button( WP_Admin_Bar $wp_admin_bar ): void {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$url = wp_nonce_url(
admin_url( 'admin-post.php?action=cgt_fha_refresh_feed' ),
'cgt_fha_refresh_feed_action',
'cgt_fha_refresh_feed_nonce'
);
$wp_admin_bar->add_node(
array(
'id' => 'cgt-fha-refresh-confederal',
'title' => 'Actualiser les actus confédérales',
'href' => $url,
'meta' => array(
'title' => 'Synchroniser immédiatement les actualités depuis cgt.fr',
),
)
);
}
/**
* Traitement du rafraîchissement manuel sécurisé par nonce.
*/
public static function handle_manual_refresh(): void {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'Action non autorisée.', 'cgt-fha' ), 403 );
}
check_admin_referer( 'cgt_fha_refresh_feed_action', 'cgt_fha_refresh_feed_nonce' );
delete_transient( self::LOCK_TRANSIENT );
self::get_feed( true );
$redirect = add_query_arg(
array(
'page' => 'cgt-fha-settings',
'tab' => 'confederal',
'cgt_feed_refreshed' => '1',
),
admin_url( 'themes.php' )
);
wp_safe_redirect( $redirect );
exit;
}
/**
* Retourne les données du flux confédéral (cache -> réseau -> backup -> fallback).
*
* @param bool $force_refresh Force une requête réseau immédiate.
* @return array<string, mixed>
*/
public static function get_feed( bool $force_refresh = false ): array {
if ( ! $force_refresh ) {
$cached = get_transient( self::TRANSIENT_KEY );
if ( is_array( $cached ) && ! empty( $cached['featured'] ) ) {
return $cached;
}
}
// Anti-tempête : évite de relancer des requêtes HTTP bloquantes si cgt.fr vient d'échouer.
if ( $force_refresh || false === get_transient( self::LOCK_TRANSIENT ) ) {
$fresh = self::fetch_and_parse();
if ( ! empty( $fresh['featured']['title'] ) && ! empty( $fresh['latest'] ) ) {
set_transient( self::TRANSIENT_KEY, $fresh, 3 * HOUR_IN_SECONDS );
update_option( self::BACKUP_OPTION, $fresh, false );
delete_transient( self::LOCK_TRANSIENT );
return $fresh;
}
set_transient( self::LOCK_TRANSIENT, 1, 5 * MINUTE_IN_SECONDS );
}
$backup = get_option( self::BACKUP_OPTION, array() );
if ( is_array( $backup ) && ! empty( $backup['featured']['title'] ) ) {
return $backup;
}
return self::get_static_fallback();
}
/**
* Retourne l'état du cache pour l'onglet d'administration.
*
* @return array<string, mixed>
*/
public static function get_cache_status(): array {
$transient = get_transient( self::TRANSIENT_KEY );
$backup = get_option( self::BACKUP_OPTION, array() );
$data = is_array( $transient ) && ! empty( $transient ) ? $transient : ( is_array( $backup ) ? $backup : array() );
return array(
'has_transient' => is_array( $transient ) && ! empty( $transient ),
'fetched_at' => $data['fetched_at'] ?? 0,
'source' => $data['source'] ?? 'Fallback local',
'featured' => $data['featured'] ?? array(),
);
}
/**
* Télécharge et parse cgt.fr (avec enrichissement sur /actualites puis sur la page article si besoin).
*
* @return array<string, mixed>
*/
private static function fetch_and_parse(): array {
$home_html = self::remote_get_html( 'https://www.cgt.fr/' );
$featured = array();
$latest = array();
$source = 'https://www.cgt.fr/';
if ( '' !== $home_html ) {
$parsed = self::parse_homepage_html( $home_html );
$featured = $parsed['featured'];
$latest = $parsed['latest'];
}
$needs_actualites = empty( $featured['title'] )
|| '' === trim( (string) ( $featured['summary'] ?? '' ) )
|| empty( $featured['image_url'] )
|| count( $latest ) < 3;
if ( ! $needs_actualites ) {
foreach ( $latest as $item ) {
if ( '' === trim( (string) ( $item['summary'] ?? '' ) ) || empty( $item['image_url'] ) ) {
$needs_actualites = true;
break;
}
}
}
if ( $needs_actualites ) {
$actus_html = self::remote_get_html( 'https://www.cgt.fr/actualites' );
if ( '' !== $actus_html ) {
$actus_items = self::parse_actualites_html( $actus_html );
if ( ! empty( $actus_items ) ) {
$by_path = array();
foreach ( $actus_items as $act ) {
$key = self::normalize_url_key( $act['url'] );
if ( '' !== $key ) {
$by_path[ $key ] = $act;
}
}
// Enrichit "featured" sans écraser une image haute définition déjà extraite.
if ( ! empty( $featured['url'] ) ) {
$f_key = self::normalize_url_key( $featured['url'] );
if ( isset( $by_path[ $f_key ] ) ) {
if ( '' === trim( (string) ( $featured['summary'] ?? '' ) ) && ! empty( $by_path[ $f_key ]['summary'] ) ) {
$featured['summary'] = $by_path[ $f_key ]['summary'];
}
if ( empty( $featured['image_url'] ) && ! empty( $by_path[ $f_key ]['image_url'] ) ) {
$featured['image_url'] = $by_path[ $f_key ]['image_url'];
}
if ( ( empty( $featured['category'] ) || 'Confédération CGT' === $featured['category'] ) && ! empty( $by_path[ $f_key ]['category'] ) ) {
$featured['category'] = $by_path[ $f_key ]['category'];
}
}
}
// Enrichit les 3 cartes "latest" depuis /actualites sans écraser image_a_la_une.
foreach ( $latest as $idx => $item ) {
$l_key = self::normalize_url_key( $item['url'] );
if ( isset( $by_path[ $l_key ] ) ) {
if ( '' === trim( (string) ( $item['summary'] ?? '' ) ) && ! empty( $by_path[ $l_key ]['summary'] ) ) {
$latest[ $idx ]['summary'] = $by_path[ $l_key ]['summary'];
}
if ( empty( $item['image_url'] ) && ! empty( $by_path[ $l_key ]['image_url'] ) ) {
$latest[ $idx ]['image_url'] = $by_path[ $l_key ]['image_url'];
}
if ( ( empty( $item['category'] ) || 'Confédération CGT' === $item['category'] ) && ! empty( $by_path[ $l_key ]['category'] ) ) {
$latest[ $idx ]['category'] = $by_path[ $l_key ]['category'];
}
}
}
// Fallback complet si la page d'accueil a changé de structure.
if ( empty( $featured['title'] ) && count( $actus_items ) >= 2 ) {
$featured = array_shift( $actus_items );
$latest = array_slice( $actus_items, 0, 3 );
$source = 'https://www.cgt.fr/actualites (fallback)';
} elseif ( count( $latest ) < 3 ) {
$seen = array( self::normalize_url_key( (string) ( $featured['url'] ?? '' ) ) );
foreach ( $latest as $l ) {
$seen[] = self::normalize_url_key( (string) $l['url'] );
}
foreach ( $actus_items as $act ) {
if ( count( $latest ) >= 3 ) {
break;
}
$act_key = self::normalize_url_key( $act['url'] );
if ( '' !== $act_key && ! in_array( $act_key, $seen, true ) ) {
$latest[] = $act;
$seen[] = $act_key;
}
}
}
}
}
}
if ( empty( $featured['title'] ) || empty( $latest ) ) {
return array();
}
// Fallback final : complète un éventuel article épinglé absent de la page 1 d'/actualites.
if ( '' === trim( (string) ( $featured['summary'] ?? '' ) ) || empty( $featured['image_url'] ) ) {
$featured = self::enrich_from_article_page( $featured );
}
foreach ( $latest as $idx => $item ) {
if ( '' === trim( (string) ( $item['summary'] ?? '' ) ) || empty( $item['image_url'] ) ) {
$latest[ $idx ] = self::enrich_from_article_page( $item );
}
}
return array(
'fetched_at' => time(),
'source' => $source,
'featured' => self::normalize_article( $featured, 240 ),
'latest' => array_map(
static fn( array $item ): array => self::normalize_article( $item, 190 ),
array_slice( $latest, 0, 3 )
),
);
}
/**
* Requête HTTP GET sécurisée avec timeout 10s.
*/
private static function remote_get_html( string $url ): string {
$response = wp_remote_get(
$url,
array(
'timeout' => 10,
'redirection' => 3,
'user-agent' => 'Mozilla/5.0 (compatible; CGT-FHA-Theme/1.1; +https://cgt-fha.fr/)',
'headers' => array(
'Accept' => 'text/html,application/xhtml+xml',
'Accept-Language' => 'fr-FR,fr;q=0.9',
),
)
);
if ( is_wp_error( $response ) ) {
return '';
}
$code = (int) wp_remote_retrieve_response_code( $response );
if ( $code < 200 || $code >= 400 ) {
return '';
}
return (string) wp_remote_retrieve_body( $response );
}
/**
* Parse la page d'accueil cgt.fr :
* - "À la une de la CGT" (#block-bluedrop-views-block-derniers-ajouts-block-2, .relative-wrapper)
* - "mais aussi..." (#block-views-block-derniers-ajouts-block-1, .views-row)
*
* @return array{featured: array<string, string>, latest: array<int, array<string, string>>}
*/
private static function parse_homepage_html( string $html ): array {
$xpath = self::create_xpath( $html );
if ( ! $xpath ) {
return array( 'featured' => array(), 'latest' => array() );
}
$featured = array();
$latest = array();
// 1. Bloc « à la une de la cgt » (ID Drupal exact + secours par titre de section).
$une_root = null;
$une_nodes = $xpath->query( '//section[@id="block-bluedrop-views-block-derniers-ajouts-block-2"]' );
if ( $une_nodes instanceof DOMNodeList && $une_nodes->length > 0 ) {
$une_root = $une_nodes->item( 0 );
} else {
$une_root = self::find_section_by_heading_text( $xpath, 'la une de la cgt' );
}
if ( $une_root ) {
$wrappers = $xpath->query( './/div[contains(@class,"relative-wrapper")]', $une_root );
$card_el = ( $wrappers instanceof DOMNodeList && $wrappers->length > 0 ) ? $wrappers->item( 0 ) : $une_root;
$parsed = self::extract_drupal_row( $xpath, $card_el );
if ( ! empty( $parsed['title'] ) && ! empty( $parsed['url'] ) ) {
$featured = $parsed;
}
}
// 2. Bloc « mais aussi... » (ID Drupal exact + secours par titre de section).
$mais_root = null;
$mais_nodes = $xpath->query( '//section[@id="block-views-block-derniers-ajouts-block-1"]' );
if ( $mais_nodes instanceof DOMNodeList && $mais_nodes->length > 0 ) {
$mais_root = $mais_nodes->item( 0 );
} else {
$mais_root = self::find_section_by_heading_text( $xpath, 'mais aussi' );
}
if ( $mais_root ) {
$rows = $xpath->query( './/div[contains(@class,"views-row")]', $mais_root );
if ( $rows instanceof DOMNodeList ) {
$seen = array( self::normalize_url_key( (string) ( $featured['url'] ?? '' ) ) );
foreach ( $rows as $row ) {
if ( count( $latest ) >= 3 ) {
break;
}
$item = self::extract_drupal_row( $xpath, $row );
$key = self::normalize_url_key( (string) ( $item['url'] ?? '' ) );
if ( ! empty( $item['title'] ) && '' !== $key && ! in_array( $key, $seen, true ) ) {
$latest[] = $item;
$seen[] = $key;
}
}
}
}
return array(
'featured' => $featured,
'latest' => $latest,
);
}
/**
* Parse la liste des articles de https://www.cgt.fr/actualites (jusqu'à 25 lignes .views-row).
*
* @return array<int, array<string, string>>
*/
private static function parse_actualites_html( string $html ): array {
$xpath = self::create_xpath( $html );
if ( ! $xpath || ! $xpath->document->documentElement ) {
return array();
}
$rows = $xpath->query( '//main//div[contains(@class,"views-row")]|//div[contains(@class,"view-content")]//div[contains(@class,"views-row")]' );
if ( ! ( $rows instanceof DOMNodeList ) || 0 === $rows->length ) {
return array();
}
$articles = array();
$seen = array();
foreach ( $rows as $row ) {
if ( count( $articles ) >= 25 ) {
break;
}
$item = self::extract_drupal_row( $xpath, $row );
$key = self::normalize_url_key( (string) ( $item['url'] ?? '' ) );
if ( ! empty( $item['title'] ) && '' !== $key && ! isset( $seen[ $key ] ) ) {
$seen[ $key ] = true;
$articles[] = $item;
}
}
return $articles;
}
/**
* Extrait proprement un article depuis un conteneur Drupal (bloc À la une ou .views-row).
*
* @return array<string, string>
*/
private static function extract_drupal_row( DOMXPath $xpath, DOMNode $row ): array {
$link_el = null;
$h_links = $xpath->query( './/h3//a[@href]|.//h2//a[@href]|.//h4//a[@href]', $row );
if ( $h_links instanceof DOMNodeList ) {
foreach ( $h_links as $cand ) {
$href = trim( $cand->getAttribute( 'href' ) );
if ( self::is_article_href( $href ) ) {
$link_el = $cand;
break;
}
}
}
if ( ! $link_el ) {
$fallback_links = $xpath->query( './/a[@href and not(contains(@href,"/terms/")) and not(contains(@href,"/taxonomy/")) and not(contains(@class,"taxonomy-style")) and not(contains(@class,"more-link"))]', $row );
if ( $fallback_links instanceof DOMNodeList ) {
foreach ( $fallback_links as $cand ) {
$href = trim( $cand->getAttribute( 'href' ) );
if ( self::is_article_href( $href ) ) {
$link_el = $cand;
break;
}
}
}
}
if ( ! $link_el ) {
return array();
}
$url = self::absolutize_url( $link_el->getAttribute( 'href' ) );
$title = self::normalize_space( $link_el->textContent );
if ( '' === $url || strlen( $title ) < 6 ) {
return array();
}
// Catégories (.taxonomy-style hors badge .highlighted).
$cats = array();
$cat_nodes = $xpath->query( './/*[contains(@class,"taxonomy-style")]', $row );
if ( $cat_nodes instanceof DOMNodeList ) {
foreach ( $cat_nodes as $cat_node ) {
if ( $cat_node instanceof DOMElement && false !== strpos( $cat_node->getAttribute( 'class' ), 'highlighted' ) ) {
continue;
}
$cat_txt = self::normalize_space( $cat_node->textContent );
if ( '' !== $cat_txt && strlen( $cat_txt ) < 45 && ! in_array( $cat_txt, $cats, true ) ) {
$cats[] = $cat_txt;
}
}
}
$category = ! empty( $cats ) ? implode( ' | ', array_slice( $cats, 0, 2 ) ) : 'Confédération CGT';
// Résumé (.field-type-text-long ou paragraphe dans .txt-container).
$summary = '';
$p_nodes = $xpath->query( './/*[contains(@class,"field-type-text-long")]|.//div[contains(@class,"txt-container")]//p|.//p', $row );
if ( $p_nodes instanceof DOMNodeList ) {
foreach ( $p_nodes as $p ) {
$txt = self::normalize_space( $p->textContent );
if ( strlen( $txt ) >= 10 && $txt !== $title ) {
$summary = $txt;
break;
}
}
}
// Image (.views-field-field-imagette-media img en priorité, sinon premier img).
$image_url = '';
$img_nodes = $xpath->query( './/div[contains(@class,"views-field-field-imagette-media")]//img|.//img', $row );
if ( $img_nodes instanceof DOMNodeList && $img_nodes->length > 0 ) {
$img = $img_nodes->item( 0 );
if ( $img instanceof DOMElement ) {
$src = $img->getAttribute( 'data-src' ) ?: $img->getAttribute( 'src' );
if ( '' === $src && $img->hasAttribute( 'srcset' ) ) {
$parts = explode( ',', $img->getAttribute( 'srcset' ) );
$first = trim( (string) $parts[0] );
$src = strtok( $first, ' ' ) ?: '';
}
$image_url = self::absolutize_url( $src );
}
}
return array(
'title' => $title,
'summary' => $summary,
'image_url' => $image_url,
'category' => $category,
'url' => $url,
);
}
/**
* Enrichit un article directement depuis sa page individuelle sur cgt.fr si résumé ou image manquent.
*
* @param array<string, string> $item Article partiel.
* @return array<string, string>
*/
private static function enrich_from_article_page( array $item ): array {
if ( empty( $item['url'] ) ) {
return $item;
}
$html = self::remote_get_html( $item['url'] );
if ( '' === $html ) {
return $item;
}
$xpath = self::create_xpath( $html );
if ( ! $xpath ) {
return $item;
}
if ( '' === trim( (string) ( $item['summary'] ?? '' ) ) ) {
$candidates = array(
'.//*[contains(@class,"chapo") or contains(@class,"field-name-field-chapo")]',
'//meta[@property="og:description"]/@content',
'//meta[@name="description"]/@content',
'//main//article//p',
);
foreach ( $candidates as $query ) {
$nodes = $xpath->query( $query );
if ( $nodes instanceof DOMNodeList && $nodes->length > 0 ) {
foreach ( $nodes as $node ) {
$txt = self::normalize_space( $node instanceof DOMAttr ? $node->value : $node->textContent );
if ( strlen( $txt ) >= 15 && $txt !== ( $item['title'] ?? '' ) ) {
$item['summary'] = $txt;
break 2;
}
}
}
}
}
if ( empty( $item['image_url'] ) ) {
$og_img = $xpath->query( '//meta[@property="og:image"]/@content' );
if ( $og_img instanceof DOMNodeList && $og_img->length > 0 ) {
$src = trim( (string) $og_img->item( 0 )->nodeValue );
if ( '' !== $src ) {
$item['image_url'] = self::absolutize_url( $src );
}
}
}
return $item;
}
/**
* Localise la section ancêtre correspondant à un titre textuel donné.
*/
private static function find_section_by_heading_text( DOMXPath $xpath, string $needle ): ?DOMNode {
$headings = $xpath->query( '//h1|//h2|//h3' );
if ( ! ( $headings instanceof DOMNodeList ) ) {
return null;
}
foreach ( $headings as $heading ) {
$text = self::normalize_space( $heading->textContent );
$low = function_exists( 'mb_strtolower' ) ? mb_strtolower( $text, 'UTF-8' ) : strtolower( $text );
if ( false !== strpos( $low, $needle ) ) {
$cur = $heading->parentNode;
while ( $cur && $cur instanceof DOMElement ) {
if ( 'section' === strtolower( $cur->tagName ) ) {
return $cur;
}
$cur = $cur->parentNode;
}
return $heading->parentNode;
}
}
return null;
}
/**
* Vérifie qu'un href pointe vers un article (et non une taxonomie ou l'index /actualites).
*/
private static function is_article_href( string $href ): bool {
if ( '' === $href || '#' === $href || 0 === strpos( $href, 'mailto:' ) || 0 === strpos( $href, 'tel:' ) ) {
return false;
}
if ( false !== strpos( $href, '/terms/' ) || false !== strpos( $href, '/taxonomy/' ) ) {
return false;
}
$path = untrailingslashit( (string) wp_parse_url( $href, PHP_URL_PATH ) );
return '' !== $path && '/actualites' !== $path && '/' !== $path;
}
/**
* Normalise une URL sur son chemin pour la correspondance fiable entre accueil et /actualites.
*/
private static function normalize_url_key( string $url ): string {
$path = (string) wp_parse_url( trim( $url ), PHP_URL_PATH );
$path = strtolower( untrailingslashit( $path ) );
return '' === $path || '/' === $path ? '' : $path;
}
/**
* Initialise un DOMXPath UTF-8 fiable sur PHP 8.x sans altérer les accents ni apostrophes typographiques.
*/
private static function create_xpath( string $html ): ?DOMXPath {
if ( '' === trim( $html ) || ! class_exists( 'DOMDocument' ) ) {
return null;
}
if ( function_exists( 'mb_encode_numericentity' ) ) {
$prepared = mb_encode_numericentity( $html, array( 0x80, 0x10FFFF, 0, ~0 ), 'UTF-8' );
} else {
$prepared = preg_replace( '/<head\b[^>]*>/i', '$0<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">', $html, 1 ) ?: $html;
}
$prev = libxml_use_internal_errors( true );
$dom = new DOMDocument( '1.0', 'UTF-8' );
$dom->loadHTML( $prepared, LIBXML_NONET | LIBXML_NOWARNING | LIBXML_NOERROR );
libxml_clear_errors();
libxml_use_internal_errors( $prev );
return new DOMXPath( $dom );
}
/**
* Convertit une URL relative cgt.fr en URL absolue.
*/
private static function absolutize_url( string $raw ): string {
$raw = trim( $raw );
if ( '' === $raw || 0 === strpos( $raw, 'data:' ) || 0 === strpos( $raw, 'javascript:' ) ) {
return '';
}
if ( 0 === strpos( $raw, '//' ) ) {
return 'https:' . $raw;
}
if ( preg_match( '#^https?://#i', $raw ) ) {
return esc_url_raw( $raw );
}
if ( '/' === $raw[0] ) {
return esc_url_raw( 'https://www.cgt.fr' . $raw );
}
return esc_url_raw( 'https://www.cgt.fr/' . ltrim( $raw, '/' ) );
}
/**
* Normalise les espaces blancs et entités HTML.
*/
private static function normalize_space( string $text ): string {
$decoded = html_entity_decode( wp_strip_all_tags( $text ), ENT_QUOTES | ENT_HTML5, 'UTF-8' );
return trim( (string) preg_replace( '/\s+/u', ' ', $decoded ) );
}
/**
* Nettoie et tronque un article pour l'affichage sans phrase générique répétitive.
*
* @param array<string, string> $item Données brutes de l'article.
* @return array<string, string>
*/
private static function normalize_article( array $item, int $max_chars = 190 ): array {
$placeholder = CGT_FHA_URI . '/assets/img/placeholder.svg';
$summary = self::normalize_space( (string) ( $item['summary'] ?? '' ) );
if ( '' !== $summary && function_exists( 'mb_strlen' ) && mb_strlen( $summary, 'UTF-8' ) > $max_chars ) {
$summary = rtrim( mb_substr( $summary, 0, $max_chars - 1, 'UTF-8' ) ) . '…';
}
return array(
'title' => self::normalize_space( (string) ( $item['title'] ?? '' ) ),
'summary' => $summary,
'image_url' => ! empty( $item['image_url'] ) ? esc_url_raw( (string) $item['image_url'] ) : $placeholder,
'category' => self::normalize_space( (string) ( $item['category'] ?? 'Confédération CGT' ) ),
'url' => ! empty( $item['url'] ) ? esc_url_raw( (string) $item['url'] ) : 'https://www.cgt.fr/actualites',
);
}
/**
* Fallback statique si cgt.fr est inaccessible lors du premier démarrage.
*
* @return array<string, mixed>
*/
private static function get_static_fallback(): array {
$placeholder = CGT_FHA_URI . '/assets/img/placeholder.svg';
return array(
'fetched_at' => 0,
'source' => 'Fallback éditorial local',
'featured' => array(
'title' => 'Salaires, retraites, services publics : toutes et tous mobilisés avec la CGT',
'summary' => 'Retrouvez les dossiers nationaux, les revendications confédérales et les appels à l\'action portés par la CGT partout en France.',
'image_url' => $placeholder,
'category' => 'À la une',
'url' => 'https://www.cgt.fr/actualites',
),
'latest' => array(
array(
'title' => 'Pouvoir d\'achat : augmenter les salaires et le SMIC',
'summary' => 'Les propositions économiques de la CGT pour indexer les salaires sur l\'inflation et revaloriser les grilles.',
'image_url' => $placeholder,
'category' => 'Salaires',
'url' => 'https://www.cgt.fr/actualites',
),
array(
'title' => 'Conditions de travail & santé au travail',
'summary' => 'Prévenir l\'usure professionnelle, renforcer le rôle des élus CSE et défendre les droits des salarié·e·s.',
'image_url' => $placeholder,
'category' => 'Travail',
'url' => 'https://www.cgt.fr/actualites',
),
array(
'title' => 'Services publics de proximité dans nos territoires',
'summary' => 'Défendre l\'hôpital public, l\'école, les transports et les services publics essentiels en milieu rural.',
'image_url' => $placeholder,
'category' => 'Services publics',
'url' => 'https://www.cgt.fr/actualites',
),
),
);
}
/**
* Rendu HTML/CSS de la Section 4 (fidèle à la maquette).
*/
public static function render_section( string $section_title = 'ACTUALITÉ CONFÉDÉRALE' ): void {
$feed = self::get_feed();
$featured = $feed['featured'] ?? array();
$latest = $feed['latest'] ?? array();
if ( empty( $featured ) ) {
return;
}
?>
<section class="cgt-section cgt-section--soft" aria-labelledby="cgt-confederal-heading">
<div class="cgt-container">
<h2 id="cgt-confederal-heading" class="cgt-section__title"><?php echo esc_html( $section_title ); ?></h2>
<!-- Bloc supérieur « À LA UNE » -->
<article class="cgt-confederal-featured">
<div class="cgt-confederal-featured__media">
<img
src="<?php echo esc_url( $featured['image_url'] ); ?>"
alt="<?php echo esc_attr( $featured['title'] ); ?>"
class="cgt-confederal-featured__img"
loading="lazy"
decoding="async"
/>
<span class="cgt-confederal-featured__badge">À LA UNE</span>
</div>
<div class="cgt-confederal-featured__box">
<span class="cgt-confederal-featured__kicker"><?php echo esc_html( $featured['category'] ?: 'À LA UNE' ); ?></span>
<h3 class="cgt-confederal-featured__title"><?php echo esc_html( $featured['title'] ); ?></h3>
<?php if ( '' !== trim( (string) ( $featured['summary'] ?? '' ) ) ) : ?>
<p class="cgt-confederal-featured__summary"><?php echo esc_html( $featured['summary'] ); ?></p>
<?php endif; ?>
<a
href="<?php echo esc_url( $featured['url'] ); ?>"
class="cgt-btn cgt-btn--outline-dark"
target="_blank"
rel="noopener noreferrer"
>LIRE SUR CGT.FR ↗</a>
</div>
</article>
<!-- Grille inférieure : 3 articles -->
<?php if ( ! empty( $latest ) ) : ?>
<div class="cgt-confederal-grid">
<?php foreach ( $latest as $item ) : ?>
<article class="cgt-confederal-card">
<img
src="<?php echo esc_url( $item['image_url'] ); ?>"
alt="<?php echo esc_attr( $item['title'] ); ?>"
class="cgt-confederal-card__img"
loading="lazy"
decoding="async"
/>
<div class="cgt-confederal-card__box">
<h3 class="cgt-confederal-card__title"><?php echo esc_html( $item['title'] ); ?></h3>
<?php if ( '' !== trim( (string) ( $item['summary'] ?? '' ) ) ) : ?>
<p class="cgt-confederal-card__summary"><?php echo esc_html( $item['summary'] ); ?></p>
<?php endif; ?>
<div class="cgt-confederal-card__cta">
<a
href="<?php echo esc_url( $item['url'] ); ?>"
class="cgt-confederal-more"
target="_blank"
rel="noopener noreferrer"
>
<span class="cgt-confederal-more__label">Lire la suite</span>
<span class="cgt-confederal-more__arrow" aria-hidden="true">→</span>
</a>
</div>
</div>
</article>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</section>
<?php
}
}
CGT_FHA_Confederal_Feed::init();

180
inc/seo-performance.php Normal file
View File

@ -0,0 +1,180 @@
<?php
/**
* SEO local, OpenGraph, Alerte Indexation Admin & Optimisation Performance.
*
* @package CGT_FHA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Titre SEO personnalisé.
*/
add_filter( 'pre_get_document_title', 'cgt_fha_document_title', 20 );
function cgt_fha_document_title( string $title ): string {
$site_brand = 'Union Locale CGT Foix Haute-Ariège';
if ( is_front_page() ) {
return $site_brand . ' | Défense des salariés et action syndicale';
}
if ( is_singular() ) {
return wp_strip_all_tags( get_the_title() ) . ' | ' . $site_brand;
}
if ( is_home() ) {
return 'Actualités locales | ' . $site_brand;
}
if ( is_archive() ) {
return wp_strip_all_tags( get_the_archive_title() ) . ' | ' . $site_brand;
}
if ( is_404() ) {
return 'Page introuvable | ' . $site_brand;
}
return $title ?: $site_brand;
}
/**
* Calcule la meta description adaptée au contexte courant.
*/
function cgt_fha_get_meta_description(): string {
$opts = cgt_fha_get_options();
if ( is_front_page() ) {
return wp_strip_all_tags(
"Union Locale CGT de Foix et de la Haute-Ariège : union des syndicats CGT du territoire, rattachement des salarié·e·s isolé·e·s via le syndicat Multipros et permanences à l'Espace Sabart."
);
}
if ( is_singular() ) {
$post = get_queried_object();
if ( $post instanceof WP_Post ) {
$raw = has_excerpt( $post ) ? $post->post_excerpt : $post->post_content;
$txt = trim( (string) preg_replace( '/\s+/u', ' ', wp_strip_all_tags( strip_shortcodes( $raw ) ) ) );
if ( '' !== $txt ) {
return wp_html_excerpt( $txt, 158, '…' );
}
}
}
if ( is_category() || is_tag() ) {
$desc = trim( wp_strip_all_tags( term_description() ) );
if ( '' !== $desc ) {
return wp_html_excerpt( $desc, 158, '…' );
}
}
return wp_html_excerpt( (string) $opts['footer_desc'], 158, '…' );
}
/**
* Injection automatique des balises <meta name="description"> et OpenGraph.
*/
add_action( 'wp_head', 'cgt_fha_render_meta_and_og', 2 );
function cgt_fha_render_meta_and_og(): void {
$opts = cgt_fha_get_options();
$title = cgt_fha_document_title( wp_get_document_title() );
$description = cgt_fha_get_meta_description();
$og_type = is_single() ? 'article' : 'website';
if ( is_front_page() ) {
$url = home_url( '/' );
} elseif ( is_singular() ) {
$url = get_permalink() ?: home_url( '/' );
} else {
global $wp;
$url = home_url( add_query_arg( array(), $wp->request ?? '' ) );
}
$og_image = (string) $opts['hero_bg_url'];
if ( is_singular() && has_post_thumbnail() ) {
$thumb_url = get_the_post_thumbnail_url( get_queried_object_id(), 'cgt-featured' );
if ( $thumb_url ) {
$og_image = $thumb_url;
}
}
?>
<meta name="description" content="<?php echo esc_attr( $description ); ?>" />
<meta property="og:locale" content="fr_FR" />
<meta property="og:site_name" content="Union Locale CGT Foix Haute-Ariège" />
<meta property="og:type" content="<?php echo esc_attr( $og_type ); ?>" />
<meta property="og:title" content="<?php echo esc_attr( $title ); ?>" />
<meta property="og:description" content="<?php echo esc_attr( $description ); ?>" />
<meta property="og:url" content="<?php echo esc_url( $url ); ?>" />
<?php if ( '' !== $og_image ) : ?>
<meta property="og:image" content="<?php echo esc_url( $og_image ); ?>" />
<?php endif; ?>
<meta name="twitter:card" content="summary_large_image" />
<?php
}
/**
* Alerte rouge dans le tableau de bord si l'indexation des moteurs de recherche est bloquée.
*/
add_action( 'admin_notices', 'cgt_fha_indexation_warning_notice' );
function cgt_fha_indexation_warning_notice(): void {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
if ( '0' === (string) get_option( 'blog_public' ) ) {
$reading_url = admin_url( 'options-reading.php' );
?>
<div class="notice notice-error" style="border-left-color:#d20012; background:#fff5f5;">
<p>
<strong style="color:#d20012;">Alerte SEO — Indexation bloquée :</strong>
Votre site demande actuellement aux moteurs de recherche de ne pas l'indexer.
<a href="<?php echo esc_url( $reading_url ); ?>">Rendez-vous dans Réglages &gt; Lecture</a>
et décochez « Demander aux moteurs de recherche de ne pas indexer ce site ».
</p>
</div>
<?php
}
}
/**
* Nettoyage du head WordPress et suppression de wp-emoji / wp-embed pour un TTFB et LCP optimaux.
*/
add_action( 'init', 'cgt_fha_cleanup_wp_bloat' );
function cgt_fha_cleanup_wp_bloat(): void {
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
remove_action( 'admin_print_styles', 'print_emoji_styles' );
remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
remove_action( 'wp_head', 'rsd_link' );
remove_action( 'wp_head', 'wlwmanifest_link' );
remove_action( 'wp_head', 'wp_generator' );
remove_action( 'wp_head', 'wp_shortlink_wp_head' );
remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
}
add_action( 'wp_footer', 'cgt_fha_disable_wp_embed' );
function cgt_fha_disable_wp_embed(): void {
wp_deregister_script( 'wp-embed' );
}
/**
* Ajoute loading="lazy" et decoding="async" sur les images hors ligne de flottaison.
*
* @param array<string, string> $attr Attributs de la balise img.
* @return array<string, string>
*/
add_filter( 'wp_get_attachment_image_attributes', 'cgt_fha_lazy_image_attributes', 10, 1 );
function cgt_fha_lazy_image_attributes( array $attr ): array {
if ( empty( $attr['fetchpriority'] ) && empty( $attr['loading'] ) ) {
$attr['loading'] = 'lazy';
}
if ( empty( $attr['decoding'] ) ) {
$attr['decoding'] = 'async';
}
return $attr;
}

776
inc/theme-options.php Normal file
View File

@ -0,0 +1,776 @@
<?php
/**
* Panneau d'administration WordPress : Apparence > Réglages UL CGT
*
* Toutes les options sont pré-remplies par défaut via wp_parse_args()
* afin que le thème soit immédiatement fonctionnel dès son activation.
*
* @package CGT_FHA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
const CGT_FHA_OPTION_KEY = 'cgt_fha_options';
const CGT_FHA_SCHEMA_VERSION = '1.2.0';
/**
* Valeurs par défaut complètes de toutes les options du thème.
*
* @return array<string, mixed>
*/
function cgt_fha_get_defaults(): array {
return array(
// Onglet 1 : Identité & Coordonnées.
'phone' => '07 60 49 64 69',
'email' => 'union-locale@cgt-fha.fr',
'address' => "Espace Sabart, 10 Av. de l'Ayroule, 09400 Tarascon-sur-Ariège",
'hours' => "Permanences d'accueil et juridiques : Mardi et Jeudi de 9h30 à 12h30, et sur rendez-vous.",
'facebook_url' => 'https://www.facebook.com/profile.php?id=61552410568856',
'instagram_url' => '',
'youtube_url' => '',
'header_logo_url' => CGT_FHA_URI . '/assets/img/banniere-ul-noir.png',
'footer_logo_url' => CGT_FHA_URI . '/assets/img/banniere-ul-blanc.png',
'footer_desc' => "L'Union Locale CGT de Foix et de la Haute-Ariège rassemble tous les syndicats CGT de son périmètre et rattache directement les salarié·e·s isolé·e·s au sein de son syndicat multiprofessionnel (Multipros).",
'footer_call' => "Une lutte dans votre entreprise, une info à partager ? Contactez l'UL",
'news_url' => home_url( '/actualites/' ),
'calendar_url' => home_url( '/calendrier/' ),
'contact_url' => home_url( '/contact/' ),
'join_url' => home_url( '/syndiquez-vous/' ),
'legal_url' => home_url( '/mentions-legales/' ),
// Onglet 2 : Bandeau Mobilisation auto-expirant.
'banner_enabled' => 0,
'banner_text' => 'MOBILISATION : Grève et manifestation à Foix - Allées de Villote',
'banner_url' => '',
'banner_expires' => wp_date( 'Y-m-d\TH:i', time() + 7 * DAY_IN_SECONDS ),
// Onglet 3 : Page d'accueil — Hero.
'hero_bg_url' => CGT_FHA_URI . '/assets/img/hero-ariege.jpg',
'hero_title_line1' => 'Union Locale CGT Foix Haute-Ariège',
'hero_title_line2' => 'Votre syndicat de proximité !',
'hero_quote' => '« La régression sociale ne se négocie pas, elle se combat ! » — Henri Krasucki, Secrétaire Général de la CGT de 1982 à 1992',
'hero_btn1_label' => "J'ai besoin d'aide",
'hero_btn1_url' => home_url( '/contact/' ),
'hero_btn2_label' => 'Rejoindre la CGT',
'hero_btn2_url' => home_url( '/syndiquez-vous/' ),
// Onglet 3 : Section 2 — À quoi nous servons ?
'missions_title' => 'À QUOI NOUS SERVONS ?',
'missions_subtitle' => "L'Union Locale fédère l'ensemble des syndicats CGT du bassin de Foix et de la Haute-Ariège, et accueille directement les salarié·e·s sans syndicat d'entreprise grâce à son syndicat multiprofessionnel (Multipros).",
'mission_1_icon' => 'fist',
'mission_1_title' => "S'ORGANISER",
'mission_1_text' => "Unir tous les syndicats CGT de Foix et de la Haute-Ariège, créer une section dans votre entreprise ou vous syndiquer directement via le syndicat Multipros de l'Union Locale.",
'mission_2_icon' => 'shield',
'mission_2_title' => 'SE DÉFENDRE',
'mission_2_text' => "Faire respecter vos droits, vos salaires et vos conditions de travail à Foix comme en Haute-Ariège, avec l'appui solidaire de nos syndicats, conseillers du salarié et défenseurs.",
'mission_3_icon' => 'chat',
'mission_3_title' => "S'INFORMER & SE FORMER",
'mission_3_text' => "Partager l'actualité des luttes à Foix et en Haute-Ariège et exercer votre droit légal à la formation syndicale (CFESES) pour agir collectivement.",
// Onglet 3 : Titres Actualités locales & confédérales.
'local_news_title' => 'SUR LE TERRAIN À FOIX ET EN HAUTE-ARIÈGE',
'local_news_more' => 'Voir toutes les actualités locales →',
'confederal_title' => 'ACTUALITÉ CONFÉDÉRALE',
// Onglet 3 : Section 5 — Salariés isolés & TPE (Multipros).
'tpe_enabled' => 1,
'tpe_badge' => "Syndicat Multipros de l'UL · TPE, PME & Isolé·e·s",
'tpe_title' => "SALARIÉS ISOLÉS & TPE : VOUS N'ÊTES PAS SEULS",
'tpe_text' => "À Foix comme en Haute-Ariège, même sans section syndicale ni CSE dans votre entreprise (TPE, commerce, artisanat, chantier, association…), l'Union Locale est votre maison commune : vous êtes rattaché·e directement au syndicat multiprofessionnel (Multipros) de l'UL.",
'tpe_point_1' => "Rattachement au syndicat Multipros de l'UL : ne restez plus isolé·e et rejoignez la solidarité de tous les syndicats CGT de Foix et de la Haute-Ariège.",
'tpe_point_2' => "Confidentialité absolue : aucune prise de contact ni adhésion n'est portée à la connaissance de votre employeur sans votre accord.",
'tpe_point_3' => "Conseillers du Salarié : accompagnement gratuit et défense à vos côtés lors d'un entretien préalable à licenciement ou d'un litige.",
'tpe_btn_label' => "Contacter l'UL en toute confidentialité",
'tpe_btn_url' => home_url( '/contact/' ),
// Onglet 3 : Section 6 — Formation Syndicale (CFESES) & Appli Mobile (désactivée par défaut).
'cfeses_enabled' => 1,
'cfeses_eyebrow' => 'Droit individuel & vie militante',
'cfeses_title' => 'Formation Syndicale (CFESES)',
'cfeses_text' => "Tout·e salarié·e a droit au Congé de Formation Économique, Sociale, Environnementale et Syndicale : jusqu'à 12 jours par an avec maintien intégral de salaire. Remettez votre demande à l'employeur au moins 30 jours avant le stage.",
'cfeses_btn_label' => 'Demander une formation syndicale',
'cfeses_btn_url' => home_url( '/contact/' ),
'app_enabled' => 0,
'app_eyebrow' => 'Outil militant 100 % hors-ligne',
'app_title' => "L'Application Mobile UL CGT Foix Haute-Ariège",
'app_text' => 'Suivez les actualités locales, recevez les alertes mobilisation en temps réel et gardez votre carte de syndiqué virtuelle & vos 13 timbres toujours sur vous (Android / KMP).',
'app_btn_label' => "Télécharger l'application (.apk / Store)",
'app_download_url' => 'https://cgt-fha.fr/',
'app_qr_url' => CGT_FHA_URI . '/assets/img/qr-placeholder.svg',
// Onglet 3 : Section 7 — Réseau syndical CGT (5 cartes verticales).
'network_enabled' => 1,
'network_title' => 'RÉSEAU SYNDICAL CGT',
'network_1_enabled' => 1,
'network_1_logo' => CGT_FHA_URI . '/assets/img/logo-cgt-09.jpg',
'network_1_label' => 'UD CGT 09',
'network_1_desc' => "Union Départementale des syndicats CGT de l'Ariège : coordination départementale des luttes et solidarité interprofessionnelle.",
'network_1_btn' => 'Visiter le site ↗',
'network_1_url' => 'https://ariege.cgt.fr/',
'network_2_enabled' => 1,
'network_2_logo' => CGT_FHA_URI . '/assets/img/logo-cgt.png',
'network_2_label' => 'Confédération CGT',
'network_2_desc' => 'Site national de la CGT : actualités confédérales, campagnes interprofessionnelles, analyses et repères revendicatifs.',
'network_2_btn' => 'Visiter le site ↗',
'network_2_url' => 'https://www.cgt.fr/',
'network_3_enabled' => 1,
'network_3_logo' => CGT_FHA_URI . '/assets/img/logo-nvo.png',
'network_3_label' => 'La NVO',
'network_3_desc' => "La Nouvelle Vie Ouvrière : le média d'information sociale et syndicale de la CGT au service du monde du travail.",
'network_3_btn' => 'Visiter le site ↗',
'network_3_url' => 'https://www.nvo.fr/',
'network_4_enabled' => 1,
'network_4_logo' => CGT_FHA_URI . '/assets/img/logo-ihs.jpg',
'network_4_label' => 'IHS CGT',
'network_4_desc' => "Institut CGT d'Histoire Sociale : mémoire vivante des luttes sociales, archives et recherches sur le mouvement ouvrier.",
'network_4_btn' => 'Visiter le site ↗',
'network_4_url' => 'https://www.ihs.cgt.fr/',
'network_5_enabled' => 1,
'network_5_logo' => CGT_FHA_URI . '/assets/img/logo-indecosa.png',
'network_5_label' => 'INDECOSA-CGT',
'network_5_desc' => 'Association de la CGT pour l\'information et la défense des consommateurs salarié·e·s (logement, énergie, consommation).',
'network_5_btn' => 'Visiter le site ↗',
'network_5_url' => 'https://www.indecosa-cgt.fr/',
);
}
/**
* Retourne les options fusionnées avec les valeurs par défaut (mise en cache mémoire par requête).
*
* @param bool $fresh Force la relecture depuis la base de données.
* @return array<string, mixed>
*/
function cgt_fha_get_options( bool $fresh = false ): array {
static $cached = null;
if ( null !== $cached && ! $fresh ) {
return $cached;
}
$saved = get_option( CGT_FHA_OPTION_KEY, array() );
$saved = is_array( $saved ) ? $saved : array();
$merged = wp_parse_args( $saved, cgt_fha_get_defaults() );
$media_keys = array(
'hero_bg_url',
'header_logo_url',
'footer_logo_url',
'app_qr_url',
'network_1_logo',
'network_2_logo',
'network_3_logo',
'network_4_logo',
'network_5_logo',
);
// Garantit que les visuels critiques vidés par erreur retombent sur le défaut.
$defaults = cgt_fha_get_defaults();
foreach ( $media_keys as $media_key ) {
if ( empty( $merged[ $media_key ] ) ) {
$merged[ $media_key ] = $defaults[ $media_key ];
}
}
$cached = $merged;
return $cached;
}
/**
* Migration automatique 1.0.0 -> 1.1.0 pour les sites où le thème est déjà activé.
*/
add_action( 'init', 'cgt_fha_maybe_upgrade_options', 5 );
function cgt_fha_maybe_upgrade_options(): void {
if ( CGT_FHA_SCHEMA_VERSION === get_option( 'cgt_fha_schema_version', '1.0.0' ) ) {
return;
}
$defaults = cgt_fha_get_defaults();
$saved = get_option( CGT_FHA_OPTION_KEY, array() );
if ( is_array( $saved ) && ! empty( $saved ) ) {
// Bascule du logo de pied de page vers la bannière texte blanc si ancien défaut ou vide.
if ( empty( $saved['footer_logo_url'] ) || false !== strpos( (string) $saved['footer_logo_url'], 'logo-ul-light.svg' ) ) {
$saved['footer_logo_url'] = $defaults['footer_logo_url'];
}
// Désactive le bloc Application Mobile par défaut tant que le contenu n'est pas prêt.
$saved['app_enabled'] = 0;
// Remplace les anciennes chaînes par défaut 1.0.0 si elles n'ont pas été personnalisées.
$old_v1_defaults = array(
'local_news_title' => 'SUR LE TERRAIN EN HAUTE-ARIÈGE',
'footer_desc' => "Syndicat interprofessionnel de proximité au service des salarié·e·s, privé·e·s d'emploi et retraité·e·s de Foix et de la Haute-Ariège.",
'mission_1_text' => "Construire le syndicat dans votre entreprise, préparer les élections CSE et ne plus rester isolé face à l'employeur.",
'mission_2_text' => "Faire respecter vos droits, vos salaires et vos conditions de travail, avec l'appui de nos conseillers du salarié et juristes.",
'mission_3_text' => 'Connaître les actualités des luttes en Haute-Ariège et bénéficier de vos droits à la formation syndicale (CFESES).',
'tpe_badge' => 'Salariés sans CSE · TPE / PME',
'tpe_text' => "Vous travaillez dans une petite entreprise (< 11 salariés), un commerce, l'artisanat ou sur un chantier sans représentant du personnel ? L'Union Locale CGT vous accueille et vous défend.",
'tpe_point_1' => "Confidentialité absolue : aucune démarche n'est portée à la connaissance de votre employeur sans votre accord explicite.",
'tpe_point_2' => "Syndicat Multipros : adhérez et organisez-vous collectivement même dans une très petite entreprise dépourvue de section syndicale.",
'tpe_point_3' => 'Conseillers du Salarié : accompagnement gratuit lors des entretiens préalables à un licenciement ou une rupture.',
'network_2_label' => 'Confédération CGT (cgt.fr)',
'network_3_label' => 'La NVO (nvo.fr)',
);
foreach ( $old_v1_defaults as $key => $old_val ) {
if ( isset( $saved[ $key ] ) && $saved[ $key ] === $old_val ) {
$saved[ $key ] = $defaults[ $key ];
}
}
// Remplace les anciens placeholders SVG du Réseau CGT par les 5 logos officiels (1.2.0).
for ( $i = 1; $i <= 5; $i++ ) {
$logo_key = 'network_' . $i . '_logo';
$cur_logo = (string) ( $saved[ $logo_key ] ?? '' );
if ( '' === $cur_logo || ( false !== strpos( $cur_logo, 'network-' ) && false !== strpos( $cur_logo, '.svg' ) ) ) {
$saved[ $logo_key ] = $defaults[ $logo_key ];
}
}
$saved = wp_parse_args( $saved, $defaults );
update_option( CGT_FHA_OPTION_KEY, $saved );
cgt_fha_get_options( true );
}
// Purge le cache confédéral pour forcer le nouvel extracteur sur la page d'accueil.
delete_transient( 'cgt_fha_confederal_feed' );
delete_transient( 'cgt_fha_confederal_feed_lock' );
delete_option( 'cgt_fha_confederal_feed_backup' );
update_option( 'cgt_fha_schema_version', CGT_FHA_SCHEMA_VERSION, true );
}
/**
* Vérifie si le bandeau d'alerte mobilisation doit être affiché.
*/
function cgt_fha_is_banner_active(): bool {
$opts = cgt_fha_get_options();
if ( empty( $opts['banner_enabled'] ) || empty( $opts['banner_text'] ) || empty( $opts['banner_expires'] ) ) {
return false;
}
$tz = wp_timezone();
$expire_dt = DateTimeImmutable::createFromFormat( 'Y-m-d\TH:i', (string) $opts['banner_expires'], $tz );
if ( ! $expire_dt ) {
return false;
}
$now_ts = (int) current_time( 'timestamp' );
return $now_ts < $expire_dt->getTimestamp();
}
/**
* Enregistrement du réglage et de la page d'administration.
*/
add_action( 'admin_menu', 'cgt_fha_register_admin_page' );
function cgt_fha_register_admin_page(): void {
add_theme_page(
'Réglages UL CGT Foix Haute-Ariège',
'Réglages UL CGT',
'manage_options',
'cgt-fha-settings',
'cgt_fha_render_admin_page'
);
}
add_action( 'admin_init', 'cgt_fha_register_settings' );
function cgt_fha_register_settings(): void {
register_setting(
'cgt_fha_settings_group',
CGT_FHA_OPTION_KEY,
array(
'type' => 'array',
'sanitize_callback' => 'cgt_fha_sanitize_options',
'default' => cgt_fha_get_defaults(),
)
);
}
/**
* Pré-remplit l'option en base lors de l'activation du thème (autoload = true, taille ~5 Ko).
*/
add_action( 'after_switch_theme', 'cgt_fha_seed_default_options' );
function cgt_fha_seed_default_options(): void {
if ( false === get_option( CGT_FHA_OPTION_KEY, false ) ) {
add_option( CGT_FHA_OPTION_KEY, cgt_fha_get_defaults(), '', 'yes' );
}
update_option( 'cgt_fha_schema_version', CGT_FHA_SCHEMA_VERSION, true );
}
/**
* Nettoyage et validation de toutes les options soumises dans l'admin.
*
* @param mixed $input Données brutes du formulaire.
* @return array<string, mixed>
*/
function cgt_fha_sanitize_options( $input ): array {
$input = is_array( $input ) ? $input : array();
$defaults = cgt_fha_get_defaults();
$existing = cgt_fha_get_options( true );
$clean = array();
$text_fields = array(
'phone',
'address',
'footer_call',
'banner_text',
'hero_title_line1',
'hero_title_line2',
'hero_btn1_label',
'hero_btn2_label',
'missions_title',
'mission_1_title',
'mission_2_title',
'mission_3_title',
'local_news_title',
'local_news_more',
'confederal_title',
'tpe_badge',
'tpe_title',
'tpe_btn_label',
'cfeses_eyebrow',
'cfeses_title',
'cfeses_btn_label',
'app_eyebrow',
'app_title',
'app_btn_label',
'network_title',
'network_1_label',
'network_1_btn',
'network_2_label',
'network_2_btn',
'network_3_label',
'network_3_btn',
'network_4_label',
'network_4_btn',
'network_5_label',
'network_5_btn',
);
foreach ( $text_fields as $field ) {
$val = isset( $input[ $field ] ) ? sanitize_text_field( wp_unslash( (string) $input[ $field ] ) ) : ( $existing[ $field ] ?? $defaults[ $field ] );
$clean[ $field ] = $val;
}
$textarea_fields = array(
'hours',
'footer_desc',
'hero_quote',
'missions_subtitle',
'mission_1_text',
'mission_2_text',
'mission_3_text',
'tpe_text',
'tpe_point_1',
'tpe_point_2',
'tpe_point_3',
'cfeses_text',
'app_text',
'network_1_desc',
'network_2_desc',
'network_3_desc',
'network_4_desc',
'network_5_desc',
);
foreach ( $textarea_fields as $field ) {
$val = isset( $input[ $field ] ) ? sanitize_textarea_field( wp_unslash( (string) $input[ $field ] ) ) : ( $existing[ $field ] ?? $defaults[ $field ] );
$clean[ $field ] = $val;
}
$clean['email'] = isset( $input['email'] )
? sanitize_email( wp_unslash( (string) $input['email'] ) )
: $defaults['email'];
$url_fields = array(
'facebook_url',
'instagram_url',
'youtube_url',
'header_logo_url',
'footer_logo_url',
'news_url',
'calendar_url',
'contact_url',
'join_url',
'legal_url',
'banner_url',
'hero_bg_url',
'hero_btn1_url',
'hero_btn2_url',
'tpe_btn_url',
'cfeses_btn_url',
'app_download_url',
'app_qr_url',
'network_1_logo',
'network_1_url',
'network_2_logo',
'network_2_url',
'network_3_logo',
'network_3_url',
'network_4_logo',
'network_4_url',
'network_5_logo',
'network_5_url',
);
foreach ( $url_fields as $field ) {
$raw = isset( $input[ $field ] ) ? trim( (string) wp_unslash( $input[ $field ] ) ) : ( $existing[ $field ] ?? $defaults[ $field ] );
$clean[ $field ] = '' === $raw ? '' : esc_url_raw( $raw );
}
$checkbox_fields = array(
'banner_enabled',
'tpe_enabled',
'cfeses_enabled',
'app_enabled',
'network_enabled',
'network_1_enabled',
'network_2_enabled',
'network_3_enabled',
'network_4_enabled',
'network_5_enabled',
);
foreach ( $checkbox_fields as $field ) {
$clean[ $field ] = ! empty( $input[ $field ] ) ? 1 : 0;
}
// Validation datetime-local (YYYY-MM-DDTHH:MM).
$raw_expires = isset( $input['banner_expires'] ) ? sanitize_text_field( wp_unslash( (string) $input['banner_expires'] ) ) : $defaults['banner_expires'];
$clean['banner_expires'] = preg_match( '/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/', $raw_expires ) ? $raw_expires : $defaults['banner_expires'];
// Validation des icônes de mission.
$valid_icons = array_keys( cgt_fha_get_mission_icon_choices() );
foreach ( array( 'mission_1_icon', 'mission_2_icon', 'mission_3_icon' ) as $icon_key ) {
$chosen = isset( $input[ $icon_key ] ) ? sanitize_key( (string) $input[ $icon_key ] ) : $defaults[ $icon_key ];
$clean[ $icon_key ] = in_array( $chosen, $valid_icons, true ) ? $chosen : $defaults[ $icon_key ];
}
return $clean;
}
/**
* Liste des icônes disponibles dans le sélecteur admin des 3 cartes de mission.
*
* @return array<string, string>
*/
function cgt_fha_get_mission_icon_choices(): array {
return array(
'fist' => 'Poing levé / Collectif',
'shield' => 'Bouclier / Défense des droits',
'chat' => 'Bulles d\'échange / Information & Formation',
'megaphone' => 'Mégaphone / Mobilisation',
'scale' => 'Balance / Prud\'hommes & Juridique',
'users' => 'Collectif salarié·e·s',
'book' => 'Livre / Formation CFESES',
);
}
/**
* Helper d'affichage d'un champ texte/URL/textarea dans l'admin.
*/
function cgt_fha_admin_field_row( string $key, string $label, string $type = 'text', string $desc = '' ): void {
$opts = cgt_fha_get_options();
$val = $opts[ $key ] ?? '';
$id = 'cgt_fha_' . $key;
$name = CGT_FHA_OPTION_KEY . '[' . $key . ']';
?>
<tr>
<th scope="row"><label for="<?php echo esc_attr( $id ); ?>"><?php echo esc_html( $label ); ?></label></th>
<td>
<?php if ( 'textarea' === $type ) : ?>
<textarea id="<?php echo esc_attr( $id ); ?>" name="<?php echo esc_attr( $name ); ?>" rows="3" class="large-text"><?php echo esc_textarea( (string) $val ); ?></textarea>
<?php elseif ( 'checkbox' === $type ) : ?>
<label>
<input type="checkbox" id="<?php echo esc_attr( $id ); ?>" name="<?php echo esc_attr( $name ); ?>" value="1" <?php checked( ! empty( $val ) ); ?> />
<span><?php echo esc_html( $desc ); ?></span>
</label>
<?php else : ?>
<input type="<?php echo esc_attr( $type ); ?>" id="<?php echo esc_attr( $id ); ?>" name="<?php echo esc_attr( $name ); ?>" value="<?php echo esc_attr( (string) $val ); ?>" class="<?php echo 'datetime-local' === $type ? 'regular-text' : 'large-text'; ?>" />
<?php endif; ?>
<?php if ( '' !== $desc && 'checkbox' !== $type ) : ?>
<p class="description"><?php echo esc_html( $desc ); ?></p>
<?php endif; ?>
</td>
</tr>
<?php
}
/**
* Helper d'affichage d'un sélecteur d'image via la Médiathèque WordPress.
*/
function cgt_fha_admin_media_row( string $key, string $label, string $default_url, string $desc = '', bool $dark_preview = false ): void {
$opts = cgt_fha_get_options();
$val = ! empty( $opts[ $key ] ) ? (string) $opts[ $key ] : $default_url;
$id = 'cgt_fha_' . $key;
$name = CGT_FHA_OPTION_KEY . '[' . $key . ']';
$preview_bg = $dark_preview ? '#1c1e21' : '#f8fafc';
?>
<tr>
<th scope="row"><label for="<?php echo esc_attr( $id ); ?>"><?php echo esc_html( $label ); ?></label></th>
<td>
<div style="display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin-bottom:10px;">
<input type="url" id="<?php echo esc_attr( $id ); ?>" name="<?php echo esc_attr( $name ); ?>" value="<?php echo esc_url( $val ); ?>" class="regular-text" />
<button type="button" class="button button-secondary" data-cgt-media-select="<?php echo esc_attr( $id ); ?>">Choisir dans la Médiathèque</button>
<button type="button" class="button" data-cgt-media-clear="<?php echo esc_attr( $id ); ?>" data-cgt-default-url="<?php echo esc_url( $default_url ); ?>">Rétablir par défaut</button>
</div>
<img id="<?php echo esc_attr( $id . '_preview' ); ?>" src="<?php echo esc_url( $val ); ?>" alt="" style="max-width:260px; max-height:110px; border:1px solid #cbd5e1; border-radius:6px; background:<?php echo esc_attr( $preview_bg ); ?>; padding:6px;" />
<?php if ( '' !== $desc ) : ?>
<p class="description"><?php echo esc_html( $desc ); ?></p>
<?php endif; ?>
</td>
</tr>
<?php
}
/**
* Rendu de la page d'administration Apparence > Réglages UL CGT.
*/
function cgt_fha_render_admin_page(): void {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$defaults = cgt_fha_get_defaults();
$opts = cgt_fha_get_options( true );
$active_tab = isset( $_GET['tab'] ) ? sanitize_key( (string) $_GET['tab'] ) : 'identity';
if ( ! in_array( $active_tab, array( 'identity', 'banner', 'homepage', 'confederal' ), true ) ) {
$active_tab = 'identity';
}
$feed_status = class_exists( 'CGT_FHA_Confederal_Feed' ) ? CGT_FHA_Confederal_Feed::get_cache_status() : array();
?>
<div class="wrap cgt-admin-wrap">
<h1 style="display:flex; align-items:center; gap:10px;">
<span style="display:inline-block; width:14px; height:14px; background:#d20012; border-radius:3px;"></span>
Réglages de l'Union Locale CGT Foix Haute-Ariège
</h1>
<p>Tous les textes, images, icônes, coordonnées et liens du thème sont modifiables ici sans toucher au code.</p>
<?php if ( isset( $_GET['cgt_feed_refreshed'] ) ) : ?>
<div class="notice notice-success is-dismissible">
<p><strong>Actualités confédérales (`cgt.fr`) synchronisées avec succès.</strong></p>
</div>
<?php endif; ?>
<?php settings_errors(); ?>
<nav class="nav-tab-wrapper" role="tablist" aria-label="Onglets de réglages UL CGT">
<a href="#identity" class="nav-tab <?php echo 'identity' === $active_tab ? 'nav-tab-active' : ''; ?>" data-cgt-tab="identity" role="tab" aria-selected="<?php echo 'identity' === $active_tab ? 'true' : 'false'; ?>">1. Identité &amp; Coordonnées</a>
<a href="#banner" class="nav-tab <?php echo 'banner' === $active_tab ? 'nav-tab-active' : ''; ?>" data-cgt-tab="banner" role="tab" aria-selected="<?php echo 'banner' === $active_tab ? 'true' : 'false'; ?>">2. Bandeau Mobilisation</a>
<a href="#homepage" class="nav-tab <?php echo 'homepage' === $active_tab ? 'nav-tab-active' : ''; ?>" data-cgt-tab="homepage" role="tab" aria-selected="<?php echo 'homepage' === $active_tab ? 'true' : 'false'; ?>">3. Page d'accueil &amp; Blocs</a>
<a href="#confederal" class="nav-tab <?php echo 'confederal' === $active_tab ? 'nav-tab-active' : ''; ?>" data-cgt-tab="confederal" role="tab" aria-selected="<?php echo 'confederal' === $active_tab ? 'true' : 'false'; ?>">4. Flux Confédéral (cgt.fr)</a>
</nav>
<form method="post" action="options.php" style="margin-top:20px;">
<?php settings_fields( 'cgt_fha_settings_group' ); ?>
<input type="hidden" name="cgt_fha_active_tab" value="<?php echo esc_attr( $active_tab ); ?>" />
<!-- ONGLET 1 : IDENTITÉ & COORDONNÉES -->
<div data-cgt-panel="identity" <?php echo 'identity' !== $active_tab ? 'hidden' : ''; ?>>
<h2>Coordonnées &amp; Identité visuelle</h2>
<table class="form-table" role="presentation">
<?php
cgt_fha_admin_media_row( 'header_logo_url', 'Logo En-tête', $defaults['header_logo_url'], 'Par défaut : bannière officielle Union Locale CGT Foix Haute-Ariège (assets/img/banniere-ul-noir.png).' );
cgt_fha_admin_media_row( 'footer_logo_url', 'Logo Pied de page (version blanche)', $defaults['footer_logo_url'], 'Affiché sur le fond sombre du pied de page (assets/img/banniere-ul-blanc.png par défaut).', true );
cgt_fha_admin_field_row( 'phone', 'Téléphone', 'text', 'Affiché dans la barre supérieure et le pied de page.' );
cgt_fha_admin_field_row( 'email', 'Adresse e-mail', 'email' );
cgt_fha_admin_field_row( 'address', 'Adresse des locaux', 'text' );
cgt_fha_admin_field_row( 'hours', 'Horaires des permanences', 'textarea' );
cgt_fha_admin_field_row( 'facebook_url', 'URL Page Facebook', 'url' );
cgt_fha_admin_field_row( 'instagram_url', 'URL Instagram (optionnel)', 'url' );
cgt_fha_admin_field_row( 'youtube_url', 'URL YouTube (optionnel)', 'url' );
cgt_fha_admin_field_row( 'footer_desc', 'Présentation pied de page', 'textarea' );
cgt_fha_admin_field_row( 'footer_call', 'Appel militant pied de page', 'text' );
?>
</table>
<h2>Pages clés de l'Union Locale</h2>
<table class="form-table" role="presentation">
<?php
cgt_fha_admin_field_row( 'news_url', 'URL page Actualités', 'url' );
cgt_fha_admin_field_row( 'calendar_url', 'URL page Calendrier', 'url' );
cgt_fha_admin_field_row( 'contact_url', "URL page Besoin d'aide / Contact", 'url' );
cgt_fha_admin_field_row( 'join_url', 'URL page Syndiquez-vous', 'url' );
cgt_fha_admin_field_row( 'legal_url', 'URL Mentions légales & Confidentialité', 'url' );
?>
</table>
<?php submit_button( 'Enregistrer les réglages' ); ?>
</div>
<!-- ONGLET 2 : BANDEAU MOBILISATION -->
<div data-cgt-panel="banner" <?php echo 'banner' !== $active_tab ? 'hidden' : ''; ?>>
<h2>Bandeau d'Alerte Mobilisation Auto-Expirant</h2>
<p class="description">
Le bandeau rouge CGT s'affiche uniquement si la case <strong>Activer le bandeau</strong> est cochée <strong>ET</strong> que l'heure actuelle du site
(<code><?php echo esc_html( current_time( 'd/m/Y H:i' ) ); ?></code>) est antérieure à la date d'expiration.
</p>
<table class="form-table" role="presentation">
<?php
cgt_fha_admin_field_row( 'banner_enabled', 'Activer le bandeau', 'checkbox', 'Afficher le bandeau rouge de mobilisation sous la barre supérieure.' );
cgt_fha_admin_field_row( 'banner_text', 'Mot d\'ordre & lieu', 'text', 'Exemple : MOBILISATION : Grève et manifestation à Foix - Allées de Villote' );
cgt_fha_admin_field_row( 'banner_url', 'Lien URL au clic (optionnel)', 'url', 'Laissez vide si le bandeau ne doit pas être cliquable.' );
cgt_fha_admin_field_row( 'banner_expires', 'Date et heure d\'expiration automatique', 'datetime-local', 'Passé cet horaire, le bandeau disparaît automatiquement.' );
?>
</table>
<?php submit_button( 'Enregistrer les réglages' ); ?>
</div>
<!-- ONGLET 3 : PAGE D'ACCUEIL -->
<div data-cgt-panel="homepage" <?php echo 'homepage' !== $active_tab ? 'hidden' : ''; ?>>
<h2>Section 1 — Bannière Hero Plein Écran</h2>
<table class="form-table" role="presentation">
<?php
cgt_fha_admin_media_row( 'hero_bg_url', 'Image panoramique de fond', $defaults['hero_bg_url'], 'Image sombre de montagne/Ariège recommandée (1600×720 px).' );
cgt_fha_admin_field_row( 'hero_title_line1', 'Titre H1 — Ligne 1', 'text' );
cgt_fha_admin_field_row( 'hero_title_line2', 'Titre H1 — Ligne 2', 'text' );
cgt_fha_admin_field_row( 'hero_quote', 'Citation sous le titre', 'textarea' );
cgt_fha_admin_field_row( 'hero_btn1_label', 'Bouton gauche — Libellé', 'text' );
cgt_fha_admin_field_row( 'hero_btn1_url', 'Bouton gauche — Lien URL', 'url' );
cgt_fha_admin_field_row( 'hero_btn2_label', 'Bouton droit — Libellé', 'text' );
cgt_fha_admin_field_row( 'hero_btn2_url', 'Bouton droit — Lien URL', 'url' );
?>
</table>
<hr />
<h2>Section 2 — « À QUOI NOUS SERVONS ? » (3 Cartes)</h2>
<table class="form-table" role="presentation">
<?php
cgt_fha_admin_field_row( 'missions_title', 'Titre de la section', 'text' );
cgt_fha_admin_field_row( 'missions_subtitle', 'Chapeau de présentation (Union des syndicats & Multipros)', 'textarea' );
$icon_choices = cgt_fha_get_mission_icon_choices();
for ( $i = 1; $i <= 3; $i++ ) :
$icon_key = 'mission_' . $i . '_icon';
$title_key = 'mission_' . $i . '_title';
$text_key = 'mission_' . $i . '_text';
?>
<tr>
<th scope="row"><label for="<?php echo esc_attr( 'cgt_fha_' . $icon_key ); ?>">Carte <?php echo (int) $i; ?> — Icône SVG</label></th>
<td>
<select id="<?php echo esc_attr( 'cgt_fha_' . $icon_key ); ?>" name="<?php echo esc_attr( CGT_FHA_OPTION_KEY . '[' . $icon_key . ']' ); ?>">
<?php foreach ( $icon_choices as $slug => $label ) : ?>
<option value="<?php echo esc_attr( $slug ); ?>" <?php selected( $opts[ $icon_key ], $slug ); ?>><?php echo esc_html( $label ); ?></option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php
cgt_fha_admin_field_row( $title_key, 'Carte ' . $i . ' — Titre', 'text' );
cgt_fha_admin_field_row( $text_key, 'Carte ' . $i . ' — Description', 'textarea' );
endfor;
?>
</table>
<hr />
<h2>Sections 3 &amp; 4 — Titres Actualités</h2>
<table class="form-table" role="presentation">
<?php
cgt_fha_admin_field_row( 'local_news_title', 'Titre Actualités locales', 'text' );
cgt_fha_admin_field_row( 'local_news_more', 'Libellé lien « Voir toutes... »', 'text' );
cgt_fha_admin_field_row( 'confederal_title', 'Titre Actualité confédérale', 'text' );
?>
</table>
<hr />
<h2>Section 5 — Salariés isolés &amp; TPE (Syndicat Multipros)</h2>
<table class="form-table" role="presentation">
<?php
cgt_fha_admin_field_row( 'tpe_enabled', 'Afficher ce bloc', 'checkbox', 'Afficher la section Salariés isolés & TPE sur la page d\'accueil.' );
cgt_fha_admin_field_row( 'tpe_badge', 'Surtitre / Badge', 'text' );
cgt_fha_admin_field_row( 'tpe_title', 'Titre du bloc', 'text' );
cgt_fha_admin_field_row( 'tpe_text', 'Paragraphe explicatif', 'textarea' );
cgt_fha_admin_field_row( 'tpe_point_1', 'Point clé 1 (Rattachement Multipros)', 'textarea' );
cgt_fha_admin_field_row( 'tpe_point_2', 'Point clé 2 (Confidentialité)', 'textarea' );
cgt_fha_admin_field_row( 'tpe_point_3', 'Point clé 3 (Conseillers du Salarié)', 'textarea' );
cgt_fha_admin_field_row( 'tpe_btn_label', 'Libellé du bouton', 'text' );
cgt_fha_admin_field_row( 'tpe_btn_url', 'Lien URL du bouton', 'url' );
?>
</table>
<hr />
<h2>Section 6 — Formation Syndicale (CFESES) &amp; Application Mobile</h2>
<table class="form-table" role="presentation">
<?php
cgt_fha_admin_field_row( 'cfeses_enabled', 'Afficher le bloc CFESES', 'checkbox', 'Afficher la colonne Formation Syndicale (CFESES).' );
cgt_fha_admin_field_row( 'cfeses_eyebrow', 'CFESES — Surtitre', 'text' );
cgt_fha_admin_field_row( 'cfeses_title', 'CFESES — Titre', 'text' );
cgt_fha_admin_field_row( 'cfeses_text', 'CFESES — Texte explicatif', 'textarea' );
cgt_fha_admin_field_row( 'cfeses_btn_label', 'CFESES — Libellé bouton', 'text' );
cgt_fha_admin_field_row( 'cfeses_btn_url', 'CFESES — Lien URL', 'url' );
cgt_fha_admin_field_row(
'app_enabled',
'Afficher le bloc Appli Mobile',
'checkbox',
'Désactivé par défaut tant que le contenu / fichier de téléchargement n\'est pas prêt. Cochez pour afficher ce bloc sur la page d\'accueil.'
);
cgt_fha_admin_field_row( 'app_eyebrow', 'Appli — Surtitre', 'text' );
cgt_fha_admin_field_row( 'app_title', 'Appli — Titre', 'text' );
cgt_fha_admin_field_row( 'app_text', 'Appli — Présentation', 'textarea' );
cgt_fha_admin_field_row( 'app_btn_label', 'Appli — Libellé bouton téléchargement', 'text' );
cgt_fha_admin_field_row( 'app_download_url', 'Appli — Lien direct (.apk / Play Store)', 'url' );
cgt_fha_admin_media_row( 'app_qr_url', 'Appli — Image QR Code', $defaults['app_qr_url'], 'Téléversez le QR Code pointant vers votre fichier .apk ou fiche Store.' );
?>
</table>
<hr />
<h2>Section 7 — Réseau Syndical CGT (Cartes avec logo, description et bouton)</h2>
<table class="form-table" role="presentation">
<?php
cgt_fha_admin_field_row( 'network_enabled', 'Afficher la section Réseau CGT', 'checkbox', 'Afficher la grille de cartes du réseau syndical CGT en bas de page d\'accueil.' );
cgt_fha_admin_field_row( 'network_title', 'Titre de la section', 'text' );
for ( $i = 1; $i <= 5; $i++ ) {
cgt_fha_admin_field_row( 'network_' . $i . '_enabled', 'Carte ' . $i . ' — Afficher', 'checkbox', 'Afficher cette carte dans le Réseau Syndical CGT.' );
cgt_fha_admin_media_row( 'network_' . $i . '_logo', 'Carte ' . $i . ' — Logo', $defaults[ 'network_' . $i . '_logo' ] );
cgt_fha_admin_field_row( 'network_' . $i . '_label', 'Carte ' . $i . ' — Titre', 'text' );
cgt_fha_admin_field_row( 'network_' . $i . '_desc', 'Carte ' . $i . ' — Description courte', 'textarea' );
cgt_fha_admin_field_row( 'network_' . $i . '_btn', 'Carte ' . $i . ' — Libellé bouton', 'text' );
cgt_fha_admin_field_row( 'network_' . $i . '_url', 'Carte ' . $i . ' — URL du site', 'url' );
}
?>
</table>
<?php submit_button( 'Enregistrer les réglages' ); ?>
</div>
</form>
<!-- ONGLET 4 : FLUX CONFÉDÉRAL (hors formulaire options.php pour le bouton POST dédié) -->
<div data-cgt-panel="confederal" <?php echo 'confederal' !== $active_tab ? 'hidden' : ''; ?> style="margin-top:20px;">
<h2>État du flux automatique « Actualité Confédérale » (`cgt.fr`)</h2>
<div class="card" style="max-width:760px; padding:16px 20px;">
<p>
<strong>Statut du cache :</strong>
<?php echo ! empty( $feed_status['has_transient'] ) ? '<span style="color:#0a7d2b;font-weight:700;">Actif (Transient valide)</span>' : '<span style="color:#b45309;font-weight:700;">Expiré ou en attente de synchronisation</span>'; ?>
</p>
<p>
<strong>Dernière synchronisation :</strong>
<?php echo ! empty( $feed_status['fetched_at'] ) ? esc_html( wp_date( 'd/m/Y à H:i:s', (int) $feed_status['fetched_at'] ) ) : 'Pas encore effectuée'; ?>
</p>
<p>
<strong>Source utilisée :</strong>
<?php echo esc_html( (string) ( $feed_status['source'] ?? 'Non définie' ) ); ?>
</p>
<?php if ( ! empty( $feed_status['featured']['title'] ) ) : ?>
<div style="margin:14px 0; padding:12px 14px; background:#f8fafc; border:1px solid #cbd5e1; border-radius:8px;">
<p style="margin:0 0 4px;"><strong>Article « À la une » en cache :</strong></p>
<p style="margin:0 0 4px; font-size:15px;"><strong><?php echo esc_html( $feed_status['featured']['title'] ); ?></strong></p>
<p style="margin:0; color:#4a5568;"><?php echo esc_html( $feed_status['featured']['summary'] ?? '' ); ?></p>
</div>
<?php endif; ?>
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
<input type="hidden" name="action" value="cgt_fha_refresh_feed" />
<?php wp_nonce_field( 'cgt_fha_refresh_feed_action', 'cgt_fha_refresh_feed_nonce' ); ?>
<button type="submit" class="button button-primary">Actualiser les actus confédérales maintenant</button>
</form>
</div>
</div>
</div>
<?php
}

65
index.php Normal file
View File

@ -0,0 +1,65 @@
<?php
/**
* Gabarit de secours général (recherche et boucle générique WordPress).
*
* @package CGT_FHA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
get_header();
$heading = is_search()
? sprintf( 'Résultats de recherche pour « %s »', get_search_query() )
: ( get_bloginfo( 'name' ) ?: 'Union Locale CGT Foix Haute-Ariège' );
?>
<section class="cgt-page-hero">
<div class="cgt-container">
<nav class="cgt-breadcrumb" aria-label="<?php esc_attr_e( 'Fil d\'Ariane', 'cgt-fha' ); ?>">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php esc_html_e( 'Accueil', 'cgt-fha' ); ?></a>
<span aria-hidden="true">/</span>
<span><?php echo esc_html( $heading ); ?></span>
</nav>
<h1 class="cgt-page-hero__title"><?php echo esc_html( $heading ); ?></h1>
</div>
</section>
<section class="cgt-section cgt-section--white">
<div class="cgt-container">
<?php if ( have_posts() ) : ?>
<div class="cgt-news-grid">
<?php
while ( have_posts() ) :
the_post();
cgt_fha_render_local_post_card();
endwhile;
?>
</div>
<div class="cgt-pagination">
<?php
the_posts_pagination(
array(
'mid_size' => 2,
'prev_text' => '← Précédent',
'next_text' => 'Suivant →',
)
);
?>
</div>
<?php else : ?>
<p><?php esc_html_e( 'Aucun résultat ne correspond à votre recherche.', 'cgt-fha' ); ?></p>
<form role="search" method="get" class="cgt-search-form" action="<?php echo esc_url( home_url( '/' ) ); ?>" style="margin-left:0;">
<label for="cgt-index-search" class="screen-reader-text"><?php esc_html_e( 'Rechercher sur le site', 'cgt-fha' ); ?></label>
<input type="search" id="cgt-index-search" name="s" value="<?php echo esc_attr( get_search_query() ); ?>" placeholder="<?php esc_attr_e( 'Nouvelle recherche…', 'cgt-fha' ); ?>" />
<button type="submit" class="cgt-btn cgt-btn--primary"><?php esc_html_e( 'Rechercher', 'cgt-fha' ); ?></button>
</form>
<?php endif; ?>
</div>
</section>
<?php
get_footer();

61
page.php Normal file
View File

@ -0,0 +1,61 @@
<?php
/**
* Gabarit de page standard (page.php) : Contact, Calendrier, Syndiquez-vous, Mentions légales...
* Compatible avec les shortcodes et hooks des extensions sœurs cgt-wp-calendar et cgt-wp-forms.
*
* @package CGT_FHA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
get_header();
?>
<?php
while ( have_posts() ) :
the_post();
?>
<section class="cgt-page-hero">
<div class="cgt-container--narrow">
<nav class="cgt-breadcrumb" aria-label="<?php esc_attr_e( 'Fil d\'Ariane', 'cgt-fha' ); ?>">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php esc_html_e( 'Accueil', 'cgt-fha' ); ?></a>
<span aria-hidden="true">/</span>
<span><?php the_title(); ?></span>
</nav>
<h1 class="cgt-page-hero__title"><?php the_title(); ?></h1>
</div>
</section>
<article id="post-<?php the_ID(); ?>" <?php post_class( 'cgt-article-wrap' ); ?>>
<div class="cgt-container--narrow">
<?php if ( has_post_thumbnail() ) : ?>
<div class="cgt-article__featured">
<?php the_post_thumbnail( 'cgt-featured', array( 'fetchpriority' => 'high' ) ); ?>
</div>
<?php endif; ?>
<div class="entry-content">
<?php
the_content();
wp_link_pages(
array(
'before' => '<div class="page-links">' . esc_html__( 'Pages :', 'cgt-fha' ),
'after' => '</div>',
)
);
?>
</div>
<?php
// Emplacement propre pour accueillir cgt-wp-calendar ou cgt-wp-forms selon le slug de page.
do_action( 'cgt_fha_after_page_content', get_post_field( 'post_name', get_the_ID() ) );
?>
</div>
</article>
<?php endwhile; ?>
<?php
get_footer();

131
single.php Normal file
View File

@ -0,0 +1,131 @@
<?php
/**
* Gabarit d'article local (single.php) : catégorie, date, contenu, partage social sans traceur et navigation.
*
* @package CGT_FHA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
get_header();
?>
<?php
while ( have_posts() ) :
the_post();
$cats = get_the_category();
$cat_obj = ! empty( $cats ) ? $cats[0] : null;
$share_url = get_permalink();
$share_txt = get_the_title();
?>
<section class="cgt-page-hero">
<div class="cgt-container--narrow">
<nav class="cgt-breadcrumb" aria-label="<?php esc_attr_e( 'Fil d\'Ariane', 'cgt-fha' ); ?>">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php esc_html_e( 'Accueil', 'cgt-fha' ); ?></a>
<span aria-hidden="true">/</span>
<a href="<?php echo esc_url( cgt_fha_get_local_news_archive_url() ); ?>"><?php esc_html_e( 'Actualités', 'cgt-fha' ); ?></a>
<?php if ( $cat_obj ) : ?>
<span aria-hidden="true">/</span>
<a href="<?php echo esc_url( get_category_link( $cat_obj->term_id ) ); ?>"><?php echo esc_html( $cat_obj->name ); ?></a>
<?php endif; ?>
</nav>
<h1 class="cgt-page-hero__title"><?php the_title(); ?></h1>
</div>
</section>
<article id="post-<?php the_ID(); ?>" <?php post_class( 'cgt-article-wrap' ); ?>>
<div class="cgt-container--narrow">
<header class="cgt-article__header">
<div class="cgt-article__meta">
<?php if ( $cat_obj ) : ?>
<a href="<?php echo esc_url( get_category_link( $cat_obj->term_id ) ); ?>" class="cgt-pill-cat">
<?php echo esc_html( $cat_obj->name ); ?>
</a>
<?php endif; ?>
<time datetime="<?php echo esc_attr( get_the_date( 'c' ) ); ?>">
<?php echo esc_html( get_the_date( 'j F Y' ) ); ?>
</time>
<span aria-hidden="true">•</span>
<span><?php esc_html_e( 'Union Locale CGT Foix Haute-Ariège', 'cgt-fha' ); ?></span>
</div>
</header>
<?php if ( has_post_thumbnail() ) : ?>
<div class="cgt-article__featured">
<?php the_post_thumbnail( 'cgt-featured', array( 'fetchpriority' => 'high' ) ); ?>
</div>
<?php endif; ?>
<div class="entry-content">
<?php
the_content();
wp_link_pages(
array(
'before' => '<div class="page-links">' . esc_html__( 'Pages :', 'cgt-fha' ),
'after' => '</div>',
)
);
?>
</div>
<!-- Partage social souverain (liens directs sans script traceur) -->
<aside class="cgt-share-box" aria-label="<?php esc_attr_e( 'Partager cet article', 'cgt-fha' ); ?>">
<span class="cgt-share-box__label"><?php esc_html_e( 'Partager cette information :', 'cgt-fha' ); ?></span>
<div class="cgt-share-box__actions">
<a
href="<?php echo esc_url( 'https://www.facebook.com/sharer/sharer.php?u=' . rawurlencode( $share_url ) ); ?>"
class="cgt-share-btn"
target="_blank"
rel="noopener noreferrer"
>Facebook</a>
<a
href="<?php echo esc_url( 'https://wa.me/?text=' . rawurlencode( $share_txt . ' — ' . $share_url ) ); ?>"
class="cgt-share-btn"
target="_blank"
rel="noopener noreferrer"
>WhatsApp</a>
<a
href="<?php echo esc_url( 'mailto:?subject=' . rawurlencode( $share_txt ) . '&body=' . rawurlencode( $share_url ) ); ?>"
class="cgt-share-btn"
>E-mail</a>
<button type="button" class="cgt-share-btn" data-cgt-copy-url="<?php echo esc_url( $share_url ); ?>">
<?php esc_html_e( 'Copier le lien', 'cgt-fha' ); ?>
</button>
</div>
</aside>
<?php
$prev_post = get_previous_post();
$next_post = get_next_post();
if ( $prev_post || $next_post ) :
?>
<nav class="cgt-post-nav" aria-label="<?php esc_attr_e( 'Navigation entre articles', 'cgt-fha' ); ?>">
<div>
<?php if ( $prev_post ) : ?>
<a href="<?php echo esc_url( get_permalink( $prev_post ) ); ?>" class="cgt-post-nav__item">
<span class="cgt-post-nav__dir">← <?php esc_html_e( 'Article précédent', 'cgt-fha' ); ?></span>
<strong><?php echo esc_html( get_the_title( $prev_post ) ); ?></strong>
</a>
<?php endif; ?>
</div>
<div>
<?php if ( $next_post ) : ?>
<a href="<?php echo esc_url( get_permalink( $next_post ) ); ?>" class="cgt-post-nav__item" style="text-align:right;">
<span class="cgt-post-nav__dir"><?php esc_html_e( 'Article suivant', 'cgt-fha' ); ?> →</span>
<strong><?php echo esc_html( get_the_title( $next_post ) ); ?></strong>
</a>
<?php endif; ?>
</div>
</nav>
<?php endif; ?>
<?php do_action( 'cgt_fha_after_single_post', get_the_ID() ); ?>
</div>
</article>
<?php endwhile; ?>
<?php
get_footer();

1541
style.css Normal file

File diff suppressed because it is too large Load Diff

158
theme.json Normal file
View File

@ -0,0 +1,158 @@
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"appearanceTools": false,
"color": {
"custom": false,
"customGradient": false,
"defaultPalette": false,
"defaultGradients": false,
"palette": [
{
"name": "Rouge CGT",
"slug": "cgt-red",
"color": "#d20012"
},
{
"name": "Rouge CGT Foncé",
"slug": "cgt-red-dark",
"color": "#a8000e"
},
{
"name": "Fond Principal",
"slug": "bg-main",
"color": "#ffffff"
},
{
"name": "Fond Doux",
"slug": "bg-soft",
"color": "#f1f3f5"
},
{
"name": "Sombre Topbar & Footer",
"slug": "bg-topbar",
"color": "#1c1e21"
},
{
"name": "Texte Principal",
"slug": "text-main",
"color": "#1a1a1a"
},
{
"name": "Texte Secondaire",
"slug": "text-muted",
"color": "#4a5568"
},
{
"name": "Bordure Carte",
"slug": "border-card",
"color": "#cbd5e1"
}
]
},
"typography": {
"customFontSize": true,
"defaultFontSizes": false,
"fontFamilies": [
{
"name": "Système Moderne",
"slug": "system-sans",
"fontFamily": "system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif"
}
],
"fontSizes": [
{
"name": "Petit",
"slug": "small",
"size": "0.875rem"
},
{
"name": "Normal",
"slug": "medium",
"size": "1rem"
},
{
"name": "Grand",
"slug": "large",
"size": "1.25rem"
},
{
"name": "Très grand",
"slug": "xlarge",
"size": "1.75rem"
},
{
"name": "Titre Principal",
"slug": "xxlarge",
"size": "2.5rem"
}
]
},
"border": {
"radiusSizes": [
{
"name": "Bouton",
"slug": "button",
"size": "8px"
},
{
"name": "Carte",
"slug": "card",
"size": "12px"
},
{
"name": "Encart",
"slug": "panel",
"size": "14px"
},
{
"name": "Pilule",
"slug": "pill",
"size": "999px"
}
]
},
"layout": {
"contentSize": "820px",
"wideSize": "1160px"
}
},
"styles": {
"color": {
"background": "var(--wp--preset--color--bg-main)",
"text": "var(--wp--preset--color--text-main)"
},
"typography": {
"fontFamily": "var(--wp--preset--font-family--system-sans)",
"fontSize": "var(--wp--preset--font-size--medium)",
"lineHeight": "1.65"
},
"elements": {
"link": {
"color": {
"text": "var(--wp--preset--color--cgt-red)"
},
":hover": {
"color": {
"text": "var(--wp--preset--color--cgt-red-dark)"
}
}
},
"button": {
"color": {
"background": "var(--wp--preset--color--cgt-red)",
"text": "#ffffff"
},
"border": {
"radius": "8px"
},
":hover": {
"color": {
"background": "var(--wp--preset--color--cgt-red-dark)"
}
}
}
}
}
}