__('订阅计划', 'yoone-subscriptions'), 'target' => 'yoone_subscriptions_data', // 在 simple、variable 以及 yoone_bundle(混装)产品类型上显示 'class' => array('show_if_simple', 'show_if_variable', 'show_if_yoone_bundle'), 'priority' => 80, ); return $tabs; } /** * 渲染面板内容 */ public function render_panel() { global $post; $product = wc_get_product($post->ID); $cfg = Yoone_Subscriptions::get_config($product); wp_nonce_field('yoone_subscriptions_save', 'yoone_subscriptions_nonce'); // 面板在 simple/variable/yoone_bundle 上显示 echo '
'; } /** * 保存订阅配置 */ public function save_meta($post_id) { if (! isset($_POST['yoone_subscriptions_nonce']) || ! wp_verify_nonce($_POST['yoone_subscriptions_nonce'], 'yoone_subscriptions_save')) { return; // 安全验证失败 } if (! current_user_can('edit_post', $post_id)) return; $enabled = isset($_POST['yoone_sub_enabled']) && 'yes' === $_POST['yoone_sub_enabled']; $period = isset($_POST['yoone_sub_period']) ? sanitize_text_field($_POST['yoone_sub_period']) : 'month'; $qty = isset($_POST['yoone_sub_qty_default']) ? absint($_POST['yoone_sub_qty_default']) : 1; $min_qty = isset($_POST['yoone_sub_min_qty']) ? absint($_POST['yoone_sub_min_qty']) : 1; $price = isset($_POST['yoone_sub_price']) ? wc_clean($_POST['yoone_sub_price']) : ''; $tiers = isset($_POST['yoone_sub_tier_rules']) ? sanitize_text_field($_POST['yoone_sub_tier_rules']) : ''; $onetime = isset($_POST['yoone_sub_allow_onetime']) && 'yes' === $_POST['yoone_sub_allow_onetime']; $period = in_array($period, array('month','year'), true) ? $period : 'month'; $qty = max(1, $qty); $price_v = ($price === '' ? '' : wc_format_decimal($price, 2)); update_post_meta($post_id, Yoone_Subscriptions::META_ENABLED, $enabled ? '1' : ''); update_post_meta($post_id, Yoone_Subscriptions::META_PERIOD, $period); update_post_meta($post_id, Yoone_Subscriptions::META_QTY_DEFAULT, $qty); update_post_meta($post_id, Yoone_Subscriptions::META_MIN_QTY, max(1, $min_qty)); if ($price_v === '') { delete_post_meta($post_id, Yoone_Subscriptions::META_PRICE); } else { update_post_meta($post_id, Yoone_Subscriptions::META_PRICE, $price_v); } if ($tiers === '') { delete_post_meta($post_id, Yoone_Subscriptions::META_TIER_RULES); } else { update_post_meta($post_id, Yoone_Subscriptions::META_TIER_RULES, $tiers); } update_post_meta($post_id, Yoone_Subscriptions::META_ALLOW_ONETIME, $onetime ? '1' : ''); // 保存多订阅计划 $plans = array(); if (isset($_POST['yoone_sub_plans']) && is_array($_POST['yoone_sub_plans'])) { $labels = isset($_POST['yoone_sub_plans']['label']) ? (array) $_POST['yoone_sub_plans']['label'] : array(); $periods = isset($_POST['yoone_sub_plans']['period']) ? (array) $_POST['yoone_sub_plans']['period'] : array(); $prices = isset($_POST['yoone_sub_plans']['price']) ? (array) $_POST['yoone_sub_plans']['price'] : array(); $discounts = isset($_POST['yoone_sub_plans']['discount_percent']) ? (array) $_POST['yoone_sub_plans']['discount_percent'] : array(); $count = max(count($labels), count($periods), count($prices), count($discounts)); for ($i=0; $i<$count; $i++) { $label = isset($labels[$i]) ? sanitize_text_field($labels[$i]) : ''; $per = isset($periods[$i]) ? sanitize_text_field($periods[$i]) : 'month'; $per = in_array($per, array('month','year'), true) ? $per : 'month'; $price = isset($prices[$i]) ? wc_clean($prices[$i]) : ''; $price = ($price === '' ? 0.0 : floatval(wc_format_decimal($price, 2))); $disc = isset($discounts[$i]) ? floatval($discounts[$i]) : 0.0; if ($label === '' && $price <= 0 && $disc <= 0) continue; // 全空行跳过 $plans[] = array( 'id' => uniqid('plan_'), 'label' => $label ? $label : __('订阅计划', 'yoone-subscriptions'), 'period' => $per, 'price' => $price, 'discount_percent' => max(0.0, $disc), ); } } update_post_meta($post_id, Yoone_Subscriptions::META_PLANS, $plans); } /** * 注册 WooCommerce → Subscriptions 子菜单。 */ public function register_submenu() { // 仅限具有管理 WooCommerce 权限的用户可访问 add_submenu_page( 'woocommerce', __('Subscriptions', 'yoone-subscriptions'), __('Subscriptions', 'yoone-subscriptions'), 'manage_woocommerce', 'yoone-subscriptions', array($this, 'render_subscriptions_page'), 56 // 显示位置(可选) ); } /** * 渲染订阅列表管理页面。 * 支持按用户、产品、状态筛选与分页。 */ public function render_subscriptions_page() { if (! current_user_can('manage_woocommerce')) { wp_die(__('您没有权限查看该页面。', 'yoone-subscriptions')); } // 处理状态更新操作(pause/resume/cancel),带 nonce if (isset($_POST['yoone_sub_action']) && isset($_POST['_wpnonce']) && wp_verify_nonce($_POST['_wpnonce'], 'yoone_subscriptions_action')) { $action = sanitize_key($_POST['yoone_sub_action']); $sub_id = isset($_POST['yoone_sub_id']) ? absint($_POST['yoone_sub_id']) : 0; $allowed = array('pause' => 'paused', 'resume' => 'active', 'cancel' => 'canceled'); if ($sub_id > 0 && isset($allowed[$action])) { if (class_exists('Yoone_Subscriptions_DB')) { Yoone_Subscriptions_DB::update($sub_id, array('status' => $allowed[$action])); echo '' . esc_html__('状态已更新。', 'yoone-subscriptions') . '
| ' . esc_html($c) . ' | '; echo '|||||||||
|---|---|---|---|---|---|---|---|---|---|
| ' . esc_html__('暂无订阅记录。', 'yoone-subscriptions') . ' | |||||||||
| #' . intval($r['id']) . ' | '; echo '' . ($user ? esc_html($user->user_email) . ' (ID ' . intval($user->ID) . ')' : '-') . ' | '; echo '' . ($product ? esc_html($product->get_name()) . ' (ID ' . intval($product->get_id()) . ')' : 'ID ' . intval($r['product_id'])) . ' | '; echo '' . esc_html($r['period']) . ' | '; echo '' . intval($r['qty']) . ' | '; echo '' . wc_price(floatval($r['price_per_cycle'])) . ' | '; echo '' . esc_html($r['status']) . ' | '; echo '' . esc_html($r['start_date']) . ' | '; echo '' . esc_html($r['next_renewal_date']) . ' | '; echo ''; echo ''; echo ''; echo ''; echo ' | '; echo '