fix: 修复 Mermaid 渲染问题
- 启用代码块转换功能(移除 convertMermaidCodeblocks 中的 return 语句) - 添加完整的 Mermaid 代码块检测选择器 - 修复首页预览中显示原始 Mermaid 代码的问题 - 添加 argon_remove_mermaid_from_preview 函数过滤预览内容 - 更新三个文章预览模板,在预览中用 [Mermaid 图表] 替代原始代码
This commit is contained in:
652
argontheme.js
652
argontheme.js
@@ -1,4 +1,4 @@
|
|||||||
/*!
|
/*!
|
||||||
* Argon 主题核心 JavaScript
|
* Argon 主题核心 JavaScript
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -3034,6 +3034,23 @@ function resetGT4Captcha() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleHashNavigation() {
|
||||||
|
if (!location.hash) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let target = null;
|
||||||
|
try {
|
||||||
|
target = document.getElementById(decodeURIComponent(location.hash.slice(1)));
|
||||||
|
} catch (e) {
|
||||||
|
target = document.querySelector(location.hash);
|
||||||
|
}
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try { highlightJsRender(); } catch (err) { ArgonDebug.error('highlightJsRender failed:', err); }
|
||||||
|
try { lazyloadInit(); } catch (err) { ArgonDebug.error('lazyloadInit failed:', err); }
|
||||||
|
}
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// 内联脚本执行器 (Inline Script Executor)
|
// 内联脚本执行器 (Inline Script Executor)
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
@@ -3246,12 +3263,16 @@ $(document).pjax("a[href]:not([no-pjax]):not(.no-pjax):not([target='_blank']):no
|
|||||||
|
|
||||||
// Mermaid 图表渲染(需求 3.6: 页面切换时重新渲染)
|
// Mermaid 图表渲染(需求 3.6: 页面切换时重新渲染)
|
||||||
try {
|
try {
|
||||||
|
if (typeof MermaidRenderer !== 'undefined' && MermaidRenderer.init && !MermaidRenderer.initialized) {
|
||||||
|
MermaidRenderer.init();
|
||||||
|
}
|
||||||
if (typeof MermaidRenderer !== 'undefined' && MermaidRenderer.renderAllCharts) {
|
if (typeof MermaidRenderer !== 'undefined' && MermaidRenderer.renderAllCharts) {
|
||||||
MermaidRenderer.renderAllCharts();
|
MermaidRenderer.renderAllCharts();
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ArgonDebug.error('MermaidRenderer.renderAllCharts failed:', err);
|
ArgonDebug.error('MermaidRenderer.renderAllCharts failed:', err);
|
||||||
}
|
}
|
||||||
|
try { handleHashNavigation(); } catch (err) { ArgonDebug.error('handleHashNavigation failed:', err); }
|
||||||
|
|
||||||
$("html").trigger("resize");
|
$("html").trigger("resize");
|
||||||
|
|
||||||
@@ -3287,6 +3308,17 @@ $(document).pjax("a[href]:not([no-pjax]):not(.no-pjax):not([target='_blank']):no
|
|||||||
resetGT4Captcha();
|
resetGT4Captcha();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.addEventListener('hashchange', function() {
|
||||||
|
handleHashNavigation();
|
||||||
|
});
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
handleHashNavigation();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
handleHashNavigation();
|
||||||
|
}
|
||||||
|
|
||||||
/*Reference 跳转*/
|
/*Reference 跳转*/
|
||||||
$(document).on("click", ".reference-link , .reference-list-backlink" , function(e){
|
$(document).on("click", ".reference-link , .reference-list-backlink" , function(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -4365,7 +4397,7 @@ function convertMermaidCodeblocks(){
|
|||||||
|
|
||||||
// 创建容器
|
// 创建容器
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
container.className = 'mermaid-from-codeblock';
|
container.className = 'mermaid mermaid-from-codeblock';
|
||||||
container.textContent = code;
|
container.textContent = code;
|
||||||
container.dataset.processed = 'true';
|
container.dataset.processed = 'true';
|
||||||
|
|
||||||
@@ -4797,16 +4829,17 @@ void 0;
|
|||||||
initialized: false,
|
initialized: false,
|
||||||
rendered: new Set(), // 已渲染的图表 ID 集合
|
rendered: new Set(), // 已渲染的图表 ID 集合
|
||||||
config: null,
|
config: null,
|
||||||
|
compatibilityFallbackAttempted: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 等待 Mermaid 库加载
|
* 等待 Mermaid 库加载
|
||||||
* 需求 2.6: 清除缓存后首次加载时等待 Mermaid 库完全加载
|
* 需求 2.6: 清除缓存后首次加载时等待 Mermaid 库完全加载
|
||||||
* 需求 4.1: 开始渲染前检查 Mermaid 库是否已加载
|
* 需求 4.1: 开始渲染前检查 Mermaid 库是否已加载
|
||||||
* 需求 4.2: Mermaid 库未加载时等待库加载或显示错误提示
|
* 需求 4.2: Mermaid 库未加载时等待库加载或显示错误提示
|
||||||
* @param {number} timeout - 超时时间(毫秒),默认 5000ms
|
* @param {number} timeout - 超时时间(毫秒),默认 10000ms (增加超时时间以应对慢速网络)
|
||||||
* @returns {Promise<boolean>} 是否加载成功
|
* @returns {Promise<boolean>} 是否加载成功
|
||||||
*/
|
*/
|
||||||
waitForMermaid(timeout = 5000) {
|
waitForMermaid(timeout = 10000) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
// 如果已经加载,直接返回成功
|
// 如果已经加载,直接返回成功
|
||||||
if (typeof window.mermaid !== 'undefined') {
|
if (typeof window.mermaid !== 'undefined') {
|
||||||
@@ -4830,8 +4863,23 @@ void 0;
|
|||||||
else if (Date.now() - startTime > timeout) {
|
else if (Date.now() - startTime > timeout) {
|
||||||
clearInterval(checkInterval);
|
clearInterval(checkInterval);
|
||||||
this.logError(`Mermaid 库加载超时(${timeout}ms)`);
|
this.logError(`Mermaid 库加载超时(${timeout}ms)`);
|
||||||
|
|
||||||
|
// 尝试手动触发降级加载
|
||||||
|
if (typeof window.argonMermaidLoadFallback === 'function') {
|
||||||
|
this.logDebug('尝试手动触发降级加载');
|
||||||
|
window.argonMermaidLoadFallback();
|
||||||
|
// 给降级加载一点时间
|
||||||
|
setTimeout(() => {
|
||||||
|
if (typeof window.mermaid !== 'undefined') {
|
||||||
|
resolve(true);
|
||||||
|
} else {
|
||||||
resolve(false);
|
resolve(false);
|
||||||
}
|
}
|
||||||
|
}, 2000);
|
||||||
|
} else {
|
||||||
|
resolve(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}, 100); // 每 100ms 检查一次
|
}, 100); // 每 100ms 检查一次
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -4871,6 +4919,8 @@ void 0;
|
|||||||
// 配置 Mermaid
|
// 配置 Mermaid
|
||||||
// 需求 2.1-2.4: 支持多种图表类型,设置正确的主题和安全级别
|
// 需求 2.1-2.4: 支持多种图表类型,设置正确的主题和安全级别
|
||||||
try {
|
try {
|
||||||
|
// 检查 initialize 是否存在(兼容旧版本)
|
||||||
|
if (typeof window.mermaid.initialize === 'function') {
|
||||||
window.mermaid.initialize({
|
window.mermaid.initialize({
|
||||||
startOnLoad: false, // 手动控制渲染时机
|
startOnLoad: false, // 手动控制渲染时机
|
||||||
theme: theme, // 根据网站主题自动切换
|
theme: theme, // 根据网站主题自动切换
|
||||||
@@ -4917,10 +4967,13 @@ void 0;
|
|||||||
useMaxWidth: true
|
useMaxWidth: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
this.logDebug('Mermaid 配置初始化成功', { theme });
|
this.logDebug('Mermaid 配置初始化成功', { theme });
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
this.logError('Mermaid.initialize 方法不存在');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logError('Mermaid 配置初始化失败', error);
|
this.logError('Mermaid 配置初始化失败', error);
|
||||||
return false;
|
return false;
|
||||||
@@ -4951,22 +5004,27 @@ void 0;
|
|||||||
*/
|
*/
|
||||||
detectMermaidBlocks() {
|
detectMermaidBlocks() {
|
||||||
const blocks = [];
|
const blocks = [];
|
||||||
|
const seen = new Set();
|
||||||
|
const selectors = [
|
||||||
|
'div.mermaid-shortcode', // Shortcode 格式(推荐)
|
||||||
|
'div.mermaid-from-codeblock', // 代码块魔改格式
|
||||||
|
'div.mermaid', // 标准格式
|
||||||
|
'pre code.language-mermaid', // Markdown 格式(降级)
|
||||||
|
'pre[data-lang="mermaid"]', // 自定义属性格式
|
||||||
|
'code.mermaid' // 简化格式
|
||||||
|
];
|
||||||
|
|
||||||
// 需求 3.1: 扫描所有 <pre><code> 元素
|
selectors.forEach(selector => {
|
||||||
// 需求 3.2: 识别 language-mermaid 类名
|
document.querySelectorAll(selector).forEach(element => {
|
||||||
document.querySelectorAll('pre code.language-mermaid').forEach(code => {
|
if (this.isRendered(element)) {
|
||||||
// 需求 3.5: 过滤已渲染的代码块
|
return;
|
||||||
if (!this.isRendered(code)) {
|
|
||||||
blocks.push(code);
|
|
||||||
}
|
}
|
||||||
|
if (seen.has(element)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
blocks.push(element);
|
||||||
|
seen.add(element);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 需求 3.3: 识别 mermaid 类名
|
|
||||||
document.querySelectorAll('pre code.mermaid').forEach(code => {
|
|
||||||
// 需求 3.5: 过滤已渲染的代码块
|
|
||||||
if (!this.isRendered(code)) {
|
|
||||||
blocks.push(code);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.logDebug(`检测到 ${blocks.length} 个未渲染的 Mermaid 代码块`);
|
this.logDebug(`检测到 ${blocks.length} 个未渲染的 Mermaid 代码块`);
|
||||||
@@ -4985,6 +5043,22 @@ void 0;
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (element.classList && element.classList.contains('mermaid-error-container')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.classList && element.classList.contains('mermaid-loading')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.classList && element.classList.contains('mermaid-container')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.tagName === 'DIV' && element.classList.contains('mermaid') && element.querySelector('svg')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// 检查元素是否在 mermaid-container 容器中
|
// 检查元素是否在 mermaid-container 容器中
|
||||||
if (element.closest('.mermaid-container') !== null) {
|
if (element.closest('.mermaid-container') !== null) {
|
||||||
return true;
|
return true;
|
||||||
@@ -4992,233 +5066,6 @@ void 0;
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查元素是否在 HTML 注释中
|
|
||||||
* @param {HTMLElement} element - 要检查的元素
|
|
||||||
* @returns {boolean} 是否在注释中
|
|
||||||
*/
|
|
||||||
isInComment(element) {
|
|
||||||
let node = element.parentNode;
|
|
||||||
while (node) {
|
|
||||||
if (node.nodeType === Node.COMMENT_NODE) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
node = node.parentNode;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检测 Markdown 容器语法的 Mermaid 代码块
|
|
||||||
* 格式: ::: mermaid ... :::
|
|
||||||
* @param {Array} blocks - 代码块数组
|
|
||||||
*/
|
|
||||||
detectContainerBlocks(blocks) {
|
|
||||||
// 查找所有包含 ::: mermaid 的元素
|
|
||||||
const allElements = document.querySelectorAll('p, pre, code, div');
|
|
||||||
const processedElements = new Set();
|
|
||||||
|
|
||||||
allElements.forEach(element => {
|
|
||||||
// 跳过已处理的元素
|
|
||||||
if (processedElements.has(element)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const text = element.textContent.trim();
|
|
||||||
|
|
||||||
// 检查是否是开始标记
|
|
||||||
if (text.startsWith('::: mermaid') || text === '::: mermaid') {
|
|
||||||
this.logDebug('找到容器语法开始标记');
|
|
||||||
|
|
||||||
// 收集所有内容直到结束标记
|
|
||||||
const container = this.extractContainerContent(element, processedElements);
|
|
||||||
if (container && !blocks.includes(container)) {
|
|
||||||
blocks.push(container);
|
|
||||||
this.logDebug('检测到 Markdown 容器语法的 Mermaid 代码块');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提取 Markdown 容器语法的内容
|
|
||||||
* @param {HTMLElement} startElement - 包含开始标记的元素
|
|
||||||
* @param {Set} processedElements - 已处理的元素集合
|
|
||||||
* @returns {HTMLElement|null} 包含代码的容器元素
|
|
||||||
*/
|
|
||||||
extractContainerContent(startElement, processedElements) {
|
|
||||||
let codeLines = [];
|
|
||||||
let currentElement = startElement;
|
|
||||||
let foundStart = false;
|
|
||||||
let foundEnd = false;
|
|
||||||
|
|
||||||
// 标记开始元素为已处理
|
|
||||||
processedElements.add(startElement);
|
|
||||||
|
|
||||||
// 处理开始元素
|
|
||||||
// 使用 innerHTML 来获取原始内容,包括 <br> 标签
|
|
||||||
let startHTML = startElement.innerHTML;
|
|
||||||
let startText = startElement.textContent.trim();
|
|
||||||
|
|
||||||
this.logDebug('检查元素,textContent: ' + startText.substring(0, 50));
|
|
||||||
this.logDebug('innerHTML: ' + startHTML.substring(0, 100));
|
|
||||||
|
|
||||||
if (startText.startsWith('::: mermaid')) {
|
|
||||||
foundStart = true;
|
|
||||||
this.logDebug('找到容器语法开始标记');
|
|
||||||
|
|
||||||
// 检查是否整个内容都在一个元素中
|
|
||||||
if (startText.includes(':::') && startText.lastIndexOf(':::') > 10) {
|
|
||||||
// 整个容器语法在一个元素中
|
|
||||||
this.logDebug('检测到单元素容器语法');
|
|
||||||
|
|
||||||
// 使用 htmlToText 转换整个 HTML
|
|
||||||
let fullText = this.htmlToText(startHTML);
|
|
||||||
this.logDebug('转换后的完整文本: ' + fullText.substring(0, 200));
|
|
||||||
|
|
||||||
// 移除开始和结束标记
|
|
||||||
fullText = fullText.replace(/^:::\s*mermaid\s*/i, '').trim();
|
|
||||||
fullText = fullText.replace(/:::\s*$/, '').trim();
|
|
||||||
|
|
||||||
this.logDebug('移除标记后的代码: ' + fullText.substring(0, 200));
|
|
||||||
|
|
||||||
if (fullText) {
|
|
||||||
// 创建容器
|
|
||||||
const container = document.createElement('div');
|
|
||||||
container.className = 'mermaid-container-block';
|
|
||||||
container.textContent = fullText;
|
|
||||||
container.dataset.containerBlock = 'true';
|
|
||||||
|
|
||||||
// 替换开始元素
|
|
||||||
startElement.parentNode.replaceChild(container, startElement);
|
|
||||||
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 多元素容器语法(原有逻辑)
|
|
||||||
// 移除开始标记,保留同一元素中的其他内容
|
|
||||||
startText = startText.replace(/^:::\s*mermaid\s*/i, '').trim();
|
|
||||||
if (startText && !startText.startsWith(':::')) {
|
|
||||||
// 如果开始标记后有内容,需要从 HTML 中提取
|
|
||||||
// 将 <br> 转换为换行符
|
|
||||||
let contentHTML = startHTML.replace(/^:::\s*mermaid\s*<br\s*\/?>/i, '');
|
|
||||||
let contentText = this.htmlToText(contentHTML);
|
|
||||||
if (contentText.trim()) {
|
|
||||||
codeLines.push(contentText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 检查是否在同一元素中就有结束标记
|
|
||||||
if (startText.endsWith(':::')) {
|
|
||||||
foundEnd = true;
|
|
||||||
// 移除结束标记
|
|
||||||
if (codeLines.length > 0) {
|
|
||||||
let lastLine = codeLines[codeLines.length - 1];
|
|
||||||
codeLines[codeLines.length - 1] = lastLine.replace(/:::\s*$/, '').trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果还没找到结束标记,继续查找后续兄弟元素
|
|
||||||
if (foundStart && !foundEnd) {
|
|
||||||
currentElement = startElement.nextElementSibling;
|
|
||||||
|
|
||||||
while (currentElement) {
|
|
||||||
processedElements.add(currentElement);
|
|
||||||
let text = currentElement.textContent.trim();
|
|
||||||
|
|
||||||
// 检查是否是结束标记
|
|
||||||
if (text === ':::' || text.endsWith(':::')) {
|
|
||||||
foundEnd = true;
|
|
||||||
// 如果结束标记前还有内容,保留它
|
|
||||||
if (text !== ':::') {
|
|
||||||
text = text.replace(/:::\s*$/, '').trim();
|
|
||||||
if (text) {
|
|
||||||
// 将 HTML 转换为文本,保留换行符
|
|
||||||
let contentText = this.htmlToText(currentElement.innerHTML);
|
|
||||||
codeLines.push(contentText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加当前元素的内容
|
|
||||||
// 将 HTML 转换为文本,保留换行符
|
|
||||||
let contentText = this.htmlToText(currentElement.innerHTML);
|
|
||||||
if (contentText.trim()) {
|
|
||||||
codeLines.push(contentText);
|
|
||||||
} else {
|
|
||||||
// 空元素,添加空行
|
|
||||||
codeLines.push('');
|
|
||||||
}
|
|
||||||
|
|
||||||
currentElement = currentElement.nextElementSibling;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果没有找到完整的容器语法,返回 null
|
|
||||||
if (!foundStart || !foundEnd) {
|
|
||||||
this.logDebug('容器语法不完整,跳过');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 合并所有行
|
|
||||||
let code = codeLines.join('\n').trim();
|
|
||||||
|
|
||||||
this.logDebug('提取的完整代码: ' + code.substring(0, 200));
|
|
||||||
|
|
||||||
if (!code) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建一个新的容器来存储代码
|
|
||||||
const container = document.createElement('div');
|
|
||||||
container.className = 'mermaid-container-block';
|
|
||||||
container.textContent = code;
|
|
||||||
container.dataset.containerBlock = 'true';
|
|
||||||
|
|
||||||
// 替换开始元素
|
|
||||||
startElement.parentNode.replaceChild(container, startElement);
|
|
||||||
|
|
||||||
return container;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将 HTML 转换为纯文本,保留换行符
|
|
||||||
* @param {string} html - HTML 字符串
|
|
||||||
* @returns {string} 纯文本
|
|
||||||
*/
|
|
||||||
htmlToText(html) {
|
|
||||||
// 将 <br> 和 <br/> 转换为换行符
|
|
||||||
let text = html.replace(/<br\s*\/?>/gi, '\n');
|
|
||||||
// 移除其他 HTML 标签
|
|
||||||
text = text.replace(/<[^>]+>/g, '');
|
|
||||||
// 解码 HTML 实体
|
|
||||||
text = text
|
|
||||||
.replace(/ /g, ' ')
|
|
||||||
.replace(/</g, '<')
|
|
||||||
.replace(/>/g, '>')
|
|
||||||
.replace(/&/g, '&')
|
|
||||||
.replace(/"/g, '"')
|
|
||||||
.replace(/'/g, "'")
|
|
||||||
.replace(/–/g, '-') // EN DASH
|
|
||||||
.replace(/—/g, '--') // EM DASH
|
|
||||||
.replace(/→/g, '->') // RIGHTWARDS ARROW
|
|
||||||
.replace(/–/g, '-') // EN DASH (named entity)
|
|
||||||
.replace(/—/g, '--') // EM DASH (named entity)
|
|
||||||
.replace(/→/g, '->'); // RIGHTWARDS ARROW (named entity)
|
|
||||||
|
|
||||||
// 转换 Unicode 字符(WordPress 可能直接输出 Unicode)
|
|
||||||
text = text
|
|
||||||
.replace(/–/g, '-') // U+2013 EN DASH
|
|
||||||
.replace(/—/g, '--') // U+2014 EM DASH
|
|
||||||
.replace(/→/g, '->'); // U+2192 RIGHTWARDS ARROW
|
|
||||||
|
|
||||||
return text;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提取代码块内容
|
* 提取代码块内容
|
||||||
* @param {HTMLElement} element - 代码块元素
|
* @param {HTMLElement} element - 代码块元素
|
||||||
@@ -5274,7 +5121,7 @@ void 0;
|
|||||||
const clonedElement = element.cloneNode(true);
|
const clonedElement = element.cloneNode(true);
|
||||||
const scripts = clonedElement.querySelectorAll('script');
|
const scripts = clonedElement.querySelectorAll('script');
|
||||||
scripts.forEach(script => script.remove());
|
scripts.forEach(script => script.remove());
|
||||||
code = clonedElement.textContent;
|
code = clonedElement.innerText || clonedElement.textContent;
|
||||||
this.logDebug('使用降级方案提取代码');
|
this.logDebug('使用降级方案提取代码');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5283,22 +5130,32 @@ void 0;
|
|||||||
// WP-Markdown 会在 script 后面再输出一次代码
|
// WP-Markdown 会在 script 后面再输出一次代码
|
||||||
scriptTag.remove();
|
scriptTag.remove();
|
||||||
} else {
|
} else {
|
||||||
code = element.textContent;
|
// 检查是否包含块级元素或换行标签
|
||||||
this.logDebug('从纯文本提取代码');
|
if (element.querySelector('br') || element.querySelector('p') || element.querySelector('div')) {
|
||||||
|
const clonedElement = element.cloneNode(true);
|
||||||
|
clonedElement.querySelectorAll('script').forEach(script => script.remove());
|
||||||
|
clonedElement.querySelectorAll('br').forEach(br => br.replaceWith('\n'));
|
||||||
|
clonedElement.querySelectorAll('p,div').forEach(node => {
|
||||||
|
node.appendChild(document.createTextNode('\n'));
|
||||||
|
});
|
||||||
|
code = clonedElement.textContent || '';
|
||||||
|
this.logDebug('检测到 HTML 结构,从 innerText 提取代码');
|
||||||
|
} else {
|
||||||
|
code = element.textContent || '';
|
||||||
|
this.logDebug('未检测到 HTML 结构,从 textContent 提取代码');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (element.tagName === 'CODE') {
|
} else if (element.tagName === 'CODE') {
|
||||||
// 修复:使用 innerText 而不是 textContent,保留换行符
|
code = element.textContent || '';
|
||||||
// textContent 可能会丢失某些格式化信息
|
this.logDebug('从 CODE 标签提取');
|
||||||
code = element.innerText || element.textContent;
|
|
||||||
this.logDebug('从 CODE 标签提取,使用 innerText');
|
|
||||||
} else if (element.tagName === 'PRE') {
|
} else if (element.tagName === 'PRE') {
|
||||||
const codeElement = element.querySelector('code');
|
const codeElement = element.querySelector('code');
|
||||||
if (codeElement) {
|
if (codeElement) {
|
||||||
code = codeElement.innerText || codeElement.textContent;
|
code = codeElement.textContent || '';
|
||||||
} else {
|
} else {
|
||||||
code = element.innerText || element.textContent;
|
code = element.textContent || '';
|
||||||
}
|
}
|
||||||
this.logDebug('从 PRE 标签提取,使用 innerText');
|
this.logDebug('从 PRE 标签提取');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 记录原始提取的代码(调试用)
|
// 记录原始提取的代码(调试用)
|
||||||
@@ -5336,6 +5193,63 @@ void 0;
|
|||||||
return code;
|
return code;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
convertLegacySyntax(code) {
|
||||||
|
let updated = code;
|
||||||
|
if (/^\s*flowchart\b/i.test(updated)) {
|
||||||
|
updated = updated.replace(/^\s*flowchart\b/i, 'graph');
|
||||||
|
}
|
||||||
|
if (/^\s*stateDiagram-v2\b/i.test(updated)) {
|
||||||
|
updated = updated.replace(/^\s*stateDiagram-v2\b/i, 'stateDiagram');
|
||||||
|
}
|
||||||
|
return updated;
|
||||||
|
},
|
||||||
|
|
||||||
|
shouldRetryWithGraphSyntax(error, code, forceLegacy) {
|
||||||
|
if (!/^\s*(flowchart|stateDiagram-v2)\b/i.test(code || '')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (forceLegacy) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (error && error.hash && Array.isArray(error.hash.expected)) {
|
||||||
|
const expected = error.hash.expected.join(' ');
|
||||||
|
const tokenText = String(error.hash.text || '').toLowerCase();
|
||||||
|
if (expected.includes('GRAPH') && tokenText === 'flowchart') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((expected.includes('STATE') || expected.includes('SD')) && tokenText === 'statediagram-v2') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const message = String(error && error.message ? error.message : '').toLowerCase();
|
||||||
|
return message.includes('graph') || message.includes('state');
|
||||||
|
},
|
||||||
|
|
||||||
|
needsModernMermaid(code) {
|
||||||
|
return /^\s*(flowchart|erDiagram|stateDiagram|stateDiagram-v2)\b/i.test(code || '');
|
||||||
|
},
|
||||||
|
|
||||||
|
tryUpgradeMermaidLibrary(element, code) {
|
||||||
|
if (this.compatibilityFallbackAttempted) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this.needsModernMermaid(code)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (typeof window.argonMermaidLoadFallback !== 'function') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.compatibilityFallbackAttempted = true;
|
||||||
|
const container = document.createElement('div');
|
||||||
|
container.className = 'mermaid';
|
||||||
|
container.textContent = code;
|
||||||
|
if (element && element.parentNode) {
|
||||||
|
element.parentNode.replaceChild(container, element);
|
||||||
|
}
|
||||||
|
window.argonMermaidLoadFallback();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
// ---------- 渲染引擎 ----------
|
// ---------- 渲染引擎 ----------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -5358,88 +5272,90 @@ void 0;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测所有代码块(一次 DOM 遍历)
|
const startRender = (blocks) => {
|
||||||
const blocks = this.detectMermaidBlocks();
|
this.logDebug(`准备渲染 ${blocks.length} 个图表 (Lazy Load)`);
|
||||||
|
if (this.observer) {
|
||||||
if (blocks.length === 0) {
|
this.observer.disconnect();
|
||||||
this.logDebug('未找到 Mermaid 代码块');
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
this.observer = new IntersectionObserver((entries, observer) => {
|
||||||
this.logDebug(`准备批量渲染 ${blocks.length} 个图表`);
|
entries.forEach(entry => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
// 需求 18.4: 将图表分为视口内和视口外两组
|
const block = entry.target;
|
||||||
const visibleBlocks = [];
|
const index = blocks.indexOf(block);
|
||||||
const invisibleBlocks = [];
|
requestAnimationFrame(() => {
|
||||||
|
this.renderChart(block, index);
|
||||||
blocks.forEach(block => {
|
});
|
||||||
if (this.isInViewport(block)) {
|
observer.unobserve(block);
|
||||||
visibleBlocks.push(block);
|
|
||||||
} else {
|
|
||||||
invisibleBlocks.push(block);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}, {
|
||||||
|
rootMargin: '200px 0px',
|
||||||
|
threshold: 0.01
|
||||||
|
});
|
||||||
|
blocks.forEach(block => {
|
||||||
|
this.observer.observe(block);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
this.logDebug(`视口内图表: ${visibleBlocks.length}, 视口外图表: ${invisibleBlocks.length}`);
|
if (this.domObserver) {
|
||||||
|
this.domObserver.disconnect();
|
||||||
// 优先渲染视口内的图表
|
this.domObserver = null;
|
||||||
let currentIndex = 0;
|
|
||||||
const batchSize = 3; // 每批渲染 3 个图表
|
|
||||||
|
|
||||||
const renderBatch = (blockList, isVisible) => {
|
|
||||||
if (currentIndex >= blockList.length) {
|
|
||||||
// 当前列表渲染完成
|
|
||||||
if (isVisible && invisibleBlocks.length > 0) {
|
|
||||||
// 视口内图表渲染完成,开始渲染视口外图表
|
|
||||||
this.logDebug('视口内图表渲染完成,开始渲染视口外图表');
|
|
||||||
currentIndex = 0;
|
|
||||||
requestAnimationFrame(() => renderBatch(invisibleBlocks, false));
|
|
||||||
} else {
|
|
||||||
this.logDebug(`完成渲染 ${blocks.length} 个图表`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const blocks = this.detectMermaidBlocks();
|
||||||
|
if (blocks.length === 0) {
|
||||||
|
this.logDebug('未找到 Mermaid 代码块');
|
||||||
|
if (typeof MutationObserver === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let finished = false;
|
||||||
|
const waitStart = Date.now();
|
||||||
|
const stopWaiting = (message) => {
|
||||||
|
if (finished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finished = true;
|
||||||
|
if (this.domObserver) {
|
||||||
|
this.domObserver.disconnect();
|
||||||
|
this.domObserver = null;
|
||||||
|
}
|
||||||
|
if (message) {
|
||||||
|
this.logDebug(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const tryRender = () => {
|
||||||
|
const pending = this.detectMermaidBlocks();
|
||||||
|
if (pending.length > 0) {
|
||||||
|
stopWaiting();
|
||||||
|
startRender(pending);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
const maxWait = 4000;
|
||||||
|
this.domObserver = new MutationObserver(() => {
|
||||||
|
if (tryRender()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Date.now() - waitStart > maxWait) {
|
||||||
|
stopWaiting('等待 Mermaid 代码块超时');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.domObserver.observe(document.body, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!finished) {
|
||||||
|
if (!tryRender()) {
|
||||||
|
stopWaiting('等待 Mermaid 代码块超时');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, maxWait);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const endIndex = Math.min(currentIndex + batchSize, blockList.length);
|
startRender(blocks);
|
||||||
|
|
||||||
// 渲染当前批次
|
|
||||||
for (let i = currentIndex; i < endIndex; i++) {
|
|
||||||
const globalIndex = blocks.indexOf(blockList[i]);
|
|
||||||
this.renderChart(blockList[i], globalIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentIndex = endIndex;
|
|
||||||
|
|
||||||
// 继续下一批
|
|
||||||
requestAnimationFrame(() => renderBatch(blockList, isVisible));
|
|
||||||
};
|
|
||||||
|
|
||||||
// 开始渲染(优先渲染视口内图表)
|
|
||||||
if (visibleBlocks.length > 0) {
|
|
||||||
requestAnimationFrame(() => renderBatch(visibleBlocks, true));
|
|
||||||
} else if (invisibleBlocks.length > 0) {
|
|
||||||
// 如果没有视口内图表,直接渲染视口外图表
|
|
||||||
requestAnimationFrame(() => renderBatch(invisibleBlocks, false));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查元素是否在视口内
|
|
||||||
* @param {HTMLElement} element - 要检查的元素
|
|
||||||
* @returns {boolean} 是否在视口内
|
|
||||||
*/
|
|
||||||
isInViewport(element) {
|
|
||||||
const rect = element.getBoundingClientRect();
|
|
||||||
const windowHeight = window.innerHeight || document.documentElement.clientHeight;
|
|
||||||
const windowWidth = window.innerWidth || document.documentElement.clientWidth;
|
|
||||||
|
|
||||||
// 元素至少部分可见
|
|
||||||
return (
|
|
||||||
rect.top < windowHeight &&
|
|
||||||
rect.bottom > 0 &&
|
|
||||||
rect.left < windowWidth &&
|
|
||||||
rect.right > 0
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -5472,7 +5388,8 @@ void 0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 提取代码
|
// 提取代码
|
||||||
const code = this.extractMermaidCode(element);
|
const rawCode = this.extractMermaidCode(element);
|
||||||
|
const code = rawCode;
|
||||||
|
|
||||||
if (!code) {
|
if (!code) {
|
||||||
this.logDebug(`代码块为空,跳过: ${chartId}`);
|
this.logDebug(`代码块为空,跳过: ${chartId}`);
|
||||||
@@ -5513,45 +5430,65 @@ void 0;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渲染图表
|
const onRenderSuccess = (svg, bindFunctions) => {
|
||||||
const renderPromise = window.mermaid.render(`mermaid-svg-${chartId}`, code);
|
container.innerHTML = svg;
|
||||||
|
|
||||||
// 检查返回值是否是 Promise
|
|
||||||
if (!renderPromise || typeof renderPromise.then !== 'function') {
|
|
||||||
this.logError('Mermaid.render 没有返回 Promise,可能是版本不兼容');
|
|
||||||
// 尝试使用旧版 API
|
|
||||||
this.renderChartLegacy(loadingContainer, code, container, chartId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderPromise.then(result => {
|
|
||||||
// 渲染成功
|
|
||||||
container.innerHTML = result.svg;
|
|
||||||
|
|
||||||
// 保存原始代码(用于主题切换时重新渲染)
|
|
||||||
container.dataset.mermaidCode = code;
|
container.dataset.mermaidCode = code;
|
||||||
container.dataset.currentTheme = this.getMermaidTheme();
|
container.dataset.currentTheme = this.getMermaidTheme();
|
||||||
|
|
||||||
// 需求 3.5: 添加渲染状态标记,避免重复渲染
|
|
||||||
container.setAttribute('data-mermaid-rendered', 'true');
|
container.setAttribute('data-mermaid-rendered', 'true');
|
||||||
|
|
||||||
// 替换加载动画为渲染结果
|
|
||||||
if (loadingContainer.parentNode) {
|
if (loadingContainer.parentNode) {
|
||||||
loadingContainer.parentNode.replaceChild(container, loadingContainer);
|
loadingContainer.parentNode.replaceChild(container, loadingContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 标记为已渲染
|
|
||||||
this.rendered.add(container);
|
this.rendered.add(container);
|
||||||
|
|
||||||
// 应用样式增强(包含淡入动画)
|
|
||||||
this.applyStyles(container);
|
this.applyStyles(container);
|
||||||
|
if (typeof bindFunctions === 'function') {
|
||||||
|
try {
|
||||||
|
bindFunctions(container);
|
||||||
|
} catch (bindError) {
|
||||||
|
this.logError('Mermaid bindFunctions 执行失败', bindError);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.logDebug(`图表渲染成功: ${chartId}`);
|
this.logDebug(`图表渲染成功: ${chartId}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderResult = window.mermaid.render(`mermaid-svg-${chartId}`, code);
|
||||||
|
|
||||||
|
if (renderResult && typeof renderResult.then === 'function') {
|
||||||
|
renderResult.then(result => {
|
||||||
|
onRenderSuccess(result.svg, result.bindFunctions);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
// 需求 18.5: 渲染失败时记录错误但不抛出异常
|
// 需求 18.5: 渲染失败时记录错误但不抛出异常
|
||||||
|
const retryCode = this.convertLegacySyntax(code);
|
||||||
|
if (this.shouldRetryWithGraphSyntax(error, code) && retryCode !== code) {
|
||||||
|
this.logDebug('语法降级后重试渲染');
|
||||||
|
this.renderChartLegacy(loadingContainer, retryCode, container, chartId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.tryUpgradeMermaidLibrary(loadingContainer, code)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.logError(`图表渲染失败: ${chartId}`, error);
|
this.logError(`图表渲染失败: ${chartId}`, error);
|
||||||
this.handleRenderError(loadingContainer, error, code);
|
this.handleRenderError(loadingContainer, error, rawCode);
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (renderResult && typeof renderResult === 'object' && typeof renderResult.svg === 'string') {
|
||||||
|
onRenderSuccess(renderResult.svg, renderResult.bindFunctions);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof renderResult === 'string') {
|
||||||
|
onRenderSuccess(renderResult);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logError('Mermaid.render 没有返回 Promise,可能是版本不兼容');
|
||||||
|
if (this.tryUpgradeMermaidLibrary(loadingContainer, code)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const legacyCode = this.convertLegacySyntax(code);
|
||||||
|
this.renderChartLegacy(loadingContainer, legacyCode, container, chartId);
|
||||||
|
return;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 需求 18.5: 捕获所有异常,确保不影响其他图表
|
// 需求 18.5: 捕获所有异常,确保不影响其他图表
|
||||||
@@ -5613,6 +5550,9 @@ void 0;
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logError('旧版 API 渲染失败', error);
|
this.logError('旧版 API 渲染失败', error);
|
||||||
|
if (this.tryUpgradeMermaidLibrary(element, code)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.handleRenderError(element, error, code);
|
this.handleRenderError(element, error, code);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
287
functions.php
287
functions.php
@@ -2824,7 +2824,6 @@ function argon_comment_text_render($text){
|
|||||||
return argon_apply_comment_macros($text);
|
return argon_apply_comment_macros($text);
|
||||||
}
|
}
|
||||||
add_filter('comment_text', 'argon_comment_text_render', 9);
|
add_filter('comment_text', 'argon_comment_text_render', 9);
|
||||||
add_filter('the_content', 'argon_comment_text_render', 9);
|
|
||||||
|
|
||||||
//评论发送处理
|
//评论发送处理
|
||||||
function post_comment_preprocessing($comment){
|
function post_comment_preprocessing($comment){
|
||||||
@@ -4612,6 +4611,19 @@ function shortcode_mermaid($attr,$content=""){
|
|||||||
|
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从内容中移除 Mermaid shortcode,用于文章预览
|
||||||
|
* 避免在预览中显示原始 Mermaid 代码
|
||||||
|
*
|
||||||
|
* @param string $content 文章内容
|
||||||
|
* @return string 移除 Mermaid shortcode 后的内容
|
||||||
|
*/
|
||||||
|
function argon_remove_mermaid_from_preview($content) {
|
||||||
|
// 移除 [mermaid]...[/mermaid] shortcode
|
||||||
|
$content = preg_replace('/\[mermaid[^\]]*\].*?\[\/mermaid\]/is', '[Mermaid 图表]', $content);
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
add_shortcode('hide_reading_time','shortcode_hide_reading_time');
|
add_shortcode('hide_reading_time','shortcode_hide_reading_time');
|
||||||
function shortcode_hide_reading_time($attr,$content=""){
|
function shortcode_hide_reading_time($attr,$content=""){
|
||||||
return "";
|
return "";
|
||||||
@@ -6422,7 +6434,33 @@ function argon_create_ai_query_log_table() {
|
|||||||
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
||||||
dbDelta($sql);
|
dbDelta($sql);
|
||||||
}
|
}
|
||||||
add_action('after_switch_theme', 'argon_create_ai_query_log_table');
|
|
||||||
|
function argon_ai_query_log_table_exists() {
|
||||||
|
global $wpdb;
|
||||||
|
$table_name = $wpdb->prefix . 'argon_ai_query_log';
|
||||||
|
$found = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name));
|
||||||
|
return $found === $table_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function argon_maybe_create_ai_query_log_table() {
|
||||||
|
static $ran = false;
|
||||||
|
if ($ran) return;
|
||||||
|
$ran = true;
|
||||||
|
|
||||||
|
$option_key = 'argon_ai_query_log_table_version';
|
||||||
|
$current_version = 1;
|
||||||
|
$saved_version = intval(get_option($option_key, 0));
|
||||||
|
|
||||||
|
if ($saved_version === $current_version && argon_ai_query_log_table_exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
argon_create_ai_query_log_table();
|
||||||
|
update_option($option_key, $current_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_action('after_switch_theme', 'argon_maybe_create_ai_query_log_table');
|
||||||
|
add_action('init', 'argon_maybe_create_ai_query_log_table', 5);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 记录 AI 查询
|
* 记录 AI 查询
|
||||||
@@ -6442,6 +6480,8 @@ function argon_log_ai_query($provider, $model, $scenario, $prompt_length, $conte
|
|||||||
global $wpdb;
|
global $wpdb;
|
||||||
$table_name = $wpdb->prefix . 'argon_ai_query_log';
|
$table_name = $wpdb->prefix . 'argon_ai_query_log';
|
||||||
|
|
||||||
|
argon_maybe_create_ai_query_log_table();
|
||||||
|
|
||||||
$wpdb->insert(
|
$wpdb->insert(
|
||||||
$table_name,
|
$table_name,
|
||||||
[
|
[
|
||||||
@@ -6490,6 +6530,10 @@ function argon_ai_query($scenario, $prompt, $content, $context = []) {
|
|||||||
// 优先使用场景化的 API 配置(新系统)
|
// 优先使用场景化的 API 配置(新系统)
|
||||||
$config = null;
|
$config = null;
|
||||||
$provider = '';
|
$provider = '';
|
||||||
|
$config_scenario = $scenario;
|
||||||
|
if ($scenario === 'spam_detection' || $scenario === 'keyword_extraction') {
|
||||||
|
$config_scenario = 'spam';
|
||||||
|
}
|
||||||
|
|
||||||
// 如果 context 中指定了 provider,使用指定的 provider
|
// 如果 context 中指定了 provider,使用指定的 provider
|
||||||
if (isset($context['provider'])) {
|
if (isset($context['provider'])) {
|
||||||
@@ -6497,19 +6541,19 @@ function argon_ai_query($scenario, $prompt, $content, $context = []) {
|
|||||||
$config = argon_get_ai_provider_config($provider);
|
$config = argon_get_ai_provider_config($provider);
|
||||||
} else {
|
} else {
|
||||||
// 否则根据场景获取活动的 API 配置
|
// 否则根据场景获取活动的 API 配置
|
||||||
$config = argon_get_active_api_config($scenario);
|
$config = argon_get_active_api_config($config_scenario);
|
||||||
if ($config && isset($config['provider'])) {
|
if ($config && !empty($config['provider'])) {
|
||||||
$provider = $config['provider'];
|
$provider = $config['provider'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果新系统没有配置,回退到旧系统
|
// 如果新系统没有配置,回退到旧系统
|
||||||
if (!$config || !isset($config['api_key'])) {
|
if (!$config || empty($provider) || empty($config['api_key'])) {
|
||||||
$provider = get_option('argon_ai_summary_provider', 'openai');
|
$provider = get_option('argon_ai_summary_provider', 'openai');
|
||||||
$config = argon_get_ai_provider_config($provider);
|
$config = argon_get_ai_provider_config($provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$config || !isset($config['api_key'])) {
|
if (!$config || empty($provider) || empty($config['api_key'])) {
|
||||||
error_log("Argon AI Query Error: Provider config not found for {$provider}");
|
error_log("Argon AI Query Error: Provider config not found for {$provider}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -6530,6 +6574,31 @@ function argon_ai_query($scenario, $prompt, $content, $context = []) {
|
|||||||
// 获取 API 端点
|
// 获取 API 端点
|
||||||
$endpoint = isset($config['api_endpoint']) ? $config['api_endpoint'] : '';
|
$endpoint = isset($config['api_endpoint']) ? $config['api_endpoint'] : '';
|
||||||
|
|
||||||
|
if (empty($model) || $provider === 'xiaomi') {
|
||||||
|
$provider_defaults = [
|
||||||
|
'openai' => 'gpt-4o-mini',
|
||||||
|
'anthropic' => 'claude-3-5-haiku-20241022',
|
||||||
|
'deepseek' => 'deepseek-chat',
|
||||||
|
'qianwen' => 'qwen-turbo',
|
||||||
|
'wenxin' => 'ernie-4.0-turbo-8k',
|
||||||
|
'doubao' => 'doubao-pro-32k',
|
||||||
|
'kimi' => 'moonshot-v1-8k',
|
||||||
|
'zhipu' => 'glm-4-flash',
|
||||||
|
'siliconflow' => 'Qwen/Qwen2.5-7B-Instruct',
|
||||||
|
'xiaomi' => 'MiMo-V2-Flash'
|
||||||
|
];
|
||||||
|
if (empty($model) && isset($provider_defaults[$provider])) {
|
||||||
|
$model = $provider_defaults[$provider];
|
||||||
|
}
|
||||||
|
if ($provider === 'xiaomi' && !empty($endpoint) && !empty($model)) {
|
||||||
|
if (strpos($endpoint, 'xiaomimimo.com') !== false && strcasecmp($model, 'MiMo-V2-Flash') === 0) {
|
||||||
|
$model = 'mimo-v2-flash';
|
||||||
|
} elseif (strpos($endpoint, 'api.mimo.xiaomi.com') !== false && strcasecmp($model, 'mimo-v2-flash') === 0) {
|
||||||
|
$model = 'MiMo-V2-Flash';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch ($provider) {
|
switch ($provider) {
|
||||||
case 'openai':
|
case 'openai':
|
||||||
@@ -6619,6 +6688,91 @@ function argon_ai_query($scenario, $prompt, $content, $context = []) {
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function argon_resolve_ai_provider_model($scenario, $context = []) {
|
||||||
|
$config = null;
|
||||||
|
$provider = '';
|
||||||
|
$config_scenario = $scenario;
|
||||||
|
if ($scenario === 'spam_detection' || $scenario === 'keyword_extraction') {
|
||||||
|
$config_scenario = 'spam';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($context) && isset($context['provider'])) {
|
||||||
|
$provider = $context['provider'];
|
||||||
|
$config = argon_get_ai_provider_config($provider);
|
||||||
|
} else {
|
||||||
|
$config = argon_get_active_api_config($config_scenario);
|
||||||
|
if ($config && !empty($config['provider'])) {
|
||||||
|
$provider = $config['provider'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$config || empty($provider) || empty($config['api_key'])) {
|
||||||
|
$provider = get_option('argon_ai_summary_provider', 'openai');
|
||||||
|
$config = argon_get_ai_provider_config($provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
$endpoint = is_array($config) && isset($config['api_endpoint']) ? $config['api_endpoint'] : '';
|
||||||
|
$model = '';
|
||||||
|
if (is_array($context) && isset($context['model'])) {
|
||||||
|
$model = $context['model'];
|
||||||
|
} elseif (is_array($config) && isset($config['model'])) {
|
||||||
|
$model = $config['model'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$provider_defaults = [
|
||||||
|
'openai' => 'gpt-4o-mini',
|
||||||
|
'anthropic' => 'claude-3-5-haiku-20241022',
|
||||||
|
'deepseek' => 'deepseek-chat',
|
||||||
|
'qianwen' => 'qwen-turbo',
|
||||||
|
'wenxin' => 'ernie-4.0-turbo-8k',
|
||||||
|
'doubao' => 'doubao-pro-32k',
|
||||||
|
'kimi' => 'moonshot-v1-8k',
|
||||||
|
'zhipu' => 'glm-4-flash',
|
||||||
|
'siliconflow' => 'Qwen/Qwen2.5-7B-Instruct',
|
||||||
|
'xiaomi' => 'MiMo-V2-Flash'
|
||||||
|
];
|
||||||
|
if (empty($model) && isset($provider_defaults[$provider])) {
|
||||||
|
$model = $provider_defaults[$provider];
|
||||||
|
}
|
||||||
|
if ($provider === 'xiaomi' && !empty($endpoint) && !empty($model)) {
|
||||||
|
if (strpos($endpoint, 'xiaomimimo.com') !== false && strcasecmp($model, 'MiMo-V2-Flash') === 0) {
|
||||||
|
$model = 'mimo-v2-flash';
|
||||||
|
} elseif (strpos($endpoint, 'api.mimo.xiaomi.com') !== false && strcasecmp($model, 'mimo-v2-flash') === 0) {
|
||||||
|
$model = 'MiMo-V2-Flash';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'provider' => $provider,
|
||||||
|
'model' => $model
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function argon_get_latest_ai_query_provider_model($scenario, $post_id = 0, $comment_id = 0) {
|
||||||
|
global $wpdb;
|
||||||
|
$table_name = $wpdb->prefix . 'argon_ai_query_log';
|
||||||
|
|
||||||
|
$where = ['scenario = %s', "status = 'success'"];
|
||||||
|
$params = [$scenario];
|
||||||
|
|
||||||
|
if (!empty($post_id)) {
|
||||||
|
$where[] = 'post_id = %d';
|
||||||
|
$params[] = intval($post_id);
|
||||||
|
}
|
||||||
|
if (!empty($comment_id)) {
|
||||||
|
$where[] = 'comment_id = %d';
|
||||||
|
$params[] = intval($comment_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "SELECT provider, model FROM {$table_name} WHERE " . implode(' AND ', $where) . " ORDER BY id DESC LIMIT 1";
|
||||||
|
$row = $wpdb->get_row($wpdb->prepare($sql, $params), ARRAY_A);
|
||||||
|
|
||||||
|
if (is_array($row) && !empty($row['provider']) && isset($row['model'])) {
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 AI 查询统计信息
|
* 获取 AI 查询统计信息
|
||||||
*
|
*
|
||||||
@@ -6960,6 +7114,25 @@ function argon_get_ai_summary($post_id) {
|
|||||||
|
|
||||||
// 如果缓存存在且内容未变化,返回缓存
|
// 如果缓存存在且内容未变化,返回缓存
|
||||||
if (!empty($cached_summary) && $cached_hash === $current_hash) {
|
if (!empty($cached_summary) && $cached_hash === $current_hash) {
|
||||||
|
$sync_key = 'argon_ai_summary_provider_model_synced_' . $post_id;
|
||||||
|
if (get_transient($sync_key) === false) {
|
||||||
|
$latest = argon_get_latest_ai_query_provider_model('summary', $post_id, 0);
|
||||||
|
if ($latest) {
|
||||||
|
$current_provider = get_post_meta($post_id, '_argon_ai_summary_provider', true);
|
||||||
|
$current_model = get_post_meta($post_id, '_argon_ai_summary_model', true);
|
||||||
|
|
||||||
|
if (!empty($latest['provider']) && $latest['provider'] !== $current_provider) {
|
||||||
|
update_post_meta($post_id, '_argon_ai_summary_provider', $latest['provider']);
|
||||||
|
}
|
||||||
|
if (isset($latest['model']) && $latest['model'] !== $current_model) {
|
||||||
|
update_post_meta($post_id, '_argon_ai_summary_model', $latest['model']);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_transient($sync_key, 1, DAY_IN_SECONDS);
|
||||||
|
} else {
|
||||||
|
set_transient($sync_key, 1, 10 * MINUTE_IN_SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
return $cached_summary;
|
return $cached_summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7245,7 +7418,7 @@ function argon_log_ai_error($provider, $error_type, $error_message, $post_id = 0
|
|||||||
* @param WP_Post $post 文章对象
|
* @param WP_Post $post 文章对象
|
||||||
* @return string|false 摘要内容或 false
|
* @return string|false 摘要内容或 false
|
||||||
*/
|
*/
|
||||||
function argon_generate_ai_summary($post) {
|
function argon_generate_ai_summary($post, $ai_context = []) {
|
||||||
// 准备文章内容
|
// 准备文章内容
|
||||||
$content = wp_strip_all_tags($post->post_content);
|
$content = wp_strip_all_tags($post->post_content);
|
||||||
$content = preg_replace('/\s+/', ' ', $content);
|
$content = preg_replace('/\s+/', ' ', $content);
|
||||||
@@ -7265,10 +7438,10 @@ function argon_generate_ai_summary($post) {
|
|||||||
$prompt = get_option('argon_ai_summary_prompt', '你是一个专业的内容摘要助手。请仔细阅读以下文章内容,用简洁、准确的语言总结文章的核心观点和主要内容。要求:1) 控制在 100-150 字以内;2) 突出文章的关键信息和亮点;3) 使用通俗易懂的语言;4) 保持客观中立的语气。');
|
$prompt = get_option('argon_ai_summary_prompt', '你是一个专业的内容摘要助手。请仔细阅读以下文章内容,用简洁、准确的语言总结文章的核心观点和主要内容。要求:1) 控制在 100-150 字以内;2) 突出文章的关键信息和亮点;3) 使用通俗易懂的语言;4) 保持客观中立的语气。');
|
||||||
|
|
||||||
// 使用统一的 AI 查询接口
|
// 使用统一的 AI 查询接口
|
||||||
$result = argon_ai_query('summary', $prompt, $content, [
|
$result = argon_ai_query('summary', $prompt, $content, array_merge([
|
||||||
'post_id' => $post->ID,
|
'post_id' => $post->ID,
|
||||||
'user_id' => get_current_user_id()
|
'user_id' => get_current_user_id()
|
||||||
]);
|
], is_array($ai_context) ? $ai_context : []));
|
||||||
|
|
||||||
// 检查结果
|
// 检查结果
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
@@ -7892,6 +8065,17 @@ function argon_check_ai_summary() {
|
|||||||
delete_transient('argon_ai_summary_generating_' . $post_id);
|
delete_transient('argon_ai_summary_generating_' . $post_id);
|
||||||
$model = get_post_meta($post_id, '_argon_ai_summary_model', true);
|
$model = get_post_meta($post_id, '_argon_ai_summary_model', true);
|
||||||
$provider = get_post_meta($post_id, '_argon_ai_summary_provider', true);
|
$provider = get_post_meta($post_id, '_argon_ai_summary_provider', true);
|
||||||
|
$latest = argon_get_latest_ai_query_provider_model('summary', $post_id, 0);
|
||||||
|
if ($latest) {
|
||||||
|
if (!empty($latest['provider']) && $latest['provider'] !== $provider) {
|
||||||
|
$provider = $latest['provider'];
|
||||||
|
update_post_meta($post_id, '_argon_ai_summary_provider', $provider);
|
||||||
|
}
|
||||||
|
if (isset($latest['model']) && $latest['model'] !== $model) {
|
||||||
|
$model = $latest['model'];
|
||||||
|
update_post_meta($post_id, '_argon_ai_summary_model', $model);
|
||||||
|
}
|
||||||
|
}
|
||||||
$code = get_post_meta($post_id, '_argon_ai_summary_code', true);
|
$code = get_post_meta($post_id, '_argon_ai_summary_code', true);
|
||||||
|
|
||||||
// 如果没有识别码,生成一个
|
// 如果没有识别码,生成一个
|
||||||
@@ -7918,16 +8102,34 @@ function argon_check_ai_summary() {
|
|||||||
// 触发生成
|
// 触发生成
|
||||||
$post = get_post($post_id);
|
$post = get_post($post_id);
|
||||||
if ($post) {
|
if ($post) {
|
||||||
$summary = argon_generate_ai_summary($post);
|
$resolved = argon_resolve_ai_provider_model('summary', [
|
||||||
|
'post_id' => $post_id,
|
||||||
|
'user_id' => get_current_user_id()
|
||||||
|
]);
|
||||||
|
$provider = isset($resolved['provider']) ? $resolved['provider'] : '';
|
||||||
|
$model = isset($resolved['model']) ? $resolved['model'] : '';
|
||||||
|
|
||||||
|
$summary = argon_generate_ai_summary($post, [
|
||||||
|
'provider' => $provider,
|
||||||
|
'model' => $model
|
||||||
|
]);
|
||||||
|
|
||||||
if ($summary !== false) {
|
if ($summary !== false) {
|
||||||
$current_hash = md5($post->post_content . $post->post_title);
|
$current_hash = md5($post->post_content . $post->post_title);
|
||||||
$provider = get_option('argon_ai_summary_provider', 'openai');
|
|
||||||
$model = get_option('argon_ai_summary_model', '');
|
|
||||||
|
|
||||||
// 生成唯一识别码
|
// 生成唯一识别码
|
||||||
$summary_code = argon_generate_summary_code();
|
$summary_code = argon_generate_summary_code();
|
||||||
|
|
||||||
|
$latest = argon_get_latest_ai_query_provider_model('summary', $post_id, 0);
|
||||||
|
if ($latest) {
|
||||||
|
if (!empty($latest['provider'])) {
|
||||||
|
$provider = $latest['provider'];
|
||||||
|
}
|
||||||
|
if (isset($latest['model'])) {
|
||||||
|
$model = $latest['model'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 保存摘要和模型信息
|
// 保存摘要和模型信息
|
||||||
update_post_meta($post_id, '_argon_ai_summary', $summary);
|
update_post_meta($post_id, '_argon_ai_summary', $summary);
|
||||||
update_post_meta($post_id, '_argon_ai_summary_hash', $current_hash);
|
update_post_meta($post_id, '_argon_ai_summary_hash', $current_hash);
|
||||||
@@ -9789,11 +9991,21 @@ function argon_detect_spam_comment_sync($comment) {
|
|||||||
// 构建评论上下文信息
|
// 构建评论上下文信息
|
||||||
$comment_text = argon_build_comment_context($comment);
|
$comment_text = argon_build_comment_context($comment);
|
||||||
|
|
||||||
|
$resolved = argon_resolve_ai_provider_model('spam_detection', [
|
||||||
|
'comment_id' => $comment->comment_ID,
|
||||||
|
'post_id' => $comment->comment_post_ID,
|
||||||
|
'user_id' => $comment->user_id
|
||||||
|
]);
|
||||||
|
$provider = isset($resolved['provider']) ? $resolved['provider'] : '';
|
||||||
|
$model = isset($resolved['model']) ? $resolved['model'] : '';
|
||||||
|
|
||||||
// 使用统一的 AI 查询接口
|
// 使用统一的 AI 查询接口
|
||||||
$result_text = argon_ai_query('spam_detection', $prompt, $comment_text, [
|
$result_text = argon_ai_query('spam_detection', $prompt, $comment_text, [
|
||||||
'comment_id' => $comment->comment_ID,
|
'comment_id' => $comment->comment_ID,
|
||||||
'post_id' => $comment->comment_post_ID,
|
'post_id' => $comment->comment_post_ID,
|
||||||
'user_id' => $comment->user_id
|
'user_id' => $comment->user_id,
|
||||||
|
'provider' => $provider,
|
||||||
|
'model' => $model
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($result_text === false) {
|
if ($result_text === false) {
|
||||||
@@ -9804,6 +10016,15 @@ function argon_detect_spam_comment_sync($comment) {
|
|||||||
$result = json_decode($result_text, true);
|
$result = json_decode($result_text, true);
|
||||||
|
|
||||||
if ($result && isset($result['content_spam'])) {
|
if ($result && isset($result['content_spam'])) {
|
||||||
|
$latest = argon_get_latest_ai_query_provider_model('spam_detection', 0, $comment->comment_ID);
|
||||||
|
if ($latest) {
|
||||||
|
if (!empty($latest['provider'])) {
|
||||||
|
$provider = $latest['provider'];
|
||||||
|
}
|
||||||
|
if (isset($latest['model'])) {
|
||||||
|
$model = $latest['model'];
|
||||||
|
}
|
||||||
|
}
|
||||||
// 转换为统一格式
|
// 转换为统一格式
|
||||||
$unified_result = [
|
$unified_result = [
|
||||||
'is_spam' => $result['content_spam'],
|
'is_spam' => $result['content_spam'],
|
||||||
@@ -9818,6 +10039,8 @@ function argon_detect_spam_comment_sync($comment) {
|
|||||||
// 保存检测结果
|
// 保存检测结果
|
||||||
update_comment_meta($comment->comment_ID, '_argon_spam_detection_result', $unified_result);
|
update_comment_meta($comment->comment_ID, '_argon_spam_detection_result', $unified_result);
|
||||||
update_comment_meta($comment->comment_ID, '_argon_spam_detection_time', time());
|
update_comment_meta($comment->comment_ID, '_argon_spam_detection_time', time());
|
||||||
|
update_comment_meta($comment->comment_ID, '_argon_spam_detection_provider', $provider);
|
||||||
|
update_comment_meta($comment->comment_ID, '_argon_spam_detection_model', $model);
|
||||||
|
|
||||||
return $unified_result;
|
return $unified_result;
|
||||||
}
|
}
|
||||||
@@ -10246,6 +10469,17 @@ function argon_async_spam_detection_handler($comment_id) {
|
|||||||
$detection_code = argon_generate_detection_code($comment_id);
|
$detection_code = argon_generate_detection_code($comment_id);
|
||||||
update_comment_meta($comment_id, '_argon_spam_detection_code', $detection_code);
|
update_comment_meta($comment_id, '_argon_spam_detection_code', $detection_code);
|
||||||
|
|
||||||
|
$config = argon_get_active_api_config('spam');
|
||||||
|
if (!empty($config) && !empty($config['api_key']) && !empty($config['provider'])) {
|
||||||
|
update_comment_meta($comment_id, '_argon_spam_detection_provider', $config['provider']);
|
||||||
|
update_comment_meta($comment_id, '_argon_spam_detection_model', isset($config['model']) ? $config['model'] : '');
|
||||||
|
} else {
|
||||||
|
$provider = get_option('argon_ai_summary_provider', 'openai');
|
||||||
|
$provider_config = argon_get_ai_provider_config($provider);
|
||||||
|
update_comment_meta($comment_id, '_argon_spam_detection_provider', $provider);
|
||||||
|
update_comment_meta($comment_id, '_argon_spam_detection_model', !empty($provider_config['model']) ? $provider_config['model'] : get_option('argon_ai_summary_model', ''));
|
||||||
|
}
|
||||||
|
|
||||||
if ($result && isset($result['is_spam'])) {
|
if ($result && isset($result['is_spam'])) {
|
||||||
$content_spam = $result['is_spam'];
|
$content_spam = $result['is_spam'];
|
||||||
$username_invalid = isset($result['username_invalid']) ? $result['username_invalid'] : false;
|
$username_invalid = isset($result['username_invalid']) ? $result['username_invalid'] : false;
|
||||||
@@ -10501,12 +10735,24 @@ function argon_spam_detection_scan() {
|
|||||||
$spam_results = [];
|
$spam_results = [];
|
||||||
$checked_ids = [];
|
$checked_ids = [];
|
||||||
|
|
||||||
|
$config = argon_get_active_api_config('spam');
|
||||||
|
if (!empty($config) && !empty($config['api_key']) && !empty($config['provider'])) {
|
||||||
|
$provider = $config['provider'];
|
||||||
|
$model = isset($config['model']) ? $config['model'] : '';
|
||||||
|
} else {
|
||||||
|
$provider = get_option('argon_ai_summary_provider', 'openai');
|
||||||
|
$provider_config = argon_get_ai_provider_config($provider);
|
||||||
|
$model = !empty($provider_config['model']) ? $provider_config['model'] : get_option('argon_ai_summary_model', '');
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($result as $item) {
|
foreach ($result as $item) {
|
||||||
$comment_id = $item['id'];
|
$comment_id = $item['id'];
|
||||||
$checked_ids[] = $comment_id;
|
$checked_ids[] = $comment_id;
|
||||||
|
|
||||||
// 记录检测时间
|
// 记录检测时间
|
||||||
update_comment_meta($comment_id, '_argon_spam_detection_time', time());
|
update_comment_meta($comment_id, '_argon_spam_detection_time', time());
|
||||||
|
update_comment_meta($comment_id, '_argon_spam_detection_provider', $provider);
|
||||||
|
update_comment_meta($comment_id, '_argon_spam_detection_model', $model);
|
||||||
|
|
||||||
// 生成识别码
|
// 生成识别码
|
||||||
$detection_code = argon_generate_detection_code($comment_id);
|
$detection_code = argon_generate_detection_code($comment_id);
|
||||||
@@ -10555,6 +10801,8 @@ function argon_spam_detection_scan() {
|
|||||||
foreach ($comments_data as $comment_data) {
|
foreach ($comments_data as $comment_data) {
|
||||||
if (!in_array($comment_data['id'], $checked_ids)) {
|
if (!in_array($comment_data['id'], $checked_ids)) {
|
||||||
update_comment_meta($comment_data['id'], '_argon_spam_detection_time', time());
|
update_comment_meta($comment_data['id'], '_argon_spam_detection_time', time());
|
||||||
|
update_comment_meta($comment_data['id'], '_argon_spam_detection_provider', $provider);
|
||||||
|
update_comment_meta($comment_data['id'], '_argon_spam_detection_model', $model);
|
||||||
$detection_code = argon_generate_detection_code($comment_data['id']);
|
$detection_code = argon_generate_detection_code($comment_data['id']);
|
||||||
update_comment_meta($comment_data['id'], '_argon_spam_detection_code', $detection_code);
|
update_comment_meta($comment_data['id'], '_argon_spam_detection_code', $detection_code);
|
||||||
}
|
}
|
||||||
@@ -10970,11 +11218,8 @@ function argon_update_mermaid_settings($settings) {
|
|||||||
/**
|
/**
|
||||||
* 检测页面内容是否包含 Mermaid 代码块
|
* 检测页面内容是否包含 Mermaid 代码块
|
||||||
*
|
*
|
||||||
* 支持多种格式:
|
* 支持 Shortcode 格式:
|
||||||
* - <div class="mermaid">
|
* - [mermaid]...[/mermaid]
|
||||||
* - <pre><code class="language-mermaid">
|
|
||||||
* - <pre data-lang="mermaid">
|
|
||||||
* - <code class="mermaid">
|
|
||||||
*
|
*
|
||||||
* @param string $content 页面内容
|
* @param string $content 页面内容
|
||||||
* @return bool 是否包含 Mermaid 代码块
|
* @return bool 是否包含 Mermaid 代码块
|
||||||
@@ -10986,11 +11231,7 @@ function argon_has_mermaid_content($content) {
|
|||||||
|
|
||||||
// 检测多种 Mermaid 代码块格式
|
// 检测多种 Mermaid 代码块格式
|
||||||
$patterns = [
|
$patterns = [
|
||||||
'/<div[^>]*class=["\']([^"\']*\s)?mermaid(\s[^"\']*)?["\'][^>]*>/i', // <div class="mermaid">
|
'/\[mermaid[^\]]*\]/i'
|
||||||
'/<code[^>]*class=["\']([^"\']*\s)?language-mermaid(\s[^"\']*)?["\'][^>]*>/i', // <code class="language-mermaid">
|
|
||||||
'/<pre[^>]*data-lang=["\']mermaid["\'][^>]*>/i', // <pre data-lang="mermaid">
|
|
||||||
'/<code[^>]*class=["\']([^"\']*\s)?mermaid(\s[^"\']*)?["\'][^>]*>/i', // <code class="mermaid">
|
|
||||||
'/:::\s*mermaid/i' // ::: mermaid (Markdown 容器语法)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($patterns as $pattern) {
|
foreach ($patterns as $pattern) {
|
||||||
|
|||||||
@@ -92,13 +92,17 @@
|
|||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
$content_for_preview = get_the_content('...');
|
||||||
|
// 移除 Mermaid shortcode,避免在预览中显示原始代码
|
||||||
|
$content_for_preview = argon_remove_mermaid_from_preview($content_for_preview);
|
||||||
|
|
||||||
if (get_option("argon_hide_shortcode_in_preview") == 'true'){
|
if (get_option("argon_hide_shortcode_in_preview") == 'true'){
|
||||||
|
|
||||||
$preview = wp_trim_words(do_shortcode(get_the_content('...')), $trim_words_count);
|
$preview = wp_trim_words(do_shortcode($content_for_preview), $trim_words_count);
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
|
|
||||||
$preview = wp_trim_words(get_the_content('...'), $trim_words_count);
|
$preview = wp_trim_words($content_for_preview, $trim_words_count);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,13 +32,17 @@
|
|||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
$content_for_preview = get_the_content('...');
|
||||||
|
// 移除 Mermaid shortcode,避免在预览中显示原始代码
|
||||||
|
$content_for_preview = argon_remove_mermaid_from_preview($content_for_preview);
|
||||||
|
|
||||||
if (get_option("argon_hide_shortcode_in_preview") == 'true'){
|
if (get_option("argon_hide_shortcode_in_preview") == 'true'){
|
||||||
|
|
||||||
$preview = wp_trim_words(do_shortcode(get_the_content('...')), $trim_words_count);
|
$preview = wp_trim_words(do_shortcode($content_for_preview), $trim_words_count);
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
|
|
||||||
$preview = wp_trim_words(get_the_content('...'), $trim_words_count);
|
$preview = wp_trim_words($content_for_preview, $trim_words_count);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,13 +84,17 @@
|
|||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
$content_for_preview = get_the_content('...');
|
||||||
|
// 移除 Mermaid shortcode,避免在预览中显示原始代码
|
||||||
|
$content_for_preview = argon_remove_mermaid_from_preview($content_for_preview);
|
||||||
|
|
||||||
if (get_option("argon_hide_shortcode_in_preview") == 'true'){
|
if (get_option("argon_hide_shortcode_in_preview") == 'true'){
|
||||||
|
|
||||||
$preview = wp_trim_words(do_shortcode(get_the_content('...')), $trim_words_count);
|
$preview = wp_trim_words(do_shortcode($content_for_preview), $trim_words_count);
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
|
|
||||||
$preview = wp_trim_words(get_the_content('...'), $trim_words_count);
|
$preview = wp_trim_words($content_for_preview, $trim_words_count);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user