From ec63b446e8f2541abfc57f001da3f978bb287b6e Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 31 Jul 2026 10:56:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=9B=BA=E5=AE=9A=E4=B8=AA=E4=BA=BA?= =?UTF-8?q?=E4=B8=8E=E4=BC=81=E4=B8=9A=E8=AE=A4=E8=AF=81=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/src/schema/sections/users/verify.js | 51 ++++---- assets/img/user/user-certification.svg | 1 + inc/helpers/aksrt-identity.php | 8 +- .../user-center-renderers/profile-auth.php | 6 +- src/AKSRT/Admin/Schema/SchemaUsers.php | 14 ++- src/AKSRT/Settings/UserRuntime.php | 32 +++-- src/AKSRT/User/AuthApply.php | 118 +++++++++--------- src/AKSRT/User/Home.php | 20 ++- 8 files changed, 139 insertions(+), 111 deletions(-) create mode 100644 assets/img/user/user-certification.svg diff --git a/assets/admin/src/schema/sections/users/verify.js b/assets/admin/src/schema/sections/users/verify.js index 7317aaa8..9f30c583 100644 --- a/assets/admin/src/schema/sections/users/verify.js +++ b/assets/admin/src/schema/sections/users/verify.js @@ -6,14 +6,19 @@ export const verifySchema = { defaults: { user_verify_enabled: true, user_verify_public_display: true, - user_verify_badge_text: '已认证', + user_verify_personal_badge_text: '个人认证', + user_verify_personal_fee: 0, + user_verify_personal_free_applications: 0, + user_verify_personal_require_real_name: false, + user_verify_enterprise_badge_text: '企业认证', + user_verify_enterprise_fee: 0, + user_verify_enterprise_free_applications: 0, + user_verify_enterprise_require_real_name: false, user_verify_allow_apply: true, user_verify_disable_desc: '由于系统正在维护,暂时无法申请身份认证\n详情请联系管理员', - user_verify_limit_level: 2, user_verify_desc: '认证用户会在昵称后显示认证徽章,同时享受多种优先待遇。申请请确保信息属实。', - user_verify_apply_option: 'real_name|实名认证\norganization|企业认证', }, groups: [ { @@ -30,28 +35,18 @@ export const verifySchema = { dependsOn: { key: 'user_verify_enabled', value: true }, }, { - key: 'user_verify_badge_text', - label: '认证徽标文案', - type: 'input', - default: '已认证', + key: 'user_verify_personal_badge_text', label: '个人认证徽标文案', type: 'input', default: '个人认证', + dependsOn: { key: 'user_verify_public_display', value: true }, + }, + { + key: 'user_verify_enterprise_badge_text', label: '企业认证徽标文案', type: 'input', default: '企业认证', dependsOn: { key: 'user_verify_public_display', value: true }, }, ], }, { - key: 'workflow', - title: '审核流程', - icon: 'fas fa-tasks', - fields: [ - { - key: 'user_verify_apply_option', - label: '申请类型选项', - type: 'textarea', - default: 'real_name|实名认证\norganization|企业认证', - help: '每行:slug|显示名称', - dependsOn: { key: 'user_verify_enabled', value: true }, - }, - ], + key: 'workflow', title: '认证方式', icon: 'fas fa-tasks', + fields: [{ type: 'alert', content: '认证方式固定为个人认证和企业认证,申请人不可自行新增或修改类型。' }], }, { key: 'apply', @@ -72,16 +67,12 @@ export const verifySchema = { default: '由于系统正在维护,暂时无法申请身份认证\n详情请联系管理员', dependsOn: { key: 'user_verify_allow_apply', value: false }, }, - { - key: 'user_verify_limit_level', - label: '申请要求等级', - type: 'number', - default: 2, - min: 0, - max: 99, - help: '0 表示不限制;依赖用户等级功能', - dependsOn: { key: 'user_verify_allow_apply', value: true }, - }, + { key: 'user_verify_personal_fee', label: '个人认证每次扣余额(元)', type: 'number', default: 0, min: 0, step: 0.01, dependsOn: { key: 'user_verify_allow_apply', value: true } }, + { key: 'user_verify_personal_free_applications', label: '个人认证赠送初始次数', type: 'number', default: 0, min: 0, max: 9999, help: '每位用户前 N 次个人认证申请免费,之后按单次费用扣余额。', dependsOn: { key: 'user_verify_allow_apply', value: true } }, + { key: 'user_verify_personal_require_real_name', label: '个人认证强制填写真实姓名', type: 'switch', default: false, dependsOn: { key: 'user_verify_allow_apply', value: true } }, + { key: 'user_verify_enterprise_fee', label: '企业认证每次扣余额(元)', type: 'number', default: 0, min: 0, step: 0.01, dependsOn: { key: 'user_verify_allow_apply', value: true } }, + { key: 'user_verify_enterprise_free_applications', label: '企业认证赠送初始次数', type: 'number', default: 0, min: 0, max: 9999, help: '每位用户前 N 次企业认证申请免费,之后按单次费用扣余额。', dependsOn: { key: 'user_verify_allow_apply', value: true } }, + { key: 'user_verify_enterprise_require_real_name', label: '企业认证强制填写真实姓名', type: 'switch', default: false, dependsOn: { key: 'user_verify_allow_apply', value: true } }, { key: 'user_verify_desc', label: '申请介绍', diff --git a/assets/img/user/user-certification.svg b/assets/img/user/user-certification.svg new file mode 100644 index 00000000..e9149534 --- /dev/null +++ b/assets/img/user/user-certification.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/inc/helpers/aksrt-identity.php b/inc/helpers/aksrt-identity.php index f9fc2a89..b2092e6a 100644 --- a/inc/helpers/aksrt-identity.php +++ b/inc/helpers/aksrt-identity.php @@ -163,7 +163,13 @@ if (!function_exists('aksrt_get_user_name')) { $icon_url = esc_url((string) ($signal['icon_url'] ?? '')); $title = (string) ($signal['title'] ?? $label); if ($type === 'verify' && !empty($args['auth']) && $auth_html === '') { - $auth_html = ' ' . esc_html($label) . ''; + + $auth_html = $icon_url !== '' + + ? '' . esc_attr($label) . '' + + : ' ' . esc_html($label) . ''; + } elseif ($type === 'level' && !empty($args['level']) && $level_html === '') { if ($icon_url !== '') { $level_html = '' . esc_attr($label) . ''; diff --git a/inc/helpers/user-center-renderers/profile-auth.php b/inc/helpers/user-center-renderers/profile-auth.php index eab75d0e..f69e0395 100644 --- a/inc/helpers/user-center-renderers/profile-auth.php +++ b/inc/helpers/user-center-renderers/profile-auth.php @@ -24,10 +24,7 @@ foreach ((array) ($settings['types'] ?? []) as $type) { $type_labels[(string) ($type['slug'] ?? '')] = (string) ($type['label'] ?? ''); } $apply_type = sanitize_key((string) ($apply['type'] ?? '')); -$limit = (int) ($settings['limit_level'] ?? 0); -$current_level = class_exists('\AKSRT\User\Level') ? (int) \AKSRT\User\Level::get_level($user_id) : 0; -$blocked_level = $limit > 0 && $current_level < $limit; -$can_apply = !empty($settings['enabled']) && !empty($settings['allow_apply']) && !$blocked_level && $status !== 'verified'; +$can_apply = !empty($settings['enabled']) && !empty($settings['allow_apply']) && $status !== 'verified'; ?>
+ diff --git a/src/AKSRT/Admin/Schema/SchemaUsers.php b/src/AKSRT/Admin/Schema/SchemaUsers.php index 686b3eee..4e5387ce 100644 --- a/src/AKSRT/Admin/Schema/SchemaUsers.php +++ b/src/AKSRT/Admin/Schema/SchemaUsers.php @@ -615,15 +615,21 @@ class SchemaUsers { ['key' => 'display', 'title' => '公开展示', 'fields' => [ ['key' => 'user_verify_enabled', 'label' => '启用身份认证', 'type' => 'switch', 'default' => true], ['key' => 'user_verify_public_display', 'label' => '公开页显示认证徽标', 'type' => 'switch', 'default' => true], - ['key' => 'user_verify_badge_text', 'label' => '认证徽标文案', 'type' => 'input', 'default' => '已认证'], + ['key' => 'user_verify_personal_badge_text', 'label' => '个人认证徽标文案', 'type' => 'input', 'default' => '个人认证'], + ['key' => 'user_verify_enterprise_badge_text', 'label' => '企业认证徽标文案', 'type' => 'input', 'default' => '企业认证'], ]], - ['key' => 'workflow', 'title' => '申请类型', 'fields' => [ - ['key' => 'user_verify_apply_option', 'label' => '申请类型选项', 'type' => 'textarea', 'default' => "real_name|实名认证\norganization|企业认证", 'desc' => '每行:slug|显示名称'], + ['key' => 'workflow', 'title' => '认证方式', 'fields' => [ + ['type' => 'alert', 'content' => '认证方式固定为个人认证和企业认证,申请人不可自行新增或修改类型。'], ]], ['key' => 'apply', 'title' => '申请设置', 'fields' => [ ['key' => 'user_verify_allow_apply', 'label' => '允许用户前台申请', 'type' => 'switch', 'default' => true], ['key' => 'user_verify_disable_desc', 'label' => '停用申请说明', 'type' => 'textarea', 'default' => "由于系统正在维护,暂时无法申请身份认证\n详情请联系管理员"], - ['key' => 'user_verify_limit_level', 'label' => '申请要求等级', 'type' => 'number', 'default' => 2, 'min' => 0, 'max' => 99, 'desc' => '0 表示不限制;依赖用户等级'], + ['key' => 'user_verify_personal_fee', 'label' => '个人认证每次扣余额(元)', 'type' => 'number', 'default' => 0, 'min' => 0, 'step' => 0.01], + ['key' => 'user_verify_personal_free_applications', 'label' => '个人认证赠送初始次数', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 9999, 'desc' => '每位用户前 N 次个人认证申请免费,之后按单次费用扣余额。'], + ['key' => 'user_verify_personal_require_real_name', 'label' => '个人认证强制填写真实姓名', 'type' => 'switch', 'default' => false], + ['key' => 'user_verify_enterprise_fee', 'label' => '企业认证每次扣余额(元)', 'type' => 'number', 'default' => 0, 'min' => 0, 'step' => 0.01], + ['key' => 'user_verify_enterprise_free_applications', 'label' => '企业认证赠送初始次数', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 9999, 'desc' => '每位用户前 N 次企业认证申请免费,之后按单次费用扣余额。'], + ['key' => 'user_verify_enterprise_require_real_name', 'label' => '企业认证强制填写真实姓名', 'type' => 'switch', 'default' => false], ['key' => 'user_verify_desc', 'label' => '申请介绍', 'type' => 'textarea', 'default' => '认证用户会在昵称后显示认证徽章,同时享受多种优先待遇。申请请确保信息属实。'], ]], ], diff --git a/src/AKSRT/Settings/UserRuntime.php b/src/AKSRT/Settings/UserRuntime.php index 001272ad..6710a67d 100644 --- a/src/AKSRT/Settings/UserRuntime.php +++ b/src/AKSRT/Settings/UserRuntime.php @@ -142,7 +142,7 @@ class UserRuntime { * User identity, level, medal, and report governance settings. * * @return array{ - * verify:array{enabled:bool,public_display:bool,badge_text:string,accept_email_verified:bool,allow_apply:bool,disable_desc:string,limit_level:int,desc:string,apply_option:string}, + * verify:array{enabled:bool,public_display:bool,allow_apply:bool,disable_desc:string,desc:string,types:array}, * level:array{enabled:bool,public_display:bool,source:string,label_prefix:string,thresholds:array}, * medal:array{enabled:bool,public_display:bool,limit:int,categories:array}>,items_by_slug:array}, * badge:array{enabled:bool,public_display:bool,limit:int,dictionary:array}, @@ -151,21 +151,35 @@ class UserRuntime { */ public static function get_user_identity_settings(): array { $settings = Settings::get_all(); - $verify_badge_text = trim((string) ($settings['user_verify_badge_text'] ?? '')); $ban_notice_text = trim((string) ($settings['user_report_ban_notice_text'] ?? '')); + $verify_types = [ + 'personal' => [ + 'slug' => 'personal', + 'label' => __('个人认证', 'aksrt'), + 'badge_text' => trim((string) ($settings['user_verify_personal_badge_text'] ?? '')) ?: __('个人认证', 'aksrt'), + 'fee' => max(0, round((float) ($settings['user_verify_personal_fee'] ?? 0), 2)), + 'free_applications' => max(0, (int) ($settings['user_verify_personal_free_applications'] ?? 0)), + 'require_real_name' => !empty($settings['user_verify_personal_require_real_name']), + ], + 'enterprise' => [ + 'slug' => 'enterprise', + 'label' => __('企业认证', 'aksrt'), + 'badge_text' => trim((string) ($settings['user_verify_enterprise_badge_text'] ?? '')) ?: __('企业认证', 'aksrt'), + 'fee' => max(0, round((float) ($settings['user_verify_enterprise_fee'] ?? 0), 2)), + 'free_applications' => max(0, (int) ($settings['user_verify_enterprise_free_applications'] ?? 0)), + 'require_real_name' => !empty($settings['user_verify_enterprise_require_real_name']), + ], + ]; $medal = self::parse_medal_catalog($settings); return [ 'verify' => [ 'enabled' => !isset($settings['user_verify_enabled']) || !empty($settings['user_verify_enabled']), 'public_display' => !isset($settings['user_verify_public_display']) || !empty($settings['user_verify_public_display']), - 'badge_text' => $verify_badge_text !== '' ? $verify_badge_text : __('已认证', 'aksrt'), - 'accept_email_verified' => false, - 'allow_apply' => !isset($settings['user_verify_allow_apply']) || !empty($settings['user_verify_allow_apply']), - 'disable_desc' => (string) ($settings['user_verify_disable_desc'] ?? ''), - 'limit_level' => max(0, (int) ($settings['user_verify_limit_level'] ?? 0)), - 'desc' => (string) ($settings['user_verify_desc'] ?? ''), - 'apply_option' => (string) ($settings['user_verify_apply_option'] ?? ''), + 'allow_apply' => !isset($settings['user_verify_allow_apply']) || !empty($settings['user_verify_allow_apply']), + 'disable_desc' => (string) ($settings['user_verify_disable_desc'] ?? ''), + 'desc' => (string) ($settings['user_verify_desc'] ?? ''), + 'types' => $verify_types, ], 'level' => [ 'enabled' => !isset($settings['user_level_s']) || !empty($settings['user_level_s']), diff --git a/src/AKSRT/User/AuthApply.php b/src/AKSRT/User/AuthApply.php index ff8be3e1..22d29ee0 100644 --- a/src/AKSRT/User/AuthApply.php +++ b/src/AKSRT/User/AuthApply.php @@ -19,6 +19,7 @@ class AuthApply { public const REVIEWED_AT_META = 'aksrt_user_verify_reviewed_at'; public const REVIEWER_META = 'aksrt_user_verify_reviewer'; public const HISTORY_META = 'aksrt_user_verify_history'; + public const APPLICATION_COUNTS_META = 'aksrt_user_verify_application_counts'; private static $instance = null; @@ -40,49 +41,30 @@ class AuthApply { } } - /** - * @return array{ - * enabled:bool,allow_apply:bool,public_display:bool,badge_text:string, - * limit_level:int,desc:string,disable_desc:string, - * types:array - * } - */ + /** @return array{enabled:bool,allow_apply:bool,public_display:bool,limit_level:int,desc:string,disable_desc:string,types:array} */ public static function settings(): array { - $all = class_exists('\AKSRT\Settings\Settings') - ? (array) \AKSRT\Settings\Settings::get_all() - : []; - $enabled = !isset($all['user_verify_enabled']) || !empty($all['user_verify_enabled']); - $types_raw = (string) ($all['user_verify_apply_option'] ?? "real_name|实名认证\norganization|企业认证"); - $types = []; - foreach (preg_split('/\r\n|\r|\n/', $types_raw) as $line) { - $line = trim($line); - if ($line === '') { - continue; - } - $parts = array_map('trim', explode('|', $line, 2)); - $slug = sanitize_key($parts[0] ?? ''); - $label = $parts[1] ?? $parts[0]; - if ($slug === '') { - continue; - } - $types[] = ['slug' => $slug, 'label' => (string) $label]; - } - if ($types === []) { - $types = [ - ['slug' => 'real_name', 'label' => __('实名认证', 'aksrt')], - ['slug' => 'organization', 'label' => __('企业认证', 'aksrt')], - ]; - } - return [ - 'enabled' => $enabled, - 'allow_apply' => !isset($all['user_verify_allow_apply']) || !empty($all['user_verify_allow_apply']), - 'public_display' => !isset($all['user_verify_public_display']) || !empty($all['user_verify_public_display']), - 'badge_text' => (string) ($all['user_verify_badge_text'] ?? __('已认证', 'aksrt')), - 'limit_level' => max(0, (int) ($all['user_verify_limit_level'] ?? 0)), - 'desc' => (string) ($all['user_verify_desc'] ?? ''), - 'disable_desc' => (string) ($all['user_verify_disable_desc'] ?? ''), - 'types' => $types, - ]; + $identity = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_user_identity_settings() : []; + return is_array($identity['verify'] ?? null) ? $identity['verify'] : []; + } + + /** @return array */ + public static function type_settings(string $type): array { + $types = self::settings()['types'] ?? []; + return is_array($types[sanitize_key($type)] ?? null) ? $types[sanitize_key($type)] : []; + } + + public static function application_count(int $user_id, string $type): int { + $counts = get_user_meta($user_id, self::APPLICATION_COUNTS_META, true); + $counts = is_array($counts) ? $counts : []; + return max(0, (int) ($counts[sanitize_key($type)] ?? 0)); + } + + private static function increment_application_count(int $user_id, string $type): void { + $counts = get_user_meta($user_id, self::APPLICATION_COUNTS_META, true); + $counts = is_array($counts) ? $counts : []; + $type = sanitize_key($type); + $counts[$type] = max(0, (int) ($counts[$type] ?? 0)) + 1; + update_user_meta($user_id, self::APPLICATION_COUNTS_META, $counts); } public static function get_status(int $user_id): string { @@ -257,6 +239,7 @@ class AuthApply { public static function application_view(array $application, int $owner_id = 0, bool $admin_context = false): array { return [ 'name' => (string) ($application['name'] ?? ''), + 'real_name' => (string) ($application['real_name'] ?? ''), 'desc' => (string) ($application['desc'] ?? ''), 'msg' => (string) ($application['msg'] ?? ''), 'type' => sanitize_key((string) ($application['type'] ?? '')), @@ -409,33 +392,27 @@ class AuthApply { if (self::get_status($user_id) === 'pending') { wp_send_json_error(['message' => __('您的申请正在审核中', 'aksrt')], 409); } - if ($s['limit_level'] > 0 && class_exists('\AKSRT\User\Level')) { - $lv = (int) Level::get_level($user_id); - if ($lv < $s['limit_level']) { - wp_send_json_error([ - 'message' => sprintf( - /* translators: %d: required level */ - __('等级不足,需达到 LV.%d 后申请', 'aksrt'), - $s['limit_level'] - ), - ], 403); - } - } - $name = isset($_POST['name']) ? sanitize_text_field(wp_unslash((string) $_POST['name'])) : ''; + $real_name = isset($_POST['real_name']) ? sanitize_text_field(wp_unslash((string) $_POST['real_name'])) : ''; $desc = isset($_POST['desc']) ? sanitize_textarea_field(wp_unslash((string) $_POST['desc'])) : ''; $msg = isset($_POST['msg']) ? sanitize_textarea_field(wp_unslash((string) $_POST['msg'])) : ''; $type = isset($_POST['type']) ? sanitize_key((string) wp_unslash($_POST['type'])) : ''; - $allowed_types = array_column((array) $s['types'], 'slug'); + $type_settings = self::type_settings($type); if ($this->text_length($name) < 4 || $this->text_length($name) > 16) { wp_send_json_error(['message' => __('认证身份长度需在 4-16 个字符之间', 'aksrt')], 422); } if ($this->text_length($desc) > 300 || $this->text_length($msg) > 500) { wp_send_json_error(['message' => __('认证说明内容过长', 'aksrt')], 422); } - if ($type === '' || !in_array($type, $allowed_types, true)) { + if ($type_settings === []) { wp_send_json_error(['message' => __('请选择有效的认证类型', 'aksrt')], 422); } + if (!empty($type_settings['require_real_name']) && $real_name === '') { + wp_send_json_error(['message' => __('请填写真实姓名', 'aksrt')], 422); + } + if ($this->text_length($real_name) > 50) { + wp_send_json_error(['message' => __('真实姓名不能超过 50 个字符', 'aksrt')], 422); + } $lock_key = 'aksrt_auth_apply_lock_' . $user_id; $lock_token = wp_generate_uuid4(); @@ -472,26 +449,52 @@ class AuthApply { } $this->renew_submission_lock($lock_key, $lock_token); + $free_applications = max(0, (int) ($type_settings['free_applications'] ?? 0)); + $application_count = self::application_count($user_id, $type); + $fee = $application_count < $free_applications ? 0.0 : max(0, (float) ($type_settings['fee'] ?? 0)); + if ($fee > 0) { + $deducted = \AKSRT\Credits\Balance::deduct( + $user_id, + $fee, + 'verify_application', + ['type' => 'verify', 'id' => $user_id], + sprintf(__('提交%s申请', 'aksrt'), (string) $type_settings['label']) + ); + if (is_wp_error($deducted)) { + $this->delete_attachments($uploaded); + $this->release_submission_lock($lock_key, $lock_token); + wp_send_json_error(['message' => $deducted->get_error_message()], 422); + } + } + $previous_payload = self::get_apply_payload($user_id); $requested_at = current_time('Y-m-d H:i'); $payload = [ 'name' => $name, + 'real_name' => $real_name, 'desc' => $desc, 'msg' => $msg, 'type' => $type, 'evidence_attachment_ids' => $uploaded, 'time' => $requested_at, + 'fee' => $fee, ]; $payload_saved = update_user_meta($user_id, self::APPLY_META, $payload); if ($payload_saved === false && get_user_meta($user_id, self::APPLY_META, true) !== $payload) { $this->delete_attachments($uploaded); + if ($fee > 0) { + \AKSRT\Credits\Balance::add($user_id, $fee, 'verify_application_refund', ['type' => 'verify', 'id' => $user_id], __('认证申请保存失败退款', 'aksrt')); + } $this->release_submission_lock($lock_key, $lock_token); wp_send_json_error(['message' => __('认证申请保存失败,请重试', 'aksrt')], 500); } $status_saved = update_user_meta($user_id, self::STATUS_META, 'pending'); if ($status_saved === false && self::get_status($user_id) !== 'pending') { $this->delete_attachments($uploaded); + if ($fee > 0) { + \AKSRT\Credits\Balance::add($user_id, $fee, 'verify_application_refund', ['type' => 'verify', 'id' => $user_id], __('认证申请保存失败退款', 'aksrt')); + } $previous_payload === [] ? delete_user_meta($user_id, self::APPLY_META) : update_user_meta($user_id, self::APPLY_META, $previous_payload); @@ -502,6 +505,7 @@ class AuthApply { delete_user_meta($user_id, self::REVIEWED_AT_META); delete_user_meta($user_id, self::REVIEWER_META); delete_user_meta($user_id, self::REASON_META); + self::increment_application_count($user_id, $type); if (!$this->owns_submission_lock($lock_key, $lock_token)) { $this->release_submission_lock($lock_key, $lock_token); diff --git a/src/AKSRT/User/Home.php b/src/AKSRT/User/Home.php index 69132c85..e951bbc1 100644 --- a/src/AKSRT/User/Home.php +++ b/src/AKSRT/User/Home.php @@ -139,12 +139,20 @@ class Home { $signals = []; if (!empty($settings['verify']['enabled']) && !empty($settings['verify']['public_display']) && $this->is_user_verified($user_id, $settings['verify'])) { - $signals[] = [ - 'type' => 'verify', - 'label' => (string) $settings['verify']['badge_text'], - 'icon' => 'check-circle', - 'tone' => 'success', - ]; + $info = class_exists('AKSRT\\User\\AuthApply') ? AuthApply::get_auth_info($user_id) : []; + $type = sanitize_key((string) ($info['type'] ?? '')); + $type_settings = is_array($settings['verify']['types'][$type] ?? null) ? $settings['verify']['types'][$type] : []; + if ($type_settings !== []) { + $label = (string) $type_settings['badge_text']; + $signals[] = [ + 'type' => 'verify', + 'label' => $label, + 'title' => $label, + 'icon' => 'check-circle', + 'icon_url' => get_theme_file_uri('/assets/img/user/user-certification.svg'), + 'tone' => 'success', + ]; + } } if (!empty($settings['level']['enabled']) && !empty($settings['level']['public_display'])) {