diff --git a/assets/css/routes/orders.css b/assets/css/routes/orders.css index 70449223..5a2ac9ad 100644 --- a/assets/css/routes/orders.css +++ b/assets/css/routes/orders.css @@ -498,3 +498,23 @@ html.dark .aksrt-orders-page__filter-chip.is-active { grid-template-columns: 1fr; } } + +/* User-center embedded orders panel */ +.uc-orders-panel.aksrt-orders-page { + padding: 0; +} +.uc-orders-panel .aksrt-orders-page__tab-badge { + display: inline-block; + min-width: 1.1em; + margin-left: 4px; + padding: 0 5px; + border-radius: 999px; + background: var(--color-danger, #e5484d); + color: #fff; + font-size: 11px; + line-height: 1.4; + vertical-align: middle; +} +.uc-orders-panel__head { + gap: 12px; +} diff --git a/inc/helpers/aksrt-user-center.php b/inc/helpers/aksrt-user-center.php index 973cc8e7..01dc099e 100644 --- a/inc/helpers/aksrt-user-center.php +++ b/inc/helpers/aksrt-user-center.php @@ -129,6 +129,7 @@ if (!function_exists('aksrt_get_user_center_tab_url')) { $url = remove_query_arg([ 'tab', 'posts_page', 'comments_page', 'favorites_page', 'credits_page', 'post_status', 'saved', 'profile_error', + 'order_tab', 'otab', 'order_status', 'order_page', 'order_type', 'section', ], aksrt_get_user_center_url()); return add_query_arg('tab', sanitize_key($tab), $url); @@ -170,6 +171,7 @@ if (!function_exists('aksrt_capture_user_center_view')) { 'favorites' => 'favorites', 'credits' => 'credits', 'vip' => 'vip', + 'orders' => 'orders', 'settings' => 'settings', 'header' => 'header', 'sidebar' => 'sidebar', @@ -194,7 +196,7 @@ if (!function_exists('aksrt_capture_user_center_panel')) { * Capture a built-in or registered user-center panel body. */ function aksrt_capture_user_center_panel(string $tab_key, array $tab, array $context): string { - $built_in_tabs = ['profile', 'posts', 'comments', 'favorites', 'credits', 'vip', 'settings']; + $built_in_tabs = ['profile', 'posts', 'comments', 'favorites', 'credits', 'vip', 'orders', 'settings']; if (in_array($tab_key, $built_in_tabs, true)) { return aksrt_capture_user_center_view($tab_key, $context); } @@ -501,7 +503,9 @@ if (!function_exists('aksrt_get_user_center_render_context')) { 'svg_empty_post' => $svgs['post'], 'svg_empty_comment' => $svgs['comment'], 'svg_empty_favorite' => $svgs['favorite'], - 'orders_url' => function_exists('aksrt_get_orders_page_url') ? aksrt_get_orders_page_url() : '', + 'orders_url' => function_exists('aksrt_get_user_center_tab_url') + ? aksrt_get_user_center_tab_url('orders') + : (function_exists('aksrt_get_orders_page_url') ? aksrt_get_orders_page_url() : ''), 'show_vip' => !empty($vip_settings['enabled']), 'show_credit_tabs' => $show_credit_tabs, 'affiliate_enabled' => $show_credit_tabs && !empty($affiliate_settings['enabled']), diff --git a/inc/helpers/user-center-renderers/profile-orders.php b/inc/helpers/user-center-renderers/profile-orders.php new file mode 100644 index 00000000..4b1d5698 --- /dev/null +++ b/inc/helpers/user-center-renderers/profile-orders.php @@ -0,0 +1,494 @@ +' . esc_html__('请先登录', 'aksrt') . ''; + return; +} + +$per_page = 20; +$paged = max(1, (int) ($_GET['order_page'] ?? 1)); +$tab = sanitize_key((string) ($_GET['order_tab'] ?? ($_GET['otab'] ?? ''))); +$status = sanitize_key((string) ($_GET['order_status'] ?? '')); +$type_filter = sanitize_key((string) ($_GET['order_type'] ?? '')); +$section = sanitize_key((string) ($_GET['section'] ?? '')); + +// Accept legacy standalone-page tab keys. +if ($tab === '' && isset($_GET['tab']) && sanitize_key((string) $_GET['tab']) !== 'orders') { + // When rendered as standalone legacy include, outer tab may be status. + $maybe = sanitize_key((string) $_GET['tab']); + if (in_array($maybe, ['pending', 'shipped', 'received', 'review', 'after', 'wait-pay', 'wait-shipped', 'wait-receive', 'wait-evaluate', 'after-sale', 'all'], true)) { + $tab = $maybe; + } +} + +$tab_aliases = [ + 'wait-pay' => 'pending', + 'wait-shipped' => 'shipped', + 'wait-receive' => 'shipped', + 'wait-evaluate' => 'review', + 'after-sale' => 'after', + 'all' => '', +]; +if (isset($tab_aliases[$tab])) { + $tab = $tab_aliases[$tab]; +} + +$tab_status_map = [ + 'pending' => \AKSRT\Payment\Order::STATUS_PENDING, + 'shipped' => \AKSRT\Payment\Order::STATUS_DELIVERED, + 'received' => \AKSRT\Payment\Order::STATUS_COMPLETED, + 'review' => \AKSRT\Payment\Order::STATUS_PENDING_REVIEW, + 'after' => \AKSRT\Payment\Order::STATUS_REFUNDING, +]; +if ($tab !== '' && isset($tab_status_map[$tab])) { + $status = $tab_status_map[$tab]; +} + +$orders_view = function_exists('aksrt_get_orders_page_view') + ? aksrt_get_orders_page_view($user_id, $paged, $per_page, $status, $type_filter) + : ['items' => [], 'total' => 0, 'total_pages' => 1, 'page' => 1, 'stats' => [], 'product_types' => []]; + +$orders = (array) ($orders_view['items'] ?? []); +$total_pages = max(1, (int) ($orders_view['total_pages'] ?? 1)); +$stats = is_array($orders_view['stats'] ?? null) ? $orders_view['stats'] : []; +$type_options = is_array($orders_view['product_types'] ?? null) ? $orders_view['product_types'] : []; +if ($type_options === [] && class_exists('\AKSRT\Core\DomainModel')) { + $type_options = array_merge(['' => __('全部类型', 'aksrt')], \AKSRT\Core\DomainModel::order_product_type_labels()); +} + +$shop = class_exists('\AKSRT\Shop\Shop') ? \AKSRT\Shop\Shop::get_instance() : null; + +$tabs = [ + '' => __('全部', 'aksrt'), + 'pending' => __('待支付', 'aksrt'), + 'shipped' => __('待收货', 'aksrt'), + 'review' => __('待评价', 'aksrt'), + 'after' => __('售后', 'aksrt'), +]; + +$base_query = ['tab' => 'orders']; +if ($type_filter !== '') { + $base_query['order_type'] = $type_filter; +} +if ($section !== '') { + $base_query['section'] = $section; +} + +/** + * Build URL staying inside user center orders tab. + * + * @param array $args + */ +$orders_url = static function (array $args = []) use ($base_query): string { + $q = array_merge($base_query, $args); + $base = function_exists('aksrt_get_user_center_url') + ? aksrt_get_user_center_url('orders') + : home_url('/profile/'); + $url = remove_query_arg( + ['order_tab', 'otab', 'order_status', 'order_page', 'order_type', 'section', 'tab'], + $base + ); + // Always keep tab=orders. + $q['tab'] = 'orders'; + // Map status filter to order_tab (avoid clashing with UC tab=). + if (isset($q['tab_status'])) { + $q['order_tab'] = $q['tab_status']; + unset($q['tab_status']); + } + foreach ($q as $k => $v) { + if ($v === null || $v === '') { + unset($q[$k]); + } + } + return add_query_arg($q, $url); +}; + +$pending_count = (int) ($stats['pending'] ?? 0); +?> +
+
+
+
+
+
+ + + + + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + + + +
+ + +
+ $type_label) : + $is_type_active = (string) $type_key === (string) $type_filter; + $type_args = [ + 'order_type' => $type_key !== '' ? $type_key : null, + 'order_tab' => $tab !== '' ? $tab : null, + 'order_page' => 1, + ]; + $type_url = $orders_url($type_args); + if ($type_key === '') { + $type_url = remove_query_arg('order_type', $type_url); + } + ?> + + + + +
+ + + +
+ $tab_label) : + $is_active = $tab === $tab_key; + $tab_url = $tab_key !== '' + ? $orders_url(['order_tab' => $tab_key, 'order_page' => 1]) + : remove_query_arg(['order_tab', 'otab', 'order_status', 'order_page'], $orders_url()); + ?> + + + 0) : ?> + + + + +
+ + + +
+ +
+
+ + + + +
+ +
+ + +
+ + + + + +
+ + + + +
+
+ + × +
+
+ + +
+ + + +
+ +
+
+ +
+
+ +
+ +
+ + + 0 && !$is_points) : ?> + () + +
+ + +
+

