$label) { $new[$key] = $label; if ('orders' === $key) { $new['subscriptions'] = __('我的订阅', 'yoone-subscriptions'); } } // 如果没有“订单”菜单,则直接追加 if (! isset($new['subscriptions'])) { $new['subscriptions'] = __('我的订阅', 'yoone-subscriptions'); } return $new; } /** * 渲染 My Account → 订阅 列表。 */ public function render_account_subscriptions() { if (! is_user_logged_in()) { echo '

' . esc_html__('请先登录以查看您的订阅。', 'yoone-subscriptions') . '

'; return; } $uid = get_current_user_id(); if (! class_exists('Yoone_Subscriptions_DB')) { echo '

' . esc_html__('订阅数据模块未加载。', 'yoone-subscriptions') . '

'; return; } $subs = Yoone_Subscriptions_DB::get_by_user($uid, array('limit' => 50, 'offset' => 0)); echo '

' . esc_html__('我的订阅', 'yoone-subscriptions') . '

'; if (empty($subs)) { echo '

' . esc_html__('您目前还没有订阅。', 'yoone-subscriptions') . '

'; return; } echo ''; foreach ($subs as $row) { $product = wc_get_product(intval($row['product_id'])); $product_name = $product ? $product->get_name() : ('#' . intval($row['product_id'])); $period_label = $row['period'] === 'year' ? __('年', 'yoone-subscriptions') : __('月', 'yoone-subscriptions'); echo ''; } echo '
' . esc_html__('商品', 'yoone-subscriptions') . ' ' . esc_html__('周期', 'yoone-subscriptions') . ' ' . esc_html__('数量', 'yoone-subscriptions') . ' ' . esc_html__('每周期金额', 'yoone-subscriptions') . ' ' . esc_html__('状态', 'yoone-subscriptions') . ' ' . esc_html__('开始时间', 'yoone-subscriptions') . ' ' . esc_html__('下次续费', 'yoone-subscriptions') . '
' . esc_html($product_name) . ' ' . esc_html($period_label) . ' ' . esc_html(intval($row['qty'])) . ' ' . wc_price(floatval($row['price_per_cycle'])) . ' ' . esc_html($row['status']) . ' ' . esc_html($row['start_date']) . ' ' . esc_html($row['next_renewal_date']) . '
'; } /** * 渲染订阅选择 UI(产品页)。 */ public function render_subscription_options() { global $product; if (! $product || ! is_a($product, 'WC_Product')) return; $cfg = Yoone_Subscriptions::get_config($product); if (! $cfg['enabled']) return; // 未开启订阅 // 前端样式/脚本 wp_enqueue_style('yoone-subs-frontend'); wp_enqueue_script('yoone-subs-frontend'); $regular_price = floatval($product->get_price()); $sub_price = $cfg['price'] > 0 ? $cfg['price'] : $regular_price; $discount = ($regular_price > 0 && $sub_price < $regular_price) ? (1 - $sub_price / $regular_price) * 100.0 : 0.0; // 简单模板输出(不使用专门模板文件,保持轻量) echo '
'; echo '

' . esc_html__('订阅选项', 'yoone-subscriptions') . '

'; // 一次性 vs 订阅 if ($cfg['allow_onetime']) { echo '

'; echo '

'; } else { echo ''; } // 周期选择 echo '

' . ' ' . '' . '

'; // 数量输入 echo '

' . ' ' . '' . '

'; // 价格与折扣展示(每周期价格) echo '

' . esc_html__('订阅价格(每周期):', 'yoone-subscriptions') . wc_price($sub_price) . ($discount > 0 ? ' ' . sprintf(esc_html__('折扣约 %.1f%%', 'yoone-subscriptions'), $discount) . '' : '') . '

