yoone-snow/yoone-snow.php

567 lines
26 KiB
PHP

<?php
/*
Plugin Name: Yoone Snow
Description: 首页 canvas 雪花效果
Version: 1.5.0
Author: Yoone
*/
if (!defined('ABSPATH')) { exit; }
function yoone_snow_is_enabled() {
return function_exists('is_front_page') ? is_front_page() : false;
}
function yoone_snow_enqueue_assets() {
if (!yoone_snow_is_enabled()) { return; }
$style_handle = 'yoone-snow-style';
$style_src = plugins_url('css/snow.css', __FILE__);
wp_register_style($style_handle, $style_src, array(), '1.1.0', 'all');
wp_enqueue_style($style_handle);
// 注册形状渲染脚本 保证主脚本之前加载
$shape_index_handle = 'yoone-snow-shapes-index';
wp_register_script($shape_index_handle, plugins_url('js/shapes/index.js', __FILE__), array(), '1.1.0', true);
$shape_utils_handle = 'yoone-snow-shapes-utils';
wp_register_script($shape_utils_handle, plugins_url('js/shapes/utils.js', __FILE__), array($shape_index_handle), '1.1.0', true);
$shape_dot_handle = 'yoone-snow-shapes-dot';
wp_register_script($shape_dot_handle, plugins_url('js/shapes/dot.js', __FILE__), array($shape_index_handle), '1.1.0', true);
$shape_flake_handle = 'yoone-snow-shapes-flake';
wp_register_script($shape_flake_handle, plugins_url('js/shapes/flake.js', __FILE__), array($shape_index_handle), '1.1.0', true);
$shape_yuanbao_handle = 'yoone-snow-shapes-yuanbao';
wp_register_script($shape_yuanbao_handle, plugins_url('js/shapes/yuanbao.js', __FILE__), array($shape_index_handle), '1.1.0', true);
$shape_coin_handle = 'yoone-snow-shapes-coin';
wp_register_script($shape_coin_handle, plugins_url('js/shapes/coin.js', __FILE__), array($shape_index_handle), '1.1.0', true);
$shape_santa_handle = 'yoone-snow-shapes-santa-hat';
wp_register_script($shape_santa_handle, plugins_url('js/shapes/santa_hat.js', __FILE__), array($shape_utils_handle), '1.1.0', true);
$shape_cane_handle = 'yoone-snow-shapes-candy-cane';
wp_register_script($shape_cane_handle, plugins_url('js/shapes/candy_cane.js', __FILE__), array($shape_utils_handle), '1.1.0', true);
$shape_sock_handle = 'yoone-snow-shapes-christmas-sock';
wp_register_script($shape_sock_handle, plugins_url('js/shapes/christmas_sock.js', __FILE__), array($shape_utils_handle), '1.1.0', true);
$shape_tree_handle = 'yoone-snow-shapes-christmas-tree';
wp_register_script($shape_tree_handle, plugins_url('js/shapes/christmas_tree.js', __FILE__), array($shape_utils_handle), '1.1.0', true);
$shape_reindeer_handle = 'yoone-snow-shapes-reindeer';
wp_register_script($shape_reindeer_handle, plugins_url('js/shapes/reindeer.js', __FILE__), array($shape_utils_handle), '1.1.0', true);
$shape_berry_handle = 'yoone-snow-shapes-christmas-berry';
wp_register_script($shape_berry_handle, plugins_url('js/shapes/christmas_berry.js', __FILE__), array($shape_utils_handle), '1.1.0', true);
// 注册并加载主脚本 设置依赖确保顺序正确
$script_handle = 'yoone-snow-script';
$script_src = plugins_url('js/snow-canvas.js', __FILE__);
wp_register_script(
$script_handle,
$script_src,
array(
$shape_index_handle,
$shape_dot_handle,
$shape_flake_handle,
$shape_yuanbao_handle,
$shape_coin_handle,
$shape_santa_handle,
$shape_cane_handle,
$shape_sock_handle,
$shape_tree_handle,
$shape_reindeer_handle,
$shape_berry_handle
),
'1.1.0',
true
);
wp_enqueue_script($script_handle);
// 将后端设置传递到前端脚本 变量名称为 YooneSnowSettings
// 简化设置 仅保留复选框选择的形状集合
$mixed_items_option = get_option('yoone_snow_mixed_items', array('dot','flake'));
if (is_string($mixed_items_option)) {
$mixed_items_option = array_filter(array_map('trim', explode(',', $mixed_items_option)));
}
$allowed_shapes = array('dot','flake','yuanbao','coin','santa_hat','candy_cane','christmas_sock','christmas_tree','reindeer','christmas_berry');
$mixed_items_sanitized = array_values(array_unique(array_intersect($mixed_items_option, $allowed_shapes)));
if (empty($mixed_items_sanitized)) { $mixed_items_sanitized = array('dot','flake'); }
// 读取媒体形状集合 并映射为可用的 URL 列表
$media_ids = get_option('yoone_snow_media_items', array());
if (!is_array($media_ids)) { $media_ids = array(); }
$media_urls = array();
$media_weights_option = get_option('yoone_snow_media_weights', array());
if (!is_array($media_weights_option)) { $media_weights_option = array(); }
$media_weights_by_url = array();
foreach ($media_ids as $mid) {
$url = wp_get_attachment_url(intval($mid));
if ($url) {
$media_urls[] = $url;
$w = isset($media_weights_option[intval($mid)]) ? intval($media_weights_option[intval($mid)]) : 1;
if ($w < 0) { $w = 0; }
$media_weights_by_url[$url] = $w;
}
}
$default_weights = 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,
);
$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;
}
// 读取尺寸组合设置 包含最小与最大半径 如未设置则回退到旧选项与默认值
$size_group = get_option('yoone_snow_size', array('min' => 1.0, 'max' => 3.0));
$radius_min_val = isset($size_group['min']) ? floatval($size_group['min']) : floatval(get_option('yoone_snow_radius_min', 1.0));
$radius_max_val = isset($size_group['max']) ? floatval($size_group['max']) : floatval(get_option('yoone_snow_radius_max', 3.0));
if ($radius_min_val < 0) { $radius_min_val = 0.0; }
if ($radius_max_val < $radius_min_val) { $radius_max_val = $radius_min_val; }
wp_localize_script($script_handle, 'YooneSnowSettings', array(
'selectedShapes' => $mixed_items_sanitized,
'mediaItems' => $media_urls,
'displayDurationSeconds' => intval(get_option('yoone_snow_home_duration', 0)),
'radiusMin' => $radius_min_val,
'radiusMax' => $radius_max_val,
'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 '<canvas id="effectiveAppsSnow" aria-hidden="true"></canvas>';
}
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 '<p>Configure snow appearance</p>';
},
'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 '<label style="margin-right:12px;"><input type="checkbox" name="yoone_snow_mixed_items[]" value="' . esc_attr($key) . '" ' . $checked . ' /> ' . esc_html($label) . '</label>';
}
echo '<p class="description">Choose shapes to render</p>';
},
'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 '<div id="yooneSnowMediaList" style="display:flex;flex-wrap:wrap;gap:12px;">';
foreach ($current_media as $attachment_id) {
$url = wp_get_attachment_thumb_url($attachment_id);
if (!$url) { $url = wp_get_attachment_url($attachment_id); }
$safe_id = intval($attachment_id);
$safe_url = esc_url($url);
echo '<div class="yoone-snow-media-item" data-attachment-id="' . $safe_id . '" style="border:1px solid #ddd;padding:8px;display:flex;flex-direction:column;align-items:center;">';
echo '<img src="' . $safe_url . '" alt="media" style="width:72px;height:72px;object-fit:contain;" />';
echo '<input type="hidden" name="yoone_snow_media_items[]" value="' . $safe_id . '" />';
echo '<button type="button" class="button yoone-snow-remove-media" style="margin-top:6px;">Remove</button>';
echo '</div>';
}
echo '</div>';
echo '<p><button type="button" class="button button-primary" id="yooneSnowAddMedia">Add Images</button></p>';
echo '<p class="description">Choose images or SVG from media library to render</p>';
},
'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 '<div id="yooneSnowWeightsContainer" style="margin-top:8px;">';
echo '<div id="yooneSnowShapeWeights" style="display:flex;flex-wrap:wrap;gap:12px;margin-bottom:12px;">';
foreach ($selected_shapes as $sk) {
if (!isset($shape_labels[$sk])) { continue; }
$val = isset($shape_weights_current[$sk]) ? intval($shape_weights_current[$sk]) : 1;
echo '<label data-shape-key="' . esc_attr($sk) . '" style="display:flex;flex-direction:column;min-width:160px;">';
echo '<span>' . esc_html($shape_labels[$sk]) . '</span>';
echo '<input type="number" min="0" name="yoone_snow_shape_weights[' . esc_attr($sk) . ']" value="' . esc_attr($val) . '" style="width:120px;" />';
echo '</label>';
}
echo '</div>';
// 渲染媒体权重 按当前媒体列表生成 输入名称为附件 ID 映射 默认 1
$current_media = get_option('yoone_snow_media_items', array());
if (!is_array($current_media)) { $current_media = array(); }
$media_weights_current = get_option('yoone_snow_media_weights', array());
if (!is_array($media_weights_current)) { $media_weights_current = array(); }
echo '<div id="yooneSnowMediaWeights" style="display:flex;flex-wrap:wrap;gap:12px;">';
foreach ($current_media as $attachment_id) {
$aid = intval($attachment_id);
$label = 'Media ' . $aid;
$val = isset($media_weights_current[$aid]) ? intval($media_weights_current[$aid]) : 1;
echo '<label data-attachment-id="' . esc_attr($aid) . '" style="display:flex;flex-direction:column;min-width:160px;">';
echo '<span>' . esc_html($label) . '</span>';
echo '<input type="number" min="0" name="yoone_snow_media_weights[' . esc_attr($aid) . ']" value="' . esc_attr($val) . '" style="width:120px;" />';
echo '</label>';
}
echo '</div>';
echo '<p class="description">Higher value increases selection probability 0 disables default is 1</p>';
echo '</div>';
// 绑定交互脚本 通过已有 admin 脚本实现动态刷新
},
'yoone_snow',
'yoone_snow_section'
);
// 注册首页显示时长设置 项为整数秒 0 表示无限
register_setting('yoone_snow_options', 'yoone_snow_home_duration', array(
'type' => 'integer',
'sanitize_callback' => function($value) {
// 将输入转换为非负整数 单位为秒 0 表示无限
$num = intval($value);
if ($num < 0) { $num = 0; }
return $num;
},
'default' => 0,
));
// 添加首页显示时长字段 输入为数字最小值为 0
add_settings_field(
'yoone_snow_home_duration',
'Home Display Duration Seconds',
function() {
// 读取当前设置值 并渲染数字输入框
$current = intval(get_option('yoone_snow_home_duration', 0));
echo '<input type="number" min="0" name="yoone_snow_home_duration" value="' . esc_attr($current) . '" style="width:120px;" />';
echo '<p class="description">Duration in seconds for snow on home 0 means infinite</p>';
},
'yoone_snow',
'yoone_snow_section'
);
// 尺寸组合设置 使用单一选项 snow size 存储最小与最大半径
register_setting('yoone_snow_options', 'yoone_snow_size', array(
'type' => 'array',
'sanitize_callback' => function($value) {
// 将输入统一为包含 min 与 max 的数值数组 并保证非负与 max 不小于 min
if (!is_array($value)) { $value = array(); }
$min = isset($value['min']) ? floatval($value['min']) : 1.0;
$max = isset($value['max']) ? floatval($value['max']) : 3.0;
if ($min < 0) { $min = 0.0; }
if ($max < $min) { $max = $min; }
return array('min' => $min, 'max' => $max);
},
'default' => array('min' => 1.0, 'max' => 3.0),
));
add_settings_field(
'yoone_snow_size',
'Snow Size',
function() {
// 渲染组合输入 使用同一选项保存最小与最大半径
$grp = get_option('yoone_snow_size', array('min' => 1.0, 'max' => 3.0));
$min = isset($grp['min']) ? floatval($grp['min']) : 1.0;
$max = isset($grp['max']) ? floatval($grp['max']) : 3.0;
echo '<label style="margin-right:12px;">Min <input type="number" min="0" step="0.1" name="yoone_snow_size[min]" value="' . esc_attr($min) . '" style="width:120px;" /></label>';
echo '<label>Max <input type="number" min="0" step="0.1" name="yoone_snow_size[max]" value="' . esc_attr($max) . '" style="width:120px;" /></label>';
echo '<p class="description">Random radius in [min max] single option</p>';
},
'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 '<label style="margin-right:12px;">Min <input type="number" min="0" step="0.1" name="yoone_snow_drift_min" value="' . esc_attr($min) . '" style="width:120px;" /></label>';
echo '<label>Max <input type="number" min="0" step="0.1" name="yoone_snow_drift_max" value="' . esc_attr($max) . '" style="width:120px;" /></label>';
echo '<p class="description">Random vertical drift speed base in [min max]</p>';
},
'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 '<label style="margin-right:12px;">Min <input type="number" min="0" step="0.1" name="yoone_snow_swing_min" value="' . esc_attr($min) . '" style="width:120px;" /></label>';
echo '<label>Max <input type="number" min="0" step="0.1" name="yoone_snow_swing_max" value="' . esc_attr($max) . '" style="width:120px;" /></label>';
echo '<p class="description">Random horizontal swing amplitude base in [min max] before offset scale</p>';
},
'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 '<div class="wrap">';
echo '<h1>Yoone Snow</h1>';
echo '<form method="post" action="options.php">';
settings_fields('yoone_snow_options');
do_settings_sections('yoone_snow');
submit_button();
echo '</form>';
echo '</div>';
}
);
}
// 在 admin 初始化时注册设置 在 admin 菜单挂载页面
add_action('admin_init', 'yoone_snow_register_settings');
add_action('admin_menu', 'yoone_snow_add_settings_page');
add_action('admin_enqueue_scripts', 'yoone_snow_admin_enqueue');
// 在插件列表行添加 Settings 链接 指向设置页面
function yoone_snow_plugin_action_links($links) {
// 构造设置页面链接 使用 admin_url 保证后台路径正确
$settingsUrl = admin_url('options-general.php?page=yoone_snow');
$settingsLink = '<a href="' . esc_url($settingsUrl) . '">Settings</a>';
// 将设置链接插入到最前面 便于用户点击
array_unshift($links, $settingsLink);
return $links;
}
// 绑定到当前插件的 action links 钩子 使用 plugin_basename 计算插件标识
add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'yoone_snow_plugin_action_links');