festive-seasons-pro.php aktualisiert
This commit is contained in:
@@ -1,419 +1,419 @@
|
||||
<?php
|
||||
/*
|
||||
Plugin Name: Festive Seasons Pro (Clean & Robust)
|
||||
Description: Zeigt saisonale Effekte (Schnee, Eier, Spinnen, Ballons, Feuerwerk) für feste Feiertage und individuelle Geburtstage an.
|
||||
Version: 3.4
|
||||
Author: M_Viper
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class Festive_Seasons_Pro {
|
||||
|
||||
public function __construct() {
|
||||
add_action('init', [$this, 'init_plugin']);
|
||||
}
|
||||
|
||||
public function init_plugin() {
|
||||
add_action('wp_enqueue_scripts', [$this, 'load_assets']);
|
||||
add_action('wp_footer', [$this, 'render_music_consent']);
|
||||
add_action('admin_menu', [$this, 'add_admin_menu_page']);
|
||||
add_action('admin_init', [$this, 'register_settings']);
|
||||
add_action('widgets_init', [$this, 'register_widget']);
|
||||
add_shortcode('festive_event', [$this, 'render_shortcode']);
|
||||
}
|
||||
|
||||
public function get_active_events() {
|
||||
if (isset($_GET['fsp_test_date'])) {
|
||||
$today = sanitize_text_field($_GET['fsp_test_date']);
|
||||
} else {
|
||||
$today = date('Y-m-d');
|
||||
}
|
||||
|
||||
$active_events = [];
|
||||
|
||||
foreach ($this->get_fixed_events() as $event_key => $event_data) {
|
||||
if (isset($event_data['start'], $event_data['end']) && $today >= $event_data['start'] && $today <= $event_data['end']) {
|
||||
if (get_option("fsp_fixed_{$event_key}", 'yes') === 'yes') {
|
||||
$active_events[] = $event_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->get_custom_events($today) as $event_data) {
|
||||
$active_events[] = $event_data;
|
||||
}
|
||||
|
||||
return $active_events;
|
||||
}
|
||||
|
||||
private function get_fixed_events() {
|
||||
$test_year = isset($_GET['fsp_test_date']) ? substr(sanitize_text_field($_GET['fsp_test_date']), 0, 4) : date('Y');
|
||||
$year = is_numeric($test_year) ? $test_year : date('Y');
|
||||
$easter_date = date('Y-m-d', easter_date($year));
|
||||
|
||||
return [
|
||||
'advent' => ['name' => 'Adventszeit', 'start' => "$year-12-01", 'end' => "$year-12-23", 'class' => 'festive-advent', 'effects' => ['snow']],
|
||||
'christmas' => ['name' => 'Weihnachten', 'start' => "$year-12-24", 'end' => "$year-12-26", 'class' => 'festive-christmas', 'effects' => ['snow', 'music', 'star', 'santa']], // NEU: Santa-Animation
|
||||
'newyear' => ['name' => 'Silvester', 'start' => "$year-12-31", 'end' => ($year + 1) . "-01-01", 'class' => 'festive-newyear', 'effects' => ['newyear_fireworks']],
|
||||
'halloween' => ['name' => 'Halloween', 'start' => "$year-10-31", 'end' => "$year-10-31", 'class' => 'festive-halloween', 'effects' => ['spiders']],
|
||||
'easter' => ['name' => 'Ostern', 'start' => date('Y-m-d', strtotime($easter_date . ' -1 day')), 'end' => date('Y-m-d', strtotime($easter_date)), 'class' => 'festive-easter', 'effects' => ['eggs']],
|
||||
];
|
||||
}
|
||||
|
||||
private function get_custom_events($today) {
|
||||
$custom_events = get_option('fsp_events', []);
|
||||
$active_custom_events = [];
|
||||
$today_day_month = date('m-d', strtotime($today));
|
||||
|
||||
if (is_array($custom_events)) {
|
||||
foreach ($custom_events as $event) {
|
||||
if (empty($event['date']) || !is_array($event)) continue;
|
||||
$event_date = sanitize_text_field($event['date']);
|
||||
$date_obj = DateTime::createFromFormat('d-m', $event_date) ?: DateTime::createFromFormat('Y-m-d', $event_date);
|
||||
if ($date_obj && $date_obj->format('m-d') === $today_day_month) {
|
||||
$name = trim(($event['name'] ?? '') . ' ' . ($event['text'] ?? ''));
|
||||
$active_custom_events[] = [
|
||||
'name' => $name ?: 'Besonderer Tag!',
|
||||
'class' => 'festive-birthday',
|
||||
'effects' => ['balloons', 'confetti']
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $active_custom_events;
|
||||
}
|
||||
|
||||
public function load_assets() {
|
||||
$active_events = $this->get_active_events();
|
||||
if (empty($active_events)) return;
|
||||
|
||||
$body_classes = [];
|
||||
$effects_to_load = [];
|
||||
|
||||
foreach ($active_events as $event) {
|
||||
if (!empty($event['class'])) $body_classes[] = $event['class'];
|
||||
if (!empty($event['effects'])) $effects_to_load = array_merge($effects_to_load, $event['effects']);
|
||||
}
|
||||
|
||||
add_filter('body_class', function($classes) use ($body_classes) {
|
||||
return array_merge($classes, array_unique($body_classes));
|
||||
});
|
||||
|
||||
wp_enqueue_style('fsp-style', plugin_dir_url(__FILE__) . 'assets/css/festive.css', [], '3.4');
|
||||
wp_enqueue_script('jquery');
|
||||
|
||||
wp_localize_script('jquery', 'fsp_vars', [
|
||||
'plugin_url' => plugin_dir_url(__FILE__)
|
||||
]);
|
||||
|
||||
if (in_array('confetti', $effects_to_load) || in_array('newyear_fireworks', $effects_to_load)) {
|
||||
wp_enqueue_script('fsp-confetti-lib', plugin_dir_url(__FILE__) . 'assets/js/canvas-confetti.min.js', [], '3.4', true);
|
||||
}
|
||||
|
||||
foreach (array_unique($effects_to_load) as $effect) {
|
||||
switch ($effect) {
|
||||
case 'snow':
|
||||
wp_enqueue_script('fsp-snow', plugin_dir_url(__FILE__) . 'assets/js/snowstorm.js', [], '3.4', true);
|
||||
break;
|
||||
case 'confetti':
|
||||
wp_add_inline_script('fsp-confetti-lib', 'jQuery(document).ready(function($) { setTimeout(() => confetti({particleCount: 200, spread: 120, origin: { y: 0.6 } }), 1000); });');
|
||||
break;
|
||||
case 'eggs':
|
||||
wp_enqueue_script('fsp-eggs', plugin_dir_url(__FILE__) . 'assets/js/easter-eggs.js', ['jquery'], '3.4', true);
|
||||
break;
|
||||
case 'spiders':
|
||||
wp_enqueue_script('fsp-spiders', plugin_dir_url(__FILE__) . 'assets/js/halloween-spiders.js', ['jquery'], '3.4', true);
|
||||
break;
|
||||
case 'balloons':
|
||||
wp_enqueue_script('fsp-balloons', plugin_dir_url(__FILE__) . 'assets/js/balloons.js', ['jquery'], '3.4', true);
|
||||
break;
|
||||
case 'star':
|
||||
wp_enqueue_script('fsp-star', plugin_dir_url(__FILE__) . 'assets/js/christmas-star.js', ['jquery'], '3.4', true);
|
||||
break;
|
||||
case 'santa': // NEU: Santa-Animation
|
||||
wp_enqueue_script('fsp-santa', plugin_dir_url(__FILE__) . 'assets/js/santa-sleigh.js', ['jquery'], '3.4', true);
|
||||
break;
|
||||
case 'newyear_fireworks':
|
||||
$this->add_newyear_script();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function add_newyear_script() {
|
||||
$script = '
|
||||
jQuery(document).ready(function($) {
|
||||
if (!$("body").hasClass("festive-newyear")) {
|
||||
return;
|
||||
}
|
||||
if (typeof confetti === "undefined") {
|
||||
console.error("FSP: Konfetti-Bibliothek nicht gefunden.");
|
||||
return;
|
||||
}
|
||||
|
||||
function runBigFireworks() {
|
||||
var count = 250;
|
||||
var defaults = { origin: { y: 0.7 }, zIndex: 999999, colors: ["#bb0000", "#ffffff", "#ff0000", "#ffbb00", "#ffee00", "#00ff00", "#0099ff", "#0000ff"] };
|
||||
function fire(particleRatio, opts) {
|
||||
confetti(Object.assign({}, defaults, opts, { particleCount: Math.floor(count * particleRatio) }));
|
||||
}
|
||||
fire(0.25, { spread: 26, startVelocity: 55 });
|
||||
fire(0.2, { spread: 60 });
|
||||
fire(0.35, { spread: 100, decay: 0.91, scalar: 0.8 });
|
||||
fire(0.1, { spread: 120, startVelocity: 25, decay: 0.92, scalar: 1.2 });
|
||||
fire(0.1, { spread: 120, startVelocity: 45 });
|
||||
|
||||
var rainDefaults = { origin: { y: 0 }, angle: 90, drift: 0, gravity: 1.2, scalar: 1.2, zIndex: 999999 };
|
||||
confetti(Object.assign({}, rainDefaults, { particleCount: 40, x: 0.1, colors: ["#ff0000", "#00ff00", "#0000ff", "#ffff00"] }));
|
||||
confetti(Object.assign({}, rainDefaults, { particleCount: 40, x: 0.5, colors: ["#bb0000", "#ffffff", "#ffbb00", "#ffee00"] }));
|
||||
confetti(Object.assign({}, rainDefaults, { particleCount: 40, x: 0.9, colors: ["#ff0000", "#00ff00", "#0000ff", "#ffff00"] }));
|
||||
}
|
||||
|
||||
function createRocket(isLastRocket) {
|
||||
const startX = Math.random() * window.innerWidth;
|
||||
|
||||
const $rocket = $("<div class=\"fsp-rocket\"></div>").css({
|
||||
position: "fixed",
|
||||
width: "6px",
|
||||
height: "25px",
|
||||
background: "linear-gradient(to top, #ff4500, #ffa500)",
|
||||
bottom: "-30px",
|
||||
left: startX + "px",
|
||||
zIndex: 999999,
|
||||
borderRadius: "50% 50% 0 0",
|
||||
boxShadow: "0 0 15px 5px rgba(255, 165, 0, 0.8)"
|
||||
});
|
||||
|
||||
$("body").append($rocket);
|
||||
|
||||
$rocket.animate(
|
||||
{ bottom: window.innerHeight * 0.8 },
|
||||
{
|
||||
duration: 1800,
|
||||
easing: "linear",
|
||||
complete: function() {
|
||||
const x = startX / window.innerWidth;
|
||||
const y = 0.2;
|
||||
|
||||
confetti({
|
||||
particleCount: 75,
|
||||
spread: 100,
|
||||
origin: { x: x, y: y },
|
||||
colors: ["#ff0000", "#ffa500", "#ffff00", "#ffffff"],
|
||||
gravity: 1.1,
|
||||
scalar: 1.0,
|
||||
startVelocity: 40
|
||||
});
|
||||
|
||||
if (isLastRocket) {
|
||||
setTimeout(runBigFireworks, 500);
|
||||
}
|
||||
|
||||
$(this).remove();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function runNewYearShow() {
|
||||
const rocketCount = 5 + Math.floor(Math.random() * 4);
|
||||
|
||||
for (let i = 0; i < rocketCount; i++) {
|
||||
const isLast = (i === rocketCount - 1);
|
||||
setTimeout(() => createRocket(isLast), i * 400);
|
||||
}
|
||||
}
|
||||
|
||||
runNewYearShow();
|
||||
setInterval(runNewYearShow, 12000);
|
||||
});
|
||||
';
|
||||
wp_add_inline_script('fsp-confetti-lib', $script);
|
||||
}
|
||||
|
||||
public function add_admin_menu_page() {
|
||||
add_options_page('Festive Seasons Pro', 'Festive Seasons', 'manage_options', 'festive-seasons-pro', [$this, 'render_admin_page']);
|
||||
}
|
||||
|
||||
public function register_settings() {
|
||||
register_setting('fsp_settings_group', 'fsp_events');
|
||||
foreach (array_keys($this->get_fixed_events()) as $key) {
|
||||
register_setting('fsp_settings_group', "fsp_fixed_{$key}");
|
||||
}
|
||||
register_setting('fsp_settings_group', 'fsp_enable_music');
|
||||
}
|
||||
|
||||
public function render_admin_page() {
|
||||
$events = get_option('fsp_events', []);
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1>Festive Seasons Pro Einstellungen</h1>
|
||||
<form method="post" action="options.php">
|
||||
<?php settings_fields('fsp_settings_group'); ?>
|
||||
<?php do_settings_sections('fsp_settings_group'); ?>
|
||||
|
||||
<h2>Allgemeine Einstellungen</h2>
|
||||
<table class="form-table" role="presentation">
|
||||
<tr>
|
||||
<th scope="row">Musik-Einwilligung</th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<label><input type="checkbox" name="fsp_enable_music" value="yes" <?php checked(get_option('fsp_enable_music', 'yes'), 'yes'); ?> /> Einwilligungsbox für Weihnachtsmusik anzeigen (funktioniert nur, wenn Weihnachten aktiv ist).</label>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2>Feste Feiertage</h2>
|
||||
<table class="form-table" role="presentation">
|
||||
<?php foreach ($this->get_fixed_events() as $key => $event): ?>
|
||||
<tr>
|
||||
<th scope="row"><?php echo esc_html($event['name']); ?></th>
|
||||
<td>
|
||||
<label><input type="checkbox" name="fsp_fixed_<?php echo $key; ?>" value="yes" <?php checked(get_option("fsp_fixed_{$key}", 'yes'), 'yes'); ?> /> Aktivieren</label>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
|
||||
<h2>Geburtstage & Jubiläe</h2>
|
||||
<p>Hier können Sie beliebige Ereignisse hinzufügen. Das Datum wird im Format <strong>TT-MM</strong> (z.B. 24-12) oder <strong>JJJJ-MM-TT</strong> (z.B. 2024-05-10) angegeben.</p>
|
||||
<div id="fsp-events-container">
|
||||
<?php if (is_array($events)) : ?>
|
||||
<?php foreach ($events as $index => $event) : ?>
|
||||
<div class="fsp-event-row" style="margin-bottom: 10px; display: flex; gap: 10px; align-items: center;">
|
||||
<input type="text" name="fsp_events[<?php echo $index; ?>][name]" placeholder="Name (z.B. Max)" value="<?php echo esc_attr($event['name'] ?? ''); ?>" style="width: 200px;" />
|
||||
<input type="text" name="fsp_events[<?php echo $index; ?>][date]" placeholder="Datum (TT-MM)" value="<?php echo esc_attr($event['date'] ?? ''); ?>" style="width: 100px;" />
|
||||
<input type="text" name="fsp_events[<?php echo $index; ?>][text]" placeholder="Text (z.B. wird 30!)" value="<?php echo esc_attr($event['text'] ?? ''); ?>" style="flex-grow: 1;" />
|
||||
<button type="button" class="button button-secondary fsp-remove-event">Entfernen</button>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<button type="button" id="fsp-add-event" class="button button-primary">+ Neues Ereignis hinzufügen</button>
|
||||
|
||||
<?php submit_button(); ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
jQuery(document).ready(function($) {
|
||||
$("#fsp-add-event").on("click", function() {
|
||||
var index = $("#fsp-events-container .fsp-event-row").length;
|
||||
var newRow = \'<div class="fsp-event-row" style="margin-bottom: 10px; display: flex; gap: 10px; align-items: center;"><input type="text" name="fsp_events[\' + index + \'][name]" placeholder="Name (z.B. Max)" style="width: 200px;" /><input type="text" name="fsp_events[\' + index + \'][date]" placeholder="Datum (TT-MM)" style="width: 100px;" /><input type="text" name="fsp_events[\' + index + \'][text]" placeholder="Text (z.B. wird 30!)" style="flex-grow: 1;" /><button type="button" class="button button-secondary fsp-remove-event">Entfernen</button></div>\';
|
||||
$("#fsp-events-container").append(newRow);
|
||||
});
|
||||
$(document).on("click", ".fsp-remove-event", function() {
|
||||
$(this).closest(".fsp-event-row").remove();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function render_shortcode() {
|
||||
$active_events = $this->get_active_events();
|
||||
if (empty($active_events)) return '';
|
||||
$names = array_map(fn($e) => $e['name'], $active_events);
|
||||
return '<div class="fsp-today">Heute feiern wir: <strong>' . esc_html(implode(' + ', $names)) . '</strong></div>';
|
||||
}
|
||||
|
||||
public function register_widget() {
|
||||
register_widget('FSP_Widget');
|
||||
}
|
||||
|
||||
public function render_music_consent() {
|
||||
if (get_option('fsp_enable_music', 'yes') !== 'yes') {
|
||||
return;
|
||||
}
|
||||
|
||||
$active_events = $this->get_active_events();
|
||||
$has_music = false;
|
||||
foreach ($active_events as $event) {
|
||||
if (in_array('music', $event['effects'] ?? [])) { $has_music = true; break; }
|
||||
}
|
||||
if (!$has_music) return;
|
||||
|
||||
$audio_url = plugin_dir_url(__FILE__) . 'assets/audio/xmas-jingle.mp3';
|
||||
echo '<div id="fsp-music-consent" style="position:fixed;bottom:20px;right:20px;background:#fff;color:#333;padding:20px;border-radius:8px;z-index:99999;box-shadow:0 4px 15px rgba(0,0,0,0.2);display:none;max-width:300px;">
|
||||
<p style="margin:0 0 15px 0;">Weihnachtsmusik abspielen?</p>
|
||||
<button id="fsp-music-yes" style="background:#c0392b;color:#fff;border:none;padding:8px 15px;border-radius:5px;cursor:pointer;margin-right:10px;">Ja</button>
|
||||
<button id="fsp-music-no" style="background:#bdc3c7;color:#333;border:none;padding:8px 15px;border-radius:5px;cursor:pointer;">Nein</button>
|
||||
</div>
|
||||
|
||||
<audio id="fsp-xmas-audio" src="' . $audio_url . '" loop style="display:none;"></audio>
|
||||
|
||||
<script>
|
||||
jQuery(function($) {
|
||||
const consentBox = $("#fsp-music-consent");
|
||||
const audioPlayer = $("#fsp-xmas-audio")[0];
|
||||
|
||||
setTimeout(() => consentBox.fadeIn(500), 2000);
|
||||
|
||||
$("#fsp-music-yes").on("click", function() {
|
||||
const playPromise = audioPlayer.play();
|
||||
|
||||
if (playPromise !== undefined) {
|
||||
playPromise.then(_ => {
|
||||
console.log("FSP: Musik wird abgespielt.");
|
||||
}).catch(error => {
|
||||
console.error("FSP: Autoplay blockiert. Zeige Steuerelemente an.");
|
||||
audioPlayer.style.position = "fixed";
|
||||
audioPlayer.style.bottom = "20px";
|
||||
audioPlayer.style.left = "20px";
|
||||
audioPlayer.style.zIndex = "99999";
|
||||
audioPlayer.style.width = "250px";
|
||||
audioPlayer.style.display = "block";
|
||||
audioPlayer.controls = true;
|
||||
});
|
||||
}
|
||||
consentBox.fadeOut(300);
|
||||
});
|
||||
|
||||
$("#fsp-music-no").on("click", function() {
|
||||
consentBox.fadeOut(300);
|
||||
});
|
||||
});
|
||||
</script>';
|
||||
}
|
||||
}
|
||||
|
||||
class FSP_Widget extends WP_Widget {
|
||||
public function __construct() {
|
||||
parent::__construct('fsp_widget', 'Festive Seasons Anlass', ['description' => 'Zeigt den heutigen festlichen Anlass an.']);
|
||||
}
|
||||
|
||||
public function widget($args, $instance) {
|
||||
global $festive_seasons_pro_instance;
|
||||
if (!$festive_seasons_pro_instance) return;
|
||||
|
||||
$active_events = $festive_seasons_pro_instance->get_active_events();
|
||||
if (empty($active_events)) return;
|
||||
|
||||
$names = array_map(fn($e) => $e['name'], $active_events);
|
||||
echo $args['before_widget'];
|
||||
if (!empty($instance['title'])) {
|
||||
echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title'];
|
||||
}
|
||||
echo '<div style="text-align:center; padding:15px; background:rgba(255,255,255,0.2); border-radius:10px;">' . esc_html(implode(' + ', $names)) . '</div>';
|
||||
echo $args['after_widget'];
|
||||
}
|
||||
|
||||
public function form($instance) {
|
||||
$title = !empty($instance['title']) ? $instance['title'] : 'Heute ist...';
|
||||
?>
|
||||
<p><label for="<?php echo esc_attr($this->get_field_id('title')); ?>">Titel:</label><input class="widefat" id="<?php echo esc_attr($this->get_field_id('title')); ?>" name="<?php echo esc_attr($this->get_field_name('title')); ?>" type="text" value="<?php echo esc_attr($title); ?>"></p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance) {
|
||||
$instance = [];
|
||||
$instance['title'] = (!empty($new_instance['title'])) ? sanitize_text_field($new_instance['title']) : '';
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
|
||||
<?php
|
||||
/*
|
||||
Plugin Name: Festive Seasons Pro
|
||||
Description: Zeigt saisonale Effekte (Schnee, Eier, Spinnen, Ballons, Feuerwerk) für feste Feiertage und individuelle Geburtstage an.
|
||||
Version: 1.0
|
||||
Author: M_Viper
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class Festive_Seasons_Pro {
|
||||
|
||||
public function __construct() {
|
||||
add_action('init', [$this, 'init_plugin']);
|
||||
}
|
||||
|
||||
public function init_plugin() {
|
||||
add_action('wp_enqueue_scripts', [$this, 'load_assets']);
|
||||
add_action('wp_footer', [$this, 'render_music_consent']);
|
||||
add_action('admin_menu', [$this, 'add_admin_menu_page']);
|
||||
add_action('admin_init', [$this, 'register_settings']);
|
||||
add_action('widgets_init', [$this, 'register_widget']);
|
||||
add_shortcode('festive_event', [$this, 'render_shortcode']);
|
||||
}
|
||||
|
||||
public function get_active_events() {
|
||||
if (isset($_GET['fsp_test_date'])) {
|
||||
$today = sanitize_text_field($_GET['fsp_test_date']);
|
||||
} else {
|
||||
$today = date('Y-m-d');
|
||||
}
|
||||
|
||||
$active_events = [];
|
||||
|
||||
foreach ($this->get_fixed_events() as $event_key => $event_data) {
|
||||
if (isset($event_data['start'], $event_data['end']) && $today >= $event_data['start'] && $today <= $event_data['end']) {
|
||||
if (get_option("fsp_fixed_{$event_key}", 'yes') === 'yes') {
|
||||
$active_events[] = $event_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->get_custom_events($today) as $event_data) {
|
||||
$active_events[] = $event_data;
|
||||
}
|
||||
|
||||
return $active_events;
|
||||
}
|
||||
|
||||
private function get_fixed_events() {
|
||||
$test_year = isset($_GET['fsp_test_date']) ? substr(sanitize_text_field($_GET['fsp_test_date']), 0, 4) : date('Y');
|
||||
$year = is_numeric($test_year) ? $test_year : date('Y');
|
||||
$easter_date = date('Y-m-d', easter_date($year));
|
||||
|
||||
return [
|
||||
'advent' => ['name' => 'Adventszeit', 'start' => "$year-12-01", 'end' => "$year-12-23", 'class' => 'festive-advent', 'effects' => ['snow']],
|
||||
'christmas' => ['name' => 'Weihnachten', 'start' => "$year-12-24", 'end' => "$year-12-26", 'class' => 'festive-christmas', 'effects' => ['snow', 'music', 'star', 'santa']], // NEU: Santa-Animation
|
||||
'newyear' => ['name' => 'Silvester', 'start' => "$year-12-31", 'end' => ($year + 1) . "-01-01", 'class' => 'festive-newyear', 'effects' => ['newyear_fireworks']],
|
||||
'halloween' => ['name' => 'Halloween', 'start' => "$year-10-31", 'end' => "$year-10-31", 'class' => 'festive-halloween', 'effects' => ['spiders']],
|
||||
'easter' => ['name' => 'Ostern', 'start' => date('Y-m-d', strtotime($easter_date . ' -1 day')), 'end' => date('Y-m-d', strtotime($easter_date)), 'class' => 'festive-easter', 'effects' => ['eggs']],
|
||||
];
|
||||
}
|
||||
|
||||
private function get_custom_events($today) {
|
||||
$custom_events = get_option('fsp_events', []);
|
||||
$active_custom_events = [];
|
||||
$today_day_month = date('m-d', strtotime($today));
|
||||
|
||||
if (is_array($custom_events)) {
|
||||
foreach ($custom_events as $event) {
|
||||
if (empty($event['date']) || !is_array($event)) continue;
|
||||
$event_date = sanitize_text_field($event['date']);
|
||||
$date_obj = DateTime::createFromFormat('d-m', $event_date) ?: DateTime::createFromFormat('Y-m-d', $event_date);
|
||||
if ($date_obj && $date_obj->format('m-d') === $today_day_month) {
|
||||
$name = trim(($event['name'] ?? '') . ' ' . ($event['text'] ?? ''));
|
||||
$active_custom_events[] = [
|
||||
'name' => $name ?: 'Besonderer Tag!',
|
||||
'class' => 'festive-birthday',
|
||||
'effects' => ['balloons', 'confetti']
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $active_custom_events;
|
||||
}
|
||||
|
||||
public function load_assets() {
|
||||
$active_events = $this->get_active_events();
|
||||
if (empty($active_events)) return;
|
||||
|
||||
$body_classes = [];
|
||||
$effects_to_load = [];
|
||||
|
||||
foreach ($active_events as $event) {
|
||||
if (!empty($event['class'])) $body_classes[] = $event['class'];
|
||||
if (!empty($event['effects'])) $effects_to_load = array_merge($effects_to_load, $event['effects']);
|
||||
}
|
||||
|
||||
add_filter('body_class', function($classes) use ($body_classes) {
|
||||
return array_merge($classes, array_unique($body_classes));
|
||||
});
|
||||
|
||||
wp_enqueue_style('fsp-style', plugin_dir_url(__FILE__) . 'assets/css/festive.css', [], '3.4');
|
||||
wp_enqueue_script('jquery');
|
||||
|
||||
wp_localize_script('jquery', 'fsp_vars', [
|
||||
'plugin_url' => plugin_dir_url(__FILE__)
|
||||
]);
|
||||
|
||||
if (in_array('confetti', $effects_to_load) || in_array('newyear_fireworks', $effects_to_load)) {
|
||||
wp_enqueue_script('fsp-confetti-lib', plugin_dir_url(__FILE__) . 'assets/js/canvas-confetti.min.js', [], '3.4', true);
|
||||
}
|
||||
|
||||
foreach (array_unique($effects_to_load) as $effect) {
|
||||
switch ($effect) {
|
||||
case 'snow':
|
||||
wp_enqueue_script('fsp-snow', plugin_dir_url(__FILE__) . 'assets/js/snowstorm.js', [], '3.4', true);
|
||||
break;
|
||||
case 'confetti':
|
||||
wp_add_inline_script('fsp-confetti-lib', 'jQuery(document).ready(function($) { setTimeout(() => confetti({particleCount: 200, spread: 120, origin: { y: 0.6 } }), 1000); });');
|
||||
break;
|
||||
case 'eggs':
|
||||
wp_enqueue_script('fsp-eggs', plugin_dir_url(__FILE__) . 'assets/js/easter-eggs.js', ['jquery'], '3.4', true);
|
||||
break;
|
||||
case 'spiders':
|
||||
wp_enqueue_script('fsp-spiders', plugin_dir_url(__FILE__) . 'assets/js/halloween-spiders.js', ['jquery'], '3.4', true);
|
||||
break;
|
||||
case 'balloons':
|
||||
wp_enqueue_script('fsp-balloons', plugin_dir_url(__FILE__) . 'assets/js/balloons.js', ['jquery'], '3.4', true);
|
||||
break;
|
||||
case 'star':
|
||||
wp_enqueue_script('fsp-star', plugin_dir_url(__FILE__) . 'assets/js/christmas-star.js', ['jquery'], '3.4', true);
|
||||
break;
|
||||
case 'santa': // NEU: Santa-Animation
|
||||
wp_enqueue_script('fsp-santa', plugin_dir_url(__FILE__) . 'assets/js/santa-sleigh.js', ['jquery'], '3.4', true);
|
||||
break;
|
||||
case 'newyear_fireworks':
|
||||
$this->add_newyear_script();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function add_newyear_script() {
|
||||
$script = '
|
||||
jQuery(document).ready(function($) {
|
||||
if (!$("body").hasClass("festive-newyear")) {
|
||||
return;
|
||||
}
|
||||
if (typeof confetti === "undefined") {
|
||||
console.error("FSP: Konfetti-Bibliothek nicht gefunden.");
|
||||
return;
|
||||
}
|
||||
|
||||
function runBigFireworks() {
|
||||
var count = 250;
|
||||
var defaults = { origin: { y: 0.7 }, zIndex: 999999, colors: ["#bb0000", "#ffffff", "#ff0000", "#ffbb00", "#ffee00", "#00ff00", "#0099ff", "#0000ff"] };
|
||||
function fire(particleRatio, opts) {
|
||||
confetti(Object.assign({}, defaults, opts, { particleCount: Math.floor(count * particleRatio) }));
|
||||
}
|
||||
fire(0.25, { spread: 26, startVelocity: 55 });
|
||||
fire(0.2, { spread: 60 });
|
||||
fire(0.35, { spread: 100, decay: 0.91, scalar: 0.8 });
|
||||
fire(0.1, { spread: 120, startVelocity: 25, decay: 0.92, scalar: 1.2 });
|
||||
fire(0.1, { spread: 120, startVelocity: 45 });
|
||||
|
||||
var rainDefaults = { origin: { y: 0 }, angle: 90, drift: 0, gravity: 1.2, scalar: 1.2, zIndex: 999999 };
|
||||
confetti(Object.assign({}, rainDefaults, { particleCount: 40, x: 0.1, colors: ["#ff0000", "#00ff00", "#0000ff", "#ffff00"] }));
|
||||
confetti(Object.assign({}, rainDefaults, { particleCount: 40, x: 0.5, colors: ["#bb0000", "#ffffff", "#ffbb00", "#ffee00"] }));
|
||||
confetti(Object.assign({}, rainDefaults, { particleCount: 40, x: 0.9, colors: ["#ff0000", "#00ff00", "#0000ff", "#ffff00"] }));
|
||||
}
|
||||
|
||||
function createRocket(isLastRocket) {
|
||||
const startX = Math.random() * window.innerWidth;
|
||||
|
||||
const $rocket = $("<div class=\"fsp-rocket\"></div>").css({
|
||||
position: "fixed",
|
||||
width: "6px",
|
||||
height: "25px",
|
||||
background: "linear-gradient(to top, #ff4500, #ffa500)",
|
||||
bottom: "-30px",
|
||||
left: startX + "px",
|
||||
zIndex: 999999,
|
||||
borderRadius: "50% 50% 0 0",
|
||||
boxShadow: "0 0 15px 5px rgba(255, 165, 0, 0.8)"
|
||||
});
|
||||
|
||||
$("body").append($rocket);
|
||||
|
||||
$rocket.animate(
|
||||
{ bottom: window.innerHeight * 0.8 },
|
||||
{
|
||||
duration: 1800,
|
||||
easing: "linear",
|
||||
complete: function() {
|
||||
const x = startX / window.innerWidth;
|
||||
const y = 0.2;
|
||||
|
||||
confetti({
|
||||
particleCount: 75,
|
||||
spread: 100,
|
||||
origin: { x: x, y: y },
|
||||
colors: ["#ff0000", "#ffa500", "#ffff00", "#ffffff"],
|
||||
gravity: 1.1,
|
||||
scalar: 1.0,
|
||||
startVelocity: 40
|
||||
});
|
||||
|
||||
if (isLastRocket) {
|
||||
setTimeout(runBigFireworks, 500);
|
||||
}
|
||||
|
||||
$(this).remove();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function runNewYearShow() {
|
||||
const rocketCount = 5 + Math.floor(Math.random() * 4);
|
||||
|
||||
for (let i = 0; i < rocketCount; i++) {
|
||||
const isLast = (i === rocketCount - 1);
|
||||
setTimeout(() => createRocket(isLast), i * 400);
|
||||
}
|
||||
}
|
||||
|
||||
runNewYearShow();
|
||||
setInterval(runNewYearShow, 12000);
|
||||
});
|
||||
';
|
||||
wp_add_inline_script('fsp-confetti-lib', $script);
|
||||
}
|
||||
|
||||
public function add_admin_menu_page() {
|
||||
add_options_page('Festive Seasons Pro', 'Festive Seasons', 'manage_options', 'festive-seasons-pro', [$this, 'render_admin_page']);
|
||||
}
|
||||
|
||||
public function register_settings() {
|
||||
register_setting('fsp_settings_group', 'fsp_events');
|
||||
foreach (array_keys($this->get_fixed_events()) as $key) {
|
||||
register_setting('fsp_settings_group', "fsp_fixed_{$key}");
|
||||
}
|
||||
register_setting('fsp_settings_group', 'fsp_enable_music');
|
||||
}
|
||||
|
||||
public function render_admin_page() {
|
||||
$events = get_option('fsp_events', []);
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1>Festive Seasons Pro Einstellungen</h1>
|
||||
<form method="post" action="options.php">
|
||||
<?php settings_fields('fsp_settings_group'); ?>
|
||||
<?php do_settings_sections('fsp_settings_group'); ?>
|
||||
|
||||
<h2>Allgemeine Einstellungen</h2>
|
||||
<table class="form-table" role="presentation">
|
||||
<tr>
|
||||
<th scope="row">Musik-Einwilligung</th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<label><input type="checkbox" name="fsp_enable_music" value="yes" <?php checked(get_option('fsp_enable_music', 'yes'), 'yes'); ?> /> Einwilligungsbox für Weihnachtsmusik anzeigen (funktioniert nur, wenn Weihnachten aktiv ist).</label>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2>Feste Feiertage</h2>
|
||||
<table class="form-table" role="presentation">
|
||||
<?php foreach ($this->get_fixed_events() as $key => $event): ?>
|
||||
<tr>
|
||||
<th scope="row"><?php echo esc_html($event['name']); ?></th>
|
||||
<td>
|
||||
<label><input type="checkbox" name="fsp_fixed_<?php echo $key; ?>" value="yes" <?php checked(get_option("fsp_fixed_{$key}", 'yes'), 'yes'); ?> /> Aktivieren</label>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
|
||||
<h2>Geburtstage & Jubiläe</h2>
|
||||
<p>Hier können Sie beliebige Ereignisse hinzufügen. Das Datum wird im Format <strong>TT-MM</strong> (z.B. 24-12) oder <strong>JJJJ-MM-TT</strong> (z.B. 2024-05-10) angegeben.</p>
|
||||
<div id="fsp-events-container">
|
||||
<?php if (is_array($events)) : ?>
|
||||
<?php foreach ($events as $index => $event) : ?>
|
||||
<div class="fsp-event-row" style="margin-bottom: 10px; display: flex; gap: 10px; align-items: center;">
|
||||
<input type="text" name="fsp_events[<?php echo $index; ?>][name]" placeholder="Name (z.B. Max)" value="<?php echo esc_attr($event['name'] ?? ''); ?>" style="width: 200px;" />
|
||||
<input type="text" name="fsp_events[<?php echo $index; ?>][date]" placeholder="Datum (TT-MM)" value="<?php echo esc_attr($event['date'] ?? ''); ?>" style="width: 100px;" />
|
||||
<input type="text" name="fsp_events[<?php echo $index; ?>][text]" placeholder="Text (z.B. wird 30!)" value="<?php echo esc_attr($event['text'] ?? ''); ?>" style="flex-grow: 1;" />
|
||||
<button type="button" class="button button-secondary fsp-remove-event">Entfernen</button>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<button type="button" id="fsp-add-event" class="button button-primary">+ Neues Ereignis hinzufügen</button>
|
||||
|
||||
<?php submit_button(); ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
jQuery(document).ready(function($) {
|
||||
$("#fsp-add-event").on("click", function() {
|
||||
var index = $("#fsp-events-container .fsp-event-row").length;
|
||||
var newRow = \'<div class="fsp-event-row" style="margin-bottom: 10px; display: flex; gap: 10px; align-items: center;"><input type="text" name="fsp_events[\' + index + \'][name]" placeholder="Name (z.B. Max)" style="width: 200px;" /><input type="text" name="fsp_events[\' + index + \'][date]" placeholder="Datum (TT-MM)" style="width: 100px;" /><input type="text" name="fsp_events[\' + index + \'][text]" placeholder="Text (z.B. wird 30!)" style="flex-grow: 1;" /><button type="button" class="button button-secondary fsp-remove-event">Entfernen</button></div>\';
|
||||
$("#fsp-events-container").append(newRow);
|
||||
});
|
||||
$(document).on("click", ".fsp-remove-event", function() {
|
||||
$(this).closest(".fsp-event-row").remove();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function render_shortcode() {
|
||||
$active_events = $this->get_active_events();
|
||||
if (empty($active_events)) return '';
|
||||
$names = array_map(fn($e) => $e['name'], $active_events);
|
||||
return '<div class="fsp-today">Heute feiern wir: <strong>' . esc_html(implode(' + ', $names)) . '</strong></div>';
|
||||
}
|
||||
|
||||
public function register_widget() {
|
||||
register_widget('FSP_Widget');
|
||||
}
|
||||
|
||||
public function render_music_consent() {
|
||||
if (get_option('fsp_enable_music', 'yes') !== 'yes') {
|
||||
return;
|
||||
}
|
||||
|
||||
$active_events = $this->get_active_events();
|
||||
$has_music = false;
|
||||
foreach ($active_events as $event) {
|
||||
if (in_array('music', $event['effects'] ?? [])) { $has_music = true; break; }
|
||||
}
|
||||
if (!$has_music) return;
|
||||
|
||||
$audio_url = plugin_dir_url(__FILE__) . 'assets/audio/xmas-jingle.mp3';
|
||||
echo '<div id="fsp-music-consent" style="position:fixed;bottom:20px;right:20px;background:#fff;color:#333;padding:20px;border-radius:8px;z-index:99999;box-shadow:0 4px 15px rgba(0,0,0,0.2);display:none;max-width:300px;">
|
||||
<p style="margin:0 0 15px 0;">Weihnachtsmusik abspielen?</p>
|
||||
<button id="fsp-music-yes" style="background:#c0392b;color:#fff;border:none;padding:8px 15px;border-radius:5px;cursor:pointer;margin-right:10px;">Ja</button>
|
||||
<button id="fsp-music-no" style="background:#bdc3c7;color:#333;border:none;padding:8px 15px;border-radius:5px;cursor:pointer;">Nein</button>
|
||||
</div>
|
||||
|
||||
<audio id="fsp-xmas-audio" src="' . $audio_url . '" loop style="display:none;"></audio>
|
||||
|
||||
<script>
|
||||
jQuery(function($) {
|
||||
const consentBox = $("#fsp-music-consent");
|
||||
const audioPlayer = $("#fsp-xmas-audio")[0];
|
||||
|
||||
setTimeout(() => consentBox.fadeIn(500), 2000);
|
||||
|
||||
$("#fsp-music-yes").on("click", function() {
|
||||
const playPromise = audioPlayer.play();
|
||||
|
||||
if (playPromise !== undefined) {
|
||||
playPromise.then(_ => {
|
||||
console.log("FSP: Musik wird abgespielt.");
|
||||
}).catch(error => {
|
||||
console.error("FSP: Autoplay blockiert. Zeige Steuerelemente an.");
|
||||
audioPlayer.style.position = "fixed";
|
||||
audioPlayer.style.bottom = "20px";
|
||||
audioPlayer.style.left = "20px";
|
||||
audioPlayer.style.zIndex = "99999";
|
||||
audioPlayer.style.width = "250px";
|
||||
audioPlayer.style.display = "block";
|
||||
audioPlayer.controls = true;
|
||||
});
|
||||
}
|
||||
consentBox.fadeOut(300);
|
||||
});
|
||||
|
||||
$("#fsp-music-no").on("click", function() {
|
||||
consentBox.fadeOut(300);
|
||||
});
|
||||
});
|
||||
</script>';
|
||||
}
|
||||
}
|
||||
|
||||
class FSP_Widget extends WP_Widget {
|
||||
public function __construct() {
|
||||
parent::__construct('fsp_widget', 'Festive Seasons Anlass', ['description' => 'Zeigt den heutigen festlichen Anlass an.']);
|
||||
}
|
||||
|
||||
public function widget($args, $instance) {
|
||||
global $festive_seasons_pro_instance;
|
||||
if (!$festive_seasons_pro_instance) return;
|
||||
|
||||
$active_events = $festive_seasons_pro_instance->get_active_events();
|
||||
if (empty($active_events)) return;
|
||||
|
||||
$names = array_map(fn($e) => $e['name'], $active_events);
|
||||
echo $args['before_widget'];
|
||||
if (!empty($instance['title'])) {
|
||||
echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title'];
|
||||
}
|
||||
echo '<div style="text-align:center; padding:15px; background:rgba(255,255,255,0.2); border-radius:10px;">' . esc_html(implode(' + ', $names)) . '</div>';
|
||||
echo $args['after_widget'];
|
||||
}
|
||||
|
||||
public function form($instance) {
|
||||
$title = !empty($instance['title']) ? $instance['title'] : 'Heute ist...';
|
||||
?>
|
||||
<p><label for="<?php echo esc_attr($this->get_field_id('title')); ?>">Titel:</label><input class="widefat" id="<?php echo esc_attr($this->get_field_id('title')); ?>" name="<?php echo esc_attr($this->get_field_name('title')); ?>" type="text" value="<?php echo esc_attr($title); ?>"></p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance) {
|
||||
$instance = [];
|
||||
$instance['title'] = (!empty($new_instance['title'])) ? sanitize_text_field($new_instance['title']) : '';
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
|
||||
$festive_seasons_pro_instance = new Festive_Seasons_Pro();
|
||||
Reference in New Issue
Block a user