Files
kate522andClaude Opus 5 427968a721 chore(branding): remove leftover upstream theme identifiers
The theme was renamed Zibll/子比 → AKSRT → Jio, but upstream branding
survived the sweeps in CSS classes, the SVG sprite prefix, a persisted
widget field ID, JS events, admin Vue class names, test infrastructure
and docblocks.

Renames:
- zib-widget / zib-widget-wrap / zib-slider → jio-widget-box /
  jio-widget-box-wrap / jio-slider-box (jio-widget is taken by the modern
  widget shell, jio-box-* by the card primitives)
- zib-partners-scroll + zps-* → jio-partners-scroll + jps-*
- zib-combo-info-card + zci-* → jio-combo-info-card + jci-*
- zibsvg- → jiosvg-, including the exported picker helpers and the
  fa-zibsvg- family-prefix guard
- zibpay_type → pay_type; the dual-read fallback in PostQuery collapses
  to a single key
- [zibajax="submit"] dropped (no PHP emitter); zib_ajax.success →
  jio_ajax.success
- aks-* admin Vue classes → jio-*
- zib_palette() → palette()

User-facing vendor traces are gone: the floating "more" button default no
longer ships a zibll.com link or 子比主题 marketing copy, the notice
widget ships no preset promo entries, and the four 官网教程 links are
removed from the post-list admin schema.

Test infrastructure renamed to neutral names (docker-compose.reference.yml,
Caddyfile, article-baseline.json, modern-widgets-contract.test.cjs) with
their DB/volume/env/slug identifiers following.

Kept intentionally, documented in tests/fixtures/README.md: the golden
fixture reference fingerprint (a SHA-256 record of an external directory,
read by validate-widget-golden / generate-widget-golden-fixture /
audit-widget-system), the doesNotMatch guards that prove the old tokens are
gone, and the reference theme's own meta key in the visual fixtures.

No backward-compat or data migration: saved widget configs holding old
icon keys or the old field ID silently lose them, per the project's
rewrite-over-compatibility rule.

Verified: 132/132 node contract tests, php tests/widget-system/run.php
(146 assertions), audit-admin-contracts, audit-psr4-paths and
validate-widget-golden all green; tracked bundles regenerated and in sync.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-11-02 00:06:54 +08:00

117 lines
5.0 KiB
PHP

