(这个页面是站长自用的,用来记录他改造博客主题的过程,防止改不回去)
(本页面会持续更新一些博客优化/美化代码)
本文的某些代码仅限于Argon主题
—
Mimosa提醒您:在改动主题代码前一定要记得做好备份工作。
本文最后更新时间:2025.4.11
实况照片
iOS的实况照片实质上就是一张静态图片与heic视频格式的结合。
这里引用Apple Developer的livephotoskit.js (官方使用文档:LivePhotosKit JS | Apple Developer Documentation)来实现。
若需展示动态图片,需将鼠标悬浮至图片左上角的
LIVE
图案上。示例:
(源代码参考» WordPress 古腾堡编辑器增加 live 实况图预览模块 – 漫川笔记,由于源代码有一点bug,Mimosa对其进行二次修改:优化了编辑页面的图片展示以及展示图片路径、展示实况图片的自适应大小)
step.1
在主题的functions.php中,在<?php
后插入以下代码(注:必须在php标签内插入,没有php标签的自己建一个,因为这是php代码):
// 实况图片
function enqueue_livephotoskit_script() {
wp_enqueue_script('livephotoskit-js', 'https://source.loneapex.cn/js/livephotoskit.js', array(), null, true);
}
add_action('wp_enqueue_scripts', 'enqueue_livephotoskit_script');
function register_custom_live_photos_block() {
wp_register_script(
'custom-live-photos-block',
get_template_directory_uri() . '/block.js',
array('wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n'),
filemtime(get_template_directory() . '/block.js')
);
register_block_type('custom/live-photos-block', array(
'editor_script' => 'custom-live-photos-block',
'render_callback' => 'render_custom_live_photos_block'
));
}
add_action('init', 'register_custom_live_photos_block');
function render_custom_live_photos_block($attributes) {
if (!isset($attributes['photoURL']) || !isset($attributes['videoURL'])) {
return '';
}
$width = '100%';
$height = '300px'; // Example fixed height, adjust as necessary
return sprintf(
'<div class="live-photo-wrapper" style="width:%s; height:%s; position:relative;">
<div data-live-photo data-photo-src="%s" data-video-src="%s" style="width:100%%; height:100%%;"></div>
</div>',
esc_attr($width),
esc_attr($height),
esc_url($attributes['photoURL']),
esc_url($attributes['videoURL'])
);
}
step.2
在博客主题的根目录(与functions.php同级目录)建一个block.js
文件
(function (blocks, editor, element, components) {
var el = element.createElement;
var MediaUpload = editor.MediaUpload;
var InspectorControls = editor.InspectorControls;
var TextControl = components.TextControl;
blocks.registerBlockType('custom/live-photos-block', {
title: 'Live Photos Block',
icon: 'camera',
category: 'media',
attributes: {
photoURL: {
type: 'string',
default: ''
},
videoURL: {
type: 'string',
default: ''
},
width: {
type: 'number',
default: 400
},
height: {
type: 'number',
default: 300
}
},
edit: function (props) {
var attributes = props.attributes;
var setAttributes = props.setAttributes;
return el(
'div',
{ className: props.className },
el('p', {}, '选择图片和视频:'),
el(
MediaUpload,
{
onSelect: function (media) {
setAttributes({ photoURL: media.url });
},
allowedTypes: 'image',
render: function (obj) {
var fileName = '';
if (attributes.photoURL) {
// 从 URL 中提取文件名
fileName = attributes.photoURL.split('/').pop();
}
return el(
components.Button,
{
className: 'button button-large',
onClick: obj.open
},
attributes.photoURL ? fileName : '选择图片'
);
}
}
),
el(
MediaUpload,
{
onSelect: function (media) {
setAttributes({ videoURL: media.url });
},
allowedTypes: 'video',
render: function (obj) {
var fileNam1e = '';
if (attributes.videoURL) {
// 从 URL 中提取文件名
fileName1 = attributes.videoURL.split('/').pop();
}
return el(
components.Button,
{
className: 'button button-large',
onClick: obj.open
},
attributes.videoURL ? fileName1 : '选择视频'
);
}
}
),
el(InspectorControls, {},
el(TextControl, {
label: '宽度(px)',
value: attributes.width,
onChange: function (value) {
setAttributes({ width: parseInt(value, 10) || 0 });
}
}),
el(TextControl, {
label: '高度(px)',
value: attributes.height,
onChange: function (value) {
setAttributes({ height: parseInt(value, 10) || 0 });
}
})
)
);
},
save: function () {
// 后台通过 PHP 渲染,前端保存为空
return null;
}
});
}(
window.wp.blocks,
window.wp.editor,
window.wp.element,
window.wp.components
));
step.3
在写文章的时候应该会出现如图所示的区块,把iOS的实况照片转换成视频格式,然后分别上传图片和视频即可
文章中插入音乐播放器
<link rel="stylesheet" href="https://loneapex.cn/extra-js/Aplayer/APlayer.min.css">
<script src="https://loneapex.cn/extra-js/Aplayer/APlayer.min.js"></script>
<script src="https://loneapex.cn/extra-js/Aplayer/Meting.min.js"></script>
<meting-js
server="netease"
type="song"
id="761626"
fixed="false"
mini="false"
order="list"
loop="all"
preload="false"
list-folded="true"
></meting-js>
这里引用的是aplayer播放器+meting获取网易云音乐
参数:
- id=’外链播放器id’,必须参数(比如网易云音乐播放单曲就填写该音乐id,歌单填写歌单的id,皆可通过网易云音乐的分享链接查看具体id)
- type=[song=单曲, playlist=歌单, album=专辑, search=搜索结果, artist=艺术家],必须参数
- server=[netease=网易云音乐, tencent=QQ音乐, kugou=酷狗音乐, xiami=虾米音乐, baidu=百度音乐],必须参数
- fixed=启用固定模式,固定在左下角,默认false
- mini=在页面左下角启用迷你模式,默认false(不启用的话就是上面的效果)
- preload=[none,metadata,auto] (预加载)
- mutex=[互斥锁,默认true],默认false
- order=[random=随机播放,list=列表播放]
- loop=[all=全部循环, one=循环一次 ,none=不循环]
- volume=[音量,默认0.7]
- lrc-type=[歌词类型,默认0]
- list-folded=[列表是否折叠,默认false]
- list-max-height=列表最大高度,默认340px
- storage-name=本地存储存储密钥,用于存储播放器设置,默认metingjs
节日弹窗
差不多这个效果,附带烟花
由于每次打开网站都会显示这玩意而过于繁琐,我用 JavaScript 和 localStorage 来实现弹窗仅在每个浏览器只显示一次。
不需要烟花的可以把注释=🎇 弹窗逻辑=
下面的for循环改成for (let i = 0; i < 0; i++) {
为了防止网站主题文件的样式预设干扰,这里把所有样式后面都加了!important
权重,并且把所有变量名都起的特别长(防止重复变量名干扰)
for循环那儿可以调整烟花的个数(i < 8
那儿)和每个烟花间隔的延迟;const particleCount_2025 = 45;
可以调整每个烟花微粒的个数(别太多了,容易死机的);
colorList_2025
这个列表是烟花微粒的随机颜色
<!--弹窗-->
<style>
/* 弹窗 */
.popup_modal_2025_newyear {
display: none;
position: fixed;
z-index: 99999;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background: white !important;
padding: 20px !important;
border-radius: 10px !important;
text-align: center !important;
width: 320px !important;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3) !important;
}
.popup_modal_2025_newyear h2 {
margin: 0 !important;
font-size: 22px !important;
}
.popup_modal_2025_newyear p {
margin: 15px 0 !important;
}
.popup_modal_2025_newyear button {
margin-top: 10px !important;
padding: 8px 20px !important;
border: none !important;
background-color: #007BFF !important;
color: white !important;
border-radius: 5px !important;
cursor: pointer !important;
}
/* 烟花粒子 */
.firework_particle_2025 {
position: absolute !important;
width: 6px !important;
height: 6px !important;
opacity: 1 !important;
border-radius: 2px !important;
}
.cillo_2025_text_h2 {
color: #A52A2A !important;
}
.cillo_2025_text_p {
color: #8B4500 !important;
}
</style>
<!-- 弹窗 -->
<div id="modal_container_2025_happy_newyear" class="popup_modal_2025_newyear">
<h2 class="cillo_2025_text_h2">🎉 2025 新年快乐 🎉</h2>
<p class="cillo_2025_text_p">愿新的一年,所有的美好都如期而至,所有的期待都不负等待。</p>
<button onclick="closePopup_2025_newyear()">确定</button>
</div>
<script>
// === 🎆 烟花特效 ===
function createFireworkEffect_2025(x, y) {
const colorList_2025 = ["#FFFF00", "#7CFC00", "#33FF57", "#339FFF", "#E633FF"];
const particleCount_2025 = 45; //每个烟花的微粒数量
for (let i = 0; i < particleCount_2025; i++) {
let particleElement_2025 = document.createElement("div");
particleElement_2025.classList.add("firework_particle_2025");
particleElement_2025.style.backgroundColor = colorList_2025[Math.floor(Math.random() * colorList_2025.length)];
particleElement_2025.style.left = `${x}px`;
particleElement_2025.style.top = `${y}px`;
document.body.appendChild(particleElement_2025);
let angle_2025 = (Math.PI * 2 * i) / particleCount_2025;
let velocity_2025 = Math.random() * 4 + 2;
let gravity_2025 = 0.15;
let xVelocity_2025 = Math.cos(angle_2025) * velocity_2025;
let yVelocity_2025 = Math.sin(angle_2025) * velocity_2025;
let fadeOut_2025 = 1;
let animation_2025 = setInterval(() => {
xVelocity_2025 *= 0.98;
yVelocity_2025 += gravity_2025;
let newX_2025 = parseFloat(particleElement_2025.style.left) + xVelocity_2025;
let newY_2025 = parseFloat(particleElement_2025.style.top) + yVelocity_2025;
particleElement_2025.style.left = `${newX_2025}px`;
particleElement_2025.style.top = `${newY_2025}px`;
fadeOut_2025 -= 0.02;
particleElement_2025.style.opacity = fadeOut_2025;
if (fadeOut_2025 <= 0) {
clearInterval(animation_2025);
particleElement_2025.remove();
}
}, 20);
}
}
//随机位置
function randomPosition_2025() {
return [Math.random() * window.innerWidth * 0.9, Math.random() * window.innerHeight * 0.6];
}
// === 🎇 弹窗逻辑 ===
function showPopup_2025_newyear() {
if (!localStorage.getItem("popup_2025_newyear_shown")) {
document.getElementById("modal_container_2025_happy_newyear").style.display = "block";
for (let i = 0; i < 8; i++) {
setTimeout(() => {
let [x, y] = randomPosition_2025();
createFireworkEffect_2025(x, y);
}, i * 650); // 每次间隔 650ms
}
}
}
function closePopup_2025_newyear() {
document.getElementById("modal_container_2025_happy_newyear").style.display = "none";
localStorage.setItem("popup_2025_newyear_shown", "true");
}
showPopup_2025_newyear();
</script>
过年灯笼
详情见这篇文章:给博客挂上赛博灯笼吧 – 阿草Mimosa的小屋
(注:这东西用window.onload
加载,小心别与其他代码冲突。window.onload
的特性是其语句仅能执行一次。若有若干window.onload
代码块,仅执行第一个window.onload
。(我曾经踩过的大坑))
悼念色
为了表示悼念,使整个网站变为黑白色调的。在额外CSS的最底部添加下列代码即可:
/*网站黑白色(悼念)*/
html {
filter: grayscale(100%);
-webkit-filter: grayscale(100%);
-moz-filter: grayscale(100%);
-ms-filter: grayscale(100%);
-o-filter: grayscale(100%);
filter: url("data:image/svg+xml;utf8,#grayscale");
filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
-webkit-filter: grayscale(1);
}
站内邮件发送内容
functions.php 1432行 直接找注释//发送评论通知邮件
就行
归档页面添加说说短文章
详见Argon主题:文章归档页面添加说说类型 – 阿草Mimosa的小屋
讨论区给多个特定邮箱添加标识
(为了便于管理,我基于argon主题管理页面设置的)
在setting.php最后头(但不是最后)添加
//讨论区 「朋友」标识 号代替邮箱输入
argon_update_option_allow_tags('friend_mail_sign');
然后,去前面(出现很多tr和td、th标签的地方)加上这些:
<tr><th class="subtitle"><h2><?php _e('讨论区朋友标识', 'argon');?></h2></th></tr>
<tr><th class="subtitle" colspan="2"><h2><?php _e('讨论区朋友标识', 'argon');?></h2></th></tr>
<tr>
<th scope="row">
<label><?php _e('邮箱列表(每行一个)', 'argon');?></label>
</th>
<td>
<textarea
name="friend_mail_sign"
rows="5"
cols="50"
placeholder="example1@qq.com example2@gmail.com"
><?php echo htmlspecialchars(get_option('friend_mail_sign')); ?></textarea>
<p class="description"><?php _e('每行输入一个需要显示「朋友」标识的邮箱', 'argon');?></p>
</td>
</tr>
这样是为了在主题后台管理页面输入邮箱,然后让前端获取就行了。
所以,打开functions.php文件,找到//评论样式格式化
注释(我的在1077行)
在博主标识后面添加
<?php
$friendEmails = explode("\n", get_option('friend_mail_sign', ''));
$friendEmails = array_map('trim', $friendEmails); // 去除首尾空格
$friendEmails = array_filter($friendEmails); // 过滤空行
if (in_array($comment->comment_author_email, $friendEmails)) {
echo '<span class="badge badge-warning">' . __('朋友', 'argon') . '</span>';
}
?>
然后往下找,找到//评论样式格式化 (说说预览界面)
注释,我们也要把说说预览给打上标签,过程和代码同上。
首页文章只显示人工摘要,而非截取文字
首页显示文章摘要可以更好地让读者了解文章内容。
但是,argon主题的文章摘要功能开启后,若没有为文章添加人工摘要,则会自动截取文章的前部分文章作为摘要,这样的效果只会很丑,且无实际意义。
因此,修改主题代码:若有人工摘要则显示,若无人工摘要则不显示。
记得在 argon主题选项 的 「文章内容预览截取字数」 填上数字
在 网站根目录/wp-content/themes/argon/template-parts中 找到content-preview-1.php
(其中有多个content-preview.php,经过Mimosa实测只改动第一个即可实现效果)
将
<?php if ($trim_words_count > 0){ ?>
<div class="post-content">
<?php
if (get_option("argon_hide_shortcode_in_preview") == 'true'){
$preview = wp_trim_words(do_shortcode(get_the_content('...')), $trim_words_count);
}else{
$preview = wp_trim_words(get_the_content('...'), $trim_words_count);
}
if (post_password_required()){
$preview = __("这篇文章受密码保护,输入密码才能阅读", 'argon');
}
if ($preview == ""){
$preview = __("这篇文章没有摘要", 'argon');
}
if ($post -> post_excerpt){
$preview = $post -> post_excerpt;
}
echo $preview;
?>
</div>
<?php
}
?>
替换为
<?php
$preview = '';
if ($post -> post_excerpt){
$preview = $post -> post_excerpt;
}elseif (post_password_required()){
$preview = __("这篇文章受密码保护,输入密码才能阅读", 'argon');
}
if (!empty($preview)){
?>
<div class="post-content">
<?php
if (get_option("argon_hide_shortcode_in_preview") == 'true'){
echo do_shortcode($preview);
}else{
echo $preview;
}
?>
</div>
<?php } ?>
即可。
文内外跳转 (文章锚点)
(理论适用于h1-h6标签 仅适用于Argon)
添加至footer.php即可:转自Bensz
<!-- 标题自动锚点: Start -->
<script>
window.addEventListener('load', function() {
// 构建标题文本与 Argon ID 的映射表
const headers = document.querySelectorAll('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]');
const textToIdMap = new Map();
headers.forEach(header => {
const id = header.id;
const text = header.textContent.trim();
textToIdMap.set(text, id); // 标题文本 -> ID 映射
});
// 替换页面中的基于文本的锚点链接
const links = document.querySelectorAll('a[href^="#"]');
links.forEach(link => {
const targetText = decodeURIComponent(link.getAttribute('href').slice(1)); // 获取锚点文本
if (textToIdMap.has(targetText)) {
link.setAttribute('href', `#${textToIdMap.get(targetText)}`); // 替换为 Argon 的 ID
}
});
//文外跳转
if (window.location.hash) {
const hash = window.location.hash.slice(1); // 去掉 #
let targetElement;
// 优先检查哈希值是否是一个有效的 ID
targetElement = document.getElementById(hash);
if (!targetElement) {
// 如果哈希值是标题文本,检查映射表
const decodedHash = decodeURIComponent(hash); // 解码哈希值
if (textToIdMap.has(decodedHash)) {
const targetId = textToIdMap.get(decodedHash); // 获取对应的 ID
targetElement = document.getElementById(targetId); // 查找对应 ID 的元素
}
// 替换图片的 src 属性
const lazyImages = document.querySelectorAll('img.lazyload[data-original]');
lazyImages.forEach(img => {
img.src = img.getAttribute('data-original'); // 直接替换为真正的图片链接
});
}
// 如果找到了目标元素,滚动到该元素
if (targetElement) {
targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
});
</script>
<!-- 标题自动锚点: End -->