feat(雪花效果): 新增多种圣诞主题雪花形状和媒体选择功能
新增了多种圣诞主题的雪花形状渲染函数,包括硬币、麋鹿、圣诞帽等 添加了媒体选择功能,支持上传图片作为雪花形状 重构了雪花渲染逻辑,使用全局注册表管理形状渲染函数 更新了.gitignore文件,添加release目录忽略 新增了媒体管理相关的JavaScript文件和SVG资源文件
This commit is contained in:
parent
a95b3e2362
commit
1415a37dcb
|
|
@ -1 +1,2 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
release
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 8.2 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 12 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 10 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 12 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.9 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 11 KiB |
|
|
@ -0,0 +1,74 @@
|
||||||
|
(function(){
|
||||||
|
// 后台媒体选择交互脚本 用于在设置页选择媒体项目
|
||||||
|
function initAdminMedia(){
|
||||||
|
// 条件判断 如果没有媒体按钮则不执行
|
||||||
|
var addButton = document.getElementById('yooneSnowAddMedia');
|
||||||
|
var listContainer = document.getElementById('yooneSnowMediaList');
|
||||||
|
if (!addButton || !listContainer) { return; }
|
||||||
|
|
||||||
|
// 绑定移除按钮事件 使用事件委托处理动态元素
|
||||||
|
listContainer.addEventListener('click', function(event){
|
||||||
|
// 条件判断 如果点击的是移除按钮则执行删除
|
||||||
|
var target = event.target;
|
||||||
|
if (target && target.classList.contains('yoone-snow-remove-media')){
|
||||||
|
var item = target.closest('.yoone-snow-media-item');
|
||||||
|
if (item) { item.remove(); }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 打开媒体选择器 支持多选 图片和 SVG
|
||||||
|
addButton.addEventListener('click', function(){
|
||||||
|
// 条件判断 如果 wp.media 不可用则终止
|
||||||
|
if (typeof wp === 'undefined' || !wp.media) { return; }
|
||||||
|
var frame = wp.media({
|
||||||
|
title: 'Select images or SVG',
|
||||||
|
multiple: true,
|
||||||
|
library: { type: [ 'image', 'image/svg+xml' ] }
|
||||||
|
});
|
||||||
|
frame.on('select', function(){
|
||||||
|
var selection = frame.state().get('selection');
|
||||||
|
selection.each(function(attachment){
|
||||||
|
var data = attachment.toJSON();
|
||||||
|
var id = data.id;
|
||||||
|
var url = data.sizes && data.sizes.thumbnail ? data.sizes.thumbnail.url : data.url;
|
||||||
|
// 创建预览项与隐藏输入 保存附件 ID
|
||||||
|
var wrapper = document.createElement('div');
|
||||||
|
wrapper.className = 'yoone-snow-media-item';
|
||||||
|
wrapper.setAttribute('data-attachment-id', String(id));
|
||||||
|
wrapper.style.border = '1px solid #ddd';
|
||||||
|
wrapper.style.padding = '8px';
|
||||||
|
wrapper.style.display = 'flex';
|
||||||
|
wrapper.style.flexDirection = 'column';
|
||||||
|
wrapper.style.alignItems = 'center';
|
||||||
|
var img = document.createElement('img');
|
||||||
|
img.src = url;
|
||||||
|
img.alt = 'media';
|
||||||
|
img.style.width = '72px';
|
||||||
|
img.style.height = '72px';
|
||||||
|
img.style.objectFit = 'contain';
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.type = 'hidden';
|
||||||
|
input.name = 'yoone_snow_media_items[]';
|
||||||
|
input.value = String(id);
|
||||||
|
var removeBtn = document.createElement('button');
|
||||||
|
removeBtn.type = 'button';
|
||||||
|
removeBtn.className = 'button yoone-snow-remove-media';
|
||||||
|
removeBtn.textContent = 'Remove';
|
||||||
|
removeBtn.style.marginTop = '6px';
|
||||||
|
wrapper.appendChild(img);
|
||||||
|
wrapper.appendChild(input);
|
||||||
|
wrapper.appendChild(removeBtn);
|
||||||
|
listContainer.appendChild(wrapper);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
frame.open();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 条件判断 如果文档尚未加载则等待 DOMContentLoaded 事件
|
||||||
|
if (document.readyState === 'loading'){
|
||||||
|
document.addEventListener('DOMContentLoaded', initAdminMedia);
|
||||||
|
} else {
|
||||||
|
initAdminMedia();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
(function(){
|
||||||
|
// 注册圣诞拐杖形状渲染函数 使用 SVG 图像参考
|
||||||
|
window.YooneSnowShapeRenderers = window.YooneSnowShapeRenderers || {};
|
||||||
|
window.YooneSnowShapeRenderers.candy_cane = function(context, positionX, positionY, baseSize){
|
||||||
|
// 从设置中获取资源 URL 并加载图像 使用缓存避免重复加载
|
||||||
|
const assets = (window.YooneSnowSettings && window.YooneSnowSettings.assetsMap) ? window.YooneSnowSettings.assetsMap : {};
|
||||||
|
const url = assets['candy_cane'];
|
||||||
|
const record = window.YooneSnowGetOrLoadImage ? window.YooneSnowGetOrLoadImage(url) : { img: null, ready: false };
|
||||||
|
// 条件判断 如果图像尚未准备则跳过本次绘制
|
||||||
|
if (!record || !record.ready){ return; }
|
||||||
|
const targetHeight = baseSize * 9; // 目标高度基于基础尺寸缩放
|
||||||
|
const targetWidth = targetHeight * 0.6; // 拐杖较瘦 调整宽高比
|
||||||
|
window.YooneSnowDrawCenteredImage(context, record.img, positionX, positionY, targetWidth, targetHeight);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
(function(){
|
||||||
|
// 注册圣诞果形状渲染函数 使用 SVG 图像参考
|
||||||
|
window.YooneSnowShapeRenderers = window.YooneSnowShapeRenderers || {};
|
||||||
|
window.YooneSnowShapeRenderers.christmas_berry = function(context, positionX, positionY, baseSize){
|
||||||
|
// 从设置中获取资源 URL 并加载图像 使用缓存避免重复加载
|
||||||
|
const assets = (window.YooneSnowSettings && window.YooneSnowSettings.assetsMap) ? window.YooneSnowSettings.assetsMap : {};
|
||||||
|
const url = assets['christmas_berry'];
|
||||||
|
const record = window.YooneSnowGetOrLoadImage ? window.YooneSnowGetOrLoadImage(url) : { img: null, ready: false };
|
||||||
|
// 条件判断 如果图像尚未准备则跳过本次绘制
|
||||||
|
if (!record || !record.ready){ return; }
|
||||||
|
const targetHeight = baseSize * 6.5; // 圣诞果较小 调低高度
|
||||||
|
const targetWidth = targetHeight; // 使用方形比例
|
||||||
|
window.YooneSnowDrawCenteredImage(context, record.img, positionX, positionY, targetWidth, targetHeight);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
(function(){
|
||||||
|
// 注册圣诞袜形状渲染函数 使用 SVG 图像参考
|
||||||
|
window.YooneSnowShapeRenderers = window.YooneSnowShapeRenderers || {};
|
||||||
|
window.YooneSnowShapeRenderers.christmas_sock = function(context, positionX, positionY, baseSize){
|
||||||
|
// 从设置中获取资源 URL 并加载图像 使用缓存避免重复加载
|
||||||
|
const assets = (window.YooneSnowSettings && window.YooneSnowSettings.assetsMap) ? window.YooneSnowSettings.assetsMap : {};
|
||||||
|
const url = assets['christmas_sock'];
|
||||||
|
const record = window.YooneSnowGetOrLoadImage ? window.YooneSnowGetOrLoadImage(url) : { img: null, ready: false };
|
||||||
|
// 条件判断 如果图像尚未准备则跳过本次绘制
|
||||||
|
if (!record || !record.ready){ return; }
|
||||||
|
const targetHeight = baseSize * 8; // 目标高度基于基础尺寸缩放
|
||||||
|
const targetWidth = targetHeight * 0.8; // 袜子稍宽 调整宽高比
|
||||||
|
window.YooneSnowDrawCenteredImage(context, record.img, positionX, positionY, targetWidth, targetHeight);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
(function(){
|
||||||
|
// 注册圣诞树形状渲染函数 使用 SVG 图像参考
|
||||||
|
window.YooneSnowShapeRenderers = window.YooneSnowShapeRenderers || {};
|
||||||
|
window.YooneSnowShapeRenderers.christmas_tree = function(context, positionX, positionY, baseSize){
|
||||||
|
// 从设置中获取资源 URL 并加载图像 使用缓存避免重复加载
|
||||||
|
const assets = (window.YooneSnowSettings && window.YooneSnowSettings.assetsMap) ? window.YooneSnowSettings.assetsMap : {};
|
||||||
|
const url = assets['christmas_tree'];
|
||||||
|
const record = window.YooneSnowGetOrLoadImage ? window.YooneSnowGetOrLoadImage(url) : { img: null, ready: false };
|
||||||
|
// 条件判断 如果图像尚未准备则跳过本次绘制
|
||||||
|
if (!record || !record.ready){ return; }
|
||||||
|
const targetHeight = baseSize * 9; // 圣诞树较高 使用更大高度
|
||||||
|
const targetWidth = targetHeight * 0.8; // 按比例缩放保证不太宽
|
||||||
|
window.YooneSnowDrawCenteredImage(context, record.img, positionX, positionY, targetWidth, targetHeight);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
(function(){
|
||||||
|
// 注册铜钱形状渲染函数 外圆加中间正方形孔
|
||||||
|
window.YooneSnowShapeRenderers = window.YooneSnowShapeRenderers || {};
|
||||||
|
window.YooneSnowShapeRenderers.coin = function(context, positionX, positionY, baseSize){
|
||||||
|
// 函数用于绘制铜钱形状 使用合成模式扣出孔
|
||||||
|
const outerRadius = baseSize * 3; // 将基础尺寸放大为外圆半径
|
||||||
|
context.save();
|
||||||
|
context.beginPath();
|
||||||
|
context.fillStyle = '#FFD700';
|
||||||
|
context.arc(positionX, positionY, outerRadius, 0, Math.PI * 2);
|
||||||
|
context.fill();
|
||||||
|
const holeSize = outerRadius * 0.6; // 正方形孔边长基于外圆半径
|
||||||
|
context.globalCompositeOperation = 'destination-out';
|
||||||
|
context.beginPath();
|
||||||
|
context.rect(
|
||||||
|
positionX - holeSize / 2,
|
||||||
|
positionY - holeSize / 2,
|
||||||
|
holeSize,
|
||||||
|
holeSize
|
||||||
|
);
|
||||||
|
context.fill();
|
||||||
|
context.restore();
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
(function(){
|
||||||
|
// 注册 dot 形状渲染函数 使用填充圆形作为雪花
|
||||||
|
window.YooneSnowShapeRenderers = window.YooneSnowShapeRenderers || {};
|
||||||
|
window.YooneSnowShapeRenderers.dot = function(context, positionX, positionY, baseSize){
|
||||||
|
// 函数用于在指定位置绘制圆点形状 雪花颜色为白色
|
||||||
|
const finalRadius = baseSize; // 使用基础半径作为圆点大小
|
||||||
|
context.beginPath();
|
||||||
|
context.arc(positionX, positionY, finalRadius, 0, Math.PI * 2);
|
||||||
|
context.fillStyle = 'rgba(255,255,255,0.9)';
|
||||||
|
context.fill();
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
(function(){
|
||||||
|
// 注册雪花形状渲染函数 恢复为原始六角雪花绘制样式
|
||||||
|
window.YooneSnowShapeRenderers = window.YooneSnowShapeRenderers || {};
|
||||||
|
window.YooneSnowShapeRenderers.flake = function(context, positionX, positionY, baseSize){
|
||||||
|
// 将基础尺寸转换为原始函数中的 size 参数 以保持形状大小一致
|
||||||
|
const branchSize = baseSize * 3;
|
||||||
|
context.save();
|
||||||
|
context.translate(positionX, positionY);
|
||||||
|
context.fillStyle = 'rgba(255,255,255,0.9)';
|
||||||
|
context.strokeStyle = 'rgba(255,255,255,0.9)';
|
||||||
|
context.lineWidth = branchSize * 0.15;
|
||||||
|
// 循环绘制六个分支 每次旋转 60 度
|
||||||
|
for (let branchIndex = 0; branchIndex < 6; branchIndex++) {
|
||||||
|
context.rotate(Math.PI / 3);
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(0, 0);
|
||||||
|
context.lineTo(0, branchSize);
|
||||||
|
context.stroke();
|
||||||
|
// 在主分支上绘制三个小分叉 保持与原始实现一致
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(0, branchSize * 0.3);
|
||||||
|
context.lineTo(branchSize * 0.3, branchSize * 0.5);
|
||||||
|
context.stroke();
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(0, branchSize * 0.5);
|
||||||
|
context.lineTo(-branchSize * 0.3, branchSize * 0.7);
|
||||||
|
context.stroke();
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(0, branchSize * 0.7);
|
||||||
|
context.lineTo(branchSize * 0.3, branchSize * 0.9);
|
||||||
|
context.stroke();
|
||||||
|
}
|
||||||
|
context.restore();
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
(function(){
|
||||||
|
// 初始化全局渲染注册表 用于统一管理形状渲染函数
|
||||||
|
if (!window.YooneSnowShapeRenderers) {
|
||||||
|
// 条件判断 如果不存在则创建空对象
|
||||||
|
window.YooneSnowShapeRenderers = {};
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
(function(){
|
||||||
|
// 注册麋鹿形状渲染函数 使用 SVG 图像参考
|
||||||
|
window.YooneSnowShapeRenderers = window.YooneSnowShapeRenderers || {};
|
||||||
|
window.YooneSnowShapeRenderers.reindeer = function(context, positionX, positionY, baseSize){
|
||||||
|
// 从设置中获取资源 URL 并加载图像 使用缓存避免重复加载
|
||||||
|
const assets = (window.YooneSnowSettings && window.YooneSnowSettings.assetsMap) ? window.YooneSnowSettings.assetsMap : {};
|
||||||
|
const url = assets['reindeer'];
|
||||||
|
const record = window.YooneSnowGetOrLoadImage ? window.YooneSnowGetOrLoadImage(url) : { img: null, ready: false };
|
||||||
|
// 条件判断 如果图像尚未准备则跳过本次绘制
|
||||||
|
if (!record || !record.ready){ return; }
|
||||||
|
const targetHeight = baseSize * 8.5; // 麋鹿高度设置略大
|
||||||
|
const targetWidth = targetHeight; // 使用接近方形的比例
|
||||||
|
window.YooneSnowDrawCenteredImage(context, record.img, positionX, positionY, targetWidth, targetHeight);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
(function(){
|
||||||
|
// 注册圣诞帽形状渲染函数 使用 SVG 图像参考
|
||||||
|
window.YooneSnowShapeRenderers = window.YooneSnowShapeRenderers || {};
|
||||||
|
window.YooneSnowShapeRenderers.santa_hat = function(context, positionX, positionY, baseSize){
|
||||||
|
// 从设置中获取资源 URL 并加载图像 使用缓存避免重复加载
|
||||||
|
const assets = (window.YooneSnowSettings && window.YooneSnowSettings.assetsMap) ? window.YooneSnowSettings.assetsMap : {};
|
||||||
|
const url = assets['santa_hat'];
|
||||||
|
const record = window.YooneSnowGetOrLoadImage ? window.YooneSnowGetOrLoadImage(url) : { img: null, ready: false };
|
||||||
|
// 条件判断 如果图像尚未准备则跳过本次绘制
|
||||||
|
if (!record || !record.ready){ return; }
|
||||||
|
const targetHeight = baseSize * 8; // 目标高度基于基础尺寸缩放
|
||||||
|
const targetWidth = targetHeight; // 按方形比例绘制 保持居中
|
||||||
|
window.YooneSnowDrawCenteredImage(context, record.img, positionX, positionY, targetWidth, targetHeight);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
(function(){
|
||||||
|
// 全局图像缓存对象 存放已加载的图像资源
|
||||||
|
window.YooneSnowImageCache = window.YooneSnowImageCache || {};
|
||||||
|
|
||||||
|
// 获取或加载图像 根据 URL 返回图像对象和加载状态
|
||||||
|
window.YooneSnowGetOrLoadImage = function(imageUrl){
|
||||||
|
// 条件判断 如果未提供 URL 则返回空
|
||||||
|
if (!imageUrl || typeof imageUrl !== 'string'){
|
||||||
|
return { img: null, ready: false };
|
||||||
|
}
|
||||||
|
const existing = window.YooneSnowImageCache[imageUrl];
|
||||||
|
// 条件判断 如果已存在缓存则直接返回
|
||||||
|
if (existing && existing.ready){
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
if (existing && !existing.ready){
|
||||||
|
// 条件判断 如果正在加载则返回当前状态
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
// 创建新的图像对象 并开始加载
|
||||||
|
const img = new Image();
|
||||||
|
const record = { img: img, ready: false };
|
||||||
|
window.YooneSnowImageCache[imageUrl] = record;
|
||||||
|
img.onload = function(){
|
||||||
|
// 加载成功 标记为可用
|
||||||
|
record.ready = true;
|
||||||
|
};
|
||||||
|
img.onerror = function(){
|
||||||
|
// 加载失败 从缓存移除避免重复错误
|
||||||
|
delete window.YooneSnowImageCache[imageUrl];
|
||||||
|
};
|
||||||
|
img.src = imageUrl;
|
||||||
|
return record;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 居中绘制图像 根据目标中心点和宽高进行缩放绘制
|
||||||
|
window.YooneSnowDrawCenteredImage = function(context, img, centerX, centerY, width, height){
|
||||||
|
// 条件判断 如果图像不存在则不绘制
|
||||||
|
if (!img) { return; }
|
||||||
|
const drawX = centerX - width / 2;
|
||||||
|
const drawY = centerY - height / 2;
|
||||||
|
context.drawImage(img, drawX, drawY, width, height);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
(function(){
|
||||||
|
// 注册元宝形状渲染函数 使用 SVG 路径或贝塞尔曲线近似
|
||||||
|
window.YooneSnowShapeRenderers = window.YooneSnowShapeRenderers || {};
|
||||||
|
const outerPath = (typeof Path2D !== 'undefined') ? new Path2D('M947.4 326.8l0.4-0.1H804.2C814 346 819 364.4 819 381.5c0 18.6-6 46.5-34.3 73.8-17.4 16.7-41.1 31.2-70.5 43.2-54.7 22.1-126.5 34.4-202.3 34.4s-147.6-12.2-202.3-34.4c-29.4-12-53.1-26.5-70.5-43.2-28.3-27.2-34.3-55.2-34.3-73.8 0-17.2 4.9-35.5 14.4-54.8h-150c-29.3 0-53.1 27.1-53.1 60.6C46 634.4 256.5 826 511.7 826c258.1 0 470.3-195.7 496.4-447-0.7-29-27.6-52.2-60.7-52.2z') : null;
|
||||||
|
const topPath = (typeof Path2D !== 'undefined') ? new Path2D('M512 488.4c144.7 0 262.7-47.4 262.7-107.1 0-57.7-118-183.2-262.7-183.2S249.3 321.7 249.3 381.4c0 59.7 118 107 262.7 107z') : null;
|
||||||
|
window.YooneSnowShapeRenderers.yuanbao = function(context, positionX, positionY, baseSize){
|
||||||
|
// 函数用于绘制元宝形状 根据基础尺寸进行缩放
|
||||||
|
if (outerPath && topPath){
|
||||||
|
// 条件判断 如果支持 Path2D 则使用 SVG 路径绘制
|
||||||
|
context.save();
|
||||||
|
context.translate(positionX, positionY);
|
||||||
|
const scaleFactor = (baseSize * 4.2) / 512;
|
||||||
|
context.scale(scaleFactor, scaleFactor);
|
||||||
|
context.translate(-512, -512);
|
||||||
|
context.fillStyle = '#FFC003';
|
||||||
|
context.fill(outerPath);
|
||||||
|
context.fill(topPath);
|
||||||
|
context.restore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 回退方案 使用贝塞尔曲线近似绘制元宝
|
||||||
|
context.save();
|
||||||
|
context.translate(positionX, positionY);
|
||||||
|
context.fillStyle = '#FFC003';
|
||||||
|
const totalWidth = baseSize * 2.6 * 1.4; // 调整比例保证大小一致
|
||||||
|
const halfWidth = totalWidth / 2;
|
||||||
|
const upperHeight = baseSize * 1.1 * 1.4;
|
||||||
|
const lowerHeight = baseSize * 0.85 * 1.4;
|
||||||
|
const rimLift = upperHeight * 0.25;
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(-halfWidth, -rimLift);
|
||||||
|
context.bezierCurveTo(
|
||||||
|
-halfWidth * 0.65, -upperHeight * 1.0,
|
||||||
|
-halfWidth * 0.25, -upperHeight * 1.25,
|
||||||
|
0, -upperHeight
|
||||||
|
);
|
||||||
|
context.bezierCurveTo(
|
||||||
|
halfWidth * 0.25, -upperHeight * 1.25,
|
||||||
|
halfWidth * 0.65, -upperHeight * 1.0,
|
||||||
|
halfWidth, -rimLift
|
||||||
|
);
|
||||||
|
context.bezierCurveTo(
|
||||||
|
halfWidth * 0.65, lowerHeight * 0.95,
|
||||||
|
halfWidth * 0.25, lowerHeight * 1.1,
|
||||||
|
0, lowerHeight
|
||||||
|
);
|
||||||
|
context.bezierCurveTo(
|
||||||
|
-halfWidth * 0.25, lowerHeight * 1.1,
|
||||||
|
-halfWidth * 0.65, lowerHeight * 0.95,
|
||||||
|
-halfWidth, -rimLift
|
||||||
|
);
|
||||||
|
context.closePath();
|
||||||
|
context.fill();
|
||||||
|
context.restore();
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
@ -1,22 +1,28 @@
|
||||||
(function(){
|
(function(){
|
||||||
// 初始化函数 用于启动雪花效果
|
// 初始化函数 用于启动雪花效果
|
||||||
function init(){
|
function init(){
|
||||||
var canvas = document.getElementById('effectiveAppsSnow');
|
const canvas = document.getElementById('effectiveAppsSnow');
|
||||||
// 条件判断 如果未找到画布元素则不执行
|
// 条件判断 如果未找到画布元素则不执行
|
||||||
if (!canvas) return;
|
if (!canvas) return;
|
||||||
var context = canvas.getContext('2d');
|
const context = canvas.getContext('2d');
|
||||||
var viewportWidth = window.innerWidth;
|
let viewportWidth = window.innerWidth;
|
||||||
var viewportHeight = window.innerHeight;
|
let viewportHeight = window.innerHeight;
|
||||||
var devicePixelRatio = window.devicePixelRatio || 1;
|
const devicePixelRatio = window.devicePixelRatio || 1;
|
||||||
|
|
||||||
// 从后端配置读取雪花形状 默认值为 dot
|
// 读取选中的形状集合 简化为仅使用复选框集合
|
||||||
var configuredShape = (window.YooneSnowSettings && window.YooneSnowSettings.shape) ? window.YooneSnowSettings.shape : 'dot';
|
const selectedShapes = (window.YooneSnowSettings && Array.isArray(window.YooneSnowSettings.selectedShapes) && window.YooneSnowSettings.selectedShapes.length > 0)
|
||||||
|
? window.YooneSnowSettings.selectedShapes
|
||||||
|
: ['dot','flake'];
|
||||||
|
// 读取媒体形状列表 用于将媒体图片作为形状参与渲染
|
||||||
|
const mediaItems = (window.YooneSnowSettings && Array.isArray(window.YooneSnowSettings.mediaItems))
|
||||||
|
? window.YooneSnowSettings.mediaItems
|
||||||
|
: [];
|
||||||
|
|
||||||
function resizeCanvas(){
|
function resizeCanvas(){
|
||||||
viewportWidth = window.innerWidth;
|
viewportWidth = window.innerWidth;
|
||||||
viewportHeight = window.innerHeight;
|
viewportHeight = window.innerHeight;
|
||||||
var displayWidth = viewportWidth;
|
const displayWidth = viewportWidth;
|
||||||
var displayHeight = viewportHeight;
|
const displayHeight = viewportHeight;
|
||||||
canvas.style.width = displayWidth + 'px';
|
canvas.style.width = displayWidth + 'px';
|
||||||
canvas.style.height = displayHeight + 'px';
|
canvas.style.height = displayHeight + 'px';
|
||||||
canvas.width = Math.floor(displayWidth * devicePixelRatio);
|
canvas.width = Math.floor(displayWidth * devicePixelRatio);
|
||||||
|
|
@ -26,16 +32,22 @@
|
||||||
|
|
||||||
resizeCanvas();
|
resizeCanvas();
|
||||||
|
|
||||||
var snowflakeCount = Math.floor(Math.min(400, Math.max(120, (viewportWidth * viewportHeight) / 12000)));
|
const snowflakeCount = Math.floor(Math.min(400, Math.max(120, (viewportWidth * viewportHeight) / 12000)));
|
||||||
var snowflakes = [];
|
const snowflakes = [];
|
||||||
for (var i = 0; i < snowflakeCount; i++){
|
for (let i = 0; i < snowflakeCount; i++){
|
||||||
// 为每个雪花确定形状类型 如果是 mixed 则随机赋值 dot 或 flake
|
// 为每个雪花确定形状类型 从选中集合与媒体列表的合并池中随机选择
|
||||||
var snowflakeShapeType;
|
const poolSize = selectedShapes.length + mediaItems.length;
|
||||||
if (configuredShape === 'mixed') {
|
const randomIndex = Math.floor(Math.random() * Math.max(1, poolSize));
|
||||||
// 条件判断 随机选择雪花形状
|
let chosenType = 'dot';
|
||||||
snowflakeShapeType = Math.random() < 0.5 ? 'dot' : 'flake';
|
let chosenImageUrl = null;
|
||||||
} else {
|
if (randomIndex < selectedShapes.length) {
|
||||||
snowflakeShapeType = configuredShape;
|
// 条件判断 使用普通形状类型
|
||||||
|
chosenType = selectedShapes[randomIndex];
|
||||||
|
} else if (mediaItems.length > 0) {
|
||||||
|
// 条件判断 使用媒体图片作为形状 并记录其 URL
|
||||||
|
const mediaIndex = randomIndex - selectedShapes.length;
|
||||||
|
chosenType = 'media_image';
|
||||||
|
chosenImageUrl = mediaItems[mediaIndex % mediaItems.length];
|
||||||
}
|
}
|
||||||
snowflakes.push({
|
snowflakes.push({
|
||||||
positionX: Math.random() * viewportWidth,
|
positionX: Math.random() * viewportWidth,
|
||||||
|
|
@ -43,13 +55,14 @@
|
||||||
radius: Math.random() * 2 + 1,
|
radius: Math.random() * 2 + 1,
|
||||||
driftSpeed: Math.random() * 0.6 + 0.4,
|
driftSpeed: Math.random() * 0.6 + 0.4,
|
||||||
swingAmplitude: Math.random() * 0.8 + 0.2,
|
swingAmplitude: Math.random() * 0.8 + 0.2,
|
||||||
shapeType: snowflakeShapeType
|
shapeType: chosenType,
|
||||||
|
imageUrl: chosenImageUrl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSnowflakes(){
|
function updateSnowflakes(){
|
||||||
for (var j = 0; j < snowflakes.length; j++){
|
for (let j = 0; j < snowflakes.length; j++){
|
||||||
var flake = snowflakes[j];
|
const flake = snowflakes[j];
|
||||||
flake.positionY += flake.driftSpeed * 2 + flake.radius * 0.25;
|
flake.positionY += flake.driftSpeed * 2 + flake.radius * 0.25;
|
||||||
flake.positionX += Math.sin(flake.positionY * 0.01) * flake.swingAmplitude;
|
flake.positionX += Math.sin(flake.positionY * 0.01) * flake.swingAmplitude;
|
||||||
if (flake.positionY > viewportHeight + 5){
|
if (flake.positionY > viewportHeight + 5){
|
||||||
|
|
@ -62,60 +75,28 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绘制雪花形状 使用线段绘制六角雪花
|
// 使用全局渲染注册表 根据形状类型选择渲染函数
|
||||||
function drawSnowflake(x, y, size) {
|
|
||||||
context.save();
|
|
||||||
context.translate(x, y);
|
|
||||||
context.fillStyle = 'rgba(255,255,255,0.9)';
|
|
||||||
context.strokeStyle = 'rgba(255,255,255,0.9)';
|
|
||||||
context.lineWidth = size * 0.15;
|
|
||||||
|
|
||||||
// 循环绘制六个分支
|
|
||||||
for (var i = 0; i < 6; i++) {
|
|
||||||
context.rotate(Math.PI / 3);
|
|
||||||
context.beginPath();
|
|
||||||
context.moveTo(0, 0);
|
|
||||||
context.lineTo(0, size);
|
|
||||||
context.stroke();
|
|
||||||
|
|
||||||
// 绘制分支上的小分叉
|
|
||||||
context.beginPath();
|
|
||||||
context.moveTo(0, size * 0.3);
|
|
||||||
context.lineTo(size * 0.3, size * 0.5);
|
|
||||||
context.stroke();
|
|
||||||
|
|
||||||
context.beginPath();
|
|
||||||
context.moveTo(0, size * 0.5);
|
|
||||||
context.lineTo(-size * 0.3, size * 0.7);
|
|
||||||
context.stroke();
|
|
||||||
|
|
||||||
context.beginPath();
|
|
||||||
context.moveTo(0, size * 0.7);
|
|
||||||
context.lineTo(size * 0.3, size * 0.9);
|
|
||||||
context.stroke();
|
|
||||||
}
|
|
||||||
|
|
||||||
context.restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 绘制圆点形状 使用填充圆形作为雪花
|
|
||||||
function drawDot(x, y, size) {
|
|
||||||
context.beginPath();
|
|
||||||
context.arc(x, y, size, 0, Math.PI * 2);
|
|
||||||
context.fillStyle = 'rgba(255,255,255,0.9)';
|
|
||||||
context.fill();
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawSnowflakes(){
|
function drawSnowflakes(){
|
||||||
context.clearRect(0, 0, viewportWidth, viewportHeight);
|
context.clearRect(0, 0, viewportWidth, viewportHeight);
|
||||||
|
|
||||||
for (var k = 0; k < snowflakes.length; k++){
|
for (let k = 0; k < snowflakes.length; k++){
|
||||||
var flake = snowflakes[k];
|
const flake = snowflakes[k];
|
||||||
// 条件判断 根据形状类型绘制雪花
|
// 条件判断 如果是媒体图片类型则使用通用图像渲染
|
||||||
if (flake.shapeType === 'dot') {
|
if (flake.shapeType === 'media_image' && flake.imageUrl){
|
||||||
drawDot(flake.positionX, flake.positionY, flake.radius);
|
const record = window.YooneSnowGetOrLoadImage ? window.YooneSnowGetOrLoadImage(flake.imageUrl) : { img: null, ready: false };
|
||||||
} else {
|
if (record && record.ready){
|
||||||
drawSnowflake(flake.positionX, flake.positionY, flake.radius * 3);
|
const targetHeight = flake.radius * 8;
|
||||||
|
const targetWidth = targetHeight;
|
||||||
|
window.YooneSnowDrawCenteredImage(context, record.img, flake.positionX, flake.positionY, targetWidth, targetHeight);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 否则执行注册表中的形状渲染函数
|
||||||
|
const registry = window.YooneSnowShapeRenderers || {};
|
||||||
|
const renderer = registry[flake.shapeType] || registry['dot'];
|
||||||
|
if (typeof renderer === 'function'){
|
||||||
|
renderer(context, flake.positionX, flake.positionY, flake.radius);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
197
yoone-snow.php
197
yoone-snow.php
|
|
@ -19,22 +19,100 @@ function yoone_snow_enqueue_assets() {
|
||||||
wp_register_style($style_handle, $style_src, array(), '1.1.0', 'all');
|
wp_register_style($style_handle, $style_src, array(), '1.1.0', 'all');
|
||||||
wp_enqueue_style($style_handle);
|
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_handle = 'yoone-snow-script';
|
||||||
$script_src = plugins_url('js/snow-canvas.js', __FILE__);
|
$script_src = plugins_url('js/snow-canvas.js', __FILE__);
|
||||||
wp_register_script($script_handle, $script_src, array(), '1.1.0', true);
|
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);
|
wp_enqueue_script($script_handle);
|
||||||
|
|
||||||
// 将后端设置传递到前端脚本 变量名称为 YooneSnowSettings
|
// 将后端设置传递到前端脚本 变量名称为 YooneSnowSettings
|
||||||
$shape = get_option('yoone_snow_shape', 'dot');
|
// 简化设置 仅保留复选框选择的形状集合
|
||||||
if (!in_array($shape, array('dot', 'flake', 'mixed'), true)) {
|
$mixed_items_option = get_option('yoone_snow_mixed_items', array('dot','flake'));
|
||||||
// 如果选项值不合法则回退到默认值 dot
|
if (is_string($mixed_items_option)) {
|
||||||
$shape = 'dot';
|
$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();
|
||||||
|
foreach ($media_ids as $mid) {
|
||||||
|
$url = wp_get_attachment_url(intval($mid));
|
||||||
|
if ($url) { $media_urls[] = $url; }
|
||||||
}
|
}
|
||||||
wp_localize_script($script_handle, 'YooneSnowSettings', array(
|
wp_localize_script($script_handle, 'YooneSnowSettings', array(
|
||||||
'shape' => $shape,
|
'selectedShapes' => $mixed_items_sanitized,
|
||||||
|
'mediaItems' => $media_urls,
|
||||||
|
// 传递资源基础映射 用于前端按需加载 SVG 图像
|
||||||
|
'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__),
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 在后台设置页面加载媒体库脚本和交互脚本 用于选择 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() {
|
function yoone_snow_render_overlay() {
|
||||||
if (!yoone_snow_is_enabled()) { return; }
|
if (!yoone_snow_is_enabled()) { return; }
|
||||||
static $yoone_snow_rendered = false;
|
static $yoone_snow_rendered = false;
|
||||||
|
|
@ -49,16 +127,22 @@ add_action('wp_footer', 'yoone_snow_render_overlay', 100);
|
||||||
|
|
||||||
// 注册设置页面和设置项 用于选择雪花形状
|
// 注册设置页面和设置项 用于选择雪花形状
|
||||||
function yoone_snow_register_settings() {
|
function yoone_snow_register_settings() {
|
||||||
// 注册设置项 选项名称为 yoone_snow_shape 默认值为 dot
|
// 移除形状下拉选项 仅保留复选集合设置
|
||||||
register_setting('yoone_snow_options', 'yoone_snow_shape', array(
|
|
||||||
'type' => 'string',
|
// 注册 mixed 形状集合设置项 默认包含 dot 和 flake
|
||||||
|
register_setting('yoone_snow_options', 'yoone_snow_mixed_items', array(
|
||||||
|
'type' => 'array',
|
||||||
'sanitize_callback' => function($value) {
|
'sanitize_callback' => function($value) {
|
||||||
// 对提交的值进行校验 只允许 dot flake mixed 三种
|
// 将输入统一为数组 并过滤到允许的集合
|
||||||
$allowed = array('dot', 'flake', 'mixed');
|
$allowed = array('dot','flake','yuanbao','coin','santa_hat','candy_cane','christmas_sock','christmas_tree','reindeer','christmas_berry');
|
||||||
if (!is_string($value)) { return 'dot'; }
|
if (is_string($value)) {
|
||||||
return in_array($value, $allowed, true) ? $value : 'dot';
|
$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' => 'dot',
|
'default' => array('dot','flake'),
|
||||||
));
|
));
|
||||||
|
|
||||||
// 添加设置分区 标题为 Snow Settings
|
// 添加设置分区 标题为 Snow Settings
|
||||||
|
|
@ -72,19 +156,81 @@ function yoone_snow_register_settings() {
|
||||||
'yoone_snow'
|
'yoone_snow'
|
||||||
);
|
);
|
||||||
|
|
||||||
// 添加设置字段 下拉选择雪花形状
|
// 移除下拉字段 保留复选框作为唯一选择入口
|
||||||
|
|
||||||
|
// 添加形状复选集合 用于选择参与渲染的形状
|
||||||
add_settings_field(
|
add_settings_field(
|
||||||
'yoone_snow_shape',
|
'yoone_snow_mixed_items',
|
||||||
'Snow Shape',
|
'Shapes',
|
||||||
function() {
|
function() {
|
||||||
// 渲染选择框 选项值 dot flake mixed
|
$current_list = get_option('yoone_snow_mixed_items', array('dot','flake'));
|
||||||
$current = get_option('yoone_snow_shape', 'dot');
|
if (is_string($current_list)) {
|
||||||
echo '<select name="yoone_snow_shape" id="yoone_snow_shape">';
|
$current_list = array_filter(array_map('trim', explode(',', $current_list)));
|
||||||
echo '<option value="dot"' . selected($current, 'dot', false) . '>Dot</option>';
|
}
|
||||||
echo '<option value="flake"' . selected($current, 'flake', false) . '>Snowflake</option>';
|
$options = array(
|
||||||
echo '<option value="mixed"' . selected($current, 'mixed', false) . '>Mixed</option>';
|
'dot' => 'Dot',
|
||||||
echo '</select>';
|
'flake' => 'Snowflake',
|
||||||
echo '<p class="description">Choose dot snowflake or mixed</p>';
|
'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'
|
||||||
|
);
|
||||||
|
|
||||||
|
// 注册媒体形状集合 设置项保存为附件 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',
|
||||||
'yoone_snow_section'
|
'yoone_snow_section'
|
||||||
|
|
@ -115,6 +261,7 @@ function yoone_snow_add_settings_page() {
|
||||||
// 在 admin 初始化时注册设置 在 admin 菜单挂载页面
|
// 在 admin 初始化时注册设置 在 admin 菜单挂载页面
|
||||||
add_action('admin_init', 'yoone_snow_register_settings');
|
add_action('admin_init', 'yoone_snow_register_settings');
|
||||||
add_action('admin_menu', 'yoone_snow_add_settings_page');
|
add_action('admin_menu', 'yoone_snow_add_settings_page');
|
||||||
|
add_action('admin_enqueue_scripts', 'yoone_snow_admin_enqueue');
|
||||||
|
|
||||||
// 在插件列表行添加 Settings 链接 指向设置页面
|
// 在插件列表行添加 Settings 链接 指向设置页面
|
||||||
function yoone_snow_plugin_action_links($links) {
|
function yoone_snow_plugin_action_links($links) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue