97 KiB
Argon 主题开发文档
项目概述
Argon 是一款基于 WordPress 的现代化博客主题,采用 Material Design 设计语言,提供丰富的功能和高度的可定制性。
核心特性
- Material Design 风格界面
- 响应式布局,支持多种页面布局模式(单栏/双栏/三栏)
- 夜间模式与 AMOLED 暗黑模式
- 沉浸式主题色系统
- PJAX 无刷新页面加载
- 瀑布流文章列表布局
- 完整的评论系统(支持 Markdown、表情、点赞、置顶)
- 说说功能(类似微博的短内容发布)
- AI 摘要生成
- 代码高亮与数学公式渲染
- 友链管理系统
- 反馈系统
- 性能优化模块
技术栈
- PHP 7.0+
- WordPress 4.4+
- jQuery 3.x
- Bootstrap 4 (Argon Design System)
- Highlight.js (代码高亮)
- MathJax/KaTeX (数学公式)
- Headroom.js (顶栏自动隐藏)
项目文件结构
核心文件
argon/
├── style.css # 主题样式表 (核心样式定义,包含配色、排版、组件样式)
├── argontheme.js # 主题核心 JavaScript (负责 PJAX、界面交互、功能初始化)
├── functions.php # WordPress 主题函数 (功能入口、Hook 挂载、核心逻辑实现)
├── settings.php # 后台设置页面 (提供外观、功能开关等配置选项)
├── header.php # 页面头部模板 (HTML Head、顶部导航栏、全局变量输出)
├── footer.php # 页面底部模板 (页脚区域、JavaScript 脚本引入)
├── index.php # 首页模板 (文章列表展示)
├── single.php # 文章页模板 (单篇文章内容展示)
├── page.php # 页面模板 (独立页面展示)
├── archive.php # 归档页模板 (分类、标签、日期归档)
├── search.php # 搜索结果页模板
├── 404.php # 404 错误页面模板
├── comments.php # 评论区模板 (评论列表与发表评论表单)
├── sidebar.php # 侧边栏模板 (个人信息卡片、小工具挂载点)
├── admin.css # 后台设置页面样式
└── languages/ # 多语言包目录 (.po/.mo 文件)
功能模块文件
argon/
├── shuoshuo.php # 说说页面模板
├── timeline.php # 时间线页面模板
├── msgboard.php # 留言板页面模板
├── friend-links.php # 友链页面模板
├── feedback.php # 反馈系统
├── emotions.php # 表情系统
├── parsedown.php # Markdown 解析器
├── useragent-parser.php # User Agent 解析
├── ai-summary-query.php # AI 摘要查询接口
├── unsubscribe-comment-mailnotice.php # 评论邮件退订
└── argon-performance.js # 性能优化模块
模板片段
template-parts/
├── content-single.php # 单篇文章内容
├── content-page.php # 页面内容
├── content-preview-1.php # 文章预览样式 1
├── content-preview-2.php # 文章预览样式 2
├── content-preview-3.php # 文章预览样式 3
├── content-shuoshuo.php # 说说内容
├── content-shuoshuo-preview.php # 说说预览
├── content-shuoshuo-details.php # 说说详情
├── content-timeline.php # 时间线内容
├── content-none-search.php # 搜索无结果
├── content-none-tag.php # 标签无结果
├── ai-summary.php # AI 摘要组件
├── emotion-keyboard.php # 表情键盘
├── post-actions.php # 文章操作按钮
└── shuoshuo-operations.php # 说说操作按钮
资源文件
assets/
├── css/
│ ├── argon.css # Argon Design System 样式
│ └── bootstrap/ # Bootstrap 样式
├── js/
│ ├── argon.js # Argon Design System 脚本
│ └── easter-egg.js # 彩蛋功能
├── img/ # 图片资源
├── icons/ # 图标资源
├── vendor/ # 第三方库
├── tinymce_assets/ # TinyMCE 编辑器资源
├── argon_css_merged.css # 合并后的 CSS
└── argon_js_merged.js # 合并后的 JS
邮件模板
email-templates/
├── base.php # 邮件模板基类
├── comment-notify.php # 评论通知
├── reply-notify.php # 回复通知
├── feedback-notify.php # 反馈通知
├── spam-notify.php # 垃圾评论通知
├── blacklist-spam-notify.php # 黑名单垃圾评论通知
└── username-change-notify.php # 用户名变更通知
代码规范
CSS 规范
格式化规则
- 使用 Tab 缩进(1 Tab = 4 空格宽度)
- 每个属性独占一行
- 属性之间不要有空行
- 规则块之间保留一个空行
- 选择器与
{之间有一个空格 - 属性值后的
;前不要有空格
示例
/* 正确 */
.selector {
property: value;
another-property: value;
}
.another-selector {
property: value;
}
/* 错误 - 属性之间有空行 */
.selector {
property: value;
another-property: value;
}
注释规范
/* ==========================================================================
大区块标题
========================================================================== */
/* ---------- 小区块标题 ---------- */
/* 普通注释 */
JavaScript 规范
格式化规则
- 使用 Tab 缩进
- 字符串优先使用单引号
' - 比较运算符使用严格相等
===和!== - 语句末尾必须有分号
; - 函数名与括号之间无空格
- 关键字后有空格(if, for, while, function 等)
变量声明
- 优先使用
let和const - 避免使用
var(除非需要函数作用域或全局变量)
全局变量(需保留 var)
以下全局变量必须使用 var 声明以确保跨作用域访问:
argonConfig- 主题配置对象translation- 多语言翻译表pjaxLoading- PJAX 加载状态headroom- Headroom 实例
注释规范
// ==========================================================================
// 大区块标题
// ==========================================================================
// ---------- 小区块标题 ----------
/**
* 函数说明
* @param {string} param - 参数说明
* @returns {boolean} 返回值说明
*/
function functionName(param) {
// 单行注释
if (param === 'value') {
return true;
}
return false;
}
PHP 规范
格式化规则
- 使用 Tab 缩进
- 字符串优先使用单引号
- 数组使用短语法
[] - 类名使用 PascalCase
- 函数名使用 snake_case(遵循 WordPress 规范)
- 箭头操作符
->前后不要有空格
WordPress 特定
- 使用
esc_html(),esc_attr()等函数转义输出 - 使用
wp_nonce_field()进行安全验证 - 遵循 WordPress Coding Standards
示例
// 正确
$theme->Version
get_option('argon_theme_color')
// 错误
$theme -> Version
核心架构
主题初始化流程
主题的初始化分为服务器端(PHP)和客户端(JavaScript)两个阶段。
服务器端初始化
- functions.php 加载(WordPress 加载主题时执行)
// functions.php
// 检查 WordPress 版本兼容性
if (version_compare($GLOBALS['wp_version'], '4.4-alpha', '<')) {
echo "<div style='...'>Argon 主题不支持 Wordpress 4.4 以下版本</div>";
}
// 设置主题支持功能
function theme_slug_setup() {
add_theme_support('title-tag'); // 标题标签
add_theme_support('post-thumbnails'); // 特色图片
load_theme_textdomain('argon', get_template_directory() . '/languages'); // 多语言
}
add_action('after_setup_theme','theme_slug_setup');
// 设置全局变量
$argon_version = !(wp_get_theme()->Template) ? wp_get_theme()->Version : wp_get_theme(wp_get_theme()->Template)->Version;
$GLOBALS['theme_version'] = $argon_version;
$GLOBALS['assets_path'] = get_bloginfo('template_url');
-
导航菜单注册
主题通过
init挂钩注册了四个核心菜单位置,用于定义页面的不同导航区域:// functions.php function init_nav_menus(){ register_nav_menus( array( 'toolbar_menu' => __('顶部导航', 'argon'), // 顶部工具栏菜单 'leftbar_menu' => __('左侧栏菜单', 'argon'), // 左侧主要导航菜单 'leftbar_author_links' => __('左侧栏作者个人链接', 'argon'), // 左侧作者信息下方的图标链接 'leftbar_friend_links' => __('左侧栏友情链接', 'argon') // 左侧底部的友情链接区域 )); } add_action('init', 'init_nav_menus');- header.php 渲染(输出 HTML 头部)
// header.php
// 1. 生成 HTML 类名(根据后台设置)
$htmlclasses = "";
if (get_option('argon_page_layout') == "single"){
$htmlclasses .= "single-column ";
}
if (get_option('argon_enable_immersion_color') == "true"){
$htmlclasses .= "immersion-color ";
}
// ... 更多类名
// 2. 获取主题色配置
$themecolor = get_option("argon_theme_color", "#5e72e4");
if (isset($_COOKIE["argon_custom_theme_color"])){
if (checkHEX($_COOKIE["argon_custom_theme_color"]) &&
get_option('argon_show_customize_theme_color_picker') != 'false'){
$themecolor = $_COOKIE["argon_custom_theme_color"];
}
}
// 3. 输出 HTML 文档头
?>
<html <?php language_attributes(); ?> class="no-js <?php echo $htmlclasses;?>">
<head>
<meta charset="<?php bloginfo('charset'); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="theme-color" content="<?php echo $themecolor; ?>">
<!-- 预加载用户样式设置 - 避免样式跳变 -->
<script>
(function() {
var html = document.documentElement;
var ls = localStorage;
// 字体设置
if (ls.getItem('Argon_Use_Serif') === 'true') {
html.classList.add('use-serif');
}
// 阴影设置
if (ls.getItem('Argon_Use_Big_Shadow') === 'true') {
html.classList.add('use-big-shadow');
}
// ... 更多设置
})();
</script>
<?php
// 4. 加载 CSS 和 JavaScript
$assets_version = argon_get_assets_version();
wp_enqueue_style("argon_css_merged", $GLOBALS['assets_path'] . "/assets/argon_css_merged.css", array(), $assets_version, 'all');
wp_enqueue_style("style", $GLOBALS['assets_path'] . "/style.css", array('argon_css_merged'), $assets_version, 'all');
wp_enqueue_script("argon_js_merged", $GLOBALS['assets_path'] . "/assets/argon_js_merged.js", array(), $assets_version, false);
?>
<?php wp_head(); ?>
<!-- 5. 输出动态 CSS 变量 -->
<style id="themecolor_css">
:root{
--themecolor: <?php echo $themecolor; ?>;
--themecolor-R: <?php echo $RGB['R']; ?>;
--themecolor-G: <?php echo $RGB['G']; ?>;
--themecolor-B: <?php echo $RGB['B']; ?>;
--themecolor-H: <?php echo $HSL['H']; ?>;
--themecolor-S: <?php echo $HSL['S']; ?>;
--themecolor-L: <?php echo $HSL['L']; ?>;
}
</style>
<!-- 6. 输出全局配置对象 -->
<script>
document.documentElement.classList.remove("no-js");
var argonConfig = {
wp_path: "<?php echo $GLOBALS['wp_path']; ?>",
language: "<?php echo argon_get_locate(); ?>",
// ... 更多配置
};
</script>
<!-- 7. 夜间模式初始化脚本 -->
<script>
var darkmodeAutoSwitch = "<?php echo get_option("argon_darkmode_autoswitch");?>";
function setDarkmode(enable){ /* ... */ }
function toggleDarkmode(){ /* ... */ }
// ... 夜间模式逻辑
</script>
</head>
客户端初始化
- 兼容性修复(argontheme.js 开头)
// argontheme.js
// 确保 Prism 存在
if (typeof window.Prism === 'undefined') {
window.Prism = {
highlightAll: function() {},
highlightElement: function() {},
plugins: {}
};
}
// 确保 jQuery 插件存在
if (typeof jQuery !== 'undefined') {
(function($) {
// 修复空选择器问题
if (!$.fn._argonInit) {
$.fn._argonInit = $.fn.init;
$.fn.init = function(selector, context, root) {
if (typeof selector === 'string') {
let trimmed = selector.trim();
if (trimmed === '' || trimmed === '#') {
return new $.fn._argonInit();
}
}
return $.fn._argonInit.call(this, selector, context, root);
};
$.fn.init.prototype = $.fn;
}
})(jQuery);
}
- 工具函数定义
// argontheme.js
// Cookie 操作
function setCookie(cname, cvalue, exdays) { /* ... */ }
function getCookie(cname) { /* ... */ }
// 多语言翻译
var translation = {};
translation['en_US'] = { /* ... */ };
translation['ru_RU'] = { /* ... */ };
function __(text) {
if (typeof translation[argonConfig.language] !== 'undefined' &&
typeof translation[argonConfig.language][text] !== 'undefined') {
return translation[argonConfig.language][text];
}
return text;
}
- DOM 加载完成后初始化
// argontheme.js
$(document).ready(function() {
// 初始化顶栏
initNavbar();
// 初始化侧边栏
initSidebar();
// 初始化瀑布流
waterflowInit();
// 初始化懒加载
if (argonConfig.lazyload) {
initLazyload();
}
// 初始化图片缩放
if (argonConfig.zoomify) {
$('.post-content img').zoomify(argonConfig.zoomify);
}
// 初始化代码高亮
if (argonConfig.code_highlight.enable) {
initCodeHighlight();
}
// 初始化评论系统
initCommentSystem();
// 初始化浮动按钮
initFloatButtons();
// 初始化 PJAX
if (!argonConfig.disable_pjax) {
initPjax();
}
// 移除加载类
$('#float_action_buttons').removeClass('fabtns-unloaded');
});
资源加载策略
- CSS 加载顺序
// header.php
// 1. 合并的 CSS(包含 Bootstrap 和 Argon Design System)
wp_enqueue_style("argon_css_merged", ".../argon_css_merged.css");
// 2. 主题样式(依赖合并的 CSS)
wp_enqueue_style("style", ".../style.css", array('argon_css_merged'));
- JavaScript 加载顺序
// header.php
// 1. 资源加载器(用于备用资源加载)
wp_enqueue_script("resource_loader", ".../resource-loader.js");
// 2. 合并的 JS(包含 jQuery 和其他库)- 在头部同步加载
wp_enqueue_script("argon_js_merged", ".../argon_js_merged.js", array(), $assets_version, false);
// 3. Argon 修复补丁(必须在 wp_head() 之后)
<script src="<?php echo get_template_directory_uri(); ?>/assets/js/argon.min.js?ver=<?php echo $assets_version; ?>"></script>
// 4. 主题核心脚本(在 footer.php 中加载)
<?php $assets_version = function_exists('argon_get_assets_version') ? argon_get_assets_version() : $GLOBALS['theme_version']; ?>
<script src="<?php echo $GLOBALS['assets_path']; ?>/argontheme.js?v=<?php echo $assets_version; ?>"></script>
- 按需加载
// argontheme.js
// Google Fonts 按需加载
if (typeof ArgonResourceLoader !== "undefined") {
ArgonResourceLoader.smartLoad("//fonts.googleapis.com/css?family=...", "css");
}
// 数学公式渲染库在 footer.php 中按设置输出(get_option('argon_math_render'))
// 可选:mathjax3 / mathjax2 / katex / disabled
强制刷新机制
当主题更新后,可能需要清除客户端缓存:
// functions.php
function argon_is_force_refresh_enabled() {
$enabled_time = get_option('argon_force_refresh_enabled_time', 0);
if ($enabled_time == 0) {
return false;
}
// 1 小时后自动关闭
if (time() - $enabled_time > 3600) {
update_option('argon_force_refresh_enabled_time', 0);
return false;
}
return true;
}
function argon_get_assets_version() {
if (argon_is_force_refresh_enabled()) {
$enabled_time = get_option('argon_force_refresh_enabled_time', 0);
return $GLOBALS['theme_version'] . '.r' . $enabled_time;
}
return $GLOBALS['theme_version'];
}
强制刷新时,header.php 会输出清除缓存的脚本:
// header.php
<?php if (argon_is_force_refresh_enabled()): ?>
<script>
(function() {
var forceRefreshKey = 'argon_force_refresh_version';
var currentVersion = '<?php echo get_option('argon_force_refresh_enabled_time', 0); ?>';
var lastVersion = localStorage.getItem(forceRefreshKey);
if (lastVersion !== currentVersion) {
localStorage.setItem(forceRefreshKey, currentVersion);
if (lastVersion !== null) {
// 清除所有缓存
if ('caches' in window) {
caches.keys().then(function(names) {
return Promise.all(names.map(function(name) {
return caches.delete(name);
}));
});
}
// 重新加载页面
window.location.reload();
}
}
})();
</script>
<?php endif; ?>
全局配置对象
argonConfig 是主题的核心配置对象,在 header.php 中通过 PHP 动态生成并输出到页面:
var argonConfig = {
wp_path: "/", // WordPress 安装路径
language: "zh_CN", // 当前语言代码
dateFormat: "YMD", // 日期显示格式
// 图片缩放配置(Zoomify)
zoomify: {
duration: 200, // 缩放动画时长(毫秒)
easing: "cubic-bezier(0.4,0,0,1)", // 缓动函数
scale: 0.9 // 缩放比例
},
// 如果禁用则为 false
pangu: "false", // 盘古之白(中英文间自动加空格)
// 懒加载配置
lazyload: true, // 是否启用懒加载
lazyload_effect: "fadeIn", // 懒加载显示效果
lazyload_threshold: 800, // 提前加载阈值(像素)
fold_long_comments: false, // 是否折叠长评论
fold_long_shuoshuo: false, // 是否折叠长说说
// PJAX 配置
disable_pjax: false, // 是否禁用 PJAX
pjax_animation_durtion: 600, // PJAX 切换动画时长(毫秒)
headroom: "false", // 顶栏自动隐藏模式(false/true/absolute)
// 文章列表布局
waterflow_columns: "1", // 瀑布流列数(1/2/3)
article_list_layout_mobile: "1", // 移动端文章列表布局样式
// 代码高亮配置
code_highlight: {
enable: false, // 是否启用代码高亮
hide_linenumber: false, // 是否隐藏行号
transparent_linenumber: false, // 行号是否透明
break_line: false // 是否自动折行
}
};
配置对象的值从 WordPress 后台设置中读取,通过 PHP 的 get_option() 函数获取。例如:
// header.php
lazyload: <?php echo (get_option('argon_enable_lazyload', 'true') == 'false' ? 'false' : 'true'); ?>,
CSS 变量系统
主题使用 CSS 自定义属性(CSS Variables)实现动态主题色和样式配置。这些变量在 header.php 中通过 PHP 动态生成。
主题色变量
// header.php - 获取主题色
$themecolor = get_option("argon_theme_color", "#5e72e4");
// 支持用户自定义主题色(通过 Cookie)
if (isset($_COOKIE["argon_custom_theme_color"])) {
if (checkHEX($_COOKIE["argon_custom_theme_color"]) &&
get_option('argon_show_customize_theme_color_picker') != 'false') {
$themecolor = $_COOKIE["argon_custom_theme_color"];
}
}
// 转换为 RGB 和 HSL 值
$RGB = hexstr2rgb($themecolor);
$HSL = rgb2hsl($RGB['R'], $RGB['G'], $RGB['B']);
生成的 CSS 变量:
:root {
/* 主题色 - 十六进制 */
--themecolor: #5e72e4;
/* 主题色 - RGB 分量(用于 rgba() 函数)*/
--themecolor-R: 94;
--themecolor-G: 114;
--themecolor-B: 228;
/* 主题色 - HSL 分量(用于生成色调变体)*/
--themecolor-H: 231;
--themecolor-S: 71;
--themecolor-L: 63;
}
动画系统变量
:root {
/* 动画时长 - 遵循 Material Design 3 规范 */
--animation-fast: 150ms; // 快速动画(按钮点击等)
--animation-normal: 250ms; // 标准动画(卡片展开等)
--animation-slow: 400ms; // 慢速动画(页面切换等)
/* 缓动函数 - 融合 Material 3 + Apple 风格 */
--ease-standard: cubic-bezier(0.25, 0.1, 0.25, 1); // 标准缓动,流畅自然
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); // 弹性缓动,有活力
}
卡片样式变量
:root {
--card-radius: 4px; // 卡片圆角
--card-opacity: 0.7; // 卡片透明度
--card-blur: 20px; // 毛玻璃模糊度
--card-saturate: 180%; // 饱和度增强
--toolbar-blur: 12px; // 顶栏模糊度(卡片的 60%)
--page-background-opacity: 1; // 页面背景透明度
}
这些值可以通过后台设置动态调整:
// header.php
$card_opacity = get_option('argon_post_background_opacity', '0.7');
$card_blur = get_option('argon_card_blur', '20');
$card_saturate = get_option('argon_card_saturate', '180');
颜色变量
:root {
/* 日间模式颜色 */
--color-background: #f4f5f7; // 页面背景色
--color-foreground: #fff; // 卡片背景色
--color-widgets: #fff; // 小工具背景色
--color-border: #dce0e5; // 边框颜色
--color-text-deeper: #212529; // 深色文本
}
夜间模式通过 html.darkmode 类切换颜色变量:
html.darkmode body {
--color-background: #282828; // 深色背景
--color-foreground: #424242; // 深色卡片
--color-widgets: #555; // 深色小工具
--color-text-deeper: #eee; // 浅色文本
}
AMOLED 暗黑模式提供更深的黑色:
html.darkmode.amoled-dark body {
--color-background: #111; // 纯黑背景
--color-foreground: #000; // 纯黑卡片
--color-widgets: #151515; // 深黑小工具
}
后台设置框架
Argon 主题不依赖第三方设置框架(如 Redux 或 Codestar),而是使用原生 PHP + HTML 实现了一个轻量级的设置页面。
1. 设置页面结构
设置页面位于 settings.php,通过 functions.php 中的 add_theme_page 挂载:
// functions.php
function themeoptions_admin_menu() {
add_theme_page("Argon 主题设置", "Argon 主题选项", 'edit_themes', basename(__FILE__), 'themeoptions_page');
}
add_action('admin_menu', 'themeoptions_admin_menu');
页面内容主要由 themeoptions_page() 函数输出,采用 HTML Table 布局,包含多个选项卡(如“全局设置”、“侧栏设置”等)。
2. 选项存储与更新
设置数据的保存逻辑集成在 settings.php 顶部:
// settings.php
if (isset($_POST['update_themeoptions']) && $_POST['update_themeoptions'] == 'true') {
// 1. 验证 Nonce 安全令牌
check_admin_referer('argon_update_themeoptions', 'argon_update_themeoptions_nonce');
// 2. 处理复选框(未选中的 checkbox 不会提交,需要手动设为 false)
if (!isset($_POST['argon_enable_lazyload'])) $_POST['argon_enable_lazyload'] = 'false';
// 3. 循环更新所有选项
foreach ($_POST as $key => $value) {
if (isset($value) && $value != '') {
update_option($key, $value);
} else {
delete_option($key); // 空值则删除选项
}
}
// 4. 提示保存成功
echo '<div id="message" class="updated fade"><p><strong>设置已保存</strong></p></div>';
}
3. 添加新选项指南
要在主题中添加一个新的设置项,需遵循以下步骤:
- 在
settings.php的对应表格行中添加 HTML 输入控件。 name属性必须以argon_开头(这是约定,方便管理)。- 使用
get_option('option_name')获取当前值回显。
示例:添加一个“显示版权信息”的开关
<tr>
<th><label><?php _e('显示版权信息', 'argon');?></label></th>
<td>
<select name="argon_show_copyright">
<?php $show_copyright = get_option('argon_show_copyright', 'true'); ?>
<option value="true" <?php selected($show_copyright, 'true'); ?>>开启</option>
<option value="false" <?php selected($show_copyright, 'false'); ?>>关闭</option>
</select>
</td>
</tr>
前端交互架构 (PJAX & SPA)
Argon 主题采用 PJAX (PushState + AJAX) 技术实现单页应用 (SPA) 体验,核心逻辑位于 assets/js/argontheme.js。
1. PJAX 工作原理
- 拦截点击:监听所有
a标签点击事件。 - 获取内容:通过 AJAX 请求目标页面 URL。
- 解析响应:从响应 HTML 中提取
#content容器内容。 - 替换容器:将当前页面的
#content替换为新内容。 - 更新状态:使用
history.pushState更新浏览器 URL。 - 重载资源:重新执行内联脚本,重置事件监听器。
2. 初始化与重载机制
由于 PJAX 会替换页面的部分 DOM,依赖旧 DOM 的事件绑定与第三方实例需要在 PJAX 完成后重新初始化。Argon 的实现采用“首屏最小初始化 + PJAX 完整重初始化”的策略。
首屏加载完成后的初始化入口位于 argontheme.js 的 $(document).ready(...),主要执行性能优化模块初始化(如已加载)以及基础渲染:
$(document).ready(function(){
if (typeof initArgonPerformance === 'function') {
initArgonPerformance();
}
highlightJsRender();
waterflowInit();
});
PJAX 主流程通过 $(document).pjax(...) 建立,并在 pjax:beforeReplace 统一清理旧页面资源,在 pjax:complete 完整初始化新页面模块(包含数学公式渲染、脚本执行与各功能模块的错误隔离初始化)。
3. 脚本执行器 (Inline Script Executor)
PJAX 替换的 DOM 片段中可能包含内联 <script>。Argon 使用“创建新 script 节点并插入 head”的方式执行内联脚本,同时为每个脚本标记 data-pjax-executed,避免重复执行:
function executeInlineScripts(container) {
const scripts = container.querySelectorAll('script');
scripts.forEach((script) => {
if (script.getAttribute('data-pjax-executed') === 'true') return;
if (script.src) return;
if (!script.textContent || script.textContent.trim() === '') return;
const newScript = document.createElement('script');
newScript.text = script.textContent;
document.head.appendChild(newScript);
document.head.removeChild(newScript);
script.setAttribute('data-pjax-executed', 'true');
});
}
开发注意:如果你在文章或页面中编写了自定义 JavaScript,确保它们不依赖 document.ready,或者在 PJAX 重载时能被正确处理。
核心功能模块
1. 主题色系统
实现原理
主题色通过 PHP 动态生成 CSS 变量,支持用户自定义:
// header.php
$themecolor = get_option("argon_theme_color", "#5e72e4");
if (isset($_COOKIE["argon_custom_theme_color"])) {
$themecolor = $_COOKIE["argon_custom_theme_color"];
}
$RGB = hexstr2rgb($themecolor);
$HSL = rgb2hsl($RGB['R'], $RGB['G'], $RGB['B']);
生成的 CSS 变量:
:root {
--themecolor: #5e72e4;
--themecolor-R: 94;
--themecolor-G: 114;
--themecolor-B: 228;
--themecolor-H: 231;
--themecolor-S: 71;
--themecolor-L: 63;
}
沉浸式主题色
开启沉浸式主题色后,页面背景和卡片会使用主题色的浅色变体:
html.immersion-color body {
--color-background: rgb(var(--color-tint-86));
--color-foreground: rgb(var(--color-tint-92));
}
2. 夜间模式
切换方案
主题支持四种夜间模式切换方案,通过后台设置 argon_darkmode_autoswitch 选项控制:
- false(默认) - 手动切换,不自动切换
- system - 跟随系统,通过
prefers-color-scheme媒体查询 - time - 根据时间自动切换(22:00-7:00)
- alwayson - 始终开启夜间模式
实现代码
夜间模式的核心实现在 header.php 中:
// header.php
var darkmodeAutoSwitch = "<?php echo (get_option("argon_darkmode_autoswitch") == '' ? 'false' : get_option("argon_darkmode_autoswitch"));?>";
// 设置夜间模式
function setDarkmode(enable){
// 添加过渡类以启用平滑切换动画
document.documentElement.classList.add("theme-transitioning");
if (enable == true){
document.documentElement.classList.add("darkmode");
}else{
document.documentElement.classList.remove("darkmode");
}
// 过渡完成后移除过渡类(300ms 后)
setTimeout(function() {
document.documentElement.classList.remove("theme-transitioning");
}, 300);
// 触发滚动事件以更新顶栏状态
if (typeof jQuery !== 'undefined') {
jQuery(window).trigger("scroll");
} else {
window.dispatchEvent(new Event('scroll'));
}
// 触发自定义事件,供其他模块监听
document.dispatchEvent(new CustomEvent('argon:theme-switched', {
detail: { darkmode: enable }
}));
}
// 切换夜间模式
function toggleDarkmode(){
if (document.documentElement.classList.contains("darkmode")){
setDarkmode(false);
sessionStorage.setItem("Argon_Enable_Dark_Mode", "false");
}else{
setDarkmode(true);
sessionStorage.setItem("Argon_Enable_Dark_Mode", "true");
}
}
跟随系统方案
使用 matchMedia API 监听系统主题变化:
// header.php
function toggleDarkmodeByPrefersColorScheme(media){
// 如果用户手动设置过,则不自动切换
if (sessionStorage.getItem('Argon_Enable_Dark_Mode') == "false" ||
sessionStorage.getItem('Argon_Enable_Dark_Mode') == "true"){
return;
}
if (media.matches){
setDarkmode(true);
}else{
setDarkmode(false);
}
}
if (darkmodeAutoSwitch == 'system'){
var darkmodeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
darkmodeMediaQuery.addListener(toggleDarkmodeByPrefersColorScheme);
toggleDarkmodeByPrefersColorScheme(darkmodeMediaQuery);
}
根据时间方案
// header.php
function toggleDarkmodeByTime(){
// 如果用户手动设置过,则不自动切换
if (sessionStorage.getItem('Argon_Enable_Dark_Mode') == "false" ||
sessionStorage.getItem('Argon_Enable_Dark_Mode') == "true"){
return;
}
let hour = new Date().getHours();
// 默认:22:00-7:00 开启夜间模式
// 可通过过滤器 argon_darkmode_time_check 自定义时间范围
if (<?php echo apply_filters("argon_darkmode_time_check", "hour < 7 || hour >= 22")?>){
setDarkmode(true);
}else{
setDarkmode(false);
}
}
if (darkmodeAutoSwitch == 'time'){
toggleDarkmodeByTime();
}
AMOLED 暗黑模式
AMOLED 模式提供更深的黑色背景,适合 AMOLED 屏幕节省电量:
// header.php
function toggleAmoledDarkMode(){
document.documentElement.classList.toggle("amoled-dark");
if (document.documentElement.classList.contains("amoled-dark")){
localStorage.setItem("Argon_Enable_Amoled_Dark_Mode", "true");
}else{
localStorage.setItem("Argon_Enable_Amoled_Dark_Mode", "false");
}
}
// 页面加载时恢复 AMOLED 模式设置
if (localStorage.getItem("Argon_Enable_Amoled_Dark_Mode") == "true"){
document.documentElement.classList.add("amoled-dark");
}else if (localStorage.getItem("Argon_Enable_Amoled_Dark_Mode") == "false"){
document.documentElement.classList.remove("amoled-dark");
}
用户偏好存储
夜间模式的用户选择存储在 sessionStorage 中,AMOLED 模式存储在 localStorage 中:
sessionStorage.Argon_Enable_Dark_Mode- 夜间模式开关(会话级别)localStorage.Argon_Enable_Amoled_Dark_Mode- AMOLED 模式开关(持久化)
这样设计的原因:
- 夜间模式使用 sessionStorage,每次打开浏览器都会根据设置重新判断
- AMOLED 模式使用 localStorage,用户设置会永久保存
3. PJAX 无刷新加载
配置与初始化
PJAX 使用 jquery-pjax 库实现页面无刷新加载。配置在 argontheme.js 中:
// argontheme.js
$.pjax.defaults.timeout = 10000; // 超时时间 10 秒
var pjaxContainerSelectors = ['#primary', '#leftbar_part1_menu', '#leftbar_part2_inner', '.page-information-card-container', '#rightbar', '#wpadminbar'];
var pjaxContainers = pjaxContainerSelectors.filter(function(selector) {
return document.querySelector(selector);
});
$.pjax.defaults.container = pjaxContainers; // 要替换的容器
$.pjax.defaults.fragment = pjaxContainers; // 从响应中提取的片段
链接拦截
主题会自动拦截站内链接的点击事件:
// argontheme.js
$(document).pjax(
"a[href]:not([no-pjax]):not(.no-pjax):not([target='_blank']):not([download]):not(.reference-link):not(.reference-list-backlink):not([href^='#'])",
pjaxContainers.length ? pjaxContainers[0] : '#primary',
{ fragment: (pjaxContainers.length ? pjaxContainers : ['#primary']), timeout: $.pjax.defaults.timeout }
);
页面切换流程
PJAX 加载过程中会触发一系列事件:
// argontheme.js
// 1. 开始发送请求
$(document).on('pjax:send', function() {
// 设置加载状态
pjaxLoading = true;
// 显示加载动画
$('#content').addClass('pjax-loading');
// 添加淡出效果
$('#content, #leftbar, #rightbar').css('opacity', '0');
});
// 2. 请求成功,内容已替换
$(document).on('pjax:complete', function() {
// 清除加载状态
pjaxLoading = false;
// 移除加载动画
$('#content').removeClass('pjax-loading');
// 添加淡入效果
$('#content, #leftbar, #rightbar').animate({
opacity: 1
}, argonConfig.pjax_animation_durtion);
// 滚动到顶部
$('html, body').animate({
scrollTop: 0
}, argonConfig.pjax_animation_durtion);
// 重新初始化各功能模块(主题在 pjax:complete 内集中处理,如 waterflowInit / lazyloadInit / zoomifyInit / highlightJsRender 等)
});
// 3. 请求失败
$(document).on('pjax:error', function(xhr, textStatus, error) {
console.error('PJAX 加载失败:', error);
// 失败时会自动回退到普通页面跳转
});
// 4. 超时
$(document).on('pjax:timeout', function(event) {
// 阻止默认的超时处理(会中断请求)
event.preventDefault();
});
重新初始化
PJAX 加载完成后,需要重新初始化页面功能:
// argontheme.js
// 主题在 pjax:complete 事件里集中完成“功能重置/再初始化”(单个模块失败不会影响其他模块)
try { waterflowInit(); } catch (err) {}
try { lazyloadInit(); } catch (err) {}
try { zoomifyInit(); } catch (err) {}
try { highlightJsRender(); } catch (err) {}
try { panguInit(); } catch (err) {}
try { clampInit(); } catch (err) {}
try { tippyInit(); } catch (err) {}
try { getGithubInfoCardContent(); } catch (err) {}
try { showPostOutdateToast(); } catch (err) {}
try { calcHumanTimesOnPage(); } catch (err) {}
try { foldLongComments(); } catch (err) {}
try { foldLongShuoshuo(); } catch (err) {}
try { handleHashNavigation(); } catch (err) {}
禁用 PJAX
可以通过以下方式禁用 PJAX:
- 后台设置中禁用(
argon_pjax_disabled选项) - 给链接添加
no-pjax属性:
<a href="/page" no-pjax>普通跳转</a>
- 给链接添加
target属性:
<a href="/page" target="_blank">新窗口打开</a>
浏览器历史记录
PJAX 会自动更新浏览器历史记录,支持前进后退按钮:
// argontheme.js
$(window).on('popstate', function() {
// 浏览器前进/后退时,PJAX 会自动加载对应页面
});
性能优化
PJAX 加载时的性能优化措施:
- 只替换必要的容器(content、leftbar、rightbar)
- 使用 CSS 动画而非 JavaScript 动画
- 延迟初始化非关键功能
- 复用已加载的资源(CSS、JS)
// argontheme.js
// 动画时长可配置,设为 0 可禁用动画
pjax_animation_durtion: <?php echo (get_option("argon_disable_pjax_animation") == 'true' ? '0' : '600'); ?>
4. 瀑布流布局
实现原理
瀑布流布局通过 JavaScript 动态计算每个文章卡片的位置,实现类似 Pinterest 的多列布局。
核心算法
// argontheme.js
function waterflowInit() {
// 如果设置为单列,直接返回
if (argonConfig.waterflow_columns == "1") {
return;
}
// 监听图片加载,加载完成后重新计算布局
$("#main.article-list img").each(function(index, ele){
ele.onload = function(){
waterflowInit();
}
});
// 确定列数
let columns;
if (argonConfig.waterflow_columns == "2and3") {
// 自适应 2-3 列
if ($("#main").outerWidth() > 1000) {
columns = 3;
} else {
columns = 2;
}
}else{
columns = parseInt(argonConfig.waterflow_columns);
}
// 响应式适配:窄屏幕时强制单列
if ($("#main").outerWidth() < 650 && columns == 2) {
columns = 1;
}else if ($("#main").outerWidth() < 800 && columns == 3) {
columns = 1;
}
// 记录每列的高度
let heights = [0, 0, 0];
// 获取当前最矮列的索引
function getMinHeightPosition(){
let res = 0, minn = 2147483647;
for (var i = 0; i < columns; i++) {
if (heights[i] < minn) {
minn = heights[i];
res = i;
}
}
return res;
}
// 获取最高列的高度
function getMaxHeight(){
let res = 0;
for (let i in heights) {
res = Math.max(res, heights[i]);
}
return res;
}
// 添加瀑布流类
$("#primary").css("transition", "none").addClass("waterflow");
let $container = $("#main.article-list");
if (!$container.length){
return;
}
// 获取所有文章卡片
let $items = $container.find("article.post:not(.no-results), .shuoshuo-preview-container");
// 列数不能超过文章数量
columns = Math.max(Math.min(columns, $items.length), 1);
if (columns == 1) {
// 单列模式:移除瀑布流样式
$container.removeClass("waterflow");
$items.css("transition", "")
.css("position", "")
.css("width", "")
.css("top", "")
.css("left", "")
.css("margin", "");
$(".waterflow-placeholder").remove();
}else{
// 多列模式:计算每个卡片的位置
$container.addClass("waterflow");
$items.each(function(index, item) {
let $item = $(item);
// 设置卡片宽度(平分容器宽度,减去间距)
$item.css("transition", "none")
.css("position", "absolute")
.css("width", "calc(" + (100 / columns) + "% - " + (10 * (columns - 1) / columns) + "px)")
.css("margin", 0);
// 计算卡片高度(包含 10px 间距)
let itemHeight = $item.outerHeight() + 10;
// 找到最矮的列
let pos = getMinHeightPosition();
// 设置卡片位置
$item.css("top", heights[pos] + "px")
.css("left", (pos * $item.outerWidth() + 10 * pos) + "px");
// 更新该列的高度
heights[pos] += itemHeight;
});
}
// 创建占位元素,撑开容器高度
if ($(".waterflow-placeholder").length) {
$(".waterflow-placeholder").css("height", getMaxHeight() + "px");
}else{
$container.prepend("<div class='waterflow-placeholder' style='height: " + getMaxHeight() +"px;'></div>");
}
}
初始化与监听
// argontheme.js
// 页面加载时初始化
waterflowInit();
// 非单列模式下监听窗口大小变化
if (argonConfig.waterflow_columns != "1") {
// 窗口大小改变时重新计算
$(window).resize(function(){
waterflowInit();
});
// 监听 DOM 变化(如 PJAX 加载新内容)
new MutationObserver(function(mutations, observer){
waterflowInit();
}).observe(document.querySelector("#primary"), {
'childList': true
});
}
移动端布局切换
移动端可以使用不同的文章列表布局样式:
// argontheme.js
!function(){
var mobileLayout = argonConfig.article_list_layout_mobile || "1";
var isMobile = window.innerWidth <= 900;
function applyMobileLayout() {
var nowMobile = window.innerWidth <= 900;
if (nowMobile) {
// 添加移动端布局类
$("html").addClass("mobile-layout-" + mobileLayout);
} else {
// 移除移动端布局类
$("html").removeClass("mobile-layout-1 mobile-layout-2 mobile-layout-3");
}
}
applyMobileLayout();
$(window).resize(applyMobileLayout);
}();
配置选项
瀑布流列数通过后台设置 argon_article_list_waterflow 控制:
"1"- 单列(默认)"2"- 双列"3"- 三列"2and3"- 自适应 2-3 列(宽屏 3 列,窄屏 2 列)
性能优化
- 图片加载完成后才计算布局,避免高度计算错误
- 使用
MutationObserver监听 DOM 变化,而非轮询 - 窗口大小改变时使用防抖,避免频繁计算
- 单列模式下不监听事件,减少性能开销
CSS 配合
/* style.css */
#main.article-list.waterflow {
position: relative;
}
#main.article-list.waterflow article.post {
position: absolute;
transition: top 0.3s ease, left 0.3s ease;
}
.waterflow-placeholder {
width: 100%;
pointer-events: none;
}
5. 评论系统
数据库结构
评论数据存储在 WordPress 标准的 wp_comments 表中,扩展字段通过 wp_commentmeta 表存储:
标准字段(wp_comments 表):
comment_ID- 评论 IDcomment_post_ID- 所属文章 IDcomment_author- 评论者昵称comment_author_email- 评论者邮箱comment_author_url- 评论者网站comment_content- 评论内容(HTML)comment_parent- 父评论 ID(用于回复)user_id- 用户 ID(登录用户)comment_date- 评论时间
扩展字段(wp_commentmeta 表):
comment_upvote- 点赞数comment_is_private- 是否私密评论comment_use_markdown- 是否使用 Markdowncomment_content_source- Markdown 源码comment_edit_history- 编辑历史(JSON 格式)comment_pinned- 是否置顶qq- QQ 号(用于 QQ 头像)
AJAX 发送评论
前端通过 AJAX 提交评论,避免页面刷新:
// argontheme.js
function postComment() {
let formData = {
action: 'ajax_post_comment',
comment_post_ID: postID,
author: $('#comment_author').val(),
email: $('#comment_email').val(),
url: $('#comment_url').val(),
comment: $('#comment_content').val(),
comment_parent: replyID,
use_markdown: $('#use_markdown').is(':checked') ? 'true' : 'false',
is_private: $('#is_private').is(':checked') ? 'true' : 'false',
argon_nonce: $('#argon_comment_nonce').val(),
// 验证码相关字段
captcha_seed: $('#captcha_seed').val(),
captcha_answer: $('#captcha_answer').val()
};
$.ajax({
type: 'POST',
url: argonConfig.wp_path + "wp-admin/admin-ajax.php",
dataType: "json",
data: formData,
beforeSend: function() {
$('#comment_submit').text(__('发送中'));
$('#comment_submit').prop('disabled', true);
},
success: function(result) {
if (result.status == "success") {
// 插入新评论到页面
insertComment(result.html, result.parentID, result.commentOrder);
// 清空表单
$('#comment_content').val('');
// 更新验证码
updateCaptcha(result.newCaptchaSeed, result.newCaptcha);
} else {
alert(result.msg);
}
},
error: function() {
alert(__('评论发送失败'));
},
complete: function() {
$('#comment_submit').text(__('发送'));
$('#comment_submit').prop('disabled', false);
}
});
}
PHP 处理函数
服务器端处理评论提交:
// functions.php
function ajax_post_comment(){
// 1. IP 黑名单检查
if (argon_is_ip_blocked_global()) {
exit(json_encode(array(
'status' => 'failed',
'msg' => __('您的 IP 已被限制访问', 'argon'),
'isAdmin' => current_user_can('level_7')
)));
}
// 2. 私密评论权限检查
$parentID = $_POST['comment_parent'];
if (is_comment_private_mode($parentID)){
if (!user_can_view_comment($parentID)){
exit(json_encode(array(
'status' => 'failed',
'msg' => __('不能回复其他人的悄悄话评论', 'argon'),
'isAdmin' => current_user_can('level_7')
)));
}
}
// 3. QQ 邮箱处理
if (get_option('argon_comment_enable_qq_avatar') == 'true'){
if (check_qqnumber($_POST['email'])){
$_POST['qq'] = $_POST['email'];
$_POST['email'] .= "@qq.com";
}
}
// 4. CSRF nonce 校验
if (!isset($_POST['argon_nonce']) || !wp_verify_nonce($_POST['argon_nonce'], 'argon_comment')) {
exit(json_encode(array(
'status' => 'failed',
'msg' => __('请求已失效,请刷新页面后重试', 'argon'),
'isAdmin' => current_user_can('level_7')
)));
}
// 5. Honeypot 反垃圾检查
if (!empty($_POST['argon_comment_honeypot'])) {
exit(json_encode(array(
'status' => 'failed',
'msg' => __('Spam detected', 'argon'),
'isAdmin' => current_user_can('level_7')
)));
}
// 6. 速率限制(防止刷评论)
$rate_enable = get_option('argon_rate_limit_enable', 'true');
if ($rate_enable === 'true') {
$ip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0] : $_SERVER['REMOTE_ADDR'];
$ip = sanitize_text_field($ip);
$rate_key = 'argon_rate_cmt_' . md5($ip);
$state = get_transient($rate_key);
$now = time();
$window = intval(get_option('argon_rate_limit_window', 300)); // 窗口秒数(默认 5 分钟)
$max_count = intval(get_option('argon_rate_limit_max_count', 5)); // 窗口内最大次数
$min_interval = intval(get_option('argon_rate_limit_min_interval', 10)); // 两次最小间隔(秒)
// 检查最小间隔
if (!is_array($state)) {
$state = array('count' => 0, 'start' => $now, 'last' => 0);
}
if ($state['last'] > 0 && ($now - intval($state['last'])) < $min_interval) {
exit(json_encode(array(
'status' => 'failed',
'msg' => __('您评论过快,请稍后再试', 'argon'),
'isAdmin' => current_user_can('level_7')
)));
}
// 检查窗口内次数
if (($now - intval($state['start'])) < $window && intval($state['count']) >= $max_count) {
exit(json_encode(array(
'status' => 'failed',
'msg' => __('操作过于频繁,请稍后再试', 'argon'),
'isAdmin' => current_user_can('level_7')
)));
}
// 更新速率状态
if (($now - intval($state['start'])) >= $window) {
$state['start'] = $now;
$state['count'] = 0;
}
$state['count'] = intval($state['count']) + 1;
$state['last'] = $now;
set_transient($rate_key, $state, $window);
}
// 7. 提交评论
$comment = wp_handle_comment_submission(wp_unslash($_POST));
if (is_wp_error($comment)){
$msg = $comment->get_error_message();
exit(json_encode(array(
'status' => 'failed',
'msg' => $msg,
'isAdmin' => current_user_can('level_7')
)));
}
// 8. 设置 Cookie
$user = wp_get_current_user();
do_action('set_comment_cookies', $comment, $user);
// 9. 生成评论 HTML
$html = wp_list_comments(
array(
'type' => 'comment',
'callback' => 'argon_comment_format',
'echo' => false
),
array($comment)
);
// 10. 生成新验证码
$newCaptchaSeed = get_comment_captcha_seed(true);
$newCaptcha = get_comment_captcha($newCaptchaSeed);
// 11. 返回结果
exit(json_encode(array(
'status' => 'success',
'html' => $html,
'id' => $comment->comment_ID,
'parentID' => $comment->comment_parent,
'commentOrder' => (get_option("comment_order") == "" ? "desc" : get_option("comment_order")),
'newCaptchaSeed' => $newCaptchaSeed,
'newCaptcha' => $newCaptcha,
'isAdmin' => current_user_can('level_7'),
'isLogin' => is_user_logged_in()
)));
}
add_action('wp_ajax_ajax_post_comment', 'ajax_post_comment');
add_action('wp_ajax_nopriv_ajax_post_comment', 'ajax_post_comment');
Markdown 解析
评论支持 Markdown 语法,使用 Parsedown 库解析:
// functions.php
require_once(get_template_directory() . '/parsedown.php');
function comment_markdown_parse($comment_content){
// 允许评论中额外的 HTML 标签
global $allowedtags;
$allowedtags['pre'] = array('class' => array());
$allowedtags['i'] = array('class' => array(), 'aria-hidden' => array());
$allowedtags['img'] = array('src' => array(), 'alt' => array(), 'class' => array());
$allowedtags['ol'] = array();
$allowedtags['ul'] = array();
$allowedtags['li'] = array();
$allowedtags['span'] = array('class' => array(), 'style' => array(), 'title' => array());
$allowedtags['a']['class'] = array();
$allowedtags['a']['data-src'] = array();
$allowedtags['a']['target'] = array();
$allowedtags['h1'] = $allowedtags['h2'] = $allowedtags['h3'] = $allowedtags['h4'] = $allowedtags['h5'] = $allowedtags['h6'] = array();
// 解析 Markdown
$parsedown = new _Parsedown();
$res = $parsedown->text($comment_content);
// 为链接添加 target="_blank"
$res = preg_replace(
'/<a (.*?)>(.*?)<\/a>/',
'<a $1 target="_blank">$2</a>',
$res
);
return $res;
}
// 评论发送前处理
function post_comment_preprocessing($comment){
// 保存评论未经 Markdown 解析的源码
$_POST['comment_content_source'] = $comment['comment_content'];
// 应用评论宏(黑幕、彩幕等)
$comment['comment_content'] = argon_apply_comment_macros($comment['comment_content']);
// Markdown 解析
if ($_POST['use_markdown'] == 'true' && get_option("argon_comment_allow_markdown") != "false"){
$comment['comment_content'] = comment_markdown_parse($comment['comment_content']);
}
return $comment;
}
add_filter('preprocess_comment', 'post_comment_preprocessing');
评论宏
主题支持多种评论宏,用于实现特殊效果:
// functions.php
function argon_apply_comment_macros($text){
// 黑幕:{{黑幕|内容}} 或 {{黑幕|内容|提示}}
$text = preg_replace_callback('/\{\{黑幕\|([\s\S]*?)(?:\|([\s\S]*?))?\}\}/u', function($m){
$content = trim($m[1]);
$title = isset($m[2]) ? trim($m[2]) : '你知道的太多了';
return '<span class="heimu"' . (strlen($title) ? ' title="' . htmlspecialchars($title, ENT_QUOTES) . '"' : '') . '>' . htmlspecialchars($content) . '</span>';
}, $text);
// 彩幕:{{彩幕|内容|背景色|提示|前景色}}
$text = preg_replace_callback('/\{\{彩幕\|([\s\S]*?)\}\}/u', function($m){
$parts = explode('|', $m[1]);
$content = isset($parts[0]) ? trim($parts[0]) : '';
$bg = isset($parts[1]) ? trim($parts[1]) : '#252525';
$tip = isset($parts[2]) ? trim($parts[2]) : '你知道的太多了';
$fg = isset($parts[3]) ? trim($parts[3]) : '';
// 如果没有指定前景色,根据背景色亮度自动计算
if (empty($fg)) {
$hex = ltrim($bg, '#');
if (strlen($hex) == 6) {
$r = hexdec(substr($hex, 0, 2));
$g = hexdec(substr($hex, 2, 2));
$b = hexdec(substr($hex, 4, 2));
$luma = 0.2126 * $r + 0.7152 * $g + 0.0722 * $b;
$fg = ($luma >= 180) ? '#000' : '#fff';
} else {
$fg = '#fff';
}
}
$style = '--curtain-bg: ' . htmlspecialchars($bg, ENT_QUOTES) . '; --curtain-fg: ' . htmlspecialchars($fg, ENT_QUOTES) . ';';
return '<span class="color-curtain"' . (strlen($tip) ? ' title="' . htmlspecialchars($tip, ENT_QUOTES) . '"' : '') . ' style="' . $style . '">' . htmlspecialchars($content) . '</span>';
}, $text);
// 文字模糊:{{文字模糊|内容|提示|颜色|时间}}
$text = preg_replace_callback('/\{\{文字模糊\|([\s\S]*?)\}\}/u', function($m){
$parts = explode('|', $m[1]);
$content = isset($parts[0]) ? trim($parts[0]) : '';
$tip = isset($parts[1]) ? trim($parts[1]) : '你知道的太多了';
$color = isset($parts[2]) ? trim($parts[2]) : '';
$time = isset($parts[3]) ? trim($parts[3]) : '0.2';
$style = '--text-blur-transition-time: ' . preg_replace('/[^0-9\.]/', '', $time) . 's;';
if (strlen($color) > 0) {
$style .= ' --text-blur-color: ' . htmlspecialchars($color, ENT_QUOTES) . ';';
}
return '<span class="text-blur"' . (strlen($tip) ? ' title="' . htmlspecialchars($tip, ENT_QUOTES) . '"' : '') . ' style="' . $style . '">' . htmlspecialchars($content) . '</span>';
}, $text);
return $text;
}
add_filter('comment_text', 'argon_comment_text_render', 9);
使用示例:
{{黑幕|剧透内容}}- 鼠标悬停显示{{彩幕|彩色文字|#ff0000}}- 彩色背景{{文字模糊|模糊文字}}- 鼠标悬停清晰
6. 说说功能
自定义文章类型
说说是一个独立的自定义文章类型,类似微博的短内容发布功能:
// functions.php
add_action('init', 'init_shuoshuo');
function init_shuoshuo(){
$labels = array(
'name' => __('说说', 'argon'),
'singular_name' => __('说说', 'argon'),
'add_new' => __('发表说说', 'argon'),
'add_new_item' => __('发表说说', 'argon'),
'edit_item' => __('编辑说说', 'argon'),
'new_item' => __('新说说', 'argon'),
'view_item' => __('查看说说', 'argon'),
'search_items' => __('搜索说说', 'argon'),
'not_found' => __('暂无说说', 'argon'),
'not_found_in_trash' => __('没有已遗弃的说说', 'argon'),
'parent_item_colon' => '',
'menu_name' => __('说说', 'argon')
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'exclude_from_search' => true,
'query_var' => true,
'rewrite' => array(
'slug' => 'shuoshuo',
'with_front' => false
),
'capability_type' => 'post',
'has_archive' => false,
'hierarchical' => false,
'menu_position' => null,
'menu_icon' => 'dashicons-format-quote',
'supports' => array('editor', 'author', 'title', 'custom-fields', 'comments')
);
register_post_type('shuoshuo', $args);
}
页面模板
说说页面使用独立的模板文件 shuoshuo.php:
// shuoshuo.php
/*
Template Name: 说说
*/
query_posts("post_type=shuoshuo&post_status=publish&posts_per_page=-1");
说说内容模板
说说内容通过 template-parts/content-shuoshuo.php 渲染:
<div class="shuoshuo-item card">
<div class="card-body">
<div class="shuoshuo-author">
<?php echo get_avatar(get_the_author_meta('ID'), 40); ?>
<span class="shuoshuo-author-name">
<?php the_author(); ?>
</span>
</div>
<div class="shuoshuo-content">
<?php the_content(); ?>
</div>
<div class="shuoshuo-meta">
<span class="shuoshuo-time">
<?php echo get_the_date('Y-m-d H:i'); ?>
</span>
<span class="shuoshuo-comment-count">
<?php comments_number('0 条评论', '1 条评论', '% 条评论'); ?>
</span>
</div>
</div>
</div>
说说操作按钮
支持点赞、评论、分享等操作,通过 template-parts/shuoshuo-operations.php 实现。
折叠长说说
当说说内容超过一定长度时自动折叠:
// argontheme.js
if (argonConfig.fold_long_shuoshuo) {
$('.shuoshuo-content').each(function() {
let $content = $(this);
if ($content.height() > 300) {
$content.addClass('folded');
$content.after('<a class="unfold-btn">展开</a>');
}
});
}
7. AI 摘要功能
功能概述
AI 摘要功能允许为文章自动生成摘要,支持多种 AI 服务提供商。
查询接口
通过独立的 PHP 文件 ai-summary-query.php 处理 AI 摘要请求:
// ai-summary-query.php
$wp_load_path = dirname(dirname(dirname(dirname(__FILE__)))) . '/wp-load.php';
if (!file_exists($wp_load_path)) $wp_load_path = $_SERVER['DOCUMENT_ROOT'] . '/wp-load.php';
require_once($wp_load_path);
安全防护
实现了完善的 IP 访问限制机制:
/**
* 获取客户端真实 IP
* 优先级:CF-Connecting-IP > X-Real-IP > X-Forwarded-For > REMOTE_ADDR
*/
function argon_ai_query_get_client_ip() {
$ip = '';
// Cloudflare
if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
}
// Nginx proxy_pass 或其他反向代理
elseif (!empty($_SERVER['HTTP_X_REAL_IP'])) {
$ip = $_SERVER['HTTP_X_REAL_IP'];
}
// 通过代理转发(取第一个 IP)
elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
}
// 直连 IP
else {
$ip = $_SERVER['REMOTE_ADDR'];
}
return trim($ip);
}
访问频率限制
/**
* 检查 IP 访问频率限制
* @return bool|string true 表示允许访问,字符串表示错误信息
*/
function argon_ai_query_check_rate_limit() {
$client_ip = argon_ai_query_get_client_ip();
if (empty($client_ip)) {
return __('无法获取客户端 IP', 'argon');
}
$transient_key = 'ai_query_lock_' . md5($client_ip);
$rate_limit_key = 'ai_query_rate_' . md5($client_ip);
// 检查是否有正在进行的查询(单线程限制)
if (get_transient($transient_key)) {
return __('请等待上一次查询完成', 'argon');
}
// 检查访问频率(60秒内最多10次)
$access_count = get_transient($rate_limit_key);
if ($access_count === false) {
set_transient($rate_limit_key, 1, 60);
} else {
if ($access_count >= 10) {
return __('访问过于频繁,请稍后再试', 'argon');
}
set_transient($rate_limit_key, $access_count + 1, 60);
}
// 设置查询锁(3秒超时)
set_transient($transient_key, 1, 3);
return true;
}
AI 服务配置
在后台设置页面配置 AI 服务:
- API 端点 URL
- API 密钥
- 模型名称
- 请求参数(温度、最大 token 数等)
- 超时设置
前端调用
// argontheme.js
function loadAISummary(postId) {
$.ajax({
url: argonConfig.wp_path + '?argon_ai_query=1',
type: 'POST',
data: {
post_id: postId
},
success: function(response) {
$('#ai-summary-content').html(response.summary);
}
});
}
8. 后台设置系统
设置页面结构
settings.php 是主题的后台设置页面,包含 7000+ 行代码(当前仓库约 7273 行),提供完整的主题配置界面。
设置分类
设置页面分为多个选项卡:
- 外观设置 - 主题色、布局、卡片样式
- 功能设置 - PJAX、懒加载、代码高亮
- 文章设置 - 文章列表样式、摘要长度
- 评论设置 - 评论验证码、邮件通知
- 说说设置 - 说说页面配置
- AI 设置 - AI 摘要服务配置
- 性能优化 - 资源合并、缓存控制
- 高级设置 - 自定义 CSS/JS、SEO
选项存储
所有设置通过 WordPress Options API 存储:
// 保存设置
update_option('argon_theme_color', $_POST['argon_theme_color']);
// 读取设置
$theme_color = get_option('argon_theme_color', '#5e72e4');
设置验证
提交设置时进行安全验证:
// settings.php
if (isset($_POST['save'])) {
// 验证 nonce
check_admin_referer('argon_theme_options');
// 验证权限
if (!current_user_can('manage_options')) {
wp_die(__('权限不足', 'argon'));
}
// 保存设置
foreach ($_POST as $key => $value) {
if (strpos($key, 'argon_') === 0) {
update_option($key, sanitize_text_field($value));
}
}
echo '<div class="updated"><p>设置已保存</p></div>';
}
动态设置界面
设置页面使用 jQuery 实现动态交互:
// settings.php 内嵌脚本
$(document).ready(function() {
// 选项卡切换
$('.nav-tab').click(function() {
let target = $(this).data('target');
$('.nav-tab').removeClass('nav-tab-active');
$(this).addClass('nav-tab-active');
$('.settings-section').hide();
$('#' + target).show();
});
// 颜色选择器
$('.color-picker').wpColorPicker();
// 拖拽排序
dragula([$('#sortable-list')[0]]);
});
AI API 配置表格
支持配置多个 AI 服务提供商:
<table class="argon-ai-api-table">
<thead>
<tr>
<th>服务名称</th>
<th>API 端点</th>
<th>API 密钥</th>
<th>模型</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody id="argon-unified-api-list">
<?php
$api_list = get_option('argon_ai_api_list', []);
foreach ($api_list as $api) {
echo '<tr>';
echo '<td>' . esc_html($api['name']) . '</td>';
echo '<td>' . esc_html($api['endpoint']) . '</td>';
echo '<td>***</td>';
echo '<td>' . esc_html($api['model']) . '</td>';
echo '<td>' . ($api['enabled'] ? '启用' : '禁用') . '</td>';
echo '<td><button class="edit-api">编辑</button></td>';
echo '</tr>';
}
?>
</tbody>
</table>
9. 性能优化
资源合并
主题支持将多个 CSS 和 JS 文件合并为单个文件:
// functions.php
function argon_merge_assets() {
$css_files = [
'assets/css/bootstrap/bootstrap.min.css',
'assets/css/argon.min.css',
'style.css'
];
$merged_css = '';
foreach ($css_files as $file) {
$merged_css .= file_get_contents(get_template_directory() . '/' . $file);
}
file_put_contents(
get_template_directory() . '/assets/argon_css_merged.css',
$merged_css
);
}
懒加载
图片懒加载通过 Lazy Load 库实现:
// argontheme.js
function initLazyload() {
if (!argonConfig.lazyload) return;
$('img[data-src]').lazyload({
effect: argonConfig.lazyload_effect,
threshold: argonConfig.lazyload_threshold,
failure_limit: 10
});
}
强制刷新缓存
提供强制刷新功能,用于更新后清除客户端缓存:
// functions.php
function argon_is_force_refresh_enabled() {
$enabled_time = get_option('argon_force_refresh_enabled_time', 0);
if ($enabled_time == 0) {
return false;
}
// 检查是否超过 1 小时
if (time() - $enabled_time > 3600) {
// 自动关闭
update_option('argon_force_refresh_enabled_time', 0);
return false;
}
return true;
}
function argon_get_assets_version() {
if (argon_is_force_refresh_enabled()) {
$enabled_time = get_option('argon_force_refresh_enabled_time', 0);
return $GLOBALS['theme_version'] . '.r' . $enabled_time;
}
return $GLOBALS['theme_version'];
}
缓存控制
针对不同类型的资源设置不同的缓存策略:
// functions.php
function argon_static_resource_headers() {
if (is_admin() || argon_is_force_refresh_enabled()) {
return;
}
$request_uri = $_SERVER['REQUEST_URI'] ?? '';
$static_extensions = array('.css', '.js', '.jpg', '.jpeg', '.png', '.gif', '.svg', '.woff', '.woff2', '.ttf', '.eot', '.ico');
$is_static = false;
foreach ($static_extensions as $ext) {
if (strpos($request_uri, $ext) !== false) {
$is_static = true;
break;
}
}
if ($is_static && !headers_sent()) {
// 静态资源缓存 1 年
header('Cache-Control: public, max-age=31536000, immutable', true);
}
}
add_action('send_headers', 'argon_static_resource_headers', 30);
移动端缓存控制
禁止移动端浏览器缓存 HTML 页面,避免内容更新不及时:
// functions.php
function argon_prevent_mobile_cache() {
if (wp_is_mobile() && !is_admin()) {
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
}
}
add_action('send_headers', 'argon_prevent_mobile_cache');
10. 安全机制
HTTP 安全头部
设置安全相关的 HTTP 头部:
// functions.php
function argon_security_headers() {
if (is_admin()) {
return;
}
if (!headers_sent()) {
// 使用 Content-Security-Policy 替代 X-Frame-Options
// 允许同源嵌入,防止点击劫持
header("Content-Security-Policy: frame-ancestors 'self'", false);
// 移除 X-Frame-Options(如果存在)
header_remove('X-Frame-Options');
}
}
add_action('send_headers', 'argon_security_headers', 20);
AJAX 请求验证
所有 AJAX 请求都需要验证 nonce:
// functions.php
function ajax_post_comment() {
// 验证 nonce
check_ajax_referer('post_comment', 'nonce');
// 验证验证码
if (argon_is_comment_captcha_enabled()) {
verify_captcha();
}
// 处理评论...
}
add_action('wp_ajax_ajax_post_comment', 'ajax_post_comment');
add_action('wp_ajax_nopriv_ajax_post_comment', 'ajax_post_comment');
内容过滤
使用 WordPress 内置函数过滤用户输入:
// 过滤 HTML 标签
$comment_content = wp_filter_kses($_POST['comment']);
// 转义输出
echo esc_html($user_name);
echo esc_attr($user_email);
echo esc_url($user_url);
权限检查
在执行敏感操作前检查用户权限:
// functions.php
function user_edit_comment() {
check_ajax_referer('edit_comment', 'nonce');
$comment_id = intval($_POST['id']);
$comment = get_comment($comment_id);
// 权限检查:管理员或评论作者本人
if (!current_user_can('edit_comment', $comment_id) &&
$comment->user_id != get_current_user_id()) {
wp_send_json(array('status' => 'failed', 'reason' => '权限不足'));
}
// 执行编辑操作...
}
验证码系统
评论与部分交互功能支持验证码验证,用于减少机器人提交与恶意请求。验证码启用逻辑采用“评论独立开关 + 全局开关”组合:
- 评论验证码开关:
argon_comment_captcha_mode,取值为enabled/disabled/global - 全局验证码开关:
argon_need_captcha(兼容旧选项argon_comment_need_captcha)
当前版本的验证码实现包含:
- 算术验证码:通过
captcha_calculation生成挑战题,get_comment_captcha()输出题目,get_comment_captcha_answer()用于校验答案 - 极验验证码 (Geetest 4):通过
geetest_validate(...)校验前端提交的四个字段(lot_number/captcha_output/pass_token/gen_time)
评论场景是否启用验证码由 argon_is_comment_captcha_enabled() 决定:
function argon_is_comment_captcha_enabled() {
$mode = get_option('argon_comment_captcha_mode', 'global');
if ($mode === 'enabled') {
return true;
} elseif ($mode === 'disabled') {
return false;
}
return argon_is_captcha_enabled();
}
11. 友链管理系统
功能概述
Argon 主题内置了一套独立的友链管理系统,支持友链的申请、审核、分组和展示,无需依赖第三方插件。
数据存储
友链数据不使用 WordPress 的 Links Manager API(已废弃),而是存储在 argon_friend_links 选项中,数据结构为 JSON 数组。该数组既包含展示所需字段,也包含审核与可用性检测的状态字段:
$links = get_option('argon_friend_links', array());
// 结构示例:
// [
// {
// 'id' => 'fl_5f...',
// 'name' => '站点名称',
// 'url' => 'https://example.com',
// 'avatar' => '...',
// 'description' => '...',
// 'category' => '',
// 'email' => '',
// 'message' => '',
// 'status' => 'approved', // pending, approved
// 'verified' => false,
// 'is_wordpress' => false,
// 'accessible' => true,
// 'last_check' => 1700000000,
// 'created_at' => 1700000000,
// 'updated_at' => 1700000000
// },
// ...
// ]
核心逻辑
主要逻辑在 functions.php 中实现:
argon_add_friend_link($data): 添加新友链argon_update_friend_link($id, $data): 更新友链信息argon_handle_link_application_v3($post_data): 处理友链申请
自动获取站点信息
在申请友链和后台新增友链时,主题会自动获取目标网站的基础信息。实现入口为 argon_fetch_site_info($url),其返回结构包含可用性与安全拦截相关的状态字段:
$info = array(
'favicon' => '',
'title' => '',
'description' => '',
'author_avatar' => '',
'is_wordpress' => false,
'accessible' => false,
'blocked_by_waf' => false,
'error_reason' => ''
);
核心流程包括:
- 使用模拟浏览器的请求头与 UA 进行
wp_remote_get(timeout约 20 秒,允许最多 5 次重定向) - 根据 HTTP 状态码与页面内容特征识别 WAF 拦截(403/503/关键字命中),并写入
blocked_by_waf与error_reason - 在可访问的前提下解析
<title>、meta description,并通过多种<link rel="icon">规则获取 favicon,必要时回退到/favicon.ico - 尝试检测站点是否为 WordPress(页面特征 +
/wp-json/探测),若为 WordPress 则进一步尝试获取作者头像信息
申请频率限制与安全校验
为了防止滥用,申请入口 argon_handle_link_application_v3($post_data) 依次执行以下校验:
- IP 黑名单:读取
argon_global_blocked_ips,支持精确匹配 / 通配符 / CIDR - 频率限制:按“用户标识符”限制提交频率
- 已登录用户:
user_{ID} - 未登录用户:对
IP + User-Agent计算哈希并截断(用于避免单纯按 IP 误伤共享网络) - 计数使用 transient:
flink_apply_{identifier} - 默认限制来自选项:
argon_flink_apply_limit(默认 3)与argon_flink_apply_period(默认 3600 秒)
- 已登录用户:
- Nonce 验证:校验字段
argon_link_apply_nonce,action 为argon_link_apply - 可选验证码:当全局验证码开启时,会调用
argon_verify_captcha('flink')对友链申请场景进行验证
12. 短代码与小工具系统
Argon 主题内置了丰富的小工具区域和短代码支持,增强了内容展示的灵活性。
小工具区域 (Sidebars)
主题在 functions.php 的 argon_widgets_init 函数中注册了三个主要的小工具区域:
-
左侧栏小工具 (
leftbar-tools)- 显示在页面左侧边栏。
- 如果设置了小工具,会在侧栏增加一个 Tab 标签页。
-
右侧栏小工具 (
rightbar-tools)- 仅在 "Argon 主题选项" 中选择 "三栏布局" 时显示。
- 位于页面右侧。
-
站点概览额外内容 (
leftbar-siteinfo-extra-tools)- 用于在左侧栏站点概览卡片下方添加额外内容。
注册代码示例:
function argon_widgets_init(){
register_sidebar(
array(
'name' => __('左侧栏小工具', 'argon'),
'id' => 'leftbar-tools',
// ...
)
);
// ...
}
add_action('widgets_init', 'argon_widgets_init');
短代码系统 (Shortcodes)
主题定义了大量自定义短代码,用于在文章中快速插入特殊样式或功能组件。所有短代码均在 functions.php 中通过 add_shortcode 注册。
主要短代码列表
- 布局与样式:
[br],[label],[progressbar],[checkbox],[collapse]/[fold] - 提示框:
[alert],[admonition] - 功能组件:
[timeline],[github],[video] - 元数据:
[post_time],[post_modified_time],[hide_reading_time] - 其他:
[friendlinks],[sfriendlinks],[hidden]/[spoiler],[ref]
实现示例:Alert 短代码
[alert] 短代码用于显示带颜色的提示框,支持 color 和 icon 参数。
// 注册短代码
add_shortcode('alert','shortcode_alert');
// 回调函数实现
function shortcode_alert($attr, $content=""){
// 预处理内容
$content = shortcode_content_preprocess($attr, $content);
// 构建 HTML
$out = "<div class='alert";
$color = isset( $attr['color'] ) ? $attr['color'] : 'indigo';
// 根据颜色参数添加对应的 CSS 类
switch ($color){
case 'indigo': $out .= " alert-primary"; break;
case 'green': $out .= " alert-success"; break;
// ...
}
$out .= "'>";
// ...
return $out;
}
13. 扩展接口与 Hooks
Argon 主题提供了一些自定义的 Action 和 Filter Hooks,方便开发者在不修改核心文件的情况下扩展主题功能。
主要 Hooks 列表
Filters (过滤器)
-
argon_banner_title_html- 作用:过滤 Banner 标题的 HTML 内容。
- 位置:
header.php - 参数:
$banner_title(当前标题)
-
argon_page_background_url- 作用:过滤页面背景图片的 URL。
- 位置:
header.php - 参数:
$url(设置中的背景 URL)
-
argon_email_types- 作用:过滤邮件通知类型列表,可用于修改默认邮件模板或添加新类型。
- 位置:
email-templates/base.php - 参数:
$types(包含邮件类型配置的数组)
Actions (动作)
argon_cache_cleared- 作用:当主题缓存被清除时触发(如保存设置时)。
- 位置:
functions.php
使用示例:
// 修改 Banner 标题后缀
add_filter('argon_banner_title_html', function($title) {
return $title . ' <small>(Dev Mode)</small>';
});
// 自定义背景图片逻辑
add_filter('argon_page_background_url', function($url) {
if (is_page('special')) {
return 'https://example.com/special-bg.jpg';
}
return $url;
});
14. 国际化与多语言支持
Argon 主题完全支持国际化(I18n),允许开发者轻松创建多语言版本。
核心配置
- Text Domain:
argon - 语言包路径:
/languages - 加载逻辑:
functions.php中的theme_slug_setup函数。
function theme_slug_setup() {
// ...
load_theme_textdomain('argon', get_template_directory() . '/languages');
}
翻译指南
-
PHP 文件中: 使用 WordPress 标准本地化函数:
// 返回翻译字符串 $text = __('Hello World', 'argon'); // 直接输出翻译字符串 _e('Settings', 'argon'); // 带有上下文的翻译 _x('Post', 'noun', 'argon'); -
创建语言包:
- 当前仓库未提供
languages/argon.pot模板文件。 - 可使用 Poedit 扫描主题源代码生成新的
.po(Text Domain 选择argon),完成翻译后生成.mo。 - 将生成的
.po/.mo文件放在languages/目录下即可被加载。
- 当前仓库未提供
开发指南
本地开发环境搭建
环境要求
- PHP 7.0 或更高版本
- WordPress 4.4 或更高版本
- MySQL 5.6 或更高版本
- 支持 .htaccess 的 Web 服务器(Apache/Nginx)
安装步骤
- 安装 WordPress
- 将主题文件夹放置到
wp-content/themes/argon/ - 在 WordPress 后台启用主题
- 访问主题设置页面进行配置
开发工具推荐
- 代码编辑器:VS Code、PhpStorm
- 浏览器开发工具:Chrome DevTools、Firefox Developer Tools
- 本地服务器:XAMPP、MAMP、Local by Flywheel
- 版本控制:Git
调试技巧
启用 WordPress 调试模式
在 wp-config.php 中添加:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
查看错误日志
错误日志位于 wp-content/debug.log。
浏览器控制台
JavaScript 错误会显示在浏览器控制台中。使用 console.log() 输出调试信息:
console.log('argonConfig:', argonConfig);
console.log('PJAX loading:', pjaxLoading);
网络请求调试
使用浏览器开发工具的 Network 面板查看 AJAX 请求:
- 检查请求 URL 和参数
- 查看响应内容和状态码
- 分析请求耗时
PJAX 调试
监听 PJAX 事件输出调试信息:
$(document).on('pjax:send', function() {
console.log('PJAX: 开始加载');
});
$(document).on('pjax:complete', function() {
console.log('PJAX: 加载完成');
});
$(document).on('pjax:error', function(xhr, textStatus, error) {
console.error('PJAX 错误:', error);
});
常见开发任务
添加新的主题选项
- 在
settings.php中添加表单字段:
<tr>
<th>新选项</th>
<td>
<input type="text" name="argon_new_option"
value="<?php echo esc_attr(get_option('argon_new_option', '')); ?>" />
<p class="description">选项说明</p>
</td>
</tr>
- 在需要使用的地方读取选项:
$new_option = get_option('argon_new_option', '默认值');
修改文章列表样式
文章列表有三种预览样式,对应三个模板文件:
template-parts/content-preview-1.php- 标准卡片样式template-parts/content-preview-2.php- 大图样式template-parts/content-preview-3.php- 简洁列表样式
修改对应文件即可改变样式。
添加自定义 CSS
在后台设置页面的"高级设置"选项卡中,有"自定义 CSS"文本框,输入的 CSS 会自动添加到页面中。
或者直接修改 style.css 文件。
添加自定义 JavaScript
在后台设置页面的"高级设置"选项卡中,有"自定义 JavaScript"文本框。
或者在 argontheme.js 文件末尾添加代码。
修改评论表单
评论表单在 comments.php 文件中定义。可以修改表单字段、布局和样式。
创建新的页面模板
- 创建新的 PHP 文件,例如
custom-page.php - 在文件开头添加模板声明:
<?php
/*
Template Name: 自定义页面
*/
?>
- 编写页面内容
- 在 WordPress 后台编辑页面时,可以在"页面属性"中选择该模板
主题更新
更新检查器
主题使用 plugin-update-checker(Puc v4)实现自动更新检查。更新源由选项 argon_update_source 控制,不同取值会切换到不同的元数据地址:
// functions.php
require_once(get_template_directory() . '/theme-update-checker/plugin-update-checker.php');
$argon_update_source = get_option('argon_update_source');
switch ($argon_update_source) {
case "stop":
break;
case "fastgit":
Puc_v4_Factory::buildUpdateChecker('https://api.solstice23.top/argon/info.json?source=fastgit', get_template_directory() . '/functions.php', 'argon');
break;
case "cfworker":
Puc_v4_Factory::buildUpdateChecker('https://api.solstice23.top/argon/info.json?source=cfworker', get_template_directory() . '/functions.php', 'argon');
break;
case "solstice23top":
Puc_v4_Factory::buildUpdateChecker('https://api.solstice23.top/argon/info.json?source=0', get_template_directory() . '/functions.php', 'argon');
break;
case "github":
default:
Puc_v4_Factory::buildUpdateChecker('https://raw.githubusercontent.com/solstice23/argon-theme/master/info.json', get_template_directory() . '/functions.php', 'argon');
}
更新流程
- 主题通过更新检查器向 WordPress 更新系统注册可用版本信息
- 在后台“仪表盘 → 更新”或“外观 → 主题”中显示更新提示
- 管理员点击更新后,由 WordPress 负责下载并覆盖主题文件
手动更新
- 下载最新版本的主题文件
- 备份当前主题文件和数据库
- 删除旧的主题文件夹
- 上传新的主题文件夹
- 在后台重新激活主题
- 检查设置是否正常
多语言支持
翻译文件
主题支持多语言,翻译文件位于 languages/ 目录:
zh_TW.po/zh_TW.mo- 繁体中文en_US.po/en_US.mo- 英文ru_RU.po/ru_RU.mo- 俄文
添加新语言
当前仓库未提供 languages/argon.pot 模板文件。新增语言时可采用两种方式之一:
- 使用 Poedit 扫描主题源代码生成新的
.po(Text Domain 选择argon),完成翻译后生成.mo - 使用 WP-CLI i18n 工具自行生成 POT,再在 Poedit 中基于 POT 创建语言包
生成的 .po/.mo 文件放置到 languages/ 目录即可被 load_theme_textdomain('argon', ... ) 加载
在代码中使用翻译
PHP 中使用 __() 函数:
echo __('文本内容', 'argon');
JavaScript 中使用全局翻译函数:
// header.php 中定义翻译表
var translation = {
'确定': '<?php _e("确定", "argon"); ?>',
'取消': '<?php _e("取消", "argon"); ?>'
};
// argontheme.js 中使用
function __(text) {
return translation[text] || text;
}
alert(__('确定'));
常见问题
样式问题
样式不生效
- 检查浏览器缓存,强制刷新(Ctrl+F5)
- 在后台设置中启用"强制刷新缓存"
- 检查 CSS 选择器优先级
- 使用浏览器开发工具检查元素样式
夜间模式颜色异常
- 检查 CSS 变量是否正确定义
- 确认
html.darkmode类是否正确添加 - 检查自定义 CSS 是否覆盖了夜间模式样式
响应式布局错乱
- 检查媒体查询断点
- 确认元素宽度设置正确
- 使用浏览器开发工具的响应式模式测试
功能问题
PJAX 加载失败
- 检查浏览器控制台是否有 JavaScript 错误
- 确认目标页面的 HTML 结构正确
- 检查 PJAX 容器选择器是否匹配
- 尝试禁用 PJAX 功能排查问题
评论发送失败
- 检查 AJAX 请求是否成功
- 确认 nonce 验证是否通过
- 检查验证码是否正确
- 查看 PHP 错误日志
图片懒加载不工作
- 确认图片标签使用了
data-src属性 - 检查 Lazy Load 库是否正确加载
- 确认懒加载功能已在后台启用
- 检查浏览器控制台是否有错误
代码高亮显示异常
- 确认 Highlight.js 已加载(浏览器控制台
window.hljs存在) - 确认代码高亮已启用(
argon_enable_code_highlight为 true,且argonConfig.code_highlight.enable为 true) - 确认高亮主题 CSS 已加载(footer.php 会输出 highlight 样式链接)
- PJAX 场景下检查
pjax:complete是否触发highlightJsRender()
性能问题
页面加载缓慢
- 启用资源合并功能
- 开启图片懒加载
- 使用 CDN 加速静态资源
- 优化数据库查询
- 启用服务器缓存(如 Redis、Memcached)
- 压缩图片大小
内存占用过高
- 减少同时加载的文章数量
- 优化图片尺寸
- 清理无用的插件和主题
- 增加 PHP 内存限制(在
wp-config.php中设置WP_MEMORY_LIMIT)
JavaScript 执行卡顿
- 减少 DOM 操作频率
- 使用事件委托代替多个事件监听器
- 优化瀑布流布局计算
- 使用
requestAnimationFrame优化动画
兼容性问题
插件冲突
- 逐个禁用插件排查冲突源
- 检查插件是否修改了主题依赖的 WordPress 核心功能
- 查看插件和主题的 JavaScript 是否有命名冲突
- 联系插件作者或主题作者寻求解决方案
浏览器兼容性
主题主要支持现代浏览器:
- Chrome 60+
- Firefox 60+
- Safari 12+
- Edge 79+
不支持 IE 浏览器。如需支持旧版浏览器,需要添加 polyfill。
PHP 版本兼容性
主题要求 PHP 7.0+。如果服务器 PHP 版本过低,需要升级 PHP 版本。
最佳实践
代码组织
模块化开发
将功能拆分为独立的模块,便于维护和复用:
// 评论模块
let CommentModule = {
init: function() {
this.bindEvents();
},
bindEvents: function() {
$('#comment-submit').on('click', this.submitComment);
},
submitComment: function() {
// 提交评论逻辑
}
};
// 初始化
CommentModule.init();
避免全局污染
使用立即执行函数表达式(IIFE)封装代码:
(function($) {
'use strict';
// 私有变量和函数
let privateVar = 'value';
function privateFunction() {
// ...
}
// 公开接口
window.MyModule = {
publicMethod: function() {
// ...
}
};
})(jQuery);
使用命名空间
避免函数名冲突:
let ArgonTheme = ArgonTheme || {};
ArgonTheme.Utils = {
getCookie: function(name) {
// ...
},
setCookie: function(name, value) {
// ...
}
};
性能优化
减少 HTTP 请求
- 合并 CSS 和 JavaScript 文件
- 使用 CSS Sprites 合并小图标
- 使用字体图标代替图片图标
- 启用浏览器缓存
优化资源加载
- 异步加载非关键 JavaScript
- 延迟加载图片和视频
- 使用 WebP 格式图片
- 压缩和混淆 JavaScript 代码
数据库优化
- 使用索引加速查询
- 避免 N+1 查询问题
- 使用对象缓存(如 Redis)
- 定期清理无用数据
前端优化
- 减少 DOM 操作
- 使用 CSS3 动画代替 JavaScript 动画
- 避免强制同步布局
- 使用虚拟滚动处理长列表
安全实践
输入验证
- 验证所有用户输入
- 使用白名单而非黑名单
- 限制输入长度和格式
- 防止 SQL 注入和 XSS 攻击
输出转义
- 使用
esc_html()转义 HTML 内容 - 使用
esc_attr()转义 HTML 属性 - 使用
esc_url()转义 URL - 使用
esc_js()转义 JavaScript 字符串
权限控制
- 检查用户权限后再执行敏感操作
- 使用
current_user_can()验证权限 - 为 AJAX 请求添加 nonce 验证
- 限制文件上传类型和大小
数据保护
- 使用 HTTPS 加密传输
- 敏感数据加密存储
- 定期备份数据库
- 设置合理的文件权限
可维护性
代码注释
- 为复杂逻辑添加注释
- 使用 JSDoc 格式注释函数
- 注释应说明"为什么"而非"是什么"
- 保持注释与代码同步更新
版本控制
- 使用 Git 管理代码
- 编写清晰的提交信息
- 使用分支管理功能开发
- 定期合并和清理分支
文档编写
- 维护完整的开发文档
- 记录 API 接口和参数
- 提供使用示例
- 更新变更日志
代码审查
- 定期审查代码质量
- 检查是否遵循编码规范
- 识别潜在的性能问题
- 确保代码可读性
扩展开发
创建子主题
如果需要大量自定义修改,建议创建子主题:
-
创建子主题目录
wp-content/themes/argon-child/ -
创建
style.css:
/*
Theme Name: Argon Child
Template: argon
Version: 1.0.0
*/
- 创建
functions.php:
<?php
function argon_child_enqueue_styles() {
wp_enqueue_style('argon-parent-style', get_template_directory_uri() . '/style.css');
}
add_action('wp_enqueue_scripts', 'argon_child_enqueue_styles');
-
在 WordPress 后台启用子主题
-
在子主题中覆盖父主题的模板文件或添加新功能
开发插件扩展
为主题开发配套插件:
<?php
/*
Plugin Name: Argon Extension
Description: Argon 主题扩展插件
Version: 1.0.0
*/
// 添加新功能
function argon_extension_feature() {
// 功能代码
}
add_action('init', 'argon_extension_feature');
// 添加短代码
function argon_custom_shortcode($atts) {
return '<div class="custom-content">自定义内容</div>';
}
add_shortcode('argon_custom', 'argon_custom_shortcode');
自定义 Widget
创建自定义侧边栏小工具:
<?php
class Argon_Custom_Widget extends WP_Widget {
public function __construct() {
parent::__construct(
'argon_custom_widget',
'Argon 自定义小工具',
array('description' => '自定义小工具描述')
);
}
public function widget($args, $instance) {
echo $args['before_widget'];
echo $args['before_title'];
echo esc_html($instance['title']);
echo $args['after_title'];
// 小工具内容
echo '<div class="custom-widget-content">';
echo esc_html($instance['content']);
echo '</div>';
echo $args['after_widget'];
}
public function form($instance) {
$title = !empty($instance['title']) ? $instance['title'] : '';
$content = !empty($instance['content']) ? $instance['content'] : '';
?>
<p>
<label for="<?php echo $this->get_field_id('title'); ?>">标题:</label>
<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>"
name="<?php echo $this->get_field_name('title'); ?>"
type="text" value="<?php echo esc_attr($title); ?>">
</p>
<p>
<label for="<?php echo $this->get_field_id('content'); ?>">内容:</label>
<textarea class="widefat" id="<?php echo $this->get_field_id('content'); ?>"
name="<?php echo $this->get_field_name('content'); ?>"><?php echo esc_textarea($content); ?></textarea>
</p>
<?php
}
public function update($new_instance, $old_instance) {
$instance = array();
$instance['title'] = sanitize_text_field($new_instance['title']);
$instance['content'] = sanitize_text_field($new_instance['content']);
return $instance;
}
}
function register_argon_custom_widget() {
register_widget('Argon_Custom_Widget');
}
add_action('widgets_init', 'register_argon_custom_widget');
添加自定义短代码
创建可在文章中使用的短代码:
// 简单短代码
function argon_alert_shortcode($atts, $content = null) {
$atts = shortcode_atts(array(
'type' => 'info',
'title' => ''
), $atts);
$output = '<div class="alert alert-' . esc_attr($atts['type']) . '">';
if (!empty($atts['title'])) {
$output .= '<h4>' . esc_html($atts['title']) . '</h4>';
}
$output .= do_shortcode($content);
$output .= '</div>';
return $output;
}
add_shortcode('alert', 'argon_alert_shortcode');
// 使用方式:
// [alert type="warning" title="注意"]这是警告内容[/alert]
自定义文章类型
除了说说,还可以创建其他自定义文章类型:
function register_custom_post_type() {
$args = array(
'labels' => array(
'name' => '作品集',
'singular_name' => '作品'
),
'public' => true,
'has_archive' => true,
'rewrite' => array('slug' => 'portfolio'),
'supports' => array('title', 'editor', 'thumbnail', 'excerpt'),
'menu_icon' => 'dashicons-portfolio'
);
register_post_type('portfolio', $args);
}
add_action('init', 'register_custom_post_type');
添加自定义字段
为文章添加额外的元数据:
// 添加元框
function argon_add_custom_meta_box() {
add_meta_box(
'argon_custom_meta',
'自定义字段',
'argon_custom_meta_box_callback',
'post',
'normal',
'high'
);
}
add_action('add_meta_boxes', 'argon_add_custom_meta_box');
// 元框内容
function argon_custom_meta_box_callback($post) {
wp_nonce_field('argon_save_custom_meta', 'argon_custom_meta_nonce');
$value = get_post_meta($post->ID, '_argon_custom_field', true);
?>
<label for="argon_custom_field">自定义字段:</label>
<input type="text" id="argon_custom_field" name="argon_custom_field"
value="<?php echo esc_attr($value); ?>" style="width: 100%;">
<?php
}
// 保存元数据
function argon_save_custom_meta($post_id) {
if (!isset($_POST['argon_custom_meta_nonce'])) {
return;
}
if (!wp_verify_nonce($_POST['argon_custom_meta_nonce'], 'argon_save_custom_meta')) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
if (isset($_POST['argon_custom_field'])) {
update_post_meta(
$post_id,
'_argon_custom_field',
sanitize_text_field($_POST['argon_custom_field'])
);
}
}
add_action('save_post', 'argon_save_custom_meta');
测试与部署
本地测试
功能测试
- 测试所有页面模板是否正常显示
- 测试评论发送、回复、编辑功能
- 测试说说发布和显示
- 测试 PJAX 页面切换
- 测试夜间模式切换
- 测试响应式布局在不同设备上的表现
- 测试表单验证和错误提示
兼容性测试
- 在不同浏览器中测试(Chrome、Firefox、Safari、Edge)
- 测试移动端浏览器(iOS Safari、Android Chrome)
- 测试不同屏幕尺寸的显示效果
- 测试与常用插件的兼容性
性能测试
- 使用 Chrome DevTools 的 Lighthouse 进行性能评分
- 检查页面加载时间
- 分析资源加载瀑布图
- 测试大量数据时的性能表现
部署流程
准备工作
- 备份当前网站数据和数据库
- 检查服务器环境是否满足要求
- 准备主题文件和配置
上传主题
- 通过 FTP 上传主题文件到
wp-content/themes/argon/ - 或在 WordPress 后台上传主题 ZIP 包
- 确认文件权限正确(目录 755,文件 644)
配置主题
- 在 WordPress 后台启用主题
- 访问主题设置页面进行配置
- 设置主题色、布局等基本选项
- 配置评论系统和验证码
- 设置 AI 摘要服务(如需要)
- 配置性能优化选项
数据迁移
如果从其他主题迁移:
- 导出原主题的设置和数据
- 手动迁移必要的配置
- 检查文章格式是否正常
- 重新设置小工具和菜单
- 测试所有功能是否正常
上线检查
- 清除所有缓存(浏览器、CDN、服务器)
- 检查首页和主要页面显示
- 测试评论功能
- 检查移动端显示
- 验证 SEO 设置
- 测试表单提交
- 检查 HTTPS 证书
维护与监控
日常维护
- 定期备份网站数据和数据库
- 及时更新主题版本
- 更新 WordPress 核心和插件
- 清理垃圾评论和无用数据
- 优化数据库表
性能监控
- 监控网站加载速度
- 检查服务器资源使用情况
- 分析访问日志
- 监控错误日志
- 定期进行性能测试
安全维护
- 定期更新所有组件
- 检查文件完整性
- 监控异常登录尝试
- 定期更改管理员密码
- 检查用户权限设置
- 扫描恶意代码
故障排查
当出现问题时:
- 查看 WordPress 调试日志
- 检查 PHP 错误日志
- 查看浏览器控制台错误
- 检查服务器错误日志
- 禁用插件逐个排查
- 切换到默认主题测试
- 检查数据库连接
- 验证文件权限
参考资源
官方文档
- WordPress Codex:https://codex.wordpress.org/
- WordPress Developer Resources:https://developer.wordpress.org/
- Bootstrap 4 文档:https://getbootstrap.com/docs/4.6/
- Argon Design System:https://www.creative-tim.com/product/argon-design-system
开发工具
- WordPress Debug Bar:调试插件
- Query Monitor:性能监控插件
- Theme Check:主题检查插件
- WP-CLI:WordPress 命令行工具
学习资源
- WordPress 主题开发手册
- PHP 官方文档
- JavaScript MDN 文档
- CSS-Tricks 网站
社区支持
- GitHub Issues:https://github.com/solstice23/argon-theme/issues
- WordPress 中文论坛
- Stack Overflow
附录
常用 WordPress 函数
文章相关
the_title() // 输出文章标题
the_content() // 输出文章内容
the_excerpt() // 输出文章摘要
the_permalink() // 输出文章链接
the_post_thumbnail() // 输出特色图片
get_the_date() // 获取发布日期
get_the_author() // 获取作者名称
评论相关
comments_number() // 输出评论数量
wp_list_comments() // 输出评论列表
comment_form() // 输出评论表单
get_comment_author() // 获取评论作者
comment_text() // 输出评论内容
选项相关
get_option() // 获取选项值
update_option() // 更新选项值
delete_option() // 删除选项
add_option() // 添加选项
用户相关
is_user_logged_in() // 检查用户是否登录
current_user_can() // 检查用户权限
get_current_user_id() // 获取当前用户 ID
wp_get_current_user() // 获取当前用户对象
常用 jQuery 方法
// 选择器
$('#id') // ID 选择器
$('.class') // 类选择器
$('element') // 元素选择器
// DOM 操作
.html() // 获取或设置 HTML 内容
.text() // 获取或设置文本内容
.val() // 获取或设置表单值
.attr() // 获取或设置属性
.css() // 获取或设置样式
.addClass() // 添加类
.removeClass() // 移除类
.toggleClass() // 切换类
// 事件
.on() // 绑定事件
.off() // 解绑事件
.click() // 点击事件
.change() // 改变事件
.submit() // 提交事件
// AJAX
$.ajax() // AJAX 请求
$.get() // GET 请求
$.post() // POST 请求
常用 CSS 类
Argon 主题基于 Bootstrap 4,可以使用以下常用类:
/* 布局 */
.container // 容器
.row // 行
.col-* // 列
/* 间距 */
.m-* // margin
.p-* // padding
.mt-*, .mb-*, .ml-*, .mr-* // 单边间距
/* 文本 */
.text-center // 居中对齐
.text-left // 左对齐
.text-right // 右对齐
.text-primary // 主色文本
.text-muted // 灰色文本
/* 按钮 */
.btn // 按钮基类
.btn-primary // 主按钮
.btn-secondary // 次按钮
.btn-sm, .btn-lg // 按钮尺寸
/* 卡片 */
.card // 卡片
.card-body // 卡片内容
.card-header // 卡片头部
.card-footer // 卡片底部
主题钩子列表
Argon 主题提供的自定义钩子:
// 动作钩子
do_action('argon_before_header') // 头部之前
do_action('argon_after_header') // 头部之后
do_action('argon_before_content') // 内容之前
do_action('argon_after_content') // 内容之后
do_action('argon_before_footer') // 底部之前
do_action('argon_after_footer') // 底部之后
do_action('argon_before_comment') // 评论之前
do_action('argon_after_comment') // 评论之后
// 过滤钩子
apply_filters('argon_post_content', $content) // 文章内容
apply_filters('argon_comment_content', $content) // 评论内容
apply_filters('argon_excerpt_length', 200) // 摘要长度
apply_filters('argon_theme_color', $color) // 主题色
使用示例:
// 在头部之后添加内容
function custom_after_header() {
echo '<div class="custom-notice">自定义通知</div>';
}
add_action('argon_after_header', 'custom_after_header');
// 修改摘要长度
function custom_excerpt_length($length) {
return 150;
}
add_filter('argon_excerpt_length', 'custom_excerpt_length');
版本历史
-
v1.5.0 - 当前版本
- 添加 AI 摘要功能
- 优化性能和缓存机制
- 改进安全性
- 修复已知问题
-
v1.4.x - 功能增强
- 添加说说功能
- 改进评论系统
- 优化移动端体验
-
v1.3.x - 稳定版本
- 完善 PJAX 功能
- 添加多种文章列表样式
- 改进夜间模式
-
v1.2.x - 初始版本
- 基础功能实现
- Material Design 界面
- 响应式布局
結語
本文檔用於內部開發協作,聚焦於主題架構、關鍵模組、開發規範與排查路徑,目標是讓開發者能以一致的方法理解、修改與驗證功能。
在日常開發與維護中,建議遵循以下原則:
- 以實際程式碼為準,文件同步更新,避免規格漂移
- 變更前先界定影響範圍(頁面類型、PJAX、設定項、相依資源)
- 變更後完成基本回歸(切換頁面、文章頁、評論、行動端、暗色模式)
- 優先保留相容性與可回退性,避免破壞既有站點行為
- 對安全與效能保持敏感(輸出轉義、權限檢查、資源載入與快取)
若需討論或提案,請依內部既定流程提交(需求/缺陷、代碼審查、發布/回滾),並附上可重現步驟與必要的日誌或截圖。