refactor: rename the theme brand and every identifier from AKSRT to Jio

Full-project rename. `git grep -i aksrt` is now empty apart from the
DBMigrator 3.3.0 changelog note that documents the rename itself.

Code identifiers
- PHP namespace AKSRT\ -> Jio\ (composer PSR-4 + 378 declarations)
- global constants AKSRT_* -> JIO_* (VERSION/DIR/URI, PAY_TYPE_*, CAPTCHA_*)
- procedural functions, hooks, options, meta keys, table names,
  cookies, query vars, ajax actions and nonces: aksrt_ -> jio_
- text domain aksrt -> jio; Theme Name -> Jio
- JS globals: aksrtData/aksrtAdminData/... -> jioData/jioAdminData/...,
  window.AKSRTCaptcha & friends -> window.JioCaptcha, Aksrt* -> Jio*
- Vue components Aks*.vue -> Jio*.vue (15 files renamed + imports)
- CSS classes/data-attrs/custom properties: aksrt- -> jio-
- REST namespace aksrt/v1 -> jio/v1 (incl. payment gateway callbacks)

Storage layer
- DB tables {prefix}aksrt_* -> {prefix}jio_*; SCHEMA_VERSION 3.2.0 -> 3.3.0
  so dbDelta creates the new names on install
- widget id_base aksrt_widget_* -> jio_widget_*
- uninstall.php drop list rebuilt from the actual migrator tables
  (dropped 3 stale entries, added the 17 missing ones)

Removed
- hardcoded https://api.aksrt.com/version.json default update endpoint;
  get_endpoint() now reads the 「更新端点」 setting and do_check() no-ops
  when it is empty

Files renamed: inc/helpers/aksrt-*.php -> jio-*.php (54),
assets/admin/src/components/form/Aks*.vue -> Jio*.vue (15).
Build artifacts regenerated: assets/css/build, assets/js/runtime,
assets/admin/build.

Verified: audit-psr4-paths errors=0, audit-admin-contracts errors=0
(warnings=56, unchanged baseline), 813/813 widget-system tests,
44/44 phpunit, php -l clean across all PHP.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Opus 5 committed 2026-11-01 20:05:04 +08:00
1 parent 5b16bc6e15
commit 35bb96e82f
997 files changed
+28216 -28188

No files matched your search

