Files
wordpress-theme-aksrt/inc/helpers/comments/content.php
T
kate522 9375b1c30c refactor(assets): vendor 资产迁入标准目录并全仓去除 zibll 标识
- assets/vendor 全量迁移: fontawesome5→assets/fontawesome5, css→assets/css,
  js→assets/js/runtime(避开 14 个同名自有文件), img 合并去重→assets/img,
  fonts→assets/fonts; 删除 assets/vendor
- libs 五个与 widgets/third-party 字节相同的库不重复入库, loader paths 改指向
- 运行时切换: _win.uri=assets 根, loader baseUrl=/js/runtime, enlighter 注入
  路径同步; PHP 7 个引用文件切换并改名 $zibll_*→$runtime_*
- 去品牌: Qinver 头注释/品牌 console.log/演示链接清除, 默认文案中性化
- 功能标识符改名: zib__→aksrt__, zib_ajax→aksrt_ajax, window.zib→
  window.aksrtLegacy, zibllblock/*→aksrtblock/*, .zib-widget→.aksrt-panel,
  .zib-slider→.aksrt-slider, zib_menu_options meta 键等
- 自有 CSS 改名: legacy-utilities/compat-vars/footer shell
- admin SPA 重建; 契约测试同步(路径/断言/文件更名)
- 例外保留: tests/visual 对照环境与 fixtures 前缀(外部 Zibll 产品引用)

验证: php -l 133 个改动文件通过; runtime 86 个 JS node --check 通过;
契约测试 68/70(2 个失败经 stash 对照确认为存量问题)
2026-08-22 16:16:30 +08:00

159 lines
5.1 KiB
PHP

<?php
/**
* Comment content filters — legacy-compatible shortcodes.
*
* Supports [g=key] GIF smilies, [img=url], [code]...[/code].
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
if (!function_exists('aksrt_comment_smilie_keys')) :
/**
* Canonical legacy smilie keys (filename without .gif).
*
* @return array<int,string>
*/
function aksrt_comment_smilie_keys(): array {
return [
'aoman', 'baiyan', 'bishi', 'bizui', 'cahan', 'ciya', 'dabing', 'daku', 'deyi', 'doge',
'fadai', 'fanu', 'fendou', 'ganga', 'guzhang', 'haixiu', 'hanxiao', 'zuohengheng', 'zhuakuang',
'zhouma', 'zhemo', 'zhayanjian', 'zaijian', 'yun', 'youhengheng', 'yiwen', 'yinxian', 'xu',
'xieyanxiao', 'xiaoku', 'xiaojiujie', 'xia', 'wunai', 'wozuimei', 'weixiao', 'weiqu', 'tuosai',
'tu', 'touxiao', 'tiaopi', 'shui', 'se', 'saorao', 'qiudale', 'qinqin', 'qiaoda', 'piezui',
'penxue', 'nanguo', 'liulei', 'liuhan', 'lenghan', 'leiben', 'kun', 'kuaikule', 'ku', 'koubi',
'kelian', 'keai', 'jingya', 'jingxi', 'jingkong', 'jie', 'huaixiao', 'haqian', 'aini', 'OK',
'qiang', 'quantou', 'shengli', 'woshou', 'gouyin', 'baoquan', 'aixin', 'bangbangtang',
'xiaoyanger', 'xigua', 'hexie', 'pijiu', 'lanqiu', 'juhua', 'hecai', 'haobang', 'caidao',
'baojin', 'chi', 'dan', 'kulou', 'shuai', 'shouqiang', 'yangtuo', 'youling',
];
}
endif;
if (!function_exists('aksrt_comment_smilie_map')) :
/**
* Smilie key => URL map (GIF under assets/img/smilies).
*
* @return array<string,string>
*/
function aksrt_comment_smilie_map(): array {
static $map = null;
if (is_array($map)) {
return $map;
}
$base = trailingslashit(get_template_directory_uri()) . 'assets/img/smilies/';
$map = [];
foreach (aksrt_comment_smilie_keys() as $key) {
$map[$key] = $base . rawurlencode($key) . '.gif';
}
return $map;
}
endif;
if (!function_exists('aksrt_comment_smilies_base_uri')) :
/**
* Base URI for smilie GIFs (localized to JS).
*/
function aksrt_comment_smilies_base_uri(): string {
return trailingslashit(get_template_directory_uri()) . 'assets/img/smilies/';
}
endif;
if (!function_exists('aksrt_render_comment_smilie')) :
/**
* Render a single [g=key] smilie as <img class="smilie-icon">.
*/
function aksrt_render_comment_smilie(string $key): string {
// Preserve case for OK.gif; sanitize other keys.
$raw = trim($key);
if ($raw === '') {
return '';
}
$lookup = $raw === 'OK' ? 'OK' : sanitize_key($raw);
// Allow original casing match for files like OK.gif.
$map = aksrt_comment_smilie_map();
if (!isset($map[$lookup]) && isset($map[$raw])) {
$lookup = $raw;
}
if (!isset($map[$lookup])) {
// Fallback: try case-insensitive.
foreach ($map as $k => $url) {
if (strcasecmp((string) $k, $raw) === 0) {
$lookup = (string) $k;
break;
}
}
}
if (!isset($map[$lookup])) {
return '[g=' . esc_html($raw) . ']';
}
$label = esc_attr('[' . $lookup . ']');
return '<img' . aksrt_get_lazy_attr('lazy_comment', (string) $map[$lookup], 'smilie-icon', aksrt_get_lazy_thumb('sm'))
. ' alt="' . $label . '" title="' . $label . '" width="30" height="30" decoding="async" data-smilie="' . esc_attr($lookup) . '">';
}
endif;
if (!function_exists('aksrt_render_comment_content')) :
/**
* Filter comment body: smilies, images, code blocks (legacy parity).
*/
function aksrt_render_comment_content(string $content): string {
// [img=url]
$rendered = preg_replace_callback(
'/\[img=(https?:\/\/[^\s\[\]]+)\]/i',
static function (array $matches): string {
return '<img' . aksrt_get_lazy_attr('lazy_comment', (string) $matches[1], 'box-img comment-inline-img', aksrt_get_lazy_thumb('lg'))
. ' alt="' . esc_attr__('评论图片', 'aksrt') . '" decoding="async">';
},
$content
);
// [code]...[/code]
$rendered = str_replace(
['[code]', '[/code]'],
['<pre class="comment-code"><code>', '</code></pre>'],
(string) $rendered
);
// [link=url target=_blank]text[/link] / [link=url]text[/link]
$rendered = preg_replace(
'/\[link=(https?:\/\/[^\s\[\]]+) target=_blank\]([^\[]*)\[\/link\]/i',
'<a href="$1" target="_blank" rel="nofollow">$2</a>',
(string) $rendered
);
$rendered = preg_replace(
'/\[link=(https?:\/\/[^\s\[\]]+)\]([^\[]*)\[\/link\]/i',
'<a href="$1" rel="nofollow">$2</a>',
(string) $rendered
);
// [g=key]
$rendered = preg_replace_callback(
'/\[g=([^\]]+)\]/i',
static function (array $matches): string {
return aksrt_render_comment_smilie(trim((string) $matches[1]));
},
(string) $rendered
);
$allowed = wp_kses_allowed_html('post');
if (!isset($allowed['img'])) {
$allowed['img'] = [];
}
$allowed['img'] = array_merge($allowed['img'], [
'class' => true,
'src' => true,
'alt' => true,
'title' => true,
'width' => true,
'height' => true,
'data-src' => true,
'decoding' => true,
'data-smilie' => true,
'data-src' => true,
]);
$allowed['pre'] = array_merge($allowed['pre'] ?? [], ['class' => true]);
$allowed['code'] = $allowed['code'] ?? [];
return wp_kses((string) $rendered, $allowed);
}
endif;