'; echo '
'; } /** * 校验加入购物车的订阅参数。 */ public function validate_add_to_cart($passed, $product_id, $quantity) { $product = wc_get_product($product_id); if (! $product) return $passed; $cfg = Yoone_Subscriptions::get_config($product); if (! $cfg['enabled']) return $passed; $mode = isset($_POST['yoone_sub_purchase_mode']) ? sanitize_text_field($_POST['yoone_sub_purchase_mode']) : ''; if ($cfg['allow_onetime'] && $mode === 'onetime') return $passed; // 一次性购买,无需校验订阅参数 $period = isset($_POST['yoone_sub_period']) ? sanitize_text_field($_POST['yoone_sub_period']) : $cfg['period']; $qty = isset($_POST['yoone_sub_quantity']) ? absint($_POST['yoone_sub_quantity']) : $cfg['qty_default']; $period = in_array($period, array('month','year'), true) ? $period : $cfg['period']; $qty = max(1, $qty); if ($mode !== 'subscribe' && ! $cfg['allow_onetime']) { wc_add_notice(__('该产品仅支持订阅购买。', 'yoone-subscriptions'), 'error'); return false; } // 可根据需要扩展更多校验(库存、最大值等) return $passed; } /** * 将订阅参数写入购物车项。 */ public function add_cart_item_data($cart_item_data, $product_id, $variation_id) { $product = wc_get_product($product_id); if (! $product) return $cart_item_data; $cfg = Yoone_Subscriptions::get_config($product); if (! $cfg['enabled']) return $cart_item_data; // 若是混装子项目(存在父容器ID),不在子项目上应用订阅,避免重复计价 if (isset($cart_item_data['yoone_bundle_parent_id'])) { return $cart_item_data; } $mode = isset($_POST['yoone_sub_purchase_mode']) ? sanitize_text_field($_POST['yoone_sub_purchase_mode']) : ''; $period = isset($_POST['yoone_sub_period']) ? sanitize_text_field($_POST['yoone_sub_period']) : $cfg['period']; $qty = isset($_POST['yoone_sub_quantity']) ? absint($_POST['yoone_sub_quantity']) : $cfg['qty_default']; $period = in_array($period, array('month','year'), true) ? $period : $cfg['period']; $qty = max(1, $qty); // 如果选择一次性购买,则不写入订阅元数据,购物车中不显示任何订阅信息 if ($cfg['allow_onetime'] && $mode === 'onetime') { return $cart_item_data; } $cart_item_data['yoone_subscriptions'] = array( 'mode' => 'subscribe', 'period' => $period, 'qty' => $qty, 'price' => ($cfg['price'] > 0 ? $cfg['price'] : floatval($product->get_price())), // 每周期价格;对于混装容器,将在后续根据子项目求和覆盖 ); return $cart_item_data; } /** * 购物车/订单行项目中展示订阅摘要。 */ public function display_item_data($item_data, $cart_item) { if (empty($cart_item['yoone_subscriptions'])) return $item_data; $data = $cart_item['yoone_subscriptions']; // 仅在选择订阅购买时展示订阅信息;一次性购买不展示任何订阅相关信息 if (! isset($data['mode']) || $data['mode'] !== 'subscribe') { return $item_data; } $period_label = $data['period'] === 'year' ? __('年', 'yoone-subscriptions') : __('月', 'yoone-subscriptions'); $item_data[] = array('key' => __('购买方式', 'yoone-subscriptions'), 'value' => __('订阅', 'yoone-subscriptions')); $item_data[] = array('key' => __('周期', 'yoone-subscriptions'), 'value' => $period_label); $item_data[] = array('key' => __('订阅数量', 'yoone-subscriptions'), 'value' => intval($data['qty'])); $item_data[] = array('key' => __('订阅价格(每周期)', 'yoone-subscriptions'), 'value' => wc_price(floatval($data['price']))); return $item_data; } /** * 根据订阅规则设置行项目价格:价格 = 每周期价格 × 周期系数 × 订阅数量 × 购物车数量。 */ public function adjust_subscription_price($cart) { if (is_admin() && ! defined('DOING_AJAX')) return; if (empty($cart) || ! method_exists($cart, 'get_cart')) return; foreach ($cart->get_cart() as $key => $item) { if (empty($item['yoone_subscriptions'])) continue; $data = $item['yoone_subscriptions']; if ($data['mode'] !== 'subscribe') continue; $product = isset($item['data']) ? $item['data'] : null; if (! $product || ! is_a($product, 'WC_Product')) continue; $price_per_cycle = floatval($data['price']); $factor = Yoone_Subscriptions::period_factor($data['period']); $sub_qty = absint($data['qty']); $cart_qty = absint(isset($item['quantity']) ? $item['quantity'] : 1); // 若为混装容器,则以其子项目的价格汇总作为每周期基价(若有配置价则优先使用配置价) if (isset($item['yoone_bundle_container_id'])) { $container_id = $item['yoone_bundle_container_id']; // 使用配置价优先,否则求和子项目价 $cfg = Yoone_Subscriptions::get_config($product); if (!($cfg['price'] > 0)) { $sum = 0.0; foreach ($cart->get_cart() as $k2 => $child) { if (isset($child['yoone_bundle_parent_id']) && $child['yoone_bundle_parent_id'] === $container_id) { $child_product = isset($child['data']) ? $child['data'] : null; if ($child_product && is_a($child_product, 'WC_Product')) { $child_qty = absint(isset($child['quantity']) ? $child['quantity'] : 1); $sum += floatval($child_product->get_price()) * $child_qty; } } } $price_per_cycle = $sum; // 以子项目合计为每周期基价 } else { $price_per_cycle = floatval($cfg['price']); } // 将子项目的价格置为 0,避免重复计费 foreach ($cart->get_cart() as $k2 => $child) { if (isset($child['yoone_bundle_parent_id']) && $child['yoone_bundle_parent_id'] === $container_id) { $child_product = isset($child['data']) ? $child['data'] : null; if ($child_product && is_a($child_product, 'WC_Product')) { $child_product->set_price(0); } } } } $line_price = $price_per_cycle * $factor * $sub_qty * $cart_qty; $product->set_price($line_price); } } }