+557
View File
@@ -0,0 +1,557 @@
<?php
/**
* Jio Resource Helper
*
* 资源(CMS)相关的顶层辅助函数。
*
* 提供给模板层调用,将原始 post meta 转成视图友好的结构,
* 同时承担"显示策略"判定(是否显示价格/版本/下载按钮等)。
*
* @package Jio
*/
defined('ABSPATH') || exit;
if (!function_exists('jio_get_resource_meta')) {
/**
* 一次性取齐资源的全部元数据,已带默认值。
*
* 单次 get_post_meta($id, '', true) 调用 + WordPress 内部 meta 缓存命中,
* 避免 11 次单独查询。
*
* @param int|WP_Post|null $post
* @return array
*/
function jio_get_resource_meta($post = null): array {
$p = get_post($post);
if (!($p instanceof WP_Post)) {
return jio_default_resource_meta();
}
$pay_meta = function_exists('jio_get_pay_meta')
? jio_get_pay_meta($p)
: \Jio\Core\DomainModel::default_pay_meta();
$download_count = (int) get_post_meta($p->ID, \Jio\Core\DomainModel::RESOURCE_DOWNLOAD_COUNT_KEY, true);
$legacy_download_count = (int) get_post_meta($p->ID, 'download_count', true);
$resource_view_count = (int) get_post_meta($p->ID, \Jio\Core\DomainModel::RESOURCE_VIEW_COUNT_KEY, true);
$common_view_count = (int) get_post_meta($p->ID, \Jio\Core\DomainModel::POST_VIEW_COUNT_KEY, true);
// Normalize downloads extract_code aliases for legacy rows still stored on pay meta.
$downloads = array_values(is_array($pay_meta['downloads'] ?? null) ? $pay_meta['downloads'] : []);
$downloads = array_values(array_filter(array_map(static function ($row) {
if (!is_array($row)) {
return null;
}
$extract_keys = [
'extract_code', 'extractCode', 'extract', 'extract_key',
'extraction_code', 'extractionCode',
'code', 'password', 'pwd',
'pan_code', 'panCode', 'pan_password', 'panPassword',
'access_code', 'accessCode',
];
if (!array_key_exists('extract_code', $row)) {
foreach ($extract_keys as $alias) {
if (isset($row[$alias]) && !is_array($row[$alias]) && trim((string) $row[$alias]) !== '') {
$row['extract_code'] = (string) $row[$alias];
break;
}
}
}
$row['extract_code'] = isset($row['extract_code']) ? trim((string) $row['extract_code']) : '';
return $row;
}, $downloads)));
$virtual_sales = max(0, (int) ($pay_meta['virtual_sales'] ?? 0));
$show_sales = !isset($pay_meta['show_sales']) || !empty($pay_meta['show_sales']);
return [
'version' => (string) ($pay_meta['version'] ?? ''),
'size' => (string) ($pay_meta['size'] ?? ''),
'price' => (string) ($pay_meta['price'] ?? '0.00'),
'points_price' => (int) ($pay_meta['points_price'] ?? 0),
'pay_modo' => (($pay_meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0',
'pay_limit' => in_array((int) ($pay_meta['pay_limit'] ?? 0), [0, 1, 2], true) ? (int) $pay_meta['pay_limit'] : 0,
'original_price' => (string) ($pay_meta['original_price'] ?? '0.00'),
'vip1_price' => (string) ($pay_meta['vip1_price'] ?? '0.00'),
'vip2_price' => (string) ($pay_meta['vip2_price'] ?? '0.00'),
'vip1_points' => (int) ($pay_meta['vip1_points'] ?? 0),
'vip2_points' => (int) ($pay_meta['vip2_points'] ?? 0),
'pay_type' => (string) ($pay_meta['pay_type'] ?? \Jio\Core\DomainModel::PAY_TYPE_DOWNLOAD),
'license' => (string) ($pay_meta['license'] ?? ''),
'compat' => (string) ($pay_meta['compat'] ?? ''),
'demo_url' => (string) ($pay_meta['demo_url'] ?? ''),
'downloads' => $downloads,
'download_count' => max(0, max($download_count, $legacy_download_count)),
'view_count' => max(0, max($resource_view_count, $common_view_count)),
'virtual_sales' => $virtual_sales,
// 展示销量 = 真实订单 + 后台「销量浮动」(pay_count),与内容帖同一口径。
'sales_count' => $show_sales ? jio_get_content_sales_count($p, $pay_meta) : 0,
'show_sales' => $show_sales,
'require_login' => !empty($pay_meta['require_login']),
'require_captcha' => !empty($pay_meta['require_captcha']),
];
}
}
if (!function_exists('jio_default_resource_meta')) {
function jio_default_resource_meta(): array {
$meta = \Jio\Core\DomainModel::default_pay_meta();
return [
'version' => (string) ($meta['version'] ?? ''),
'size' => (string) ($meta['size'] ?? ''),
'price' => (string) ($meta['price'] ?? '0.00'),
'points_price' => (int) ($meta['points_price'] ?? 0),
'pay_modo' => (($meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0',
'pay_limit' => in_array((int) ($meta['pay_limit'] ?? 0), [0, 1, 2], true) ? (int) $meta['pay_limit'] : 0,
'original_price' => (string) ($meta['original_price'] ?? '0.00'),
'vip1_price' => (string) ($meta['vip1_price'] ?? '0.00'),
'vip2_price' => (string) ($meta['vip2_price'] ?? '0.00'),
'vip1_points' => (int) ($meta['vip1_points'] ?? 0),
'vip2_points' => (int) ($meta['vip2_points'] ?? 0),
'pay_type' => \Jio\Core\DomainModel::PAY_TYPE_DOWNLOAD,
'license' => (string) ($meta['license'] ?? ''),
'compat' => (string) ($meta['compat'] ?? ''),
'demo_url' => (string) ($meta['demo_url'] ?? ''),
'downloads' => [],
'download_count' => 0,
'view_count' => 0,
'virtual_sales' => 0,
'sales_count' => 0,
'show_sales' => true,
'require_login' => !empty($meta['require_login']),
'require_captcha' => !empty($meta['require_captcha']),
];
}
}
if (!function_exists('jio_resource_price_label')) {
/**
* 把价格数字渲染成展示徽章文案。
*
* @param int $price
* @return array { text:string, free:bool }
*/
function jio_resource_price_label(int $price): array {
if ($price <= 0) {
return [
'text' => __('免费', 'jio'),
'free' => true,
];
}
return [
'text' => sprintf(__('%s 积分', 'jio'), (string) $price),
'free' => false,
];
}
}
if (!function_exists('jio_resource_price_amount')) {
/**
* Format the raw resource price number for compact UI labels.
*
* @param int $price
* @return string
*/
function jio_resource_price_amount(int $price): string {
return (string) max(0, $price);
}
}
if (!function_exists('jio_resource_card_badge_text')) {
/**
* List-card pay badge (legacy equivalent).
*
* Renders for any paid post type, not only download resources.
* Returns plain text; card template wraps with link + class.
*
* @param int|WP_Post|null $post
* @return string
*/
function jio_resource_card_badge_text($post = null): string {
$p = get_post($post);
if (!($p instanceof WP_Post)) {
return '';
}
$meta = function_exists('jio_get_pay_meta') ? jio_get_pay_meta($p) : null;
if (!is_array($meta)) {
return '';
}
$pay_type = (string) ($meta['pay_type'] ?? 'no');
if ($pay_type === '' || $pay_type === 'no') {
return '';
}
$pay_modo = (($meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0';
$pay_limit = (int) ($meta['pay_limit'] ?? 0);
$type_labels = function_exists('jio_get_pay_types') ? jio_get_pay_types() : [];
$type_name = $type_labels[$pay_type] ?? __('付费内容', 'jio');
// VIP-only / purchase limit (legacy pay_limit).
if ($pay_type === 'vip' || $pay_limit > 0) {
return __('会员专属', 'jio');
}
$priced = function_exists('jio_get_user_pay_price')
? jio_get_user_pay_price($p)
: [
'amount' => $pay_modo === 'points' ? (int) ($meta['points_price'] ?? 0) : (string) ($meta['price'] ?? '0.00'),
'modo' => $pay_modo,
];
$price = $priced['amount'] ?? ($pay_modo === 'points' ? 0 : '0.00');
$pay_modo = (($priced['modo'] ?? $pay_modo) === 'points') ? 'points' : '0';
$price_minor = function_exists('jio_asset_price_minor') ? jio_asset_price_minor($price, $pay_modo) : 0;
// Free paid-type (price 0).
if ($price_minor <= 0) {
if ($pay_type === 'download') {
return __('免费资源', 'jio');
}
return str_replace(__('付费', 'jio'), __('免费', 'jio'), (string) $type_name);
}
if ($pay_modo === 'points') {
$currency = class_exists('\Jio\Settings\Settings') ? \Jio\Settings\Settings::get_currency_name() : __('积分', 'jio');
$amount = function_exists('jio_resource_price_amount')
? jio_resource_price_amount($price_minor)
: (string) (int) $price;
return sprintf('%s %s%s', $type_name, $amount, $currency);
}
$symbol = '¥';
if (class_exists('\Jio\Settings\Settings')) {
$paid = \Jio\Settings\Settings::get_paid_content_settings();
$symbol = (string) ($paid['display']['currency_symbol'] ?? '¥');
}
$amount = function_exists('jio_format_price')
? jio_format_price($price)
: (string) $price;
return sprintf('%s %s%s', $type_name, $symbol, $amount);
}
}
if (!function_exists('jio_resource_pay_type_badge')) {
/**
* 根据付费类型返回徽章 HTML。
*
* @param string $pay_type
* @return string HTML 或空字符串
*/
function jio_resource_pay_type_badge(string $pay_type): string {
$badges = [
'reading' => ['label' => __('付费阅读', 'jio'), 'color' => '#EF4444', 'icon' => 'fa-lock'],
'download'=> ['label' => __('付费下载', 'jio'), 'color' => '#F97316', 'icon' => 'fa-download'],
'gallery' => ['label' => __('付费图库', 'jio'), 'color' => '#10B981', 'icon' => 'fa-image'],
'video' => ['label' => __('付费视频', 'jio'), 'color' => '#8B5CF6', 'icon' => 'fa-play-circle'],
'vip' => ['label' => __('VIP 专属', 'jio'), 'color' => '#3B82F6', 'icon' => 'fa-certificate'],
];
if ($pay_type === 'download' || !isset($badges[$pay_type])) {
return '';
}
$b = $badges[$pay_type];
return sprintf(
'<span class="resource-pay-type-badge" style="background:%s"><i class="fa %s"></i> %s</span>',
esc_attr($b['color']),
esc_attr($b['icon']),
esc_html($b['label'])
);
}
}
if (!function_exists('jio_resource_preview_images')) {
/**
* Collect preview images for resource cards and archive thumbnails.
*
* Priority: curated featured-slide images -> featured image -> gallery/content images.
*
* @param int|WP_Post|null $post
* @param int $limit
* @return string[]
*/
function jio_resource_preview_images($post = null, int $limit = 4): array {
$p = get_post($post);
if (!($p instanceof WP_Post) || !function_exists('jio_is_resource_post') || !jio_is_resource_post($p)) {
return [];
}
$limit = max(1, min(8, $limit));
$images = [];
if (class_exists('\Jio\Core\PostMetaBox')) {
$featured_slide = (string) \Jio\Core\PostMetaBox::get_meta_value($p->ID, 'featured_slide', '');
if ($featured_slide !== '') {
$cover_ids = array_filter(array_map('absint', preg_split('/[\s,]+/', $featured_slide) ?: []));
foreach ($cover_ids as $attachment_id) {
$url = (string) wp_get_attachment_image_url($attachment_id, 'medium_large');
if ($url !== '') {
$images[] = esc_url_raw($url);
}
}
}
}
if (has_post_thumbnail($p)) {
$featured = (string) get_the_post_thumbnail_url($p, 'medium_large');
if ($featured !== '') {
$images[] = esc_url_raw($featured);
}
}
if (function_exists('jio_get_post_gallery_images')) {
$images = array_merge($images, jio_get_post_gallery_images($p->ID, $limit));
}
if (function_exists('jio_get_first_content_image_url')) {
$content_image = (string) jio_get_first_content_image_url($p->ID);
if ($content_image !== '') {
$images[] = esc_url_raw($content_image);
}
}
$images = array_values(array_unique(array_filter($images, static function ($url): bool {
return is_string($url) && $url !== '';
})));
return array_slice($images, 0, $limit);
}
}
if (!function_exists('jio_resource_primary_image_url')) {
/**
* Primary preview image for a resource post.
*
* @param int|WP_Post|null $post
* @return string
*/
function jio_resource_primary_image_url($post = null): string {
$images = jio_resource_preview_images($post, 1);
return $images[0] ?? '';
}
}
if (!function_exists('jio_resource_meta_strip')) {
/**
* 卡片用的紧凑元数据条 [v1.0 · 210MB · ↓1234]。
*
* @param array $meta jio_get_resource_meta 返回值
* @return array 字符串数组
*/
function jio_resource_meta_strip(array $meta): array {
$parts = [];
if ($meta['version'] !== '') {
$parts[] = 'v' . $meta['version'];
}
if ($meta['size'] !== '') {
$parts[] = $meta['size'];
}
if ($meta['download_count'] > 0) {
$parts[] = '↓ ' . number_format_i18n($meta['download_count']);
}
return $parts;
}
}
/**
* 是否命中下载积分免扣策略。
*/
if (!function_exists('jio_is_download_credit_exempt_user')) {
function jio_is_download_credit_exempt_user(int $user_id = 0): bool {
if ($user_id <= 0 || !class_exists('\Jio\Settings\Settings')) {
return false;
}
$paid_settings = \Jio\Settings\Settings::get_paid_content_settings();
if (empty($paid_settings['vip_free_download']) || empty($paid_settings['vip_exempt_roles'])) {
return false;
}
$user = get_userdata($user_id);
if (!$user || empty($user->roles) || !is_array($user->roles)) {
return false;
}
return !empty(array_intersect($user->roles, (array) $paid_settings['vip_exempt_roles']));
}
}
if (!function_exists('jio_can_download')) {
/**
* 是否可下载。
*
* 单一合同:委托 \Jio\Content\Visibility(收银台订单解锁 / VIP / 登录 / 日限额)。
* 不再用 cms_features.download_credit 做「按次扣积分」门禁。
*
* @param int|WP_Post|null $post
* @param int $user_id 0 表示当前用户
* @return true|WP_Error
*/
function jio_can_download($post = null, int $user_id = 0) {
if (class_exists('\Jio\Content\Visibility')) {
return \Jio\Content\Visibility::can_download_resource($post, $user_id);
}
$p = get_post($post);
if (!($p instanceof WP_Post)) {
return new WP_Error('jio_not_resource', __('该内容不是可下载资源。', 'jio'));
}
$uid = $user_id > 0 ? $user_id : get_current_user_id();
if (!function_exists('jio_user_can') || !jio_user_can('resource_download', $uid, (int) $p->ID)) {
return new WP_Error('jio_need_login', __('请先登录后再下载。', 'jio'), [
'status' => 401,
'login_url' => wp_login_url(get_permalink($p)),
]);
}
// Without Content_Visibility, only login gate remains.
return true;
}
}
if (!function_exists('jio_resource_download_cost')) {
/**
* 下载侧展示用「未解锁积分价」。
*
* 现金 pay_modo:永远 0(走订单解锁,不按次扣积分)。
* 积分 pay_modo:未购时返回积分价(用于 UI);已购订单后 0。
* 实际扣费只在收银台创建 resource 订单时发生,下载 token 不再扣积分。
*/
function jio_resource_download_cost($post = null): int {
$p = get_post($post);
$uid = function_exists('get_current_user_id') ? (int) get_current_user_id() : 0;
// Paid order → unlocked.
if ($p instanceof WP_Post && $uid > 0 && class_exists('\Jio\Payment\Order')) {
if (\Jio\Payment\Order::get_instance()->has_paid_access(
$uid,
\Jio\Core\DomainModel::ORDER_PRODUCT_RESOURCE,
(int) $p->ID
)) {
return 0;
}
}
if ($p instanceof WP_Post && $uid <= 0 && function_exists('jio_guest_has_paid_access') && jio_guest_has_paid_access((int) $p->ID)) {
return 0;
}
$priced = function_exists('jio_get_user_pay_price')
? jio_get_user_pay_price($post, $uid)
: null;
$pay_modo = is_array($priced) && (($priced['modo'] ?? '0') === 'points') ? 'points' : '0';
if (!is_array($priced) && function_exists('jio_get_pay_meta')) {
$pay = jio_get_pay_meta($post);
$pay_modo = (($pay['pay_modo'] ?? '0') === 'points') ? 'points' : '0';
}
// Cash mode: order unlock only.
if ($pay_modo !== 'points') {
return 0;
}
if ($uid > 0 && function_exists('jio_is_download_credit_exempt_user') && jio_is_download_credit_exempt_user($uid)) {
return 0;
}
if (is_array($priced)) {
return is_int($priced['amount'] ?? null) ? max(0, (int) $priced['amount']) : 0;
}
$meta = function_exists('jio_get_pay_meta') ? jio_get_pay_meta($post) : [];
return max(0, (int) ($meta['points_price'] ?? 0));
}
}
if (!function_exists('jio_resource_meta_query')) {
/**
* 「是资源」WP_Query meta_query 片段:post + _jio_is_resource = 1。
*
* @return array
*/
function jio_resource_meta_query(): array {
return [
'key' => '_jio_is_resource',
'value' => '1',
'compare' => '=',
];
}
}
if (!function_exists('jio_resource_archive_url')) {
/**
* 资源列表页 URL(/resources/)。
*/
function jio_resource_archive_url(): string {
return home_url('/resources/');
}
}
if (!function_exists('jio_is_resource_archive')) {
/**
* 当前请求是否为资源列表(/resources 虚拟归档)。
*/
function jio_is_resource_archive(): bool {
return (bool) get_query_var('jio_is_resource_archive');
}
}
if (!function_exists('jio_detect_cloud_service')) {
/**
* 从下载链接自动识别云盘服务商。
*
* @param string $url 下载链接
* @return array { key:string, name:string, color:string }
*/
function jio_detect_cloud_service(string $url): array {
$url_lower = strtolower($url);
$services = [
'baidu' => ['name' => '百度网盘', 'color' => '#1578f8', 'pattern' => ['pan.baidu.com', 'yun.baidu.com']],
'lanzou' => ['name' => '蓝奏云', 'color' => '#f37526', 'pattern' => ['lanzouf.com', 'lanzoui.com', 'lanzoux.com', 'lanzouw.com', 'lanzoup.com', 'lanzout.com', 'lanzou']],
'aliyun' => ['name' => '阿里云盘', 'color' => '#6666ff', 'pattern' => ['alipan.com', 'aliyundrive.com']],
'weiyun' => ['name' => '微云', 'color' => '#4facfe', 'pattern' => ['share.weiyun.com', 'weiyun.com']],
'onedrive' => ['name' => 'OneDrive', 'color' => '#0078d4', 'pattern' => ['1drv.ms', 'onedrive.live.com']],
'tianyi' => ['name' => '天翼云盘', 'color' => '#0099ff', 'pattern' => ['cloud.189.cn']],
'123pan' => ['name' => '123云盘', 'color' => '#2b7bff', 'pattern' => ['123pan.com', '123684.com']],
'quark' => ['name' => '夸克网盘', 'color' => '#6a5acd', 'pattern' => ['pan.quark.cn']],
'xunlei' => ['name' => '迅雷云盘', 'color' => '#00a4ff', 'pattern' => ['pan.xunlei.com']],
'mega' => ['name' => 'MEGA', 'color' => '#d92323', 'pattern' => ['mega.nz', 'mega.co.nz']],
'gofile' => ['name' => 'GoFile', 'color' => '#4caf50', 'pattern' => ['gofile.io']],
'mediafire' => ['name' => 'MediaFire', 'color' => '#1294f2', 'pattern' => ['mediafire.com']],
'github' => ['name' => 'GitHub', 'color' => '#333333', 'pattern' => ['github.com', 'raw.githubusercontent.com']],
];
foreach ($services as $key => $svc) {
foreach ($svc['pattern'] as $p) {
if (strpos($url_lower, $p) !== false) {
return ['key' => $key, 'name' => $svc['name'], 'color' => $svc['color']];
}
}
}
return ['key' => 'other', 'name' => __('下载', 'jio'), 'color' => '#6b7280'];
}
}
if (!function_exists('jio_resource_meta_icon')) {
/**
* 根据元信息字段返回对应的 Font Awesome 图标类。
*/
function jio_resource_meta_icon(string $field): string {
$icons = [
'version' => 'fa fas fa-code-branch',
'size' => 'fa fas fa-hdd',
'compat' => 'fa fas fa-laptop',
'license' => 'fa fas fa-shield-alt',
'demo_url' => 'fa fas fa-external-link-alt',
'download' => 'fa fas fa-download',
'views' => 'fa fas fa-eye',
];
return $icons[$field] ?? 'fa fas fa-info-circle';
}
}