*/ public static function get_paid_content_settings(): array { $settings = Settings::get_all(); $features = HomeCms::get_cms_features(); $catalog_note = trim((string) ($settings['payment_paid_catalog_note'] ?? '')); $manual_note = trim((string) ($settings['payment_manual_delivery_note'] ?? '')); $box_position = sanitize_key((string) ($settings['pay_box_position'] ?? 'top')); // Zibll: box_top | top | bottom | box_bottom if (!in_array($box_position, ['box_top', 'top', 'bottom', 'box_bottom'], true)) { $box_position = 'top'; } return [ 'download_login' => !empty($features['download_login']), 'download_credit' => !empty($features['download_credit']) && Settings::credits_enabled(), 'download_captcha' => !empty($features['download_captcha']), 'default_cost' => Settings::download_default_cost(), 'paid_post_types' => self::parse_slug_list((string) ($settings['payment_paid_post_types'] ?? 'post'), ['post']), 'vip_free_download' => !empty($settings['payment_vip_free_download']), 'vip_exempt_roles' => self::parse_slug_list((string) ($settings['payment_vip_exempt_roles'] ?? '')), 'catalog_note' => $catalog_note, 'manual_delivery_note' => $manual_note !== '' ? $manual_note : __('付费或人工确认内容请在订单备注中记录交付方式。', 'aksrt'), 'no_logged_in' => !isset($settings['pay_no_logged_in']) || !empty($settings['pay_no_logged_in']), 'free_logged_show' => !empty($settings['pay_free_logged_show']), 'down_alone_page' => !empty($settings['payment_down_alone_page']), 'display' => [ 'mark' => sanitize_text_field((string) ($settings['pay_mark'] ?? '付费')), 'currency_symbol' => sanitize_text_field((string) ($settings['payment_currency_symbol'] ?? '¥')), 'show_user' => !isset($settings['pay_show_user']) || !empty($settings['pay_show_user']), 'show_paycount' => !isset($settings['pay_show_paycount']) || !empty($settings['pay_show_paycount']), 'box_position' => $box_position, ], 'download' => [ 'enabled' => !empty($settings['payment_download_enable']), 'remote' => !isset($settings['payment_download_remote_s']) || !empty($settings['payment_download_remote_s']), 'verify_nonce' => !isset($settings['payment_download_verify_nonce']) || !empty($settings['payment_download_verify_nonce']), 'user_log' => max(0, min(9999, (int) ($settings['payment_download_user_log'] ?? 50))), 'post_log' => max(0, min(9999, (int) ($settings['payment_download_post_log'] ?? 50))), 'remote_size' => max(1, (int) ($settings['payment_download_remote_size'] ?? 2048)), 'remote_ext' => sanitize_text_field((string) ($settings['payment_download_remote_ext'] ?? 'zip,rar,7z')), 'alone_page' => !empty($settings['payment_down_alone_page']), ], // Content cashier coupon (zibll coupon_post_s / coupon_desc). 'coupon_post_s' => !empty($settings['coupon_post_s']), 'coupon_desc' => sanitize_textarea_field((string) ($settings['coupon_desc'] ?? '')), ]; } /** * Content coupon global switches (zibll coupon_post_s). * * @return array{enabled:bool,desc:string} */ public static function get_content_coupon_settings(): array { $settings = self::get_paid_content_settings(); return [ 'enabled' => !empty($settings['coupon_post_s']), 'desc' => (string) ($settings['coupon_desc'] ?? ''), ]; } /** * Balance recharge settings (Zibll pay_balance_* contract). * * @return array */ public static function get_payment_recharge_settings(): array { $settings = Settings::get_all(); $packages = (string) ($settings['pay_balance_product'] ?? "30|30|入门包\n98|108|推荐包"); if (is_array($settings['pay_balance_product'] ?? null)) { $packages = self::format_product_lines((array) $settings['pay_balance_product']); } $desc = sanitize_textarea_field((string) ($settings['pay_balance_desc'] ?? '')); return [ 'enabled' => !empty($settings['pay_balance_s']), 'desc' => $desc, 'auto_to_balance' => !isset($settings['pay_auto_to_balance']) || !empty($settings['pay_auto_to_balance']), 'packages_raw' => $packages, 'package_count' => self::count_structured_lines($packages), 'help_text' => $desc !== '' ? $desc : __('当前支持人工确认与测试联调;接入真实网关时复用同一组字段。', 'aksrt'), 'product' => [ 'name' => sanitize_text_field((string) ($settings['pay_balance_product_name'] ?? '')), 'price' => max(0, (float) ($settings['pay_balance_price'] ?? 0)), 'tag' => sanitize_text_field((string) ($settings['pay_balance_tag'] ?? '元')), 'tag_class' => sanitize_text_field((string) ($settings['pay_balance_tag_class'] ?? '')), 'custom_s' => !isset($settings['pay_balance_product_custom_s']) || !empty($settings['pay_balance_product_custom_s']), 'custom_limit' => max(1, min(99999, (int) ($settings['pay_balance_product_custom_limit'] ?? 9999))), ], 'transfer' => [ 'enabled' => !empty($settings['pay_balance_transfer_s']), 'service_charge' => max(0, min(50, (int) ($settings['pay_balance_transfer_service_charge'] ?? 0))), 'desc' => sanitize_textarea_field((string) ($settings['pay_balance_transfer_desc'] ?? '')), ], 'pass_charge' => [ 'enabled' => !empty($settings['pay_balance_pass_charge_s']), 'desc' => sanitize_textarea_field((string) ($settings['pay_balance_pass_charge_desc'] ?? '')), 'only_password' => !empty($settings['pay_balance_pass_charge_only_password']), ], 'exchange' => [ 'enabled' => !empty($settings['pay_balance_exchange_s']), 'rate' => max(1, min(10000, (int) ($settings['pay_balance_exchange_rate'] ?? 100))), 'desc' => sanitize_textarea_field((string) ($settings['pay_balance_exchange_desc'] ?? '')), ], ]; } /** * Dual-level VIP settings (Zibll pay_user_vip_1 / pay_user_vip_2). * * @return array */ public static function get_payment_vip_settings(): array { $settings = Settings::get_all(); $vip1_enabled = !empty($settings['pay_user_vip_1_s']); $vip2_enabled = !empty($settings['pay_user_vip_2_s']); $enabled = $vip1_enabled || $vip2_enabled; $name1 = trim((string) ($settings['pay_user_vip_1_name'] ?? '')); $name2 = trim((string) ($settings['pay_user_vip_2_name'] ?? '')); if ($name1 === '') { $name1 = __('一级会员', 'aksrt'); } if ($name2 === '') { $name2 = __('二级会员', 'aksrt'); } $badge = $vip2_enabled ? $name2 : ($vip1_enabled ? $name1 : __('VIP', 'aksrt')); $renew_price_type = sanitize_key((string) ($settings['vip_renew_price_type'] ?? 'discount')); if (!in_array($renew_price_type, ['same', 'discount', 'reduce'], true)) { $renew_price_type = 'discount'; } $default_l1 = "30|59|1|month|限时|月卡\n98|199|3|month|特惠|季卡\n365|599|12|month|超值|年卡\n999|1299|0|day|永久|永久卡"; $default_l2 = "58|99|1|month|限时|月卡\n168|299|3|month|特惠|季卡\n598|999|12|month|超值|年卡\n1299|1999|0|day|永久|永久卡"; $products_1 = sanitize_textarea_field((string) ($settings['payment_vip_1_products'] ?? $default_l1)); $products_2 = sanitize_textarea_field((string) ($settings['payment_vip_2_products'] ?? $default_l2)); // Restore newlines lost only if empty after sanitize — sanitize_textarea_field keeps \n. if (trim($products_1) === '') { $products_1 = $default_l1; } if (trim($products_2) === '') { $products_2 = $default_l2; } $desc = sanitize_textarea_field((string) ($settings['pay_user_vip_desc'] ?? '')); $more = (string) ($settings['pay_user_vip_more'] ?? ''); $allowed_equity = [ 'li' => [], 'ul' => [], 'ol' => [], 'strong' => [], 'b' => [], 'em' => [], 'i' => ['class' => true], 'span' => ['class' => true], 'br' => [], 'a' => ['href' => true, 'target' => true, 'rel' => true, 'class' => true], ]; return [ 'enabled' => $enabled, 'name' => $vip1_enabled ? $name1 : $badge, 'badge_text' => $badge, 'desc' => $desc, 'more' => wp_kses($more, $allowed_equity + ['div' => ['class' => true], 'p' => ['class' => true]]), 'help_text' => $desc !== '' ? $desc : __('会员权益以免扣下载和身份展示为主,开通后立即生效。', 'aksrt'), 'levels' => [ 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), 'img_icon' => esc_url_raw((string) ($settings['vip_1_img_icon'] ?? '')), 'product_s' => !isset($settings['vip_1_product_s']) || !empty($settings['vip_1_product_s']), 'products_raw' => $products_1, 'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit_vip_1'] ?? 0))), 'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed_vip_1'] ?? 0))), ], 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), 'img_icon' => esc_url_raw((string) ($settings['vip_2_img_icon'] ?? '')), 'product_s' => !isset($settings['vip_2_product_s']) || !empty($settings['vip_2_product_s']), 'products_raw' => $products_2, 'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit_vip_2'] ?? 0))), 'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed_vip_2'] ?? 0))), ], ], 'benefit' => [ 'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit'] ?? 0))), 'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed'] ?? 0))), 'pass_charge' => !empty($settings['pay_vip_pass_charge_s']), 'pass_charge_desc' => sanitize_textarea_field((string) ($settings['pay_vip_pass_charge_desc'] ?? '')), 'pass_charge_only_password' => !isset($settings['pay_vip_pass_charge_only_password']) || !empty($settings['pay_vip_pass_charge_only_password']), ], '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' => max(0, min(9999, (int) ($settings['vip_renew_reduce'] ?? 20))), ], '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'] ?? '')), ], 'points_exchange' => [ 'enabled' => !empty($settings['pay_vip_points_exchange_s']), 'desc' => sanitize_textarea_field((string) ($settings['pay_vip_points_exchange_desc'] ?? '')), 'packages_raw' => sanitize_textarea_field((string) ($settings['payment_vip_points_packages'] ?? "1|500|30|积分月卡\n1|5000|0|积分永久")), ], ]; } /** * @return array */ public static function get_payment_revenue_settings(): array { $settings = Settings::get_all(); $note = trim((string) ($settings['payment_revenue_note'] ?? '')); return [ 'enabled' => !empty($settings['pay_income_s']), 'share_ratio' => max(0, min(100, (int) ($settings['payment_revenue_share_ratio'] ?? 70))), 'ratio_vip1' => max(0, min(100, (int) ($settings['ratio_vip_1'] ?? 0))), 'ratio_vip2' => max(0, min(100, (int) ($settings['ratio_vip_2'] ?? 0))), 'settlement_threshold' => max(0, (int) ($settings['payment_revenue_settlement_threshold'] ?? 100)), 'cycle_days' => max(1, min(365, (int) ($settings['payment_revenue_cycle_days'] ?? 30))), 'points_rule' => sanitize_textarea_field((string) ($settings['payment_revenue_points_rule'] ?? '')), 'note' => $note !== '' ? $note : __('分成策略和台账结构已就绪,订单入账后自动按比例结算。', 'aksrt'), 'display' => [ 'desc_details' => sanitize_textarea_field((string) ($settings['pay_income_desc_details'] ?? '')), 'desc_page' => esc_url_raw((string) ($settings['pay_income_desc_page'] ?? '')), ], ]; } /** * @return array */ public static function get_payment_affiliate_settings(): array { $settings = Settings::get_all(); $note = trim((string) ($settings['pay_rebate_text_desc'] ?? '')); return [ 'enabled' => !empty($settings['pay_rebate_s']), 'ratio' => max(0, min(100, (int) ($settings['pay_rebate_ratio'] ?? 10))), 'window_days' => max(1, min(365, (int) ($settings['payment_affiliate_window_days'] ?? 30))), 'require_paid_order' => !isset($settings['payment_affiliate_require_paid_order']) || !empty($settings['payment_affiliate_require_paid_order']), 'self_s' => !isset($settings['pay_rebate_self_s']) || !empty($settings['pay_rebate_self_s']), 'show_users' => !isset($settings['pay_rebate_show_users']) || !empty($settings['pay_rebate_show_users']), 'note' => $note !== '' ? $note : __('返佣链路复用邀请体系,订单归因和结算自动衔接当前策略字段。', 'aksrt'), 'user_ratio' => [ 'user' => max(0, min(100, (int) ($settings['payment_affiliate_user_ratio'] ?? $settings['pay_rebate_ratio'] ?? 10))), 'vip1' => max(0, min(100, (int) ($settings['pay_rebate_ratio_vip_1'] ?? 0))), 'vip2' => max(0, min(100, (int) ($settings['pay_rebate_ratio_vip_2'] ?? 0))), ], 'poster' => [ 'enabled' => !isset($settings['pay_rebate_poster_s']) || !empty($settings['pay_rebate_poster_s']), 'img' => esc_url_raw((string) ($settings['pay_rebate_poster_img'] ?? '')), 'title' => sanitize_text_field((string) ($settings['pay_rebate_poster_title'] ?? '')), 'desc' => sanitize_text_field((string) ($settings['pay_rebate_poster_desc'] ?? '')), ], 'text' => [ 'desc' => sanitize_textarea_field((string) ($settings['pay_rebate_text_desc'] ?? '')), 'details_title' => sanitize_text_field((string) ($settings['pay_rebate_text_details_title'] ?? '')), 'details' => sanitize_textarea_field((string) ($settings['pay_rebate_text_details'] ?? '')), 'discount' => sanitize_text_field((string) ($settings['pay_rebate_text_discount'] ?? '')), ], ]; } /** * @return array */ public static function get_payment_gateway_settings(): array { $settings = Settings::get_all(); $mode = sanitize_key((string) ($settings['payment_gateway_mode'] ?? 'manual_review')); if (!in_array($mode, ['manual_review', 'test_gateway', 'adapter_ready'], true)) { $mode = 'manual_review'; } $help_text = trim((string) ($settings['payment_gateway_help'] ?? '')); $gateway_keys = ['wechat', 'alipay', 'paypal', 'stripe', 'balance', 'card_pass', 'xunhupay', 'xhpay', 'payjs', 'epay', 'vmq', 'codepay']; $gateways = []; foreach ($gateway_keys as $gw) { $gateways[$gw] = !empty($settings["payment_{$gw}_enabled"]); } return [ 'mode' => $mode, 'test_enabled' => !isset($settings['payment_gateway_test_enabled']) || !empty($settings['payment_gateway_test_enabled']), 'manual_review' => !isset($settings['payment_gateway_manual_review']) || !empty($settings['payment_gateway_manual_review']), 'callback_secret' => sanitize_text_field((string) ($settings['payment_gateway_callback_secret'] ?? '')), 'help_text' => $help_text !== '' ? $help_text : __('未接真实支付网关时,建议使用测试网关或人工确认模式完成联调。', 'aksrt'), 'gateways' => $gateways, 'xunhupay' => [ 'appid' => sanitize_text_field((string) ($settings['xunhupay_appid'] ?? '')), 'appsecret' => sanitize_text_field((string) ($settings['xunhupay_appsecret'] ?? '')), ], 'xhpay' => [ 'mchid' => sanitize_text_field((string) ($settings['xhpay_mchid'] ?? '')), 'alipay_v2' => sanitize_text_field((string) ($settings['xhpay_alipay_v2'] ?? '')), 'wx_h5' => sanitize_text_field((string) ($settings['xhpay_wx_h5'] ?? '')), ], 'payjs' => [ 'mchid' => sanitize_text_field((string) ($settings['payjs_mchid'] ?? '')), 'key' => sanitize_text_field((string) ($settings['payjs_key'] ?? '')), ], 'epay' => [ 'apiurl' => esc_url_raw((string) ($settings['epay_apiurl'] ?? '')), 'pid' => sanitize_text_field((string) ($settings['epay_pid'] ?? '')), 'key' => sanitize_text_field((string) ($settings['epay_key'] ?? '')), ], 'alipay_extra' => [ 'return_url' => esc_url_raw((string) ($settings['alipay_return_url'] ?? '')), 'notify_url' => esc_url_raw((string) ($settings['alipay_notify_url'] ?? '')), ], ]; } /** * Order display / checkout policy (Zibll pay_* + AKSRT order ops). * * @return array */ public static function get_order_settings(): array { $s = Settings::get_all(); $expiry = max(5, min(1440, (int) ($s['payment_order_expiry'] ?? 30))); $cookie_day = max(1, min(31, (int) ($s['pay_cookie_day'] ?? 15))); $max_minutes = max(5, min(1440, (int) ($s['payment_order_max_minutes'] ?? 30))); $box_position = sanitize_key((string) ($s['pay_box_position'] ?? 'top')); if (!in_array($box_position, ['box_top', 'top', 'bottom', 'box_bottom'], true)) { $box_position = 'top'; } $status_keys = ['pending', 'paid', 'completed', 'cancelled', 'refunded', 'refunding', 'processing']; $status_defaults = ['待支付', '已支付', '已完成', '已取消', '已退款', '退款中', '处理中']; $status_texts = []; foreach ($status_keys as $i => $key) { $val = trim((string) ($s["payment_order_status_{$key}"] ?? '')); $status_texts[$key] = $val !== '' ? $val : $status_defaults[$i]; } return [ 'prefix' => sanitize_text_field((string) ($s['payment_order_prefix'] ?? 'AKSRT')), 'expiry' => $expiry, 'show_user' => !isset($s['pay_show_user']) || !empty($s['pay_show_user']), 'show_paycount' => !isset($s['pay_show_paycount']) || !empty($s['pay_show_paycount']), 'no_logged_in' => !isset($s['pay_no_logged_in']) || !empty($s['pay_no_logged_in']), 'cookie_day' => $cookie_day, 'no_logged_remind' => sanitize_textarea_field((string) ($s['pay_no_logged_remind'] ?? '')), 'wait_float' => !isset($s['pay_wait_float_s']) || !empty($s['pay_wait_float_s']), 'order_max_minutes' => $max_minutes, 'mark' => sanitize_text_field((string) ($s['pay_mark'] ?? '付费')), 'box_position' => $box_position, 'free_logged_show' => !empty($s['pay_free_logged_show']), 'show_ip' => !empty($s['payment_show_ip']), 'show_device' => !empty($s['payment_show_device']), 'show_order_no' => !isset($s['payment_show_order_no']) || !empty($s['payment_show_order_no']), 'show_create_time' => !isset($s['payment_show_create_time']) || !empty($s['payment_show_create_time']), 'show_pay_time' => !isset($s['payment_show_pay_time']) || !empty($s['payment_show_pay_time']), 'status_texts' => $status_texts, 'service' => [ 'text' => sanitize_textarea_field((string) ($s['pay_service'] ?? '')), 'icon' => sanitize_text_field((string) ($s['pay_service_icon'] ?? '')), 'value' => sanitize_text_field((string) ($s['pay_service_value'] ?? '')), 'qq' => sanitize_text_field((string) ($s['pay_service_qq'] ?? '')), 'wechat' => esc_url_raw((string) ($s['pay_service_wechat'] ?? '')), ], ]; } /** * @return array */ public static function get_card_pass_settings(): array { $s = Settings::get_all(); $type = sanitize_key((string) ($s['card_pass_type'] ?? 'balance')); if (!in_array($type, ['balance', 'vip', 'credits'], true)) { $type = 'balance'; } $success_msg = trim((string) ($s['card_pass_success_msg'] ?? '')); $fail_msg = trim((string) ($s['card_pass_fail_msg'] ?? '')); return [ 'enabled' => !empty($s['card_pass_enabled']), 'desc' => sanitize_textarea_field((string) ($s['card_pass_desc'] ?? '')), 'type' => $type, 'prefix' => sanitize_text_field((string) ($s['card_pass_prefix'] ?? 'AK')), 'length' => max(8, min(32, (int) ($s['card_pass_length'] ?? 16))), 'batch_size' => max(1, min(500, (int) ($s['card_pass_batch_size'] ?? 50))), 'max_redeem' => max(1, min(100, (int) ($s['card_pass_max_redeem'] ?? 1))), 'expiry_days' => max(0, (int) ($s['card_pass_expiry'] ?? 0)), 'amount' => max(1, min(9999, (int) ($s['card_pass_amount'] ?? 10))), 'vip_days' => max(1, min(3650, (int) ($s['card_pass_vip_days'] ?? 30))), 'credits' => max(0, min(99999, (int) ($s['card_pass_credits'] ?? 0))), 'redeem_page' => esc_url_raw((string) ($s['card_pass_redeem_page'] ?? '')), 'success_msg' => $success_msg !== '' ? $success_msg : __('兑换成功!', 'aksrt'), 'fail_msg' => $fail_msg !== '' ? $fail_msg : __('卡号无效或已过期', 'aksrt'), ]; } /** * @return array{min_amount:int,service_charge_rate:int,text:string} */ public static function get_withdrawal_settings(): array { $s = Settings::get_all(); return [ 'min_amount' => max(1, min(99999, (int) ($s['pay_rebate_withdraw_lowest_money'] ?? 50))), 'service_charge_rate' => max(0, min(50, (int) ($s['withdraw_service_charge'] ?? 0))), 'text' => sanitize_textarea_field((string) ($s['pay_rebate_withdraw_text_details'] ?? '')), ]; } /** * Whether a registered adapter is admin-enabled. * Maps gateway ids (wechatpay) to schema toggles (payment_wechat_enabled). */ public static function is_gateway_enabled(string $gateway_id): bool { $settings = Settings::get_all(); $map = [ 'alipay' => 'payment_alipay_enabled', 'wechatpay' => 'payment_wechat_enabled', 'paypal' => 'payment_paypal_enabled', 'stripe' => 'payment_stripe_enabled', 'balance' => 'payment_balance_enabled', 'card_pass' => 'payment_card_pass_enabled', 'xunhupay' => 'payment_xunhupay_enabled', 'xhpay' => 'payment_xhpay_enabled', 'payjs' => 'payment_payjs_enabled', 'epay' => 'payment_epay_enabled', 'vmq' => 'payment_vmq_enabled', 'codepay' => 'payment_codepay_enabled', ]; $key = $map[$gateway_id] ?? ''; if ($key === '') { return false; } if ($gateway_id === 'balance') { return !empty($settings['payment_balance_enabled']) && !empty($settings['pay_balance_s']); } return !empty($settings[$key]); } /** * @param string[] $fallback * @return string[] */ private static function parse_slug_list(string $raw, array $fallback = []): array { $items = preg_split('/[\s,]+/', $raw, -1, PREG_SPLIT_NO_EMPTY); $normalized = []; foreach ((array) $items as $item) { $slug = sanitize_key((string) $item); if ($slug !== '' && !in_array($slug, $normalized, true)) { $normalized[] = $slug; } } return !empty($normalized) ? $normalized : $fallback; } private static function count_structured_lines(string $raw): int { $lines = preg_split('/[\r\n]+/', $raw, -1, PREG_SPLIT_NO_EMPTY); $count = 0; foreach ((array) $lines as $line) { if (trim((string) $line) !== '') { $count++; } } return $count; } /** * @param array $products */ private static function format_product_lines(array $products): string { $lines = []; foreach ($products as $row) { if (!is_array($row)) { continue; } $price = $row['pay_price'] ?? $row['price'] ?? ''; $value = $row['value'] ?? $row['balance'] ?? $price; $title = $row['title'] ?? $row['name'] ?? ''; $lines[] = $price . '|' . $value . '|' . $title; } return implode("\n", $lines); } }