<?php
/**
* 右上角待支付订单浮窗。
*
* @package Jio
*/
defined('ABSPATH') || exit;
if (!function_exists('jio_get_wait_pay_float_orders')) :
/**
* 当前登录用户的待支付订单(最多 5 条,剩余支付时间 ≥ 3 分钟)。
*
* @return array<int,array{view:array<string,mixed>,expires:int}>
*/
function jio_get_wait_pay_float_orders(int $user_id): array {
if ($user_id <= 0 || !class_exists('\Jio\Payment\OrderRepository') || !class_exists('\Jio\Payment\UserOrders')) {
return [];
}
$rows = \Jio\Payment\OrderRepository::get_instance()->get_user_orders($user_id, [
'status' => \Jio\Payment\Order::STATUS_PENDING,
'limit' => 5,
]);
$min_expires = time() + 3 * MINUTE_IN_SECONDS;
$views = \Jio\Payment\UserOrders::get_instance();
$orders = [];
foreach ($rows as $row) {
$expires_at = trim((string) ($row['expires_at'] ?? ''));
$expires = $expires_at !== '' ? strtotime($expires_at . ' UTC') : false;
if (!$expires || $expires < $min_expires) {
continue;
}
$orders[] = ['view' => $views->decorate_order_view($row, false), 'expires' => (int) $expires];
}
return $orders;
}
endif;
if (!function_exists('jio_get_wait_pay_order_thumb')) :
/**
* 订单缩略图:商品图优先,否则按订单类型回退彩色图标。
*
* @param array<string,mixed> $view
*/
function jio_get_wait_pay_order_thumb(array $view): string {
$image = (string) ($view['image'] ?? '');
if ($image !== '') {
$img = '<img class="radius8 fit-cover" src="' . esc_url($image) . '" alt="' . esc_attr((string) ($view['product_name'] ?? 'product-image')) . '">';
} else {
$icons = [
'vip' => ['vip_1', 'muted-box fit-cover'],
'recharge' => ['money-color-2', 'muted-box fit-cover c-blue-2'],
'points' => ['points-color', 'muted-box fit-cover c-yellow-2'],
];
[$icon, $class] = $icons[(string) ($view['product_type'] ?? '')] ?? ['order-color', 'fit-cover muted-box'];
$img = '<svg class="icon ' . esc_attr($class) . '" aria-hidden="true"><use xlink:href="#icon-' . esc_attr($icon) . '"></use></svg>';
}
return '<div class="order-thumb mr6">' . $img . '</div>';
}
endif;
if (!function_exists('jio_get_wait_pay_float_html')) :
function jio_get_wait_pay_float_html(): string {
$orders = jio_get_wait_pay_float_orders(get_current_user_id());
if (!$orders) {
return '';
}
$pay_url = function_exists('jio_get_user_center_url') ? jio_get_user_center_url('orders') : home_url('/');
$lists = '';
$countdown = '';
foreach ($orders as $order) {
$view = $order['view'];
$countdown = gmdate('c', $order['expires']);
$amount = (string) ($view['amount'] ?? '0');
$price = !empty($view['is_points']) ? (string) (int) $amount : (string) (float) round((float) $amount, 2);
$lists .= '<a class="flex list-mt10 order-item nowave" href="' . esc_url($pay_url) . '">'
. jio_get_wait_pay_order_thumb($view)
. '<div class="flex1">'
. '<div class="flex ac jsb">'
. '<div class="order-title text-ellipsis mr6 em09">' . esc_html((string) ($view['product_name'] ?? '')) . '</div>'
. '<div class="flex shrink0 abl c-red"><span class="pay-mark px12">' . esc_html((string) ($view['currency_symbol'] ?? '¥')) . '</span>' . esc_html($price) . '</div>'
. '</div>'
. '<div class="flex jsb ac mt6">'
. '<span class="c-yellow px12 countdown-box" int-second="1" max-unit="minute" data-countdown="' . esc_attr($countdown) . '" data-over-text="' . esc_attr__('交易已关闭', 'jio') . '"><span class="minute"></span>:<span class="second"></span></span>'
. '<span class="ml10 but c-red px12 p2-10">' . esc_html__('立即支付', 'jio') . '</span>'
. '</div>'
. '</div>'
. '</a>';
}
// 按钮倒计时取最后一条订单(与参考主题循环后的 $time_remaining 一致)。
return '<div class="float-right round position-top float-right-wait-pay">'
. '<span style="--this-bg:rgba(255, 82, 128, 0.9);--this-color:#ffffff;" class="float-btn wait-pay-btn hover-show nowave" data-placement="left">'
. '<svg class="icon em12" aria-hidden="true"><use xlink:href="#icon-wallet"></use></svg>'
. '<text style="font-size: 10px;">' . esc_html__('待支付', 'jio') . '</text>'
. '<text class="countdown-box" int-second="1" data-countdown="' . esc_attr($countdown) . '" data-over-text="00:00" max-unit="minute"><span class="minute"></span>:<span class="second"></span></text>'
. '<div style="width:240px;" class="hover-show-con dropdown-menu">' . $lists . '</div>'
. '</span></div>';
}
endif;
if (!function_exists('jio_wait_pay_float_window')) :
function jio_wait_pay_float_window(): void {
if (!is_user_logged_in() || !class_exists('\Jio\Settings\Settings')) {
return;
}
$order_settings = \Jio\Settings\Settings::get_order_settings();
if (empty($order_settings['wait_float'])) {
return;
}
echo jio_get_wait_pay_float_html(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- 各片段已转义
}
add_action('wp_footer', 'jio_wait_pay_float_window');
endif;