+ +

+ +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + 1) : ?> +
+ $tab !== '' ? $tab : null, + 'order_page' => $i, + ], static fn($v) => $v !== null && $v !== '')); + ?> + + + + + + +
+ + +
+ +

+
+ + + + + + + + + get_user_tickets($user_id, 50); + ?> +
+

+ +
+ +
+
+ # + + +
+
+ + · +
+
+ +
    + +
  1. + + +
  2. + +
+ +
+ + + + + + +
+
+ +
+ +

+ +
+ + + +
+

+
+

+
+
+ + + get_user_favorites($user_id); + ?> +
+

+ + + +

+ +
+ +
diff --git a/inc/helpers/user-center-renderers/sidebar-commerce.php b/inc/helpers/user-center-renderers/sidebar-commerce.php index a0b9db0a..a6ab3353 100644 --- a/inc/helpers/user-center-renderers/sidebar-commerce.php +++ b/inc/helpers/user-center-renderers/sidebar-commerce.php @@ -52,8 +52,14 @@ if (empty($orders_url) && empty($show_vip) && empty($show_credit_tabs) && empty(
- - + + diff --git a/inc/modules/user-parts/urls.php b/inc/modules/user-parts/urls.php index c36916bb..8cff7ff6 100644 --- a/inc/modules/user-parts/urls.php +++ b/inc/modules/user-parts/urls.php @@ -73,23 +73,17 @@ endif; if (!function_exists('aksrt_get_orders_page_url')) : /** - * 订单中心页面 URL(模板 templates/pages/page-orders.php)。 - * 优先已绑定页面;否则回退固定 rewrite /orders/(template-registry + routing)。 + * 订单中心 URL — 嵌在用户中心 tab=orders(zibll 同构)。 + * 旧 /orders/ 页面模板会 302 到此地址。 */ function aksrt_get_orders_page_url(): string { - $url = function_exists('aksrt_get_page_url_by_template') - ? aksrt_get_page_url_by_template('templates/pages/page-orders.php') - : ''; - if ($url !== '') { - return $url; + if (function_exists('aksrt_get_user_center_tab_url')) { + return aksrt_get_user_center_tab_url('orders'); } - if (function_exists('aksrt_get_template_url')) { - $boot = aksrt_get_template_url('orders'); - if (is_string($boot) && $boot !== '' && $boot !== home_url('/')) { - return $boot; - } + if (function_exists('aksrt_get_user_center_url')) { + return aksrt_get_user_center_url('orders'); } - return home_url('/orders/'); + return home_url('/profile/?tab=orders'); } endif; diff --git a/src/AKSRT/Core/ScriptsPart1b.php b/src/AKSRT/Core/ScriptsPart1b.php index 74f3ae88..2b59ac4d 100644 --- a/src/AKSRT/Core/ScriptsPart1b.php +++ b/src/AKSRT/Core/ScriptsPart1b.php @@ -666,8 +666,15 @@ $hmb_js = get_template_directory() . '/assets/js/header-newadd.js'; } } - // 订单中心页 - if (is_page_template('templates/pages/page-orders.php') || (bool) get_query_var('aksrt_orders')) { + // 订单中心:独立页 / 虚拟 rewrite / 用户中心 tab=orders + $is_orders_surface = is_page_template('templates/pages/page-orders.php') + || (bool) get_query_var('aksrt_orders') + || ( + (function_exists('aksrt_is_user_center_page') && aksrt_is_user_center_page()) + && isset($_GET['tab']) + && sanitize_key((string) wp_unslash($_GET['tab'])) === 'orders' + ); + if ($is_orders_surface) { wp_enqueue_style( 'aksrt-orders', $base_uri . '/assets/css/routes/orders.css', diff --git a/src/AKSRT/User/Center.php b/src/AKSRT/User/Center.php index e86cd5c9..c20216f8 100644 --- a/src/AKSRT/User/Center.php +++ b/src/AKSRT/User/Center.php @@ -71,6 +71,12 @@ class Center { 'priority' => 45, 'type' => 'panel', ], + 'orders' => [ + 'label' => __('我的订单', 'aksrt'), + 'icon' => 'receipt', + 'priority' => 48, + 'type' => 'panel', + ], 'credits' => [ 'label' => class_exists('\AKSRT\Settings\Settings') ? sprintf(__('我的%s', 'aksrt'), \AKSRT\Settings\Settings::get_currency_name()) @@ -104,7 +110,7 @@ class Center { $vip_on = class_exists('\AKSRT\Settings\Settings') && !empty(\AKSRT\Settings\Settings::get_payment_vip_settings()['enabled']); - // Follow configured order; always auto-include VIP/credits when feature on. + // Follow configured order; always auto-include VIP/orders/credits when feature on. $order = $configured; if ($vip_on && !in_array('vip', $order, true)) { $insert_at = count($order); @@ -117,6 +123,24 @@ class Center { } array_splice($order, $insert_at, 0, ['vip']); } + // Orders panel: always available when payment/shop stack exists (UserOrders or Shop). + $orders_on = class_exists('\AKSRT\Payment\UserOrders') + || class_exists('\AKSRT\Payment\Order') + || class_exists('\AKSRT\Shop\Shop'); + if ($orders_on && !in_array('orders', $order, true)) { + $insert_at = count($order); + foreach (['vip', 'credits', 'favorites'] as $anchor) { + $idx = array_search($anchor, $order, true); + if ($idx !== false) { + $insert_at = (int) $idx + ($anchor === 'vip' ? 1 : 0); + if ($anchor !== 'vip') { + $insert_at = (int) $idx + 1; + } + break; + } + } + array_splice($order, $insert_at, 0, ['orders']); + } if (($credits_on || $balance_on) && !in_array('credits', $order, true)) { $order[] = 'credits'; } @@ -134,6 +158,9 @@ class Center { if ($key === 'vip' && !$vip_on) { continue; } + if ($key === 'orders' && !$orders_on) { + continue; + } $panel = $definitions[$key]; if ($key === 'credits' && $balance_on) { $panel['label'] = __('我的资产', 'aksrt'); diff --git a/templates/pages/page-orders.php b/templates/pages/page-orders.php index 9be4d6c9..d1724bea 100644 --- a/templates/pages/page-orders.php +++ b/templates/pages/page-orders.php @@ -3,459 +3,41 @@ * Template Name: AKSRT - Orders * Template Post Type: page * - * My Orders (权益与消费): multi product_type list + shop fulfillment actions. + * Legacy standalone orders URL — redirects into user center tab (zibll-style). + * Kept as template slug so old page assignments resolve; content lives in UC. * * @package AKSRT */ defined('ABSPATH') || exit; -get_header(); - if (!is_user_logged_in()) { - $login_url = function_exists('aksrt_get_login_url') ? aksrt_get_login_url() : wp_login_url(get_permalink()); - wp_safe_redirect($login_url); - exit; + $login_url = function_exists('aksrt_get_login_url') ? aksrt_get_login_url() : wp_login_url(home_url('/profile/')); + wp_safe_redirect($login_url); + exit; } -$user_id = get_current_user_id(); -$per_page = 20; -$paged = max(1, (int) ($_GET['order_page'] ?? 1)); -$tab = sanitize_key((string) ($_GET['tab'] ?? '')); -$status = sanitize_key((string) ($_GET['order_status'] ?? '')); -$type_filter = sanitize_key((string) ($_GET['order_type'] ?? '')); -$section = sanitize_key((string) ($_GET['section'] ?? '')); +$target = function_exists('aksrt_get_user_center_url') + ? aksrt_get_user_center_url('orders') + : home_url('/profile/?tab=orders'); -$tab_status_map = [ - 'pending' => \AKSRT\Payment\Order::STATUS_PENDING, - 'shipped' => \AKSRT\Payment\Order::STATUS_DELIVERED, - 'received' => \AKSRT\Payment\Order::STATUS_COMPLETED, - 'review' => \AKSRT\Payment\Order::STATUS_PENDING_REVIEW, - 'after' => \AKSRT\Payment\Order::STATUS_REFUNDING, -]; -if ($tab !== '' && isset($tab_status_map[$tab])) { - $status = $tab_status_map[$tab]; +// Preserve filter/query from standalone page. +$keep = []; +foreach (['order_tab', 'otab', 'order_status', 'order_page', 'order_type', 'section'] as $key) { + if (isset($_GET[$key]) && (string) wp_unslash($_GET[$key]) !== '') { + $keep[$key] = sanitize_text_field(wp_unslash((string) $_GET[$key])); + } +} +// Legacy ?tab=pending on standalone page → order_tab. +if (isset($_GET['tab'])) { + $legacy_tab = sanitize_key((string) wp_unslash($_GET['tab'])); + if ($legacy_tab !== '' && $legacy_tab !== 'orders' && !isset($keep['order_tab'])) { + $keep['order_tab'] = $legacy_tab; + } +} +if ($keep !== []) { + $target = add_query_arg($keep, $target); } -$orders_view = function_exists('aksrt_get_orders_page_view') - ? aksrt_get_orders_page_view($user_id, $paged, $per_page, $status, $type_filter) - : ['items' => [], 'total' => 0, 'total_pages' => 1, 'page' => 1, 'stats' => [], 'product_types' => []]; - -$orders = (array) ($orders_view['items'] ?? []); -$total_pages = max(1, (int) ($orders_view['total_pages'] ?? 1)); -$stats = is_array($orders_view['stats'] ?? null) ? $orders_view['stats'] : []; -$type_options = is_array($orders_view['product_types'] ?? null) ? $orders_view['product_types'] : []; -if ($type_options === [] && class_exists('\AKSRT\Core\DomainModel')) { - $type_options = array_merge(['' => __('全部类型', 'aksrt')], \AKSRT\Core\DomainModel::order_product_type_labels()); -} - -$shop = class_exists('\AKSRT\Shop\Shop') ? \AKSRT\Shop\Shop::get_instance() : null; - -$tabs = [ - '' => __('全部', 'aksrt'), - 'pending' => __('待支付', 'aksrt'), - 'shipped' => __('待收货', 'aksrt'), - 'review' => __('待评价', 'aksrt'), - 'after' => __('售后', 'aksrt'), -]; - -$base_query = []; -if ($type_filter !== '') { - $base_query['order_type'] = $type_filter; -} -if ($section !== '') { - $base_query['section'] = $section; -} - -/** - * @param array $args - */ -$orders_url = static function (array $args = []) use ($base_query): string { - $q = array_merge($base_query, $args); - $url = remove_query_arg(['tab', 'order_status', 'order_page', 'order_type', 'section']); - return add_query_arg($q, $url); -}; -?> - - -
- -
- -
- __('我的订单', 'aksrt'), - 'subtitle' => __('查看商城、付费内容、会员与充值等全部订单。', 'aksrt'), - 'active' => 'orders', - ]); - } else { - echo '

' . esc_html__('我的订单', 'aksrt') . '

'; - } - ?> - - -
-
- - -
-
- - -
-
- - -
-
- - -
- - - -
- - -
- $type_label) : - $is_type_active = (string) $type_key === (string) $type_filter; - $type_url = $orders_url([ - 'order_type' => $type_key !== '' ? $type_key : null, - 'tab' => $tab !== '' ? $tab : null, - 'order_page' => 1, - ]); - if ($type_key === '') { - $type_url = remove_query_arg('order_type', $type_url); - } - ?> - - - - -
- - -
- $tab_label) : - $is_active = $tab === $tab_key; - $tab_url = $tab_key !== '' - ? $orders_url(['tab' => $tab_key, 'order_page' => 1]) - : remove_query_arg(['tab', 'order_status', 'order_page'], $orders_url()); - ?> - - - - -
- - -
- -
-
- - - - -
- -
- - -
- - - - - -
- - - - -
-
- - × -
-
- - -
- - - -
- -
-
- -
-
- -
- -
- - - 0 && !$is_points) : ?> - () - -
- - -
-

- -

- -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
- - 1) : ?> -
- $tab !== '' ? $tab : null, - 'order_page' => $i, - ])); - ?> - - - - - - -
- - -
- -

-
- - - - - - - - - get_user_tickets($user_id, 50); - ?> -
-

- -
- -
-
- # - - -
-
- - · -
-
- -
    - -
  1. - - -
  2. - -
- -
- - - - - - -
-
- -
- -

- -
- - - -
-

-
-

-
-
- - - get_user_favorites($user_id); - ?> -
-

- - - -

- -
- -
-
- - -
- - +wp_safe_redirect($target, 302); +exit;