fix(vip): let 积分兑换说明 support HTML like the reference theme
The points-exchange desc was stripped at all three layers: no sanitize_type on the schema fields (save ran sanitize_textarea_field), the runtime re-ran the same strip, and the points modal escaped it with esc_html. The reference theme declares sanitize=false and concatenates the value raw into the modal. - Schema (SPA + PHP): sanitize_type html, rows 2, help text noting HTML support - PaymentRuntime: output via wp_kses_post - VipServiceModal points modal: render via wp_kses_post instead of esc_html Verification: new contract test covers schema/runtime/modal layers; node --test tests/**/*.test.cjs 641/641 pass; php -l clean on both PHP files.
This commit is contained in:
1 parent
2e2558e5ce
commit
dcb80cff6e
5 files changed
+18
-4
No files matched your search
@@ -208,7 +208,7 @@ export const vipSchema = {
|
||||
dependsOn: { key: 'pay_vip_points_exchange_s', value: true },
|
||||
help: '每行:等级|积分|天数|标题(天数 0=永久;仅未开通会员可兑)',
|
||||
},
|
||||
{ key: 'pay_vip_points_exchange_desc', label: '兑换说明', type: 'textarea', default: '', dependsOn: { key: 'pay_vip_points_exchange_s', value: true } },
|
||||
{ key: 'pay_vip_points_exchange_desc', label: '兑换说明', type: 'textarea', sanitize_type: 'html', default: '', rows: 2, dependsOn: { key: 'pay_vip_points_exchange_s', value: true }, help: '显示在积分兑换弹窗底部,可以为提醒事项、兑换协议等,支持HTML代码' },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -243,7 +243,7 @@ class SchemaPayment {
|
||||
['key' => 'points-exchange', 'title' => '积分兑换会员', 'fields' => [
|
||||
['key' => 'pay_vip_points_exchange_s', 'label' => '启用积分兑换', 'type' => 'switch', 'default' => false],
|
||||
['key' => 'payment_vip_points_packages', 'label' => '兑换套餐', 'type' => 'textarea', 'default' => "1|500|30|积分月卡\n1|5000|0|积分永久", 'dependsOn' => ['key' => 'pay_vip_points_exchange_s', 'value' => true], 'help' => '每行:等级|积分|天数|标题(天数 0=永久;普通用户可开通,已有会员可续费同等级或升级更高等级)'],
|
||||
['key' => 'pay_vip_points_exchange_desc', 'label' => '兑换说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'pay_vip_points_exchange_s', 'value' => true]],
|
||||
['key' => 'pay_vip_points_exchange_desc', 'label' => '兑换说明', 'type' => 'textarea', 'sanitize_type' => 'html', 'default' => '', 'rows' => 2, 'dependsOn' => ['key' => 'pay_vip_points_exchange_s', 'value' => true]],
|
||||
]],
|
||||
['key' => 'modal-copy', 'title' => '界面文案', 'fields' => [
|
||||
['key' => 'pay_user_vip_desc', 'label' => '会员介绍', 'type' => 'input', 'default' => '开通VIP会员,享受会员专属折扣以及多项特权', 'dependsOn' => ['any' => [['key' => 'pay_user_vip_1_s', 'value' => true], ['key' => 'pay_user_vip_2_s', 'value' => true]]]],
|
||||
|
||||
@@ -238,7 +238,9 @@ trait VipServiceModal {
|
||||
|
||||
$desc_text = trim((string) ($points_ex['desc'] ?? ''));
|
||||
$desc = $desc_text !== ''
|
||||
? '<div class="muted-box muted-2-color padding-10 em09 mt20">' . esc_html($desc_text) . '</div>'
|
||||
// 管理员编辑的富文本说明:保存端已 wp_kses_post,这里同级别输出
|
||||
// (参考主题 zibpay_get_vip_points_exchange_modal 原样拼接)。
|
||||
? '<div class="muted-box muted-2-color padding-10 em09 mt20">' . wp_kses_post($desc_text) . '</div>'
|
||||
: '';
|
||||
|
||||
// 最低价套餐仍超出用户积分 → 参考主题的 badg c-red btn-block 提示。
|
||||
|
||||
@@ -261,7 +261,7 @@ class PaymentRuntime {
|
||||
],
|
||||
'points_exchange' => [
|
||||
'enabled' => !empty($settings['pay_vip_points_exchange_s']),
|
||||
'desc' => sanitize_textarea_field((string) ($settings['pay_vip_points_exchange_desc'] ?? '')),
|
||||
'desc' => wp_kses_post((string) ($settings['pay_vip_points_exchange_desc'] ?? '')),
|
||||
'packages_raw' => sanitize_textarea_field((string) ($settings['payment_vip_points_packages'] ?? "1|500|30|积分月卡\n1|5000|0|积分永久")),
|
||||
],
|
||||
];
|
||||
|
||||
@@ -172,3 +172,15 @@ test('弹窗内 more 与卡密说明按 HTML 渲染而非纯文本', () => {
|
||||
assert.ok(payVipJs.includes('htmlNode("div", "muted-2-color mb10 em09 muted-box padding-10 mini-radius", catalog.more)'));
|
||||
assert.ok(payVipJs.includes('htmlNode("div", "muted-box muted-2-color padding-10 mb10 em09", cardPass.desc)'));
|
||||
});
|
||||
|
||||
test('积分兑换说明按 post 级 HTML 放行并原样渲染', () => {
|
||||
// 参考主题该字段 sanitize=false 且弹窗内原样拼接;AKSRT 对齐为保存/输出
|
||||
// 双端 wp_kses_post + 弹窗 wp_kses_post 渲染。
|
||||
assert.match(vipSchemaJs, /key: 'pay_vip_points_exchange_desc', label: '兑换说明', type: 'textarea', sanitize_type: 'html'/);
|
||||
assert.match(schemaPhp, /'key' => 'pay_vip_points_exchange_desc', 'label' => '兑换说明', 'type' => 'textarea', 'sanitize_type' => 'html'/);
|
||||
const vipSettings = slice(paymentRuntime, 'public static function get_payment_vip_settings', 'public static function get_payment_revenue_settings');
|
||||
assert.match(vipSettings, /'desc'\s+=> wp_kses_post\(\(string\) \(\$settings\['pay_vip_points_exchange_desc'\]/);
|
||||
// 弹窗渲染端不再 esc_html 剥标签。
|
||||
assert.match(modalSource, /<div class="muted-box muted-2-color padding-10 em09 mt20">' \. wp_kses_post\(\$desc_text\)/);
|
||||
assert.doesNotMatch(modalSource, /esc_html\(\$desc_text\)/);
|
||||
});
|
||||
Reference in new issue
Block a user