refactor: 从 settings.php 和 functions.php 中移除所有 Mermaid 支持

- 从 settings.php 移除完整的 Mermaid 设置部分(约 370 行)
- 从 settings.php 移除 Mermaid 选项保存代码
- 从 functions.php 移除所有 Mermaid 相关函数(约 500 行)
- 从 header.php 移除 Mermaid 相关注释
- 保留 assets/vendor/mermaid/ 库文件供未来可能的插件使用
This commit is contained in:
2026-01-27 10:45:21 +08:00
parent 0a8bb3a453
commit 734822883e
3 changed files with 3 additions and 1085 deletions

View File

@@ -10939,725 +10939,17 @@ function argon_normalize_social_url($platform, $input) {
// ==========================================================================
/**
* 获取 Mermaid 配置选项
*
* @param string $option_name 配置选项名称
* @param mixed $default 默认值
* @return mixed 配置选项值
*/
function argon_get_mermaid_option($option_name, $default = null) {
// 配置选项映射表
$option_map = [
'enabled' => 'argon_enable_mermaid',
'cdn_source' => 'argon_mermaid_cdn_source',
'custom_cdn_url' => 'argon_mermaid_cdn_custom_url',
'theme' => 'argon_mermaid_theme',
'use_local' => 'argon_mermaid_use_local',
'debug_mode' => 'argon_mermaid_debug_mode'
];
// 如果使用简短名称,转换为完整选项名
$full_option_name = isset($option_map[$option_name]) ? $option_map[$option_name] : $option_name;
// 获取选项值
$value = get_option($full_option_name, $default);
// 如果值为 null 且有默认值,返回默认值
if ($value === null && $default !== null) {
return $default;
}
return $value;
}
/**
* 保存 Mermaid 配置选项
*
* @param string $option_name 配置选项名称
* @param mixed $value 配置选项值
* @return bool 是否保存成功
*/
function argon_update_mermaid_option($option_name, $value) {
// 配置选项映射表
$option_map = [
'enabled' => 'argon_enable_mermaid',
'cdn_source' => 'argon_mermaid_cdn_source',
'custom_cdn_url' => 'argon_mermaid_cdn_custom_url',
'theme' => 'argon_mermaid_theme',
'use_local' => 'argon_mermaid_use_local',
'debug_mode' => 'argon_mermaid_debug_mode'
];
// 如果使用简短名称,转换为完整选项名
$full_option_name = isset($option_map[$option_name]) ? $option_map[$option_name] : $option_name;
// 保存选项值
return update_option($full_option_name, $value);
}
/**
* 验证 Mermaid CDN URL 格式
*
* @param string $url CDN URL
* @return bool 是否为有效的 CDN URL
*/
function argon_validate_mermaid_cdn_url($url) {
// 空 URL 视为无效
if (empty(trim($url))) {
return false;
}
// 验证 URL 格式
if (!filter_var($url, FILTER_VALIDATE_URL)) {
return false;
}
// 验证是否以 .js 结尾
if (!preg_match('/\.js$/i', $url)) {
return false;
}
// 验证协议(必须是 http 或 https
$parsed_url = parse_url($url);
if (!isset($parsed_url['scheme']) || !in_array($parsed_url['scheme'], ['http', 'https'])) {
return false;
}
return true;
}
/**
* 获取当前主题模式对应的 Mermaid 主题
*
* @return string Mermaid 主题名称
*/
function argon_get_mermaid_theme() {
// 获取配置的主题
$configured_theme = argon_get_mermaid_option('theme', 'auto');
// 如果不是自动模式,直接返回配置的主题
if ($configured_theme !== 'auto') {
return $configured_theme;
}
// 自动模式:根据页面主题返回对应的 Mermaid 主题
// 注意:这个函数在 PHP 端调用,无法直接检测前端的夜间模式状态
// 实际的主题切换逻辑应该在 JavaScript 中实现
// 这里返回默认主题JavaScript 会根据实际情况覆盖
return 'default';
}
/**
* 获取 Mermaid 配置的默认值
*
* @return array 默认配置数组
*/
function argon_get_mermaid_default_config() {
return [
'enabled' => false,
'cdn_source' => 'jsdelivr',
'custom_cdn_url' => '',
'theme' => 'auto',
'use_local' => false,
'debug_mode' => false
];
}
/**
* 验证 Mermaid 配置选项
*
* @param array $settings 配置选项数组
* @return array 错误信息数组,如果没有错误则返回空数组
*/
function argon_validate_mermaid_settings($settings) {
$errors = [];
// 验证 CDN 来源
if (isset($settings['cdn_source'])) {
$valid_sources = ['jsdelivr', 'unpkg', 'custom', 'local'];
if (!in_array($settings['cdn_source'], $valid_sources)) {
$errors[] = __('无效的 CDN 来源', 'argon');
}
// 如果选择自定义 CDN验证 URL
if ($settings['cdn_source'] === 'custom') {
if (!isset($settings['custom_cdn_url']) || empty($settings['custom_cdn_url'])) {
$errors[] = __('自定义 CDN 地址不能为空', 'argon');
} elseif (!argon_validate_mermaid_cdn_url($settings['custom_cdn_url'])) {
$errors[] = __('CDN 地址格式无效,必须是有效的 URL 且以 .js 结尾', 'argon');
}
}
}
// 验证主题名称
if (isset($settings['theme'])) {
$valid_themes = ['default', 'dark', 'forest', 'neutral', 'auto'];
if (!in_array($settings['theme'], $valid_themes)) {
$errors[] = __('无效的图表主题', 'argon');
}
}
// 验证布尔值选项
$boolean_options = ['enabled', 'use_local', 'debug_mode'];
foreach ($boolean_options as $option) {
if (isset($settings[$option]) && !is_bool($settings[$option]) && !in_array($settings[$option], ['true', 'false', '1', '0', 1, 0], true)) {
$errors[] = sprintf(__('选项 %s 必须是布尔值', 'argon'), $option);
}
}
return $errors;
}
/**
* 初始化 Mermaid 默认配置
* 在主题激活时调用
*/
function argon_init_mermaid_config() {
$defaults = argon_get_mermaid_default_config();
foreach ($defaults as $key => $value) {
// 只在选项不存在时设置默认值
if (argon_get_mermaid_option($key) === false) {
argon_update_mermaid_option($key, $value);
}
}
}
/**
* 获取所有 Mermaid 配置选项
*
* @return array 配置选项数组
*/
function argon_get_all_mermaid_options() {
$defaults = argon_get_mermaid_default_config();
$options = [];
foreach ($defaults as $key => $default_value) {
$options[$key] = argon_get_mermaid_option($key, $default_value);
}
return $options;
}
/**
* 批量更新 Mermaid 配置选项
*
* @param array $settings 配置选项数组
* @return array 包含 success 和 errors 的结果数组
*/
function argon_update_mermaid_settings($settings) {
// 验证配置
$errors = argon_validate_mermaid_settings($settings);
if (!empty($errors)) {
return [
'success' => false,
'errors' => $errors
];
}
// 保存配置
$defaults = argon_get_mermaid_default_config();
foreach ($defaults as $key => $default_value) {
if (isset($settings[$key])) {
argon_update_mermaid_option($key, $settings[$key]);
}
}
return [
'success' => true,
'errors' => []
];
}
// ==========================================================================
/**
* 检测页面内容是否包含 Mermaid 代码块
*
* 支持 Shortcode 格式:
* - [mermaid]...[/mermaid]
*
* @param string $content 页面内容
* @return bool 是否包含 Mermaid 代码块
*/
function argon_has_mermaid_content($content) {
if (empty($content)) {
return false;
}
// 检测多种 Mermaid 代码块格式
$patterns = [
'/\[mermaid[^\]]*\]/i'
];
foreach ($patterns as $pattern) {
if (preg_match($pattern, $content)) {
return true;
}
}
return false;
}
/**
* 获取 Mermaid 库的 URL
* 根据配置返回对应的 CDN 或本地路径
*
* @return string Mermaid 库 URL
*/
function argon_get_mermaid_library_url() {
$cdn_source = argon_get_mermaid_option('cdn_source', 'jsdelivr');
$use_local = argon_get_mermaid_option('use_local', false);
// 如果启用本地镜像,直接返回本地路径
if ($use_local) {
return get_template_directory_uri() . '/assets/vendor/mermaid/mermaid.min.js';
}
// 根据 CDN 来源返回对应的 URL
$cdn_urls = [
'jsdelivr' => 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js',
'unpkg' => 'https://unpkg.com/mermaid@11/dist/mermaid.min.js',
'local' => get_template_directory_uri() . '/assets/vendor/mermaid/mermaid.min.js'
];
// 如果是自定义 CDN返回自定义 URL
if ($cdn_source === 'custom') {
$custom_url = argon_get_mermaid_option('custom_cdn_url', '');
if (!empty($custom_url) && argon_validate_mermaid_cdn_url($custom_url)) {
return $custom_url;
}
// 如果自定义 URL 无效,降级到 jsdelivr
return $cdn_urls['jsdelivr'];
}
// 返回对应的 CDN URL如果不存在则返回 jsdelivr
return isset($cdn_urls[$cdn_source]) ? $cdn_urls[$cdn_source] : $cdn_urls['jsdelivr'];
}
/**
* 获取备用 CDN URL 列表
* 用于加载失败时的降级处理
*
* @return array 备用 CDN URL 数组
*/
function argon_get_mermaid_fallback_urls() {
return [
'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js',
'https://unpkg.com/mermaid@11/dist/mermaid.min.js',
get_template_directory_uri() . '/assets/vendor/mermaid/mermaid.min.js'
];
}
/**
* 加载 Mermaid JavaScript 库
* 在 wp_enqueue_scripts 钩子中调用
*/
function argon_enqueue_mermaid_scripts() {
// 检查是否启用 Mermaid 支持
if (!argon_get_mermaid_option('enabled', false)) {
return;
}
// 检查当前页面是否包含 Mermaid 代码块
global $post;
$has_mermaid = false;
// 检查文章内容
if (is_singular() && isset($post->post_content)) {
$has_mermaid = argon_has_mermaid_content($post->post_content);
}
// 检查评论内容(如果启用了评论)
if (!$has_mermaid && is_singular() && comments_open()) {
$comments = get_comments([
'post_id' => $post->ID,
'status' => 'approve'
]);
foreach ($comments as $comment) {
if (argon_has_mermaid_content($comment->comment_content)) {
$has_mermaid = true;
break;
}
}
}
// 如果页面不包含 Mermaid 代码块,不加载库
if (!$has_mermaid) {
return;
}
// 检查是否应该加载 Mermaid 库(避免与插件冲突)
$should_load_library = argon_should_load_mermaid_library();
// 传递配置到前端
$mermaid_config = [
'enabled' => true,
'theme' => argon_get_mermaid_option('theme', 'auto'),
'debugMode' => argon_get_mermaid_option('debug_mode', false),
'fallbackUrls' => argon_get_mermaid_fallback_urls(),
'libraryLoadedByPlugin' => !$should_load_library // 标记库是否由插件加载
];
// 只有在没有插件加载 Mermaid 库时才加载
if ($should_load_library) {
// 获取 Mermaid 库 URL
$mermaid_url = argon_get_mermaid_library_url();
// 注册并加载 Mermaid 库
wp_enqueue_script(
'mermaid',
$mermaid_url,
[], // 不依赖其他脚本
'10.0.0', // Mermaid 版本
true // 在页脚加载
);
// 添加 async 属性实现异步加载
add_filter('script_loader_tag', 'argon_add_mermaid_async_attribute', 10, 2);
wp_localize_script('mermaid', 'argonMermaidConfig', $mermaid_config);
} else {
// 即使不加载库,也要传递配置(用于样式增强)
// 创建一个内联脚本来传递配置
wp_add_inline_script(
'jquery', // 依赖 jQueryWordPress 默认加载)
'window.argonMermaidConfig = ' . json_encode($mermaid_config) . ';',
'after'
);
}
}
add_action('wp_enqueue_scripts', 'argon_enqueue_mermaid_scripts');
/**
* 为 Mermaid 脚本添加 async 属性
*
* @param string $tag 脚本标签
* @param string $handle 脚本句柄
* @return string 修改后的脚本标签
*/
function argon_add_mermaid_async_attribute($tag, $handle) {
if ('mermaid' !== $handle) {
return $tag;
}
// 添加 async 属性和 onerror 事件处理
$tag = str_replace(' src', ' async onerror="argonMermaidLoadFallback()" src', $tag);
return $tag;
}
/**
* 添加 Mermaid 库加载失败的降级处理脚本
*/
function argon_add_mermaid_fallback_script() {
// 只在启用 Mermaid 且页面包含 Mermaid 代码块时添加
if (!argon_get_mermaid_option('enabled', false)) {
return;
}
global $post;
$has_mermaid = false;
if (is_singular() && isset($post->post_content)) {
$has_mermaid = argon_has_mermaid_content($post->post_content);
}
if (!$has_mermaid) {
return;
}
// 获取备用 CDN URL 列表
$fallback_urls = argon_get_mermaid_fallback_urls();
$fallback_urls_json = json_encode($fallback_urls);
// 输出降级处理脚本
?>
<script>
// Mermaid 库加载失败的降级处理
(function() {
'use strict';
// 备用 CDN URL 列表
const fallbackUrls = <?php echo $fallback_urls_json; ?>;
let loadAttempted = false;
/**
* 尝试从备用 CDN 加载 Mermaid 库
*/
window.argonMermaidLoadFallback = function() {
// 避免重复调用
if (loadAttempted) {
return;
}
loadAttempted = true;
console.warn('[Argon Mermaid] 主 CDN 加载失败,尝试备用 CDN');
// 尝试加载备用 CDN
loadMermaidWithFallback(fallbackUrls, 0);
};
/**
* 递归加载备用 CDN
* @param {Array} urls - CDN URL 列表
* @param {number} index - 当前尝试的索引
*/
function loadMermaidWithFallback(urls, index) {
// 如果所有 CDN 都失败了
if (index >= urls.length) {
console.error('[Argon Mermaid] 所有 CDN 加载失败');
showGlobalError();
return;
}
const url = urls[index];
console.log(`[Argon Mermaid] 尝试从备用 CDN 加载: ${url}`);
// 创建 script 标签
const script = document.createElement('script');
script.src = url;
script.async = true;
// 加载失败,尝试下一个 CDN
script.onerror = function() {
console.warn(`[Argon Mermaid] CDN ${url} 加载失败`);
loadMermaidWithFallback(urls, index + 1);
};
// 加载成功,初始化 Mermaid
script.onload = function() {
console.log(`[Argon Mermaid] 成功从备用 CDN 加载: ${url}`);
// 等待 MermaidRenderer 可用
if (typeof window.MermaidRenderer !== 'undefined') {
window.MermaidRenderer.init();
} else {
// 如果 MermaidRenderer 还未定义,等待一下
setTimeout(function() {
if (typeof window.MermaidRenderer !== 'undefined') {
window.MermaidRenderer.init();
}
}, 100);
}
};
// 添加到页面
document.head.appendChild(script);
}
/**
* 显示全局错误提示
*/
function showGlobalError() {
// 查找所有 Mermaid 代码块
const selectors = [
'div.mermaid',
'pre code.language-mermaid',
'pre[data-lang="mermaid"]',
'code.mermaid'
];
let blocks = [];
selectors.forEach(function(selector) {
const elements = document.querySelectorAll(selector);
elements.forEach(function(element) {
if (!blocks.includes(element)) {
blocks.push(element);
}
});
});
// 在每个代码块位置显示错误提示
blocks.forEach(function(block) {
const errorContainer = document.createElement('div');
errorContainer.className = 'mermaid-error-container';
errorContainer.innerHTML = `
<div class="mermaid-error-header">
<span class="mermaid-error-icon">⚠️</span>
<span class="mermaid-error-title">Mermaid 库加载失败</span>
</div>
<div class="mermaid-error-body">
<p class="mermaid-error-type">错误类型: 网络错误</p>
<p class="mermaid-error-message">无法从任何 CDN 加载 Mermaid 库,请检查网络连接或联系管理员。</p>
</div>
<details class="mermaid-error-code">
<summary>查看原始代码</summary>
<pre><code class="language-mermaid">${escapeHtml(block.textContent)}</code></pre>
</details>
`;
block.parentNode.replaceChild(errorContainer, block);
});
}
/**
* HTML 转义
* @param {string} text - 要转义的文本
* @returns {string} 转义后的文本
*/
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
})();
</script>
<?php
}
add_action('wp_head', 'argon_add_mermaid_fallback_script');
// ==========================================================================
// Mermaid 插件兼容层
// ==========================================================================
/**
* 检测已安装的 Mermaid 相关插件
*
* @return array 插件检测结果数组
*/
function argon_detect_mermaid_plugins() {
$result = [
'wp-githuber-md' => false,
'markdown-block' => false,
'code-syntax-block' => false,
'mermaid-loaded' => false
];
// 检测 WP Githuber MD 插件
if (is_plugin_active('wp-githuber-md/githuber-md.php') ||
class_exists('Githuber_Module_Mermaid')) {
$result['wp-githuber-md'] = true;
}
// 检测 Markdown Block 插件Gutenberg
if (is_plugin_active('markdown-block/markdown-block.php') ||
function_exists('markdown_block_register')) {
$result['markdown-block'] = true;
}
// 检测 Code Syntax Block 插件
if (is_plugin_active('code-syntax-block/code-syntax-block.php') ||
function_exists('code_syntax_block_register')) {
$result['code-syntax-block'] = true;
}
return $result;
}
/**
* 检查是否有插件已经加载了 Mermaid 库
*
* 通过检测已注册的脚本来判断
*
* @return bool 是否已加载
*/
function argon_is_mermaid_library_enqueued() {
// 检查常见的 Mermaid 脚本句柄
$common_handles = [
'mermaid',
'mermaid-js',
'githuber-mermaid',
'wp-mermaid',
'markdown-mermaid'
];
foreach ($common_handles as $handle) {
if (wp_script_is($handle, 'enqueued') || wp_script_is($handle, 'registered')) {
return true;
}
}
return false;
}
/**
* 获取插件兼容性状态信息
*
* @return array 包含插件检测结果和建议的数组
*/
function argon_get_mermaid_compatibility_status() {
$plugins = argon_detect_mermaid_plugins();
$library_enqueued = argon_is_mermaid_library_enqueued();
// 统计检测到的插件数量
$active_plugins = array_filter($plugins, function($value, $key) {
return $value === true && $key !== 'mermaid-loaded';
}, ARRAY_FILTER_USE_BOTH);
$plugin_count = count($active_plugins);
// 生成状态信息
$status = [
'plugins' => $plugins,
'library_enqueued' => $library_enqueued,
'plugin_count' => $plugin_count,
'has_conflict' => false,
'message' => '',
'recommendation' => ''
];
// 判断是否有冲突
if ($plugin_count > 1) {
$status['has_conflict'] = true;
$status['message'] = '检测到多个 Mermaid 插件,可能导致重复加载';
$status['recommendation'] = '建议只保留一个 Mermaid 插件,或禁用主题的 Mermaid 支持';
} elseif ($plugin_count === 1) {
$status['message'] = '检测到 Mermaid 插件,主题将自动避免重复加载';
$status['recommendation'] = '主题将只提供样式增强,不会重复加载 Mermaid 库';
} elseif ($library_enqueued) {
$status['message'] = '检测到其他来源已加载 Mermaid 库';
$status['recommendation'] = '主题将自动避免重复加载';
} else {
$status['message'] = '未检测到 Mermaid 插件';
$status['recommendation'] = '主题将负责加载 Mermaid 库';
}
return $status;
}
/**
* 修改 Mermaid 脚本加载逻辑,避免重复加载
*
* 在原有的 argon_enqueue_mermaid_scripts 函数中调用此函数
*
* @return bool 是否应该加载 Mermaid 库
*/
function argon_should_load_mermaid_library() {
// 检查是否有插件已经加载了 Mermaid
if (argon_is_mermaid_library_enqueued()) {
// 在调试模式下输出日志
if (argon_get_mermaid_option('debug_mode', false)) {
error_log('[Argon Mermaid] 检测到 Mermaid 库已由其他插件加载,跳过加载');
}
return false;
}
// 检查是否有已知的 Mermaid 插件
$plugins = argon_detect_mermaid_plugins();
$has_plugin = false;
foreach ($plugins as $key => $value) {
if ($key !== 'mermaid-loaded' && $value === true) {
$has_plugin = true;
break;
}
}
if ($has_plugin) {
// 在调试模式下输出日志
if (argon_get_mermaid_option('debug_mode', false)) {
error_log('[Argon Mermaid] 检测到 Mermaid 插件,跳过加载库');
}
return false;
}
// 没有检测到插件或已加载的库,主题应该加载
return true;
}
// ==========================================================================