fix(icons): 图标类名统一为 FA5 语法并修正一处失效图标名

主题打包的是 Font Awesome 5,solid 字形必须带样式类 fas。全站有 18 处仍写成
FA4 的裸 fa fa-*,FA5 下并不存在对应字形,表现为图标位置空白;而 FA5-only
契约此前只扫描部分运行时文件,没有覆盖模板与渲染器,这些写法一直没被拦下。

同时发现一处真实的失效图标名:profile-level.php 用的是 fa-line-chart。这是
FA4 名称,FA5 把该系列重命名为 chart-*,正确写法是 fa-chart-line。

- 18 处 "fa fa-*" 补上 fas:首页模板、组件标记、评论表单、用户等级页、菜单
  装饰、SchemaPayment 促销标签默认值、VIP 服务弹窗、ContentRenderer /
  GeneralRenderer、后台卡片样式校验、pay-vip.js
- profile-level.php 的 fa-line-chart 修正为 fa-chart-line
- 三处注释里的示例值同步为合法形态("fa fas fa-star"),避免被当成正确写法
  抄走;credits.css 注释中直接写出旧字体族名的一处改为描述性表述,否则会被
  FA5-only 契约当作违规命中
- legacy-navigation-contract:FA 资产断言改为跟随 aksrt_enqueue_fontawesome()
  这一间接层(注册点已从脚本文件移到 inc/helpers/aksrt-icons.php),并把
  fa-zibsvg-<key> 识别为项目自有 SVG sprite 族,而非 Font Awesome 字形
- vip-points-exchange-modal 契约同步断言 fa fas fa-angle-right

验证:改动前在干净 HEAD 上跑 node --test(已追踪用例)为 327 项 / 325 通过 /
2 失败,两项失败正是本次修复的失效图标名断言与 FA 版本号断言;改动后 333 项 /
333 通过(含 5 个本地专用用例共 370 项全部通过)。php -l 全部改动的 PHP 文件
通过。
This commit is contained in:
2026-09-18 23:17:05 +08:00
parent a6819ec7a5
commit 3bec2a5777
16 changed files with 40 additions and 27 deletions
@@ -17,7 +17,7 @@
<script setup> <script setup>
/** /**
* IconValue — renders any icon-picker value ("fa fas fa-x", "zibsvg-key", * IconValue — renders any icon-picker value ("fa fas fa-star", "zibsvg-key",
* "customsvg-<svg>") as inline preview markup. * "customsvg-<svg>") as inline preview markup.
*/ */
import { computed } from 'vue' import { computed } from 'vue'
@@ -42,7 +42,7 @@ export const knowledgeSchema = {
vip_2_points_default: 0, vip_2_points_default: 0,
pay_price_default: '0.01', pay_price_default: '0.01',
pay_original_price_default: '', pay_original_price_default: '',
pay_promotion_tag_default: '<i class="fa fa-fw fa-bolt"></i> 限时特惠', pay_promotion_tag_default: '<i class="fa fas fa-fw fa-bolt"></i> 限时特惠',
vip_1_price_default: '0', vip_1_price_default: '0',
vip_2_price_default: '0', vip_2_price_default: '0',
pay_rebate_discount: '0', pay_rebate_discount: '0',
@@ -213,7 +213,7 @@ export const knowledgeSchema = {
{ key: 'vip_2_points_default', label: '二级会员积分售价(积分)', type: 'number', default: 0, min: 0 }, { key: 'vip_2_points_default', label: '二级会员积分售价(积分)', type: 'number', default: 0, min: 0 },
{ key: 'pay_price_default', label: '执行价', type: 'input', sanitize_type: 'money_decimal', default: '0.01', suffix: '元' }, { key: 'pay_price_default', label: '执行价', type: 'input', sanitize_type: 'money_decimal', default: '0.01', suffix: '元' },
{ key: 'pay_original_price_default', label: '原价', type: 'input', sanitize_type: 'money_decimal', default: '', suffix: '元', help: '显示在执行价格前面,并划掉' }, { key: 'pay_original_price_default', label: '原价', type: 'input', sanitize_type: 'money_decimal', default: '', suffix: '元', help: '显示在执行价格前面,并划掉' },
{ key: 'pay_promotion_tag_default', label: '促销标签', type: 'textarea', sanitize_type: 'html', default: '<i class="fa fa-fw fa-bolt"></i> 限时特惠', rows: 1 }, { key: 'pay_promotion_tag_default', label: '促销标签', type: 'textarea', sanitize_type: 'html', default: '<i class="fa fas fa-fw fa-bolt"></i> 限时特惠', rows: 1 },
{ key: 'vip_1_price_default', label: '一级会员价格', type: 'input', sanitize_type: 'money_decimal', default: '0', suffix: '元', help: '填0则为一级会员免费' }, { key: 'vip_1_price_default', label: '一级会员价格', type: 'input', sanitize_type: 'money_decimal', default: '0', suffix: '元', help: '填0则为一级会员免费' },
{ key: 'vip_2_price_default', label: '二级会员价格', type: 'input', sanitize_type: 'money_decimal', default: '0', suffix: '元', help: '填0则为二级会员免费' }, { key: 'vip_2_price_default', label: '二级会员价格', type: 'input', sanitize_type: 'money_decimal', default: '0', suffix: '元', help: '填0则为二级会员免费' },
{ key: 'pay_rebate_discount', label: '推广折扣', type: 'input', sanitize_type: 'money_decimal', default: '0', suffix: '元', help: '通过推广链接购买,额外优惠的金额;需开启推广返佣功能,且不能超过实际购买价' }, { key: 'pay_rebate_discount', label: '推广折扣', type: 'input', sanitize_type: 'money_decimal', default: '0', suffix: '元', help: '通过推广链接购买,额外优惠的金额;需开启推广返佣功能,且不能超过实际购买价' },
+2 -2
View File
@@ -225,8 +225,8 @@
} }
.balance-charge-form .vip-product.active::before { .balance-charge-form .vip-product.active::before {
content: '\f058'; content: '\f058';
/* 本主题打包的是 FA5(family "Font Awesome 5 Free",solid 字形需 900), /* 本主题打包的是 FA5(族名 'Font Awesome 5 Free',solid 字形需 900),
Zibll 的 FA4 family "FontAwesome" 在本主题不存在 → 豆腐块(被误认破图)。 */ Zibll 遗留的 FA4 族名在本主题不存在 → 豆腐块(被误认破图)。 */
font: normal normal 900 16px/1 'Font Awesome 5 Free'; font: normal normal 900 16px/1 'Font Awesome 5 Free';
color: var(--focus-color); color: var(--focus-color);
position: absolute; position: absolute;
+1 -1
View File
@@ -1,6 +1,6 @@
/** /**
* AKSRT universal icon picker — shared admin modal for FA5, the built-in * AKSRT universal icon picker — shared admin modal for FA5, the built-in
* SVG sprite and inline custom SVG values ("fa fas fa-x" / "zibsvg-key" / * SVG sprite and inline custom SVG values ("fa fas fa-star" / "zibsvg-key" /
* "customsvg-<svg>"). * "customsvg-<svg>").
* *
* Any admin screen: call aksrt_icon_picker_assets() (PHP) and render fields * Any admin screen: call aksrt_icon_picker_assets() (PHP) and render fields
+2 -2
View File
@@ -446,7 +446,7 @@
append(tab, miniCard); append(tab, miniCard);
append(tabItem, tab); append(tabItem, tab);
var activeIcon = node("div", "abs-right active-icon"); var activeIcon = node("div", "abs-right active-icon");
append(activeIcon, node("i", "fa fa-check-circle")); append(activeIcon, node("i", "fa fas fa-check-circle"));
activeIcon.setAttribute("aria-hidden", "true"); activeIcon.setAttribute("aria-hidden", "true");
append(tabItem, activeIcon); append(tabItem, activeIcon);
append(tabs, tabItem); append(tabs, tabItem);
@@ -494,7 +494,7 @@
pointsLink.setAttribute("data-aksrt-vip-points-open", ""); pointsLink.setAttribute("data-aksrt-vip-points-open", "");
pointsLink.innerHTML = '<svg class="icon" aria-hidden="true"><use xlink:href="#icon-points-color"></use></svg>' pointsLink.innerHTML = '<svg class="icon" aria-hidden="true"><use xlink:href="#icon-points-color"></use></svg>'
+ "积分兑换会员" + "积分兑换会员"
+ '<i class="fa fa-angle-right em12 ml10" aria-hidden="true"></i>'; + '<i class="fa fas fa-angle-right em12 ml10" aria-hidden="true"></i>';
append(products, pointsLink); append(products, pointsLink);
} }
if (catalog.more) append(products, node("div", "muted-2-color mb10 em09 muted-box padding-10 mini-radius", catalog.more)); if (catalog.more) append(products, node("div", "muted-2-color mb10 em09 muted-box padding-10 mini-radius", catalog.more));
+1 -1
View File
@@ -303,7 +303,7 @@ if (!function_exists('aksrt_homepage_get_option_orderby_but')) {
$is_dropdown = ($option['dropdown'] && $dropdown_but) ? true : false; $is_dropdown = ($option['dropdown'] && $dropdown_but) ? true : false;
$d_but = $is_dropdown $d_but = $is_dropdown
? '<a href="javascript:;" data-toggle="dropdown"><span name="cat">' . esc_html__('排序', 'aksrt') . '</span><i class="fa fa-fw fa-sort opacity5" aria-hidden="true"></i></a>' ? '<a href="javascript:;" data-toggle="dropdown"><span name="cat">' . esc_html__('排序', 'aksrt') . '</span><i class="fa fas fa-fw fa-sort opacity5" aria-hidden="true"></i></a>'
: esc_html__('排序', 'aksrt'); : esc_html__('排序', 'aksrt');
$html = '<div class="flex ac">'; $html = '<div class="flex ac">';
+5 -5
View File
@@ -157,7 +157,7 @@ if (!function_exists('aksrt_widget_hot_posts')) :
if ((string) $data['primary'] !== '') { if ((string) $data['primary'] !== '') {
$thumb = '<img' . aksrt_get_lazy_attr('lazy_posts_thumb', (string) $data['primary'], 'fit-cover radius8') . ' alt="' . esc_attr((string) $data['title']) . '">'; $thumb = '<img' . aksrt_get_lazy_attr('lazy_posts_thumb', (string) $data['primary'], 'fit-cover radius8') . ' alt="' . esc_attr((string) $data['title']) . '">';
} }
$time_ago = '<i class="fa fa-clock mr3" aria-hidden="true"></i>' . esc_html((string) $data['time_ago']); $time_ago = '<i class="fa fas fa-clock mr3" aria-hidden="true"></i>' . esc_html((string) $data['time_ago']);
$permalink = esc_url((string) $data['permalink']); $permalink = esc_url((string) $data['permalink']);
if ($i === 1) { if ($i === 1) {
@@ -214,7 +214,7 @@ if (!function_exists('aksrt_widget_term_aggregation')) :
} }
$href = esc_url((string) $href); $href = esc_url((string) $href);
$icon = '<i class="fa fa-folder-open mr6" aria-hidden="true"></i>'; $icon = '<i class="fa fas fa-folder-open mr6" aria-hidden="true"></i>';
$img = aksrt_widget_term_cover_url((int) $term->term_id, true); $img = aksrt_widget_term_cover_url((int) $term->term_id, true);
$img_html = aksrt_graphic_card([ $img_html = aksrt_graphic_card([
'class' => '', 'class' => '',
@@ -241,8 +241,8 @@ if (!function_exists('aksrt_widget_term_aggregation')) :
]; ];
$query = \AKSRT\WidgetSystem\PostQuery::build($query_args, 1, []); $query = \AKSRT\WidgetSystem\PostQuery::build($query_args, 1, []);
$meta = '<span class="px12 muted-3-color text-ellipsis"><i class="fa fa-file-alt fa-fw" aria-hidden="true"></i>' . sprintf(esc_html__('%s篇文章', 'aksrt'), esc_html(aksrt_format_number(max(0, (int) $query->found_posts)))) . '</span>'; $meta = '<span class="px12 muted-3-color text-ellipsis"><i class="fa fas fa-file-alt fa-fw" aria-hidden="true"></i>' . sprintf(esc_html__('%s篇文章', 'aksrt'), esc_html(aksrt_format_number(max(0, (int) $query->found_posts)))) . '</span>';
$meta .= '<a class="but p2-10 px12 c-blue hide-sm shrink0"' . $target . ' href="' . $href . '"><i class="fa fa-angle-right" aria-hidden="true"></i>' . esc_html__('更多文章', 'aksrt') . '</a>'; $meta .= '<a class="but p2-10 px12 c-blue hide-sm shrink0"' . $target . ' href="' . $href . '"><i class="fa fas fa-angle-right" aria-hidden="true"></i>' . esc_html__('更多文章', 'aksrt') . '</a>';
$meta = '<div class="term-meta flex jsb ac">' . $meta . '</div>'; $meta = '<div class="term-meta flex jsb ac">' . $meta . '</div>';
$posts_html = ''; $posts_html = '';
@@ -271,7 +271,7 @@ if (!function_exists('aksrt_widget_term_aggregation')) :
break; break;
} }
if ($post_meta === '') { if ($post_meta === '') {
$post_meta = '<i class="fa fa-clock mr3" aria-hidden="true"></i>' . esc_html((string) $data['time_ago']); $post_meta = '<i class="fa fas fa-clock mr3" aria-hidden="true"></i>' . esc_html((string) $data['time_ago']);
} }
$posts_html .= '<div class="mt10 flex jsb ac">' . $title . '<div class="em09 muted-3-color flex0 ml10">' . $post_meta . '</div></div>'; $posts_html .= '<div class="mt10 flex jsb ac">' . $title . '<div class="em09 muted-3-color flex0 ml10">' . $post_meta . '</div></div>';
} }
+1 -1
View File
@@ -87,7 +87,7 @@ if (!function_exists('aksrt_get_input_expand_but')) :
if ($upload) { if ($upload) {
$placeholder = get_template_directory_uri() . '/assets/icons/upload-add.svg'; $placeholder = get_template_directory_uri() . '/assets/icons/upload-add.svg';
$dropdown .= '<div class="tab-pane fade dropdown-image" id="image-tab-' . esc_attr($upload_id) . '-2">'; $dropdown .= '<div class="tab-pane fade dropdown-image" id="image-tab-' . esc_attr($upload_id) . '-2">';
$dropdown .= '<p><a class="muted-color input-image-address-tab" data-image-tab="#image-tab-' . esc_attr($upload_id) . '-1" href="javascript:;"><i class="fa fa-angle-left mr6" aria-hidden="true"></i>' . esc_html__('填写图片地址', 'aksrt') . '</a></p>'; $dropdown .= '<p><a class="muted-color input-image-address-tab" data-image-tab="#image-tab-' . esc_attr($upload_id) . '-1" href="javascript:;"><i class="fa fas fa-angle-left mr6" aria-hidden="true"></i>' . esc_html__('填写图片地址', 'aksrt') . '</a></p>';
$dropdown .= '<div class="form-upload comment-image-upload">'; $dropdown .= '<div class="form-upload comment-image-upload">';
$dropdown .= '<label class="pointer comment-image-upload-label">'; $dropdown .= '<label class="pointer comment-image-upload-label">';
$dropdown .= '<div class="preview text-center mb6"><img src="' . esc_url($placeholder) . '" alt="" /></div>'; $dropdown .= '<div class="preview text-center mb6"><img src="' . esc_url($placeholder) . '" alt="" /></div>';
+1 -1
View File
@@ -54,7 +54,7 @@ function aksrt_render_menu_icon(string $icon_class, bool $enabled = true): strin
} }
// Sprite/inline values must reach aksrt_icon_markup untouched — the legacy // Sprite/inline values must reach aksrt_icon_markup untouched — the legacy
// fa-prefix padding below would corrupt them (zibsvg-hot → fa fas fa-zibsvg-hot). // FA class padding below would corrupt them (zibsvg-hot → fa fas fa-zibsvg-hot).
if (str_starts_with($icon_class, 'zibsvg-')) { if (str_starts_with($icon_class, 'zibsvg-')) {
return aksrt_icon_markup($icon_class, 'icon mr3 menu-item-icon'); return aksrt_icon_markup($icon_class, 'icon mr3 menu-item-icon');
} }
@@ -78,10 +78,10 @@ $percentage = max(0, min(100, (int) ($progress['progress'] ?? 0)));
<div class="aksrt-level-card__growth-inner"> <div class="aksrt-level-card__growth-inner">
<div class="aksrt-level-card__growth-head"> <div class="aksrt-level-card__growth-head">
<div> <div>
<strong><i class="fa fas fa-line-chart" aria-hidden="true"></i><?php esc_html_e('成长体系', 'aksrt'); ?></strong> <strong><i class="fa fas fa-chart-line" aria-hidden="true"></i><?php esc_html_e('成长体系', 'aksrt'); ?></strong>
<a class="muted-2-color" data-aksrt-level-tab="tab_integral_my" href="#tab_integral_my"><?php printf(esc_html__('我的经验值:%d', 'aksrt'), $integral); ?></a> <a class="muted-2-color" data-aksrt-level-tab="tab_integral_my" href="#tab_integral_my"><?php printf(esc_html__('我的经验值:%d', 'aksrt'), $integral); ?></a>
</div> </div>
<a id="tab-integral-date-link" class="muted-2-color" data-aksrt-level-tab="tab_integral_date" href="#tab_integral_date"><?php echo $today_integral > 0 ? esc_html(sprintf(__('今日 +%d', 'aksrt'), $today_integral)) : esc_html__('查看详情', 'aksrt'); ?><i class="fa fa-angle-right ml6" aria-hidden="true"></i></a> <a id="tab-integral-date-link" class="muted-2-color" data-aksrt-level-tab="tab_integral_date" href="#tab_integral_date"><?php echo $today_integral > 0 ? esc_html(sprintf(__('今日 +%d', 'aksrt'), $today_integral)) : esc_html__('查看详情', 'aksrt'); ?><i class="fa fas fa-angle-right ml6" aria-hidden="true"></i></a>
</div> </div>
<div class="swiper-container swiper-scroll pillar-box aksrt-level-growth" scroll-nogroup="1"> <div class="swiper-container swiper-scroll pillar-box aksrt-level-growth" scroll-nogroup="1">
<div class="swiper-wrapper"> <div class="swiper-wrapper">
@@ -141,7 +141,7 @@ $percentage = max(0, min(100, (int) ($progress['progress'] ?? 0)));
</div> </div>
<div class="tab-pane fade" id="tab_integral_my" role="tabpanel" aria-labelledby="tab-integral-my" hidden> <div class="tab-pane fade" id="tab_integral_my" role="tabpanel" aria-labelledby="tab-integral-my" hidden>
<?php if ($today_integral > 0) : ?> <?php if ($today_integral > 0) : ?>
<div class="border-bottom padding-h10 aksrt-level-list-row"><div class="flex jsb ac"><div class="flex1 mr20"><div class="font-bold mb6"><?php printf(esc_html__('今日累计 +%d', 'aksrt'), $today_integral); ?></div><div class="muted-2-color em09"><?php echo $day_max > $today_integral ? esc_html(sprintf(__('每日最多获得 %d 经验', 'aksrt'), $day_max)) : esc_html__('今日累计已达到上限', 'aksrt'); ?></div></div><a class="muted-2-color shrink0" data-aksrt-level-tab="tab_integral_date" href="#tab_integral_date" role="tab" aria-controls="tab_integral_date"><?php esc_html_e('每日详情', 'aksrt'); ?><i class="fa fa-angle-right ml6" aria-hidden="true"></i></a></div></div> <div class="border-bottom padding-h10 aksrt-level-list-row"><div class="flex jsb ac"><div class="flex1 mr20"><div class="font-bold mb6"><?php printf(esc_html__('今日累计 +%d', 'aksrt'), $today_integral); ?></div><div class="muted-2-color em09"><?php echo $day_max > $today_integral ? esc_html(sprintf(__('每日最多获得 %d 经验', 'aksrt'), $day_max)) : esc_html__('今日累计已达到上限', 'aksrt'); ?></div></div><a class="muted-2-color shrink0" data-aksrt-level-tab="tab_integral_date" href="#tab_integral_date" role="tab" aria-controls="tab_integral_date"><?php esc_html_e('每日详情', 'aksrt'); ?><i class="fa fas fa-angle-right ml6" aria-hidden="true"></i></a></div></div>
<?php endif; ?> <?php endif; ?>
<?php if ($details) : ?> <?php if ($details) : ?>
<?php foreach ($details as $row) : <?php foreach ($details as $row) :
+1 -1
View File
@@ -102,7 +102,7 @@ class SchemaPayment {
['key' => 'vip_2_points_default', 'label' => '二级会员积分售价(积分)', 'type' => 'number', 'default' => 0, 'min' => 0], ['key' => 'vip_2_points_default', 'label' => '二级会员积分售价(积分)', 'type' => 'number', 'default' => 0, 'min' => 0],
['key' => 'pay_price_default', 'label' => '执行价', 'type' => 'input', 'sanitize_type' => 'money_decimal', 'default' => '0.01', 'suffix' => '元'], ['key' => 'pay_price_default', 'label' => '执行价', 'type' => 'input', 'sanitize_type' => 'money_decimal', 'default' => '0.01', 'suffix' => '元'],
['key' => 'pay_original_price_default', 'label' => '原价', 'type' => 'input', 'sanitize_type' => 'money_decimal', 'default' => '', 'suffix' => '元', 'help' => '显示在执行价格前面,并划掉'], ['key' => 'pay_original_price_default', 'label' => '原价', 'type' => 'input', 'sanitize_type' => 'money_decimal', 'default' => '', 'suffix' => '元', 'help' => '显示在执行价格前面,并划掉'],
['key' => 'pay_promotion_tag_default', 'label' => '促销标签', 'type' => 'textarea', 'sanitize_type' => 'html', 'default' => '<i class="fa fa-fw fa-bolt"></i> 限时特惠', 'rows' => 1], ['key' => 'pay_promotion_tag_default', 'label' => '促销标签', 'type' => 'textarea', 'sanitize_type' => 'html', 'default' => '<i class="fa fas fa-fw fa-bolt"></i> 限时特惠', 'rows' => 1],
['key' => 'vip_1_price_default', 'label' => '一级会员价格', 'type' => 'input', 'sanitize_type' => 'money_decimal', 'default' => '0', 'suffix' => '元', 'help' => '填0则为一级会员免费'], ['key' => 'vip_1_price_default', 'label' => '一级会员价格', 'type' => 'input', 'sanitize_type' => 'money_decimal', 'default' => '0', 'suffix' => '元', 'help' => '填0则为一级会员免费'],
['key' => 'vip_2_price_default', 'label' => '二级会员价格', 'type' => 'input', 'sanitize_type' => 'money_decimal', 'default' => '0', 'suffix' => '元', 'help' => '填0则为二级会员免费'], ['key' => 'vip_2_price_default', 'label' => '二级会员价格', 'type' => 'input', 'sanitize_type' => 'money_decimal', 'default' => '0', 'suffix' => '元', 'help' => '填0则为二级会员免费'],
['key' => 'pay_rebate_discount', 'label' => '推广折扣', 'type' => 'input', 'sanitize_type' => 'money_decimal', 'default' => '0', 'suffix' => '元', 'help' => '通过推广链接购买,额外优惠的金额;需开启推广返佣功能,且不能超过实际购买价'], ['key' => 'pay_rebate_discount', 'label' => '推广折扣', 'type' => 'input', 'sanitize_type' => 'money_decimal', 'default' => '0', 'suffix' => '元', 'help' => '通过推广链接购买,额外优惠的金额;需开启推广返佣功能,且不能超过实际购买价'],
+2 -2
View File
@@ -251,7 +251,7 @@ trait VipServiceModal {
. '<input type="hidden" name="order_type" value="4">' . '<input type="hidden" name="order_type" value="4">'
. '<input type="hidden" name="action" value="points_initiate_pay">' . '<input type="hidden" name="action" value="points_initiate_pay">'
. '<button type="submit" class="mt6 but jb-yellow btn-block radius padding-lg" data-aksrt-vip-points-submit>' . '<button type="submit" class="mt6 but jb-yellow btn-block radius padding-lg" data-aksrt-vip-points-submit>'
. '<i class="fa fa-check" aria-hidden="true"></i>' . esc_html__('立即兑换', 'aksrt') . '<i class="fa fas fa-check" aria-hidden="true"></i>' . esc_html__('立即兑换', 'aksrt')
. '</button></div>'; . '</button></div>';
} }
@@ -268,7 +268,7 @@ trait VipServiceModal {
. '<svg class="icon" aria-hidden="true"><use xlink:href="#icon-points"></use></svg> ' . '<svg class="icon" aria-hidden="true"><use xlink:href="#icon-points"></use></svg> '
. esc_html__('我的积分', 'aksrt') . '</span>' . esc_html__('我的积分', 'aksrt') . '</span>'
. '<span class="font-bold ml6 em14"><span class="c-green mr10">' . $user_points . '</span>' . '<span class="font-bold ml6 em14"><span class="c-green mr10">' . $user_points . '</span>'
. '<i class="fa fa-angle-right" aria-hidden="true"></i></span></a></div>'; . '<i class="fa fas fa-angle-right" aria-hidden="true"></i></span></a></div>';
$lists = '<div class="muted-2-color mb6 em09">' . esc_html__('请选择需兑换的会员', 'aksrt') . '</div>' $lists = '<div class="muted-2-color mb6 em09">' . esc_html__('请选择需兑换的会员', 'aksrt') . '</div>'
. '<div class="flex hh exchange-card-box">' . $cards . '</div>'; . '<div class="flex hh exchange-card-box">' . $cards . '</div>';
@@ -125,7 +125,7 @@ final class ContentRenderer {
if (is_wp_error($href)) { if (is_wp_error($href)) {
continue; continue;
} }
$icon = '<i class="fa fa-folder-open mr6" aria-hidden="true"></i>'; $icon = '<i class="fa fas fa-folder-open mr6" aria-hidden="true"></i>';
$card = [ $card = [
'type' => (string) ($instance['type'] ?? 'style-1'), 'type' => (string) ($instance['type'] ?? 'style-1'),
'class' => 'mb10', 'class' => 'mb10',
@@ -407,7 +407,7 @@ final class GeneralRenderer {
} }
$target = $link['target'] === '_blank' ? ' target="_blank" rel="noopener noreferrer"' : ''; $target = $link['target'] === '_blank' ? ' target="_blank" rel="noopener noreferrer"' : '';
$cta_html = $cta_text !== '' && $url !== '' $cta_html = $cta_text !== '' && $url !== ''
? '<a class="zci-cta inflex ac gap6 ' . esc_attr(sanitize_html_class($cta_color)) . '" href="' . $url . '"' . $target . '><span>' . esc_html($cta_text) . '</span><i class="fa fa-arrow-right zci-arrow" aria-hidden="true"></i></a>' ? '<a class="zci-cta inflex ac gap6 ' . esc_attr(sanitize_html_class($cta_color)) . '" href="' . $url . '"' . $target . '><span>' . esc_html($cta_text) . '</span><i class="fa fas fa-arrow-right zci-arrow" aria-hidden="true"></i></a>'
: ''; : '';
$inner = '<div class="zci-body flex xx flex1">' . $icon_html; $inner = '<div class="zci-body flex xx flex1">' . $icon_html;
@@ -28,6 +28,13 @@ const scripts = join([
'src/Core/ScriptsPart1b.php', 'src/Core/ScriptsPart1b.php',
'src/Core/ScriptsPart1c.php', 'src/Core/ScriptsPart1c.php',
]); ]);
// The Font Awesome handle is registered inside aksrt_enqueue_fontawesome(), so the
// 5.15.4 asset contract has to follow that indirection rather than the enqueue call site.
const iconRuntime = join([
'src/Core/ScriptsPart1b.php',
'src/Core/ScriptsPart1c.php',
'inc/helpers/aksrt-icons.php',
]);
const header = join([ const header = join([
'header.php', 'header.php',
'inc/helpers/header/aksrt-header-render.php', 'inc/helpers/header/aksrt-header-render.php',
@@ -42,7 +49,8 @@ test('the public dependency graph uses WordPress jQuery with the local runtime s
assert.doesNotMatch(scripts, /wp_deregister_script\('jquery'\)/); assert.doesNotMatch(scripts, /wp_deregister_script\('jquery'\)/);
assert.doesNotMatch(scripts, /jquery\.min\.js'[\s\S]*?'1\.9\.1'/); assert.doesNotMatch(scripts, /jquery\.min\.js'[\s\S]*?'1\.9\.1'/);
assert.match(scripts, /bootstrap\.min\.css'[\s\S]*?'3\.4\.1'/); assert.match(scripts, /bootstrap\.min\.css'[\s\S]*?'3\.4\.1'/);
assert.match(scripts, /fontawesome5'[\s\S]*?all\.min\.css'[\s\S]*?'5\.15\.4'/); assert.match(scripts, /aksrt_enqueue_fontawesome\(/);
assert.match(iconRuntime, /fontawesome5\/css\/all\.min\.css'[\s\S]*?'5\.15\.4'/);
assert.match(scripts, /main\.min\.css/); assert.match(scripts, /main\.min\.css/);
assert.match(scripts, /loader\.js'[\s\S]*?\['jquery', 'bootstrap'\]/); assert.match(scripts, /loader\.js'[\s\S]*?\['jquery', 'bootstrap'\]/);
assert.match(read('assets/js/runtime/loader.js'), /tbquire\(\['main'\]\)/); assert.match(read('assets/js/runtime/loader.js'), /tbquire\(\['main'\]\)/);
@@ -107,6 +115,9 @@ test('Font Awesome 5 is the only icon contract across every runtime path', () =>
'fa-chevron', 'fa-icon', 'fa-icon-picker', 'fa-icons', 'fa-input', 'fa-chevron', 'fa-icon', 'fa-icon-picker', 'fa-icons', 'fa-input',
'fa-mask', 'fa-spin-hover', 'fa-toggle-theme', 'fa-xxx', 'fa-mask', 'fa-spin-hover', 'fa-toggle-theme', 'fa-xxx',
]); ]);
// The theme ships its own SVG sprite family, so fa-zibsvg-<key> is a project
// icon rather than a Font Awesome glyph — allow the prefix instead of every key.
const projectFamily = /^fa-zibsvg-/;
assert.doesNotMatch(runtime, /\bfa fa-/); assert.doesNotMatch(runtime, /\bfa fa-/);
assert.doesNotMatch(runtime, /FontAwesome|font-awesome\.min\.css|Font Awesome 4|4\.7\.0/); assert.doesNotMatch(runtime, /FontAwesome|font-awesome\.min\.css|Font Awesome 4|4\.7\.0/);
@@ -114,7 +125,7 @@ test('Font Awesome 5 is the only icon contract across every runtime path', () =>
assert.doesNotMatch(iconCss, /font:\s*normal\s+normal\s+normal\s+[^;]+Font Awesome 5 Free/); assert.doesNotMatch(iconCss, /font:\s*normal\s+normal\s+normal\s+[^;]+Font Awesome 5 Free/);
assert.equal(exists('assets/css/font-awesome.min.css'), false); assert.equal(exists('assets/css/font-awesome.min.css'), false);
for (const token of iconTokens) { for (const token of iconTokens) {
if (utility.test(token) || custom.has(token)) continue; if (utility.test(token) || custom.has(token) || projectFamily.test(token)) continue;
assert.ok(fa5.includes(`.${token}:before`), `${token} is not available in Font Awesome 5.15.4`); assert.ok(fa5.includes(`.${token}:before`), `${token} is not available in Font Awesome 5.15.4`);
} }
}); });
@@ -95,7 +95,9 @@ test('会员弹窗内的入口为参考主题同款按钮并开本地弹窗', ()
// 参考主题 zibpay_get_pay_uservip_modal 的 class 与图标顺序。 // 参考主题 zibpay_get_pay_uservip_modal 的 class 与图标顺序。
assert.match(vipJs, /node\("a", "btn-block but mb10 padding-lg c-green mini-radius"\)/); assert.match(vipJs, /node\("a", "btn-block but mb10 padding-lg c-green mini-radius"\)/);
assert.match(vipJs, /#icon-points-color/); assert.match(vipJs, /#icon-points-color/);
assert.match(vipJs, /fa fa-angle-right em12 ml10/); // 图标顺序与 class 串保持参考主题一致;FA5 样式类 `fas` 由图标契约(
// legacy-navigation-contract 的 FA5-only 约束)强制要求,故在此一并断言。
assert.match(vipJs, /fa fas fa-angle-right em12 ml10/);
assert.match(vipJs, /data-aksrt-vip-points-open/); assert.match(vipJs, /data-aksrt-vip-points-open/);
assert.match(vipJs, /openPointsModal\(pointsLink\)/); assert.match(vipJs, /openPointsModal\(pointsLink\)/);
}); });