222 lines
14 KiB
PHP
222 lines
14 KiB
PHP
<?php
|
|
/**
|
|
* Thèmes saisonniers (fêtes). Réglage : Profil → Saisons (option yb_season : auto | off | <clé>).
|
|
* Auto : voir yb2026_season_auto() (dates en heure de Paris).
|
|
* Aperçu sans rien enregistrer : ?saison=<clé> | aucune
|
|
* Le visiteur peut couper le décor (bouton dans la barre, mémorisé : localStorage yb-season=off).
|
|
*/
|
|
|
|
function yb2026_seasons()
|
|
{
|
|
$ico = array(
|
|
'pumpkin' => '<path d="M12 6.2c-1-.9-2.6-1.2-4-.6C4.6 7 3.4 10.6 4.2 14.2c.7 3.3 3.2 5.6 5.6 5.4.8 0 1.5-.4 2.2-.4s1.4.4 2.2.4c2.4.2 4.9-2.1 5.6-5.4.8-3.6-.4-7.2-3.8-8.6-1.4-.6-3-.3-4 .6z"/><path d="M12 6.2c0-1.4.6-2.6 1.8-3.2"/><path class="st-face" d="M8.3 11.2l1.5-1.6 1.1 1.6zM13.1 11.2l1.1-1.6 1.5 1.6zM8.6 14.6c1 .9 2.1 1.2 3.4 1.2s2.4-.3 3.4-1.2l-1.2.3-.8-.6-.7.7-.7-.7-.7.7-.8-.6z"/>',
|
|
'flake' => '<path d="M12 2.5v19M3.8 7.25l16.4 9.5M3.8 16.75l16.4-9.5"/><path d="M9.6 3.9L12 6.2l2.4-2.3M9.6 20.1l2.4-2.3 2.4 2.3M3.9 10.1l3.2.9-.8 3.2M20.1 13.9l-3.2-.9.8-3.2M6.3 9.8l.8 3.2-3.2.9M17.7 14.2l-.8-3.2 3.2-.9"/>',
|
|
'burst' => '<path d="M12 3v4M12 17v4M3 12h4M17 12h4M5.6 5.6l2.8 2.8M15.6 15.6l2.8 2.8M5.6 18.4l2.8-2.8M15.6 8.4l2.8-2.8"/><circle class="st-face" cx="12" cy="12" r="1.6"/>',
|
|
'clover' => '<path d="M12 12c-2.6-.4-4.6-2.2-4.2-4.3.3-1.5 2-2.2 3.2-1.3.1-1.6 1.8-2.6 3.1-1.8 1.7 1 1.4 4.7-2.1 7.4zM12 12c.4 2.6 2.2 4.6 4.3 4.2 1.5-.3 2.2-2 1.3-3.2 1.6-.1 2.6-1.8 1.8-3.1-1-1.7-4.7-1.4-7.4 2.1zM12 12c-2.6.4-4.6 2.2-4.2 4.3.3 1.5 2 2.2 3.2 1.3"/><path d="M12 12c1.4 3.2 1.3 6.3-.6 9"/>',
|
|
'egg' => '<path d="M12 3c3.6 0 6.5 5.2 6.5 10.2 0 4.3-2.9 7.3-6.5 7.3s-6.5-3-6.5-7.3C5.5 8.2 8.4 3 12 3z"/><path d="M6.2 11.6l2.3 1.6 2.3-1.6 2.4 1.6 2.3-1.6 2.3 1.6"/>',
|
|
'fish' => '<path d="M3 12c2.8-4 7-5.6 11-4.4 2 .6 3.6 2.4 4.6 4.4-1 2-2.6 3.8-4.6 4.4C10 17.6 5.8 16 3 12z"/><path d="M18.6 12l2.9-3.2v6.4z"/><circle class="st-face" cx="7.4" cy="11.2" r="1"/>',
|
|
'note' => '<path d="M9 17.5V6.2l10-2.2v11.3"/><ellipse class="st-face" cx="6.8" cy="17.6" rx="2.4" ry="1.9"/><ellipse class="st-face" cx="16.8" cy="15.4" rx="2.4" ry="1.9"/>',
|
|
'cake' => '<path d="M4 20.5h16M5 20.5v-7.2h14v7.2"/><path d="M5 16c1.6 1.2 3 1.2 4.6 0 1.6 1.2 3.2 1.2 4.8 0 1.6 1.2 3 1.2 4.6 0"/><path d="M12 13.3V9.5"/><path class="st-face" d="M12 4.2c1.2 1.4 1.5 2.4 1 3.3-.5.8-1.5.8-2 0-.5-.9-.2-1.9 1-3.3z"/>',
|
|
'crescent' => '<path d="M14.6 4.2a8.2 8.2 0 1 0 0 15.6 6.6 6.6 0 1 1 0-15.6z"/><path class="st-face" d="M17.6 9.1l.9 2.1 2.3.1-1.8 1.4.6 2.2-1.9-1.3-1.9 1.3.6-2.2-1.8-1.4 2.3-.1z"/>',
|
|
'torii' => '<path d="M3 6.2c3 .9 15 .9 18 0"/><path d="M5.2 9.4h13.6"/><path d="M7 7v13.5M17 7v13.5"/><path d="M12 7v2.4"/>',
|
|
'prompt' => '<rect x="2.5" y="4" width="19" height="16" rx="2.5"/><path d="M6.5 9.5l3 2.5-3 2.5"/><path class="st-face" d="M11.5 14h6v1.8h-6z"/>',
|
|
'tag' => '<path d="M3.5 12.6V4.5a1 1 0 0 1 1-1h8.1l8 8a1.4 1.4 0 0 1 0 2l-7.1 7.1a1.4 1.4 0 0 1-2 0z"/><circle class="st-face" cx="8" cy="8" r="1.5"/>',
|
|
);
|
|
$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' => '<svg viewBox="0 0 24 24" aria-hidden="true">' . $ico[$v[1]] . '</svg>',
|
|
);
|
|
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/<clé>/) */
|
|
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 <html> : 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(
|
|
'<button type="button" class="season-toggle' . ($s ? '' : ' season-toggle--latent') . '" data-season-toggle data-label-off="%1$s" data-label-on="%2$s" aria-label="%1$s" aria-pressed="true" title="%3$s">%4$s</button>',
|
|
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é';
|
|
?>
|
|
<div class="wrap">
|
|
<h1>Thèmes saisonniers</h1>
|
|
<?php if (!empty($_GET['updated'])) : ?><div class="notice notice-success is-dismissible"><p>Réglage enregistré.</p></div><?php endif; ?>
|
|
<p>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.</p>
|
|
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
|
|
<input type="hidden" name="action" value="yb_save_season">
|
|
<?php wp_nonce_field('yb_save_season'); ?>
|
|
<fieldset>
|
|
<?php foreach ($opts as $k => $l) : ?>
|
|
<p><label><input type="radio" name="yb_season" value="<?php echo esc_attr($k); ?>" <?php checked($mode, $k); ?>> <?php echo esc_html($l); ?></label></p>
|
|
<?php endforeach; ?>
|
|
</fieldset>
|
|
<h2>Quantité d'éléments animés</h2>
|
|
<p>Combien d'objets apparaissent en fond (étiquettes, ballons, flocons, chauves-souris, feux d'artifice...). 100 % = réglage d'origine, 0 % = aucun.</p>
|
|
<?php $dens = yb2026_season_density(); $what = array(
|
|
'nouvel-an' => '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'); ?>
|
|
<table class="form-table" role="presentation"><tbody>
|
|
<?php foreach ($all as $k => $t) : $v = $dens[$k] ?? 100; ?>
|
|
<tr>
|
|
<th scope="row"><label for="yb-dens-<?php echo esc_attr($k); ?>"><?php echo esc_html($t['label']); ?></label></th>
|
|
<td>
|
|
<input type="range" id="yb-dens-<?php echo esc_attr($k); ?>" name="yb_season_density[<?php echo esc_attr($k); ?>]" min="0" max="300" step="10" value="<?php echo (int) $v; ?>" style="width:260px;vertical-align:middle" oninput="this.nextElementSibling.textContent=this.value+' %'">
|
|
<output style="display:inline-block;min-width:52px;margin-left:8px;font-weight:600"><?php echo (int) $v; ?> %</output>
|
|
<span class="description"><?php echo esc_html($what[$k] ?? ''); ?></span>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody></table>
|
|
<p>Aperçu sans changer le réglage :
|
|
<?php foreach ($all as $k => $t) : ?><a href="<?php echo esc_url(add_query_arg('saison', $k, home_url('/'))); ?>" target="_blank"><?php echo esc_html($t['label']); ?></a> · <?php endforeach; ?>
|
|
<a href="<?php echo esc_url(add_query_arg('saison', 'aucune', home_url('/'))); ?>" target="_blank">Sans décor</a>
|
|
</p>
|
|
<?php submit_button('Enregistrer'); ?>
|
|
</form>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
add_action('admin_post_yb_save_season', function () {
|
|
if (!current_user_can('edit_pages')) wp_die('Accès refusé.');
|
|
check_admin_referer('yb_save_season');
|
|
$v = sanitize_key($_POST['yb_season'] ?? 'auto');
|
|
$dens = array();
|
|
foreach ((array) wp_unslash($_POST['yb_season_density'] ?? array()) as $k => $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;
|
|
});
|