). * Auto : voir yb2026_season_auto() (dates en heure de Paris). * Aperçu sans rien enregistrer : ?saison= | aucune * Le visiteur peut couper le décor (bouton dans la barre, mémorisé : localStorage yb-season=off). */ function yb2026_seasons() { $ico = array( 'pumpkin' => '', 'flake' => '', 'burst' => '', 'clover' => '', 'egg' => '', 'fish' => '', 'note' => '', 'cake' => '', 'crescent' => '', 'torii' => '', 'prompt' => '', 'tag' => '', ); $s = array( 'nouvel-an' => array('Nouvel An', 'burst', 'du 28 décembre au 6 janvier'), 'st-patrick' => array('Saint-Patrick', 'clover', 'du 14 au 17 mars'), 'anniversaire'=> array('Anniversaire', 'cake', 'le 14 mai'), 'algerie' => array('Indépendance de l\'Algérie', 'crescent', 'du 2 au 8 juillet'), 'japon' => array('Japon', 'torii', 'du 20 mars au 10 avril (hanami)'), 'hack' => array('Hack', 'prompt', 'le 30 novembre (journée de la sécurité informatique)'), 'paques' => array('Pâques', 'egg', 'du jeudi au lundi de Pâques'), 'poisson' => array('Poisson d\'avril', 'fish', 'le 1er avril'), 'musique' => array('Fête de la musique', 'note', 'du 19 au 21 juin'), 'juillet' => array('14 juillet', 'burst', 'du 12 au 14 juillet'), 'halloween' => array('Halloween', 'pumpkin', 'du 1er octobre au 2 novembre'), 'black-friday'=> array('Black Friday', 'tag', 'du Black Friday au Cyber Monday'), 'noel' => array('Noël', 'flake', 'du 1er au 27 décembre'), ); $out = array(); foreach ($s as $k => $v) $out[$k] = array( 'label' => $v[0], 'when' => $v[2], 'off' => 'Couper le décor ' . $v[0], 'on' => 'Remettre le décor ' . $v[0], 'icon' => '', ); return $out; } /* Saison selon la date (heure de Paris). $ts : horodatage à tester (défaut : maintenant) */ function yb2026_season_auto($ts = null) { $ts = $ts ?? time(); $y = (int) wp_date('Y', $ts); $md = (int) wp_date('nd', $ts); // ex. 1031 = 31 octobre, 106 = 6 janvier $day = function ($m, $d, $yy) { return (int) wp_date('Ymd', mktime(12, 0, 0, $m, $d, $yy)); }; $today = (int) wp_date('Ymd', $ts); /* Pâques (calcul grégorien de Meeus) : du jeudi saint au lundi de Pâques */ $a = $y % 19; $b = intdiv($y, 100); $c = $y % 100; $d = intdiv($b, 4); $e = $b % 4; $f = intdiv($b + 8, 25); $g = intdiv($b - $f + 1, 3); $h = (19 * $a + $b - $d - $g + 15) % 30; $i = intdiv($c, 4); $k = $c % 4; $l = (32 + 2 * $e + 2 * $i - $h - $k) % 7; $m = intdiv($a + 11 * $h + 22 * $l, 451); $em = intdiv($h + $l - 7 * $m + 114, 31); $ed = (($h + $l - 7 * $m + 114) % 31) + 1; /* Black Friday : lendemain du 4e jeudi de novembre, jusqu'au Cyber Monday */ $thu = 1 + ((4 - (int) date('w', mktime(12, 0, 0, 11, 1, $y)) + 7) % 7) + 21; if ($md === 401) return 'poisson'; if ($today >= $day($em, $ed - 3, $y) && $today <= $day($em, $ed + 1, $y)) return 'paques'; if ($md === 1130) return 'hack'; // Computer Security Day, passe devant le Cyber Monday if ($today >= $day(11, $thu + 1, $y) && $today <= $day(11, $thu + 4, $y)) return 'black-friday'; if ($md >= 1228 || $md <= 106) return 'nouvel-an'; if ($md >= 314 && $md <= 317) return 'st-patrick'; if ($md === 514) return 'anniversaire'; if ($md >= 702 && $md <= 708) return 'algerie'; // semaine autour du 5 juillet if ($md >= 320 && $md <= 410) return 'japon'; // hanami (après poisson d'avril et Pâques, qui passent devant) if ($md >= 619 && $md <= 621) return 'musique'; if ($md >= 712 && $md <= 714) return 'juillet'; if ($md >= 1001 && $md <= 1102) return 'halloween'; if ($md >= 1201 && $md <= 1227) return 'noel'; return ''; } /* Saison active pour cette requête ('' = aucune) */ /* Pages sobres, jamais décorées (comme les pages d'erreur Apache / NPM, qui ne connaissent pas la saison) */ function yb2026_season_blocked() { return is_404(); } function yb2026_season() { static $s = null; if ($s !== null) return $s; if (yb2026_season_blocked()) return $s = ''; $all = yb2026_seasons(); if (isset($_GET['saison'])) { $q = sanitize_key($_GET['saison']); return $s = isset($all[$q]) ? $q : ''; } $mode = (string) get_option('yb_season', 'auto'); if ($mode === 'off') return $s = ''; return $s = isset($all[$mode]) ? $mode : yb2026_season_auto(); } /* Quantité d'éléments animés par fête, en % (100 = normal). Option yb_season_density */ function yb2026_season_density() { $d = (array) get_option('yb_season_density', array()); $out = array(); foreach (array_keys(yb2026_seasons()) as $k) if (isset($d[$k])) $out[$k] = max(0, min(300, (int) $d[$k])); return $out; } /* Fêtes qui ont un CV assorti (wp-content/uploads/cv/saisons//) */ function yb2026_season_cvs() { $out = array(); foreach (array_keys(yb2026_seasons()) as $k) if (file_exists(WP_CONTENT_DIR . '/uploads/cv/saisons/' . $k . '/CV_Yasser_Boulayoune.pdf')) $out[] = $k; return $out; } /* Attribut de : fête active */ function yb2026_season_attrs() { if (yb2026_season_blocked()) return ' data-no-season'; $a = ''; if (yb2026_season()) $a .= ' data-season="' . esc_attr(yb2026_season()) . '"'; return $a; } add_action('wp_enqueue_scripts', function () { if (yb2026_season_blocked()) return; $dir = get_template_directory(); $uri = get_template_directory_uri(); wp_enqueue_style('yb-seasons', $uri . '/assets/css/seasons.css', array('yb-style'), filemtime($dir . '/assets/css/seasons.css')); wp_enqueue_script('yb-seasons', $uri . '/assets/js/seasons.js', array('yb-effects'), filemtime($dir . '/assets/js/seasons.js'), true); $list = array(); /* accent (mode sombre) de chaque fête : sert à teinter la main du curseur dans la roue */ $acc = array('nouvel-an' => '#f2c14e', 'st-patrick' => '#3ddc84', 'anniversaire' => '#2ee6c5', 'paques' => '#ff9fcb', 'poisson' => '#4fd1ff', 'musique' => '#ff5cc8', 'juillet' => '#ff4a5a', 'halloween' => '#ff7b1c', 'black-friday' => '#ffd400', 'noel' => '#ff4a5a', 'algerie' => '#2fbf71', 'japon' => '#ff5a3c', 'hack' => '#00ff66'); foreach (yb2026_seasons() as $k => $t) $list[$k] = array('label' => $t['label'], 'when' => $t['when'], 'icon' => $t['icon'], 'accent' => $acc[$k] ?? ''); wp_add_inline_script('yb-seasons', 'window.YB_SEASONS=' . wp_json_encode(array('list' => $list, 'auto' => yb2026_season_auto(), 'cv' => yb2026_season_cvs(), 'density' => (object) yb2026_season_density())) . ';', 'before'); }, 20); /* Bouton de la barre (icône de la fête) : coupe / remet le décor */ function yb2026_season_toggle() { if (yb2026_season_blocked()) return; $s = yb2026_season(); $t = $s ? yb2026_seasons()[$s] : array('label' => 'de fête', 'off' => 'Thème de fête', 'on' => 'Thème de fête', 'icon' => yb2026_seasons()['nouvel-an']['icon']); printf( '', esc_attr($t['off']), esc_attr($t['on']), esc_attr('Décor ' . $t['label']), $t['icon'] ); } /* ── Admin : Profil → Saisons ───────────────────────────────────────── */ add_action('admin_menu', function () { add_submenu_page('yb-profil', 'Saisons', 'Saisons', 'edit_pages', 'yb-saisons', 'yb2026_seasons_page'); }); function yb2026_seasons_page() { $mode = (string) get_option('yb_season', 'auto'); $auto = yb2026_season_auto(); $all = yb2026_seasons(); $opts = array('auto' => 'Automatique' . ($auto ? ' (en ce moment : ' . $all[$auto]['label'] . ')' : ' (en ce moment : aucune fête)')); foreach ($all as $k => $t) $opts[$k] = 'Toujours ' . $t['label'] . ' (en auto : ' . $t['when'] . ')'; $opts['off'] = 'Désactivé'; ?>

Thèmes saisonniers

Réglage enregistré.

Palette, décor animé et orbe de l'accueil changent selon la saison. Les visiteurs peuvent couper le décor avec le bouton de la barre de navigation.

$l) : ?>

Quantité d'éléments animés

Combien d'objets apparaissent en fond (étiquettes, ballons, flocons, chauves-souris, feux d'artifice...). 100 % = réglage d'origine, 0 % = aucun.

'feux d\'artifice', 'st-patrick' => 'trèfles', 'anniversaire' => 'ballons et confettis', 'paques' => 'pétales', 'poisson' => 'poissons et bulles', 'musique' => 'notes', 'juillet' => 'feux d\'artifice', 'halloween' => 'chauves-souris et braises', 'black-friday' => 'étiquettes de prix', 'noel' => 'flocons', 'algerie' => 'feux d\'artifice et confettis', 'japon' => 'pétales de sakura', 'hack' => 'pluie de caractères'); ?> $t) : $v = $dens[$k] ?? 100; ?>

Aperçu sans changer le réglage : $t) : ?> · Sans décor

$v) { $k = sanitize_key($k); if (isset(yb2026_seasons()[$k])) $dens[$k] = max(0, min(300, (int) $v)); } update_option('yb_season_density', $dens, false); update_option('yb_season', ($v === 'auto' || $v === 'off' || isset(yb2026_seasons()[$v])) ? $v : 'auto'); wp_safe_redirect(admin_url('admin.php?page=yb-saisons&updated=1')); exit; });