1, 'flake' => 4, 'yuanbao' => 1, 'coin' => 1, 'santa_hat' => 1, 'candy_cane' => 1, 'christmas_sock' => 1, 'christmas_tree' => 1, 'reindeer' => 1, 'christmas_berry' => 1, ); $saved_weights = get_option('yoone_snow_shape_weights', $default_weights); if (!is_array($saved_weights)) { $saved_weights = array(); } $shape_weights = array(); foreach ($default_weights as $k => $v) { $val = isset($saved_weights[$k]) ? intval($saved_weights[$k]) : intval($v); if ($val < 0) { $val = 0; } $shape_weights[$k] = $val; } wp_localize_script($script_handle, 'YooneSnowSettings', array( 'selectedShapes' => $mixed_items_sanitized, 'mediaItems' => $media_urls, 'displayDurationSeconds' => intval(get_option('yoone_snow_home_duration', 0)), 'sizeScale' => floatval(get_option('yoone_snow_size_scale', 1.0)), 'offsetScale' => floatval(get_option('yoone_snow_offset_scale', 1.0)), 'radiusMin' => floatval(get_option('yoone_snow_radius_min', 1.0)), 'radiusMax' => floatval(get_option('yoone_snow_radius_max', 3.0)), 'driftMin' => floatval(get_option('yoone_snow_drift_min', 0.4)), 'driftMax' => floatval(get_option('yoone_snow_drift_max', 1.0)), 'swingMin' => floatval(get_option('yoone_snow_swing_min', 0.2)), 'swingMax' => floatval(get_option('yoone_snow_swing_max', 1.0)), 'assetsMap' => array( 'santa_hat' => plugins_url('assets/圣诞雪帽.svg', __FILE__), 'candy_cane' => plugins_url('assets/圣诞拐杖.svg', __FILE__), 'christmas_sock' => plugins_url('assets/圣诞袜子.svg', __FILE__), 'christmas_tree' => plugins_url('assets/圣诞树.svg', __FILE__), 'reindeer' => plugins_url('assets/圣诞麋鹿.svg', __FILE__), 'christmas_berry' => plugins_url('assets/圣诞果.svg', __FILE__), ), 'shapeWeights' => $shape_weights, 'mediaWeights' => $media_weights_by_url, )); } // 在后台设置页面加载媒体库脚本和交互脚本 用于选择 SVG 或图片 function yoone_snow_admin_enqueue($hook) { // 条件判断 仅在插件设置页面加载脚本 保持性能 if ($hook !== 'settings_page_yoone_snow') { return; } // 加载媒体库脚本 以便使用 wp.media 选择器 wp_enqueue_media(); // 注册并加载后台交互脚本 $admin_script_handle = 'yoone-snow-admin-media'; wp_register_script($admin_script_handle, plugins_url('js/admin-media.js', __FILE__), array(), '1.1.0', true); wp_enqueue_script($admin_script_handle); } function yoone_snow_render_overlay() { if (!yoone_snow_is_enabled()) { return; } static $yoone_snow_rendered = false; if ($yoone_snow_rendered) { return; } $yoone_snow_rendered = true; echo ''; } add_action('wp_enqueue_scripts', 'yoone_snow_enqueue_assets'); add_action('wp_body_open', 'yoone_snow_render_overlay'); add_action('wp_footer', 'yoone_snow_render_overlay', 100); // 注册设置页面和设置项 用于选择雪花形状 function yoone_snow_register_settings() { // 移除形状下拉选项 仅保留复选集合设置 // 注册 mixed 形状集合设置项 默认包含 dot 和 flake register_setting('yoone_snow_options', 'yoone_snow_mixed_items', array( 'type' => 'array', 'sanitize_callback' => function($value) { // 将输入统一为数组 并过滤到允许的集合 $allowed = array('dot','flake','yuanbao','coin','santa_hat','candy_cane','christmas_sock','christmas_tree','reindeer','christmas_berry'); if (is_string($value)) { $value = array_filter(array_map('trim', explode(',', $value))); } if (!is_array($value)) { $value = array('dot','flake'); } $filtered = array_values(array_unique(array_intersect($value, $allowed))); return !empty($filtered) ? $filtered : array('dot','flake'); }, 'default' => array('dot','flake'), )); // 添加设置分区 标题为 Snow Settings add_settings_section( 'yoone_snow_section', 'Snow Settings', function() { // 输出分区描述 使用英文标点保证兼容 echo '
Configure snow appearance
'; }, 'yoone_snow' ); // 移除下拉字段 保留复选框作为唯一选择入口 // 添加形状复选集合 用于选择参与渲染的形状 add_settings_field( 'yoone_snow_mixed_items', 'Shapes', function() { $current_list = get_option('yoone_snow_mixed_items', array('dot','flake')); if (is_string($current_list)) { $current_list = array_filter(array_map('trim', explode(',', $current_list))); } $options = array( 'dot' => 'Dot', 'flake' => 'Snowflake', 'yuanbao' => 'Yuanbao', 'coin' => 'Coin', 'santa_hat' => 'Santa Hat', 'candy_cane' => 'Candy Cane', 'christmas_sock' => 'Christmas Sock', 'christmas_tree' => 'Christmas Tree', 'reindeer' => 'Reindeer', 'christmas_berry' => 'Christmas Berry', ); foreach ($options as $key => $label) { $checked = in_array($key, $current_list, true) ? 'checked' : ''; echo ''; } echo 'Choose shapes to render
'; }, 'yoone_snow', 'yoone_snow_section' ); register_setting('yoone_snow_options', 'yoone_snow_shape_weights', array( 'type' => 'array', 'sanitize_callback' => function($value) { $allowed = array('dot','flake','yuanbao','coin','santa_hat','candy_cane','christmas_sock','christmas_tree','reindeer','christmas_berry'); $defaults = array( 'dot' => 1, 'flake' => 4, 'yuanbao' => 1, 'coin' => 1, 'santa_hat' => 1, 'candy_cane' => 1, 'christmas_sock' => 1, 'christmas_tree' => 1, 'reindeer' => 1, 'christmas_berry' => 1, ); if (!is_array($value)) { $value = array(); } $clean = array(); foreach ($allowed as $key) { $num = isset($value[$key]) ? intval($value[$key]) : (isset($defaults[$key]) ? intval($defaults[$key]) : 1); if ($num < 0) { $num = 0; } $clean[$key] = $num; } return $clean; }, 'default' => array( 'dot' => 1, 'flake' => 4, 'yuanbao' => 1, 'coin' => 1, 'santa_hat' => 1, 'candy_cane' => 1, 'christmas_sock' => 1, 'christmas_tree' => 1, 'reindeer' => 1, 'christmas_berry' => 1, ), )); // 形状权重字段将移动到媒体形状字段之后 以满足界面顺序需求 // 注册媒体形状集合 设置项保存为附件 ID 数组 register_setting('yoone_snow_options', 'yoone_snow_media_items', array( 'type' => 'array', 'sanitize_callback' => function($value) { // 将输入统一为整数 ID 数组 并过滤无效值 if (is_string($value)) { $value = array_filter(array_map('trim', explode(',', $value))); } if (!is_array($value)) { $value = array(); } $ids = array(); foreach ($value as $item) { $id = intval($item); if ($id > 0) { $ids[] = $id; } } return array_values(array_unique($ids)); }, 'default' => array(), )); // 添加媒体形状选择字段 支持从媒体库选择图片或 SVG add_settings_field( 'yoone_snow_media_items', 'Media Shapes', function() { // 读取当前已选择的附件 ID 列表 并渲染缩略图列表与添加按钮 $current_media = get_option('yoone_snow_media_items', array()); if (!is_array($current_media)) { $current_media = array(); } echo 'Choose images or SVG from media library to render
'; }, 'yoone_snow', 'yoone_snow_section' ); // 注册媒体权重设置项 将附件 ID 映射到权重数值 默认 1 register_setting('yoone_snow_options', 'yoone_snow_media_weights', array( 'type' => 'array', 'sanitize_callback' => function($value) { // 将输入统一为附件 ID 到非负整数权重的映射 if (!is_array($value)) { $value = array(); } $clean = array(); foreach ($value as $id => $num) { $aid = intval($id); $weight = intval($num); if ($aid > 0) { if ($weight < 0) { $weight = 0; } $clean[$aid] = $weight; } } return $clean; }, 'default' => array(), )); // 在媒体形状字段之后渲染权重字段 包含形状权重与媒体权重 add_settings_field( 'yoone_snow_weights_combined', 'Weights', function() { // 渲染形状权重 输入仅显示已勾选的形状 默认 1 $selected_shapes = get_option('yoone_snow_mixed_items', array('dot','flake')); if (is_string($selected_shapes)) { $selected_shapes = array_filter(array_map('trim', explode(',', $selected_shapes))); } if (!is_array($selected_shapes)) { $selected_shapes = array('dot','flake'); } $shape_labels = array( 'dot' => 'Dot', 'flake' => 'Snowflake', 'yuanbao' => 'Yuanbao', 'coin' => 'Coin', 'santa_hat' => 'Santa Hat', 'candy_cane' => 'Candy Cane', 'christmas_sock' => 'Christmas Sock', 'christmas_tree' => 'Christmas Tree', 'reindeer' => 'Reindeer', 'christmas_berry' => 'Christmas Berry', ); $shape_weights_current = get_option('yoone_snow_shape_weights', array()); if (!is_array($shape_weights_current)) { $shape_weights_current = array(); } echo 'Higher value increases selection probability 0 disables default is 1
'; echo 'Duration in seconds for snow on home 0 means infinite
'; }, 'yoone_snow', 'yoone_snow_section' ); register_setting('yoone_snow_options', 'yoone_snow_size_scale', array( 'type' => 'number', 'sanitize_callback' => function($value) { $num = floatval($value); if ($num < 0.1) { $num = 0.1; } return $num; }, 'default' => 1.0, )); add_settings_field( 'yoone_snow_size_scale', 'Snow Size Scale', function() { $current = floatval(get_option('yoone_snow_size_scale', 1.0)); echo ''; echo 'Multiply snowflake radius default is 1.0
'; }, 'yoone_snow', 'yoone_snow_section' ); register_setting('yoone_snow_options', 'yoone_snow_offset_scale', array( 'type' => 'number', 'sanitize_callback' => function($value) { $num = floatval($value); if ($num < 0) { $num = 0; } return $num; }, 'default' => 1.0, )); add_settings_field( 'yoone_snow_offset_scale', 'Snow Horizontal Offset Scale', function() { $current = floatval(get_option('yoone_snow_offset_scale', 1.0)); echo ''; echo 'Multiply horizontal swing amplitude default is 1.0
'; }, 'yoone_snow', 'yoone_snow_section' ); // 随机范围设置 注册与字段渲染 包含半径 漂移速度 摆动幅度的最小与最大 register_setting('yoone_snow_options', 'yoone_snow_radius_min', array( 'type' => 'number', 'sanitize_callback' => function($value) { $num = floatval($value); if ($num < 0) { $num = 0; } return $num; }, 'default' => 1.0, )); register_setting('yoone_snow_options', 'yoone_snow_radius_max', array( 'type' => 'number', 'sanitize_callback' => function($value) { $min = floatval(get_option('yoone_snow_radius_min', 1.0)); $num = floatval($value); if ($num < $min) { $num = $min; } return $num; }, 'default' => 3.0, )); add_settings_field( 'yoone_snow_radius_range', 'Radius Random Range', function() { $min = floatval(get_option('yoone_snow_radius_min', 1.0)); $max = floatval(get_option('yoone_snow_radius_max', 3.0)); echo ''; echo ''; echo 'Random radius in [min max] before size scale
'; }, 'yoone_snow', 'yoone_snow_section' ); register_setting('yoone_snow_options', 'yoone_snow_drift_min', array( 'type' => 'number', 'sanitize_callback' => function($value) { $num = floatval($value); if ($num < 0) { $num = 0; } return $num; }, 'default' => 0.4, )); register_setting('yoone_snow_options', 'yoone_snow_drift_max', array( 'type' => 'number', 'sanitize_callback' => function($value) { $min = floatval(get_option('yoone_snow_drift_min', 0.4)); $num = floatval($value); if ($num < $min) { $num = $min; } return $num; }, 'default' => 1.0, )); add_settings_field( 'yoone_snow_drift_range', 'Drift Speed Random Range', function() { $min = floatval(get_option('yoone_snow_drift_min', 0.4)); $max = floatval(get_option('yoone_snow_drift_max', 1.0)); echo ''; echo ''; echo 'Random vertical drift speed base in [min max]
'; }, 'yoone_snow', 'yoone_snow_section' ); register_setting('yoone_snow_options', 'yoone_snow_swing_min', array( 'type' => 'number', 'sanitize_callback' => function($value) { $num = floatval($value); if ($num < 0) { $num = 0; } return $num; }, 'default' => 0.2, )); register_setting('yoone_snow_options', 'yoone_snow_swing_max', array( 'type' => 'number', 'sanitize_callback' => function($value) { $min = floatval(get_option('yoone_snow_swing_min', 0.2)); $num = floatval($value); if ($num < $min) { $num = $min; } return $num; }, 'default' => 1.0, )); add_settings_field( 'yoone_snow_swing_range', 'Swing Amplitude Random Range', function() { $min = floatval(get_option('yoone_snow_swing_min', 0.2)); $max = floatval(get_option('yoone_snow_swing_max', 1.0)); echo ''; echo ''; echo 'Random horizontal swing amplitude base in [min max] before offset scale
'; }, 'yoone_snow', 'yoone_snow_section' ); } // 添加设置页面到后台菜单 条目在设置菜单下 function yoone_snow_add_settings_page() { add_options_page( 'Yoone Snow', 'Yoone Snow', 'manage_options', 'yoone_snow', function() { // 渲染设置页面 表单提交到 options.php echo '