diff --git a/assets/admin/src/schema/sections/payment/recharge.js b/assets/admin/src/schema/sections/payment/recharge.js
index 3925803e..6bb0f2ec 100644
--- a/assets/admin/src/schema/sections/payment/recharge.js
+++ b/assets/admin/src/schema/sections/payment/recharge.js
@@ -111,7 +111,7 @@ export const rechargeSchema = {
{ key: 'points_pass_exchange_desc', label: '卡密兑换积分说明', type: 'textarea', default: '', rows: 2, dependsOn: { key: 'points_pass_exchange_s', value: true }, help: '用户使用卡密兑换积分时显示的内容,建议为提醒事项、兑换协议等,支持HTML代码' },
{ key: 'points_pass_exchange_only_password', label: '积分卡密单密码模式', type: 'switch', default: false, dependsOn: { key: 'points_pass_exchange_s', value: true }, help: '积分卡密仅需输入密码,不需要卡号' },
{ key: 'pay_vip_pass_charge_s', label: '启用卡密兑换会员功能', type: 'switch', default: false, help: '开启后用户可在会员购买/续费弹窗选择「卡密」渠道,使用会员卡密直接兑换会员' },
- { key: 'pay_vip_pass_charge_desc', label: '卡密兑换会员说明', type: 'textarea', default: '', rows: 2, dependsOn: { key: 'pay_vip_pass_charge_s', value: true }, help: '用户使用卡密兑换会员时显示的内容,建议为提醒事项、兑换协议等,支持HTML代码' },
+ { key: 'pay_vip_pass_charge_desc', label: '卡密兑换会员说明', type: 'textarea', sanitize_type: 'html', default: '', rows: 2, dependsOn: { key: 'pay_vip_pass_charge_s', value: true }, help: '用户使用卡密兑换会员时显示的内容,建议为提醒事项、兑换协议等,支持HTML代码' },
{ key: 'pay_vip_pass_charge_only_password', label: '会员卡密单密码模式', type: 'switch', default: false, dependsOn: { key: 'pay_vip_pass_charge_s', value: true }, help: '会员卡密仅需输入密码,不需要卡号;默认关闭,会员卡需输入卡号和密码(与其他卡密兑换一致)' },
],
},
diff --git a/assets/admin/src/schema/sections/payment/vip.js b/assets/admin/src/schema/sections/payment/vip.js
index 2fc076cd..f1b97026 100644
--- a/assets/admin/src/schema/sections/payment/vip.js
+++ b/assets/admin/src/schema/sections/payment/vip.js
@@ -11,17 +11,17 @@ export const vipSchema = {
nav_pay_vip: true,
nav_user_pay_vip: true,
pay_user_vip_1_s: true,
- pay_user_vip_1_name: '一级会员',
- pay_user_vip_1_desc: '尊享一级会员特权',
- pay_user_vip_1_equity: '
免费下载部分资源会员专属身份标识付费内容会员价',
+ pay_user_vip_1_name: '黄金会员',
+ pay_user_vip_1_desc: '尊享专属特权',
+ pay_user_vip_1_equity: '全站资源折扣购买部分内容免费阅读一对一技术指导VIP用户专属QQ群',
vip_1_img_icon: '',
pay_user_vip_2_s: true,
- pay_user_vip_2_name: '二级会员',
- pay_user_vip_2_desc: '尊享二级会员特权',
- pay_user_vip_2_equity: '更高免费下载额度更高等级身份标识更多付费内容会员价',
+ pay_user_vip_2_name: '钻石会员',
+ pay_user_vip_2_desc: '尊享专属特权',
+ pay_user_vip_2_equity: '全站资源折扣购买部分内容免费阅读一对一技术指导VIP用户专属QQ群',
vip_2_img_icon: '',
- pay_user_vip_desc: '',
- pay_user_vip_more: '',
+ pay_user_vip_desc: '开通VIP会员,享受会员专属折扣以及多项特权',
+ pay_user_vip_more: '购买后不支持退款
VIP权益仅适用于本站
欢迎与站长联系
',
pay_download_limit: 0,
pay_download_speed: 0,
pay_download_limit_vip_1: 0,
@@ -33,12 +33,10 @@ export const vipSchema = {
vip_2_product_s: true,
payment_vip_2_products: '58|99|1|month|限时|月卡\n168|299|3|month|特惠|季卡\n598|999|12|month|超值|年卡\n1299|1999|0|day|永久|永久卡',
vip_renew: true,
- vip_renew_desc: '',
vip_renew_price_type: 'discount',
vip_renew_discount: 8,
vip_renew_reduce: '20.00',
vip_upgrade: true,
- vip_upgrade_desc: '',
vip_upgrade_product: 'unit|1|按剩余天数升级\njump|199|升级永久二级会员\npermanent|299|永久一级升永久二级',
pay_vip_points_exchange_s: false,
payment_vip_points_packages: '1|500|30|积分月卡\n1|5000|0|积分永久',
@@ -67,17 +65,15 @@ export const vipSchema = {
{ key: 'nav_pay_vip', label: '导航栏购买按钮', type: 'switch', default: true, help: '在顶部导航栏显示开通会员按钮;请注意顶部导航的整体宽度。' },
{ key: 'nav_user_pay_vip', label: '用户框购买按钮', type: 'switch', default: true, help: '在导航栏用户框内显示开通会员按钮。' },
{ key: 'pay_user_vip_1_s', label: '启用一级会员', type: 'switch', default: true },
- { key: 'pay_user_vip_1_name', label: '一级会员显示名称', type: 'input', default: '一级会员', dependsOn: { key: 'pay_user_vip_1_s', value: true } },
- { key: 'pay_user_vip_1_desc', label: '一级会员一句话简介', type: 'input', default: '尊享一级会员特权', dependsOn: { key: 'pay_user_vip_1_s', value: true } },
- { key: 'pay_user_vip_1_equity', label: '一级会员权益 HTML', type: 'textarea', default: '免费下载部分资源会员专属身份标识付费内容会员价', dependsOn: { key: 'pay_user_vip_1_s', value: true }, help: '建议使用 列表项' },
+ { key: 'pay_user_vip_1_name', label: '一级会员显示名称', type: 'input', default: '黄金会员', dependsOn: { key: 'pay_user_vip_1_s', value: true } },
+ { key: 'pay_user_vip_1_desc', label: '一级会员一句话简介', type: 'input', default: '尊享专属特权', dependsOn: { key: 'pay_user_vip_1_s', value: true } },
+ { key: 'pay_user_vip_1_equity', label: '一级会员权益 HTML', type: 'textarea', sanitize_type: 'html', default: '全站资源折扣购买部分内容免费阅读一对一技术指导VIP用户专属QQ群', rows: 4, dependsOn: { key: 'pay_user_vip_1_s', value: true }, help: '建议使用 列表项' },
{ key: 'vip_1_img_icon', label: '一级会员图标 URL', type: 'input', default: '', dependsOn: { key: 'pay_user_vip_1_s', value: true }, help: '留空使用内置 vip-1.svg 图标' },
{ key: 'pay_user_vip_2_s', label: '启用二级会员', type: 'switch', default: true },
- { key: 'pay_user_vip_2_name', label: '二级会员显示名称', type: 'input', default: '二级会员', dependsOn: { key: 'pay_user_vip_2_s', value: true } },
- { key: 'pay_user_vip_2_desc', label: '二级会员一句话简介', type: 'input', default: '尊享二级会员特权', dependsOn: { key: 'pay_user_vip_2_s', value: true } },
- { key: 'pay_user_vip_2_equity', label: '二级会员权益 HTML', type: 'textarea', default: '更高免费下载额度更高等级身份标识更多付费内容会员价', dependsOn: { key: 'pay_user_vip_2_s', value: true } },
+ { key: 'pay_user_vip_2_name', label: '二级会员显示名称', type: 'input', default: '钻石会员', dependsOn: { key: 'pay_user_vip_2_s', value: true } },
+ { key: 'pay_user_vip_2_desc', label: '二级会员一句话简介', type: 'input', default: '尊享专属特权', dependsOn: { key: 'pay_user_vip_2_s', value: true } },
+ { key: 'pay_user_vip_2_equity', label: '二级会员权益 HTML', type: 'textarea', sanitize_type: 'html', default: '全站资源折扣购买部分内容免费阅读一对一技术指导VIP用户专属QQ群', rows: 4, dependsOn: { key: 'pay_user_vip_2_s', value: true } },
{ key: 'vip_2_img_icon', label: '二级会员图标 URL', type: 'input', default: '', dependsOn: { key: 'pay_user_vip_2_s', value: true }, help: '留空使用内置 vip-2.svg 图标' },
- { key: 'pay_user_vip_desc', label: '弹窗顶部会员说明', type: 'textarea', default: '' },
- { key: 'pay_user_vip_more', label: '弹窗底部补充说明 HTML', type: 'textarea', default: '' },
],
},
{
@@ -163,7 +159,6 @@ export const vipSchema = {
title: '会员续费',
fields: [
{ key: 'vip_renew', label: '允许续费', type: 'switch', default: true, help: '关闭后则不能续费,只能会员到期之后再购买。永久会员不需要续费' },
- { key: 'vip_renew_desc', label: '续费说明', type: 'textarea', default: '', dependsOn: { key: 'vip_renew', value: true } },
{
key: 'vip_renew_price_type',
label: '续费价格类型',
@@ -185,7 +180,6 @@ export const vipSchema = {
title: '会员升级',
fields: [
{ key: 'vip_upgrade', label: '允许升级', type: 'switch', default: true },
- { key: 'vip_upgrade_desc', label: '升级说明', type: 'textarea', default: '', dependsOn: { key: 'vip_upgrade', value: true } },
{
key: 'vip_upgrade_product',
label: '升级产品',
@@ -217,5 +211,30 @@ export const vipSchema = {
{ key: 'pay_vip_points_exchange_desc', label: '兑换说明', type: 'textarea', default: '', dependsOn: { key: 'pay_vip_points_exchange_s', value: true } },
],
},
+ {
+ key: 'modal-copy',
+ title: '界面文案',
+ icon: 'fa fas fa-align-left',
+ 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 }] },
+ help: '显示在开通界面顶部一句话简介,可以为会员权益简介或者活动介绍',
+ },
+ {
+ key: 'pay_user_vip_more',
+ label: '开通会员更多内容',
+ type: 'textarea',
+ sanitize_type: 'html',
+ default: '购买后不支持退款
VIP权益仅适用于本站
欢迎与站长联系
',
+ rows: 4,
+ dependsOn: { any: [{ key: 'pay_user_vip_1_s', value: true }, { key: 'pay_user_vip_2_s', value: true }] },
+ help: '显示在开通界面底部位置,可以为提醒事项、用户协议等,支持HTML代码',
+ },
+ ],
+ },
],
}
diff --git a/src/Admin/Schema/SchemaPayment.php b/src/Admin/Schema/SchemaPayment.php
index 73762713..e12d665a 100644
--- a/src/Admin/Schema/SchemaPayment.php
+++ b/src/Admin/Schema/SchemaPayment.php
@@ -159,7 +159,7 @@ class SchemaPayment {
['key' => 'points_pass_exchange_desc', 'label' => '卡密兑换积分说明', 'type' => 'textarea', 'default' => '', 'rows' => 2, 'dependsOn' => ['key' => 'points_pass_exchange_s', 'value' => true], 'help' => '用户使用卡密兑换积分时显示的内容,建议为提醒事项、兑换协议等,支持HTML代码'],
['key' => 'points_pass_exchange_only_password', 'label' => '积分卡密单密码模式', 'type' => 'switch', 'default' => false, 'dependsOn' => ['key' => 'points_pass_exchange_s', 'value' => true], 'help' => '积分卡密仅需输入密码,不需要卡号'],
['key' => 'pay_vip_pass_charge_s', 'label' => '启用卡密兑换会员功能', 'type' => 'switch', 'default' => false, 'help' => '开启后用户可在会员购买/续费弹窗选择「卡密」渠道,使用会员卡密直接兑换会员'],
- ['key' => 'pay_vip_pass_charge_desc', 'label' => '卡密兑换会员说明', 'type' => 'textarea', 'default' => '', 'rows' => 2, 'dependsOn' => ['key' => 'pay_vip_pass_charge_s', 'value' => true], 'help' => '用户使用卡密兑换会员时显示的内容,建议为提醒事项、兑换协议等,支持HTML代码'],
+ ['key' => 'pay_vip_pass_charge_desc', 'label' => '卡密兑换会员说明', 'type' => 'textarea', 'sanitize_type' => 'html', 'default' => '', 'rows' => 2, 'dependsOn' => ['key' => 'pay_vip_pass_charge_s', 'value' => true], 'help' => '用户使用卡密兑换会员时显示的内容,建议为提醒事项、兑换协议等,支持HTML代码'],
['key' => 'pay_vip_pass_charge_only_password', 'label' => '会员卡密单密码模式', 'type' => 'switch', 'default' => false, 'dependsOn' => ['key' => 'pay_vip_pass_charge_s', 'value' => true], 'help' => '会员卡密仅需输入密码,不需要卡号;默认关闭,会员卡需输入卡号和密码(与其他卡密兑换一致)'],
]],
['key' => 'points-exchange', 'title' => '余额兑换积分', 'fields' => [
@@ -188,17 +188,15 @@ class SchemaPayment {
['key' => 'nav_pay_vip', 'label' => '导航栏购买按钮', 'type' => 'switch', 'default' => true, 'help' => '在顶部导航栏显示开通会员按钮;请注意顶部导航的整体宽度。'],
['key' => 'nav_user_pay_vip', 'label' => '用户框购买按钮', 'type' => 'switch', 'default' => true, 'help' => '在导航栏用户框内显示开通会员按钮。'],
['key' => 'pay_user_vip_1_s', 'label' => '启用一级会员', 'type' => 'switch', 'default' => true],
- ['key' => 'pay_user_vip_1_name', 'label' => '一级会员显示名称', 'type' => 'input', 'default' => '一级会员', 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
- ['key' => 'pay_user_vip_1_desc', 'label' => '一级会员一句话简介', 'type' => 'input', 'default' => '尊享一级会员特权', 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
- ['key' => 'pay_user_vip_1_equity', 'label' => '一级会员权益 HTML', 'type' => 'textarea', 'default' => '免费下载部分资源会员专属身份标识付费内容会员价', 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
+ ['key' => 'pay_user_vip_1_name', 'label' => '一级会员显示名称', 'type' => 'input', 'default' => '黄金会员', 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
+ ['key' => 'pay_user_vip_1_desc', 'label' => '一级会员一句话简介', 'type' => 'input', 'default' => '尊享专属特权', 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
+ ['key' => 'pay_user_vip_1_equity', 'label' => '一级会员权益 HTML', 'type' => 'textarea', 'sanitize_type' => 'html', 'default' => '全站资源折扣购买部分内容免费阅读一对一技术指导VIP用户专属QQ群', 'rows' => 4, 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
['key' => 'vip_1_img_icon', 'label' => '一级会员图标 URL', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true], 'help' => '留空使用内置 vip-1.svg 图标'],
['key' => 'pay_user_vip_2_s', 'label' => '启用二级会员', 'type' => 'switch', 'default' => true],
- ['key' => 'pay_user_vip_2_name', 'label' => '二级会员显示名称', 'type' => 'input', 'default' => '二级会员', 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true]],
- ['key' => 'pay_user_vip_2_desc', 'label' => '二级会员一句话简介', 'type' => 'input', 'default' => '尊享二级会员特权', 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true]],
- ['key' => 'pay_user_vip_2_equity', 'label' => '二级会员权益 HTML', 'type' => 'textarea', 'default' => '更高免费下载额度更高等级身份标识更多付费内容会员价', 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true]],
+ ['key' => 'pay_user_vip_2_name', 'label' => '二级会员显示名称', 'type' => 'input', 'default' => '钻石会员', 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true]],
+ ['key' => 'pay_user_vip_2_desc', 'label' => '二级会员一句话简介', 'type' => 'input', 'default' => '尊享专属特权', 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true]],
+ ['key' => 'pay_user_vip_2_equity', 'label' => '二级会员权益 HTML', 'type' => 'textarea', 'sanitize_type' => 'html', 'default' => '全站资源折扣购买部分内容免费阅读一对一技术指导VIP用户专属QQ群', 'rows' => 4, 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true]],
['key' => 'vip_2_img_icon', 'label' => '二级会员图标 URL', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true], 'help' => '留空使用内置 vip-2.svg 图标'],
- ['key' => 'pay_user_vip_desc', 'label' => '弹窗顶部会员说明', 'type' => 'textarea', 'default' => ''],
- ['key' => 'pay_user_vip_more', 'label' => '弹窗底部补充说明 HTML', 'type' => 'textarea', 'default' => ''],
]],
['key' => 'benefit', 'title' => '会员权益', 'fields' => [
['key' => 'vip_benefit', 'label' => '会员权益', 'type' => 'tabbed', 'tabs' => [
@@ -228,7 +226,6 @@ class SchemaPayment {
]],
['key' => 'renew', 'title' => '会员续费', 'fields' => [
['key' => 'vip_renew', 'label' => '允许续费', 'type' => 'switch', 'default' => true, 'help' => '关闭后则不能续费,只能会员到期之后再购买。永久会员不需要续费'],
- ['key' => 'vip_renew_desc', 'label' => '续费说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'vip_renew', 'value' => true]],
['key' => 'vip_renew_price_type', 'label' => '续费价格类型', 'type' => 'radio', 'default' => 'discount', 'dependsOn' => ['key' => 'vip_renew', 'value' => true], 'options' => [
['label' => '相同价格', 'value' => 'same'],
['label' => '折扣价格', 'value' => 'discount'],
@@ -239,7 +236,6 @@ class SchemaPayment {
]],
['key' => 'upgrade', 'title' => '会员升级', 'fields' => [
['key' => 'vip_upgrade', 'label' => '允许升级', 'type' => 'switch', 'default' => true],
- ['key' => 'vip_upgrade_desc', 'label' => '升级说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'vip_upgrade', 'value' => true]],
['key' => 'vip_upgrade_product', 'label' => '升级产品', 'type' => 'textarea', 'default' => "unit|1|按剩余天数升级\njump|199|升级永久二级会员\npermanent|299|永久一级升永久二级", 'dependsOn' => ['key' => 'vip_upgrade', 'value' => true], 'help' => '每行一条。永久VIP1:permanent|价格|标题;剩余天:unit|每日单价|标题;跳转永久:jump|价格|标题'],
]],
]],
@@ -249,6 +245,10 @@ class SchemaPayment {
['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' => '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]]]],
+ ['key' => 'pay_user_vip_more', 'label' => '开通会员更多内容', 'type' => 'textarea', 'sanitize_type' => 'html', 'default' => '购买后不支持退款
VIP权益仅适用于本站
欢迎与站长联系
', 'rows' => 4, 'dependsOn' => ['any' => [['key' => 'pay_user_vip_1_s', 'value' => true], ['key' => 'pay_user_vip_2_s', 'value' => true]]]],
+ ]],
],
],
diff --git a/src/Settings/PaymentRuntime.php b/src/Settings/PaymentRuntime.php
index aa955a89..c5e4d7be 100644
--- a/src/Settings/PaymentRuntime.php
+++ b/src/Settings/PaymentRuntime.php
@@ -171,10 +171,10 @@ class PaymentRuntime {
$name1 = trim((string) ($settings['pay_user_vip_1_name'] ?? ''));
$name2 = trim((string) ($settings['pay_user_vip_2_name'] ?? ''));
if ($name1 === '') {
- $name1 = __('一级会员', 'aksrt');
+ $name1 = __('黄金会员', 'aksrt');
}
if ($name2 === '') {
- $name2 = __('二级会员', 'aksrt');
+ $name2 = __('钻石会员', 'aksrt');
}
$badge = $vip2_enabled ? $name2 : ($vip1_enabled ? $name1 : __('VIP', 'aksrt'));
@@ -196,8 +196,8 @@ class PaymentRuntime {
$products_2 = $default_l2;
}
- $desc = sanitize_textarea_field((string) ($settings['pay_user_vip_desc'] ?? ''));
- $more = (string) ($settings['pay_user_vip_more'] ?? '');
+ $desc = sanitize_text_field((string) ($settings['pay_user_vip_desc'] ?? __('开通VIP会员,享受会员专属折扣以及多项特权', 'aksrt')));
+ $more = (string) ($settings['pay_user_vip_more'] ?? '购买后不支持退款
VIP权益仅适用于本站
欢迎与站长联系
');
$allowed_equity = [
'li' => [],
'ul' => [],
@@ -223,8 +223,8 @@ class PaymentRuntime {
1 => [
'enabled' => $vip1_enabled,
'name' => $name1,
- 'desc' => sanitize_text_field((string) ($settings['pay_user_vip_1_desc'] ?? __('尊享一级会员特权', 'aksrt'))),
- 'equity' => wp_kses((string) (($settings['pay_user_vip_1_equity'] ?? '') !== '' ? $settings['pay_user_vip_1_equity'] : '免费下载部分资源会员专属身份标识付费内容会员价'), $allowed_equity),
+ 'desc' => sanitize_text_field((string) ($settings['pay_user_vip_1_desc'] ?? __('尊享专属特权', 'aksrt'))),
+ 'equity' => wp_kses((string) (($settings['pay_user_vip_1_equity'] ?? '') !== '' ? $settings['pay_user_vip_1_equity'] : '全站资源折扣购买部分内容免费阅读一对一技术指导VIP用户专属QQ群'), $allowed_equity),
'img_icon' => self::get_vip_icon_url(1, (string) ($settings['vip_1_img_icon'] ?? '')),
'product_s' => !isset($settings['vip_1_product_s']) || !empty($settings['vip_1_product_s']),
'products_raw' => $products_1,
@@ -233,8 +233,8 @@ class PaymentRuntime {
2 => [
'enabled' => $vip2_enabled,
'name' => $name2,
- 'desc' => sanitize_text_field((string) ($settings['pay_user_vip_2_desc'] ?? __('尊享二级会员特权', 'aksrt'))),
- 'equity' => wp_kses((string) (($settings['pay_user_vip_2_equity'] ?? '') !== '' ? $settings['pay_user_vip_2_equity'] : '更高免费下载额度更高等级身份标识更多付费内容会员价'), $allowed_equity),
+ 'desc' => sanitize_text_field((string) ($settings['pay_user_vip_2_desc'] ?? __('尊享专属特权', 'aksrt'))),
+ 'equity' => wp_kses((string) (($settings['pay_user_vip_2_equity'] ?? '') !== '' ? $settings['pay_user_vip_2_equity'] : '全站资源折扣购买部分内容免费阅读一对一技术指导VIP用户专属QQ群'), $allowed_equity),
'img_icon' => self::get_vip_icon_url(2, (string) ($settings['vip_2_img_icon'] ?? '')),
'product_s' => !isset($settings['vip_2_product_s']) || !empty($settings['vip_2_product_s']),
'products_raw' => $products_2,
@@ -246,14 +246,12 @@ class PaymentRuntime {
],
'renew' => [
'enabled' => !isset($settings['vip_renew']) || !empty($settings['vip_renew']),
- 'desc' => sanitize_textarea_field((string) ($settings['vip_renew_desc'] ?? '')),
'price_type' => $renew_price_type,
'discount' => max(1, min(100, (int) ($settings['vip_renew_discount'] ?? 8))),
'reduce' => self::money_decimal($settings['vip_renew_reduce'] ?? '20.00', '20.00', 999900),
],
'upgrade' => [
'enabled' => !isset($settings['vip_upgrade']) || !empty($settings['vip_upgrade']),
- 'desc' => sanitize_textarea_field((string) ($settings['vip_upgrade_desc'] ?? '')),
// Multi-line upgrade product rules — must not collapse newlines.
'product' => sanitize_textarea_field((string) ($settings['vip_upgrade_product'] ?? '')),
],
diff --git a/tests/widget-system/vip-modal-copy-fields.test.cjs b/tests/widget-system/vip-modal-copy-fields.test.cjs
new file mode 100644
index 00000000..27a43827
--- /dev/null
+++ b/tests/widget-system/vip-modal-copy-fields.test.cjs
@@ -0,0 +1,145 @@
+/**
+ * VIP 后台设置弹窗文案字段契约(对照参考主题 zibll 修正)。
+ *
+ * 硬约束:
+ * 1) 弹窗文案字段更名为「会员介绍」(pay_user_vip_desc, input) 与
+ * 「开通会员更多内容」(pay_user_vip_more, textarea rows 4 +
+ * sanitize_type html),并从「会员等级」组移到分区末尾的
+ * 「界面文案」(modal-copy) 独立分组;
+ * 2) 文案默认值对齐 zibll(黄金会员/钻石会员、尊享专属特权、权益四项、
+ * 会员介绍与开通会员更多内容默认值),SPA schema / PHP schema /
+ * PaymentRuntime 回退三处一致——Settings::get_all() 不合并
+ * schema 默认值,运行时回退即实际默认值;
+ * 3) vip_renew_desc / vip_upgrade_desc 为死配置(AKSRT 无续费/升级
+ * 卡渲染面,全仓零消费方),两份 schema 与 PaymentRuntime 均已删除;
+ * 4) 权益与卡密说明字段保存时保留 HTML(sanitize_type html),
+ * 不再被 sanitize_textarea_field 剥掉标签。
+ */
+const test = require('node:test');
+const assert = require('node:assert');
+const fs = require('node:fs');
+const path = require('node:path');
+
+const root = path.join(__dirname, '..', '..');
+const read = (...seg) => fs.readFileSync(path.join(root, ...seg), 'utf8');
+
+const vipSchemaJs = read('assets', 'admin', 'src', 'schema', 'sections', 'payment', 'vip.js');
+const schemaPhp = read('src', 'Admin', 'Schema', 'SchemaPayment.php');
+const paymentRuntime = read('src', 'Settings', 'PaymentRuntime.php');
+const rechargeJs = read('assets', 'admin', 'src', 'schema', 'sections', 'payment', 'recharge.js');
+
+const DESC_DEFAULT = '开通VIP会员,享受会员专属折扣以及多项特权';
+const MORE_DEFAULT = '购买后不支持退款
VIP权益仅适用于本站
欢迎与站长联系
';
+const EQUITY_DEFAULT = '全站资源折扣购买部分内容免费阅读一对一技术指导VIP用户专属QQ群';
+
+// 取两个标记之间的源码段(分组切片,避免断言误伤其它功能的同名键)。
+function slice(source, from, to) {
+ const start = source.indexOf(from);
+ assert.notStrictEqual(start, -1, `missing ${from}`);
+ const end = source.indexOf(to, start + from.length);
+ return source.slice(start, end === -1 ? undefined : end);
+}
+
+test('弹窗文案字段更名为会员介绍/开通会员更多内容并改为正确类型', () => {
+ for (const [name, src] of [['vip.js', vipSchemaJs], ['SchemaPayment.php', schemaPhp]]) {
+ assert.ok(!src.includes('弹窗顶部会员说明') && !src.includes('弹窗底部补充说明 HTML'), `${name} 旧名称应已移除`);
+ assert.ok(src.includes('会员介绍') && src.includes('开通会员更多内容'), `${name} 应含新名称`);
+ }
+ // 会员介绍为单行 input(zibll text「一句话简介」);开通会员更多内容为 rows 4 的 HTML textarea。
+ assert.match(
+ vipSchemaJs,
+ /key: 'pay_user_vip_desc',\s*\n\s*label: '会员介绍',\s*\n\s*type: 'input',\s*\n\s*default: '开通VIP会员,享受会员专属折扣以及多项特权'/
+ );
+ assert.match(
+ vipSchemaJs,
+ /key: 'pay_user_vip_more',\s*\n\s*label: '开通会员更多内容',\s*\n\s*type: 'textarea',\s*\n\s*sanitize_type: 'html'[\s\S]*?rows: 4/
+ );
+ assert.match(
+ schemaPhp,
+ /'key' => 'pay_user_vip_desc', 'label' => '会员介绍', 'type' => 'input', 'default' => '开通VIP会员,享受会员专属折扣以及多项特权'/
+ );
+ assert.match(
+ schemaPhp,
+ /'key' => 'pay_user_vip_more', 'label' => '开通会员更多内容', 'type' => 'textarea', 'sanitize_type' => 'html'[\s\S]*?'rows' => 4/
+ );
+ // 帮助文本对齐 zibll 的 desc。
+ assert.ok(vipSchemaJs.includes('显示在开通界面顶部一句话简介,可以为会员权益简介或者活动介绍'));
+ assert.ok(vipSchemaJs.includes('显示在开通界面底部位置,可以为提醒事项、用户协议等,支持HTML代码'));
+});
+
+test('两个文案字段位于分区末尾的界面文案分组且不再属于会员等级组', () => {
+ const modalJs = vipSchemaJs.indexOf("key: 'modal-copy'");
+ const modalPhp = schemaPhp.indexOf("'key' => 'modal-copy'");
+ assert.notStrictEqual(modalJs, -1, 'vip.js 应含 modal-copy 分组');
+ assert.notStrictEqual(modalPhp, -1, 'SchemaPayment.php 应含 modal-copy 分组');
+ assert.ok(modalJs > vipSchemaJs.indexOf("key: 'points-exchange'"), 'vip.js modal-copy 应在分区末尾');
+ assert.ok(modalPhp > schemaPhp.indexOf("'key' => 'points-exchange'"), 'SchemaPayment.php modal-copy 应在分区末尾');
+ // modal-copy 之后不再出现其它分组/字段 key。
+ // modal-copy 之后(至分区末尾)不再出现其它分组/字段 key;dependsOn 引用的等级开关除外。
+ assert.doesNotMatch(vipSchemaJs.slice(modalJs), /key: '(?!modal-copy|pay_user_vip_desc|pay_user_vip_more|pay_user_vip_1_s|pay_user_vip_2_s)/);
+ const phpTail = slice(schemaPhp, "'key' => 'modal-copy'", "'revenue'");
+ assert.doesNotMatch(phpTail, /'key' => '(?!modal-copy|pay_user_vip_desc|pay_user_vip_more|pay_user_vip_1_s|pay_user_vip_2_s)/);
+ // 「会员等级」组不再包含这两个字段。
+ assert.doesNotMatch(slice(vipSchemaJs, "key: 'basic'", "key: 'benefit'"), /pay_user_vip_desc|pay_user_vip_more/);
+ assert.doesNotMatch(slice(schemaPhp, "'key' => 'basic'", "'key' => 'benefit'"), /pay_user_vip_desc|pay_user_vip_more/);
+ // 依赖:任一等级启用时显示(zibll pay_user_vip_1_s 依赖的双等级适配)。
+ assert.ok(
+ vipSchemaJs.includes("dependsOn: { any: [{ key: 'pay_user_vip_1_s', value: true }, { key: 'pay_user_vip_2_s', value: true }] }"),
+ 'vip.js 应为 any 双等级依赖'
+ );
+ assert.ok(
+ schemaPhp.includes("'dependsOn' => ['any' => [['key' => 'pay_user_vip_1_s', 'value' => true], ['key' => 'pay_user_vip_2_s', 'value' => true]]]"),
+ 'SchemaPayment.php 应为 any 双等级依赖'
+ );
+});
+
+test('续费/升级说明死配置已从两份 schema 与运行时删除', () => {
+ for (const [name, src] of [['vip.js', vipSchemaJs], ['SchemaPayment.php', schemaPhp], ['PaymentRuntime.php', paymentRuntime]]) {
+ assert.ok(!src.includes('vip_renew_desc'), `${name} 不应再含 vip_renew_desc`);
+ assert.ok(!src.includes('vip_upgrade_desc'), `${name} 不应再含 vip_upgrade_desc`);
+ }
+});
+
+test('文案默认值三处一致并对齐 zibll', () => {
+ // SPA defaults 块与字段级 default。
+ assert.ok(vipSchemaJs.includes("pay_user_vip_1_name: '黄金会员'"));
+ assert.ok(vipSchemaJs.includes("pay_user_vip_2_name: '钻石会员'"));
+ assert.ok(vipSchemaJs.includes("pay_user_vip_1_desc: '尊享专属特权'"));
+ assert.ok(vipSchemaJs.includes("pay_user_vip_2_desc: '尊享专属特权'"));
+ assert.ok(vipSchemaJs.includes(`pay_user_vip_desc: '${DESC_DEFAULT}'`));
+ assert.ok(vipSchemaJs.includes(`pay_user_vip_more: '${MORE_DEFAULT}'`));
+ assert.ok(vipSchemaJs.includes(`default: '${EQUITY_DEFAULT}'`));
+ // PHP schema 字段 default。
+ assert.ok(schemaPhp.includes("'default' => '黄金会员'"));
+ assert.ok(schemaPhp.includes("'default' => '钻石会员'"));
+ assert.ok(schemaPhp.includes(`'default' => '${DESC_DEFAULT}'`));
+ assert.ok(schemaPhp.includes(`'default' => '${MORE_DEFAULT}'`));
+ // PaymentRuntime 运行时回退(get_all 不合并 schema 默认值,回退即实际默认值)。
+ assert.ok(paymentRuntime.includes(`$desc = sanitize_text_field((string) ($settings['pay_user_vip_desc'] ?? __('${DESC_DEFAULT}', 'aksrt')))`));
+ assert.ok(paymentRuntime.includes(`$more = (string) ($settings['pay_user_vip_more'] ?? '${MORE_DEFAULT}')`));
+ assert.ok(paymentRuntime.includes("$name1 = __('黄金会员', 'aksrt');"));
+ assert.ok(paymentRuntime.includes("$name2 = __('钻石会员', 'aksrt');"));
+ assert.ok(paymentRuntime.includes("$settings['pay_user_vip_1_desc'] ?? __('尊享专属特权', 'aksrt')"));
+ assert.ok(paymentRuntime.includes("$settings['pay_user_vip_2_desc'] ?? __('尊享专属特权', 'aksrt')"));
+ assert.ok(paymentRuntime.includes(EQUITY_DEFAULT));
+ // 旧默认值不再出现在任何一处。
+ for (const [name, src] of [['vip.js', vipSchemaJs], ['SchemaPayment.php', schemaPhp], ['PaymentRuntime.php', paymentRuntime]]) {
+ assert.ok(!/尊享一级会员特权|尊享二级会员特权|免费下载部分资源|更高免费下载额度/.test(src), `${name} 旧默认值应已移除`);
+ }
+});
+
+test('权益与卡密说明字段保存时保留 HTML', () => {
+ assert.ok(vipSchemaJs.includes("key: 'pay_user_vip_1_equity', label: '一级会员权益 HTML', type: 'textarea', sanitize_type: 'html'"));
+ assert.ok(vipSchemaJs.includes("key: 'pay_user_vip_2_equity', label: '二级会员权益 HTML', type: 'textarea', sanitize_type: 'html'"));
+ assert.ok(schemaPhp.includes("'key' => 'pay_user_vip_1_equity', 'label' => '一级会员权益 HTML', 'type' => 'textarea', 'sanitize_type' => 'html'"));
+ assert.ok(schemaPhp.includes("'key' => 'pay_user_vip_2_equity', 'label' => '二级会员权益 HTML', 'type' => 'textarea', 'sanitize_type' => 'html'"));
+ assert.ok(rechargeJs.includes("key: 'pay_vip_pass_charge_desc', label: '卡密兑换会员说明', type: 'textarea', sanitize_type: 'html'"));
+ assert.ok(schemaPhp.includes("'key' => 'pay_vip_pass_charge_desc', 'label' => '卡密兑换会员说明', 'type' => 'textarea', 'sanitize_type' => 'html'"));
+});
+
+test('会员介绍运行时按单行文本净化', () => {
+ // 只收敛 VIP 设置函数:充值等其它设置的 $desc 与本文无关。
+ const vipSettings = slice(paymentRuntime, 'public static function get_payment_vip_settings', 'public static function get_payment_revenue_settings');
+ assert.ok(vipSettings.includes("$desc = sanitize_text_field((string) ($settings['pay_user_vip_desc']"));
+ assert.ok(!vipSettings.includes('$desc = sanitize_textarea_field'));
+});