Refactoring : sécurité (XSS), découpage en modules inc/* et js/admin/*, IDs résolus par slug, perf (caches, cron Gravatar, assets auto-hébergés), tests

This commit is contained in:
2026-06-10 21:30:25 +02:00
parent e6b73df516
commit 9280c3b9ce
44 changed files with 3209 additions and 2907 deletions

100
tests/run-tests.php Normal file
View File

@@ -0,0 +1,100 @@
<?php
/**
* Tests du thème THALIM — fonctions pures à fort enjeu.
*
* Exécution (environnement Docker de dev) :
* docker exec wordpress php /var/www/html/wp-content/themes/thalim/tests/run-tests.php
*
* Pas de PHPUnit (pas de pipeline) : assertions maison, sortie lisible,
* code retour ≠ 0 en cas d'échec. Charge WordPress (wp-load) car les
* fonctions testées vivent dans functions.php/inc/*.
*/
if (PHP_SAPI !== 'cli') {
exit("CLI only\n");
}
$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_HOST'] ?? 'localhost';
$_SERVER['REQUEST_URI'] = $_SERVER['REQUEST_URI'] ?? '/';
require dirname(__DIR__, 4) . '/wp-load.php';
$failures = 0;
$count = 0;
function check(string $name, $actual, $expected): void {
global $failures, $count;
$count++;
if ($actual === $expected) {
echo " ok $name\n";
} else {
$failures++;
echo " FAIL $name\n attendu: " . var_export($expected, true)
. "\n obtenu : " . var_export($actual, true) . "\n";
}
}
echo "== thalim_bilingual ==\n";
check('FR par défaut', thalim_bilingual('Bonjour // Hello'), 'Bonjour');
check('EN explicite', thalim_bilingual('Bonjour // Hello', 'en'), 'Hello');
check('FR explicite', thalim_bilingual('Bonjour // Hello', 'fr'), 'Bonjour');
check('sans séparateur', thalim_bilingual('Bonjour', 'en'), 'Bonjour');
check('EN vide → FR', thalim_bilingual('Bonjour // ', 'en'), 'Bonjour');
check('espaces normalisés', thalim_bilingual(' Bonjour // Hello ', 'en'), 'Hello');
check('chaîne vide', thalim_bilingual('', 'en'), '');
check('séparateur multiple', thalim_bilingual('A // B // C', 'en'), 'B // C');
echo "== thalim_en_url ==\n";
$GLOBALS['thalim_lang_override'] = 'fr';
check('no-op en FR', thalim_en_url(home_url('/membres/')), home_url('/membres/'));
$GLOBALS['thalim_lang_override'] = 'en';
$home = rtrim(home_url(), '/');
check('préfixe /en', thalim_en_url($home . '/membres/'), $home . '/en/membres/');
check('idempotente', thalim_en_url($home . '/en/membres/'), $home . '/en/membres/');
unset($GLOBALS['thalim_lang_override']);
echo "== thalim_cat_name ==\n";
$articles = get_term_by('slug', 'articles', 'category');
check('FR = nom natif', thalim_cat_name($articles, 'fr'), $articles->name);
$en_meta = get_term_meta($articles->term_id, 'titre_anglais', true);
check('EN = titre_anglais ou fallback', thalim_cat_name($articles, 'en'), $en_meta ?: $articles->name);
check('valeur non-term', thalim_cat_name('Texte brut'), 'Texte brut');
echo "== thalim_format_date ==\n";
check('date vide', thalim_format_date(''), '');
check('0000-00-00', thalim_format_date('0000-00-00 00:00:00'), '');
check('format Y', thalim_format_date('2026-03-15 00:00:00', 'fr', 'Y'), '2026');
check('format Y-m-d', thalim_format_date('2026-03-15 10:30:00', 'fr', 'Y-m-d'), '2026-03-15');
echo "== config (résolution par slug) ==\n";
check('cat seance', thalim_cat_id('seance'), 12);
check('cat non-classe', thalim_cat_id('non-classe'), 31);
check('cat vie-du-labo', thalim_cat_id('vie-du-labo'), 9);
check('cat publications', thalim_cat_id('publications'), 4);
check('cat message-labo', thalim_cat_id('message-labo'), 268);
check('clé inconnue', thalim_cat_id('nexiste-pas'), 0);
check('slug inexistant', thalim_term_id_by_slug('slug-bidon-xyz'), 0);
check('rôles exclus', thalim_excluded_role_ids(), [600, 598]);
echo "== thalim_get_active_pinned_ids ==\n";
check('catégorie 0 → []', thalim_get_active_pinned_ids(0), []);
echo "== thalim_get_seance_parent_id ==\n";
global $wpdb;
$seance_id = (int) $wpdb->get_var(
"SELECT tr.object_id FROM {$wpdb->term_relationships} tr
JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
JOIN {$wpdb->posts} p ON p.ID = tr.object_id
WHERE tt.term_id = 12 AND p.post_status = 'publish' LIMIT 1"
);
if ($seance_id) {
$parent = thalim_get_seance_parent_id($seance_id);
check('séance a un parent publié', $parent > 0, true);
check('lien = parent + ancre', thalim_get_seance_link($seance_id), get_permalink($parent) . '#seance-' . $seance_id);
} else {
echo " skip aucune séance publiée en base\n";
}
check('séance inexistante → 0', thalim_get_seance_parent_id(999999999), 0);
echo "\n$count tests, $failures échec(s)\n";
exit($failures ? 1 : 0);