'GET', 'callback' => [__CLASS__, 'get_subscriptions'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); register_rest_route('woonoow/v1', '/subscriptions/(?P\d+)', [ 'methods' => 'GET', 'callback' => [__CLASS__, 'get_subscription'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); register_rest_route('woonoow/v1', '/subscriptions/(?P\d+)', [ 'methods' => 'PUT', 'callback' => [__CLASS__, 'update_subscription'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); register_rest_route('woonoow/v1', '/subscriptions/(?P\d+)/cancel', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'cancel_subscription'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); register_rest_route('woonoow/v1', '/subscriptions/(?P\d+)/renew', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'renew_subscription'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); register_rest_route('woonoow/v1', '/subscriptions/(?P\d+)/pause', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'pause_subscription'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); register_rest_route('woonoow/v1', '/subscriptions/(?P\d+)/resume', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'resume_subscription'], 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, ]); // Customer routes register_rest_route('woonoow/v1', '/account/subscriptions', [ 'methods' => 'GET', 'callback' => [__CLASS__, 'get_customer_subscriptions'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); register_rest_route('woonoow/v1', '/account/subscriptions/(?P\d+)', [ 'methods' => 'GET', 'callback' => [__CLASS__, 'get_customer_subscription'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); register_rest_route('woonoow/v1', '/account/subscriptions/(?P\d+)/cancel', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'customer_cancel'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); register_rest_route('woonoow/v1', '/account/subscriptions/(?P\d+)/pause', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'customer_pause'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); register_rest_route('woonoow/v1', '/account/subscriptions/(?P\d+)/resume', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'customer_resume'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); register_rest_route('woonoow/v1', '/account/subscriptions/(?P\d+)/renew', [ 'methods' => 'POST', 'callback' => [__CLASS__, 'customer_renew'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); } /** * Get all subscriptions (admin) */ public static function get_subscriptions(WP_REST_Request $request) { $args = [ 'status' => $request->get_param('status'), 'product_id' => $request->get_param('product_id'), 'user_id' => $request->get_param('user_id'), 'limit' => $request->get_param('per_page') ?: 20, 'offset' => (($request->get_param('page') ?: 1) - 1) * ($request->get_param('per_page') ?: 20), ]; $subscriptions = SubscriptionManager::get_all($args); $total = SubscriptionManager::count(['status' => $args['status']]); // Enrich with product and user info $enriched = []; foreach ($subscriptions as $subscription) { $enriched[] = self::enrich_subscription($subscription); } return new WP_REST_Response([ 'subscriptions' => $enriched, 'total' => $total, 'page' => $request->get_param('page') ?: 1, 'per_page' => $args['limit'], ]); } /** * Get single subscription (admin) */ public static function get_subscription(WP_REST_Request $request) { $subscription = SubscriptionManager::get($request->get_param('id')); if (!$subscription) { return new WP_Error('not_found', __('Subscription not found', 'woonoow'), ['status' => 404]); } $enriched = self::enrich_subscription($subscription); $enriched['orders'] = SubscriptionManager::get_orders($subscription->id); return new WP_REST_Response($enriched); } /** * Update subscription (admin) */ public static function update_subscription(WP_REST_Request $request) { global $wpdb; $subscription = SubscriptionManager::get($request->get_param('id')); if (!$subscription) { return new WP_Error('not_found', __('Subscription not found', 'woonoow'), ['status' => 404]); } $data = $request->get_json_params(); $allowed_fields = ['status', 'next_payment_date', 'end_date', 'billing_period', 'billing_interval']; $update_data = []; $format = []; foreach ($allowed_fields as $field) { if (isset($data[$field])) { $update_data[$field] = $data[$field]; $format[] = is_numeric($data[$field]) ? '%d' : '%s'; } } if (empty($update_data)) { return new WP_Error('no_data', __('No valid fields to update', 'woonoow'), ['status' => 400]); } $table = $wpdb->prefix . 'woonoow_subscriptions'; $updated = $wpdb->update($table, $update_data, ['id' => $subscription->id], $format, ['%d']); if ($updated === false) { return new WP_Error('update_failed', __('Failed to update subscription', 'woonoow'), ['status' => 500]); } return new WP_REST_Response(['success' => true]); } /** * Cancel subscription (admin) */ public static function cancel_subscription(WP_REST_Request $request) { $data = $request->get_json_params(); $reason = $data['reason'] ?? 'Cancelled by admin'; $result = SubscriptionManager::cancel($request->get_param('id'), $reason); if (!$result) { return new WP_Error('cancel_failed', __('Failed to cancel subscription', 'woonoow'), ['status' => 500]); } return new WP_REST_Response(['success' => true]); } /** * Renew subscription (admin - force immediate renewal) */ public static function renew_subscription(WP_REST_Request $request) { $result = SubscriptionManager::renew($request->get_param('id')); if (!$result) { return new WP_Error('renew_failed', __('Failed to process renewal', 'woonoow'), ['status' => 500]); } return new WP_REST_Response(['success' => true, 'order_id' => $result['order_id']]); } /** * Pause subscription (admin) */ public static function pause_subscription(WP_REST_Request $request) { $result = SubscriptionManager::pause($request->get_param('id')); if (!$result) { return new WP_Error('pause_failed', __('Failed to pause subscription', 'woonoow'), ['status' => 500]); } return new WP_REST_Response(['success' => true]); } /** * Resume subscription (admin) */ public static function resume_subscription(WP_REST_Request $request) { $result = SubscriptionManager::resume($request->get_param('id')); if (!$result) { return new WP_Error('resume_failed', __('Failed to resume subscription', 'woonoow'), ['status' => 500]); } return new WP_REST_Response(['success' => true]); } /** * Get customer's subscriptions */ public static function get_customer_subscriptions(WP_REST_Request $request) { $user_id = get_current_user_id(); $subscriptions = SubscriptionManager::get_by_user($user_id, [ 'status' => $request->get_param('status'), 'limit' => $request->get_param('per_page') ?: 20, 'offset' => (($request->get_param('page') ?: 1) - 1) * ($request->get_param('per_page') ?: 20), ]); // Enrich each subscription $enriched = []; foreach ($subscriptions as $subscription) { $enriched[] = self::enrich_subscription($subscription); } return new WP_REST_Response($enriched); } /** * Get customer's subscription detail */ public static function get_customer_subscription(WP_REST_Request $request) { $user_id = get_current_user_id(); $subscription = SubscriptionManager::get($request->get_param('id')); if (!$subscription || $subscription->user_id != $user_id) { return new WP_Error('not_found', __('Subscription not found', 'woonoow'), ['status' => 404]); } $enriched = self::enrich_subscription($subscription); $enriched['orders'] = SubscriptionManager::get_orders($subscription->id); return new WP_REST_Response($enriched); } /** * Customer cancel their own subscription */ public static function customer_cancel(WP_REST_Request $request) { // Check if customer cancellation is allowed $settings = ModuleRegistry::get_settings('subscription'); if (empty($settings['allow_customer_cancel'])) { return new WP_Error('not_allowed', __('Customer cancellation is not allowed', 'woonoow'), ['status' => 403]); } $user_id = get_current_user_id(); $subscription = SubscriptionManager::get($request->get_param('id')); if (!$subscription || $subscription->user_id != $user_id) { return new WP_Error('not_found', __('Subscription not found', 'woonoow'), ['status' => 404]); } $data = $request->get_json_params(); $reason = $data['reason'] ?? 'Cancelled by customer'; $result = SubscriptionManager::cancel($subscription->id, $reason); if (!$result) { return new WP_Error('cancel_failed', __('Failed to cancel subscription', 'woonoow'), ['status' => 500]); } return new WP_REST_Response(['success' => true]); } /** * Customer pause their own subscription */ public static function customer_pause(WP_REST_Request $request) { // Check if customer pause is allowed $settings = ModuleRegistry::get_settings('subscription'); if (empty($settings['allow_customer_pause'])) { return new WP_Error('not_allowed', __('Customer pause is not allowed', 'woonoow'), ['status' => 403]); } $user_id = get_current_user_id(); $subscription = SubscriptionManager::get($request->get_param('id')); if (!$subscription || $subscription->user_id != $user_id) { return new WP_Error('not_found', __('Subscription not found', 'woonoow'), ['status' => 404]); } $result = SubscriptionManager::pause($subscription->id); if (!$result) { return new WP_Error('pause_failed', __('Failed to pause subscription. Maximum pauses may have been reached.', 'woonoow'), ['status' => 500]); } return new WP_REST_Response(['success' => true]); } /** * Customer resume their own subscription */ public static function customer_resume(WP_REST_Request $request) { $user_id = get_current_user_id(); $subscription = SubscriptionManager::get($request->get_param('id')); if (!$subscription || $subscription->user_id != $user_id) { return new WP_Error('not_found', __('Subscription not found', 'woonoow'), ['status' => 404]); } $result = SubscriptionManager::resume($subscription->id); if (!$result) { return new WP_Error('resume_failed', __('Failed to resume subscription', 'woonoow'), ['status' => 500]); } return new WP_REST_Response(['success' => true]); } /** * Customer renew their own subscription (Early Renewal) */ public static function customer_renew(WP_REST_Request $request) { $user_id = get_current_user_id(); $subscription = SubscriptionManager::get($request->get_param('id')); if (!$subscription || $subscription->user_id != $user_id) { return new WP_Error('not_found', __('Subscription not found', 'woonoow'), ['status' => 404]); } // Check if subscription is active (for early renewal) or on-hold with no pending payment if ($subscription->status !== 'active' && $subscription->status !== 'on-hold') { return new WP_Error('not_allowed', __('Only active subscriptions can be renewed early', 'woonoow'), ['status' => 403]); } // Trigger renewal $result = SubscriptionManager::renew($subscription->id); // SubscriptionManager::renew returns array (success) or false (failed) if (!$result) { return new WP_Error('renew_failed', __('Failed to create renewal order', 'woonoow'), ['status' => 500]); } return new WP_REST_Response([ 'success' => true, 'order_id' => $result['order_id'], 'status' => $result['status'] ]); } /** * Enrich subscription with product and user info */ private static function enrich_subscription($subscription) { $enriched = (array) $subscription; // Add product info $product_id = $subscription->variation_id ?: $subscription->product_id; $product = wc_get_product($product_id); $enriched['product_name'] = $product ? $product->get_name() : __('Unknown Product', 'woonoow'); $enriched['product_image'] = $product ? wp_get_attachment_url($product->get_image_id()) : ''; // Add user info $user = get_userdata($subscription->user_id); $enriched['user_email'] = $user ? $user->user_email : ''; $enriched['user_name'] = $user ? $user->display_name : __('Unknown User', 'woonoow'); // Add computed fields $enriched['is_active'] = $subscription->status === 'active'; $enriched['can_pause'] = $subscription->status === 'active'; $enriched['can_resume'] = $subscription->status === 'on-hold'; $enriched['can_cancel'] = in_array($subscription->status, ['active', 'on-hold', 'pending']); // Format billing info $period_labels = [ 'day' => __('day', 'woonoow'), 'week' => __('week', 'woonoow'), 'month' => __('month', 'woonoow'), 'year' => __('year', 'woonoow'), ]; $interval = $subscription->billing_interval > 1 ? $subscription->billing_interval . ' ' : ''; $period = $period_labels[$subscription->billing_period] ?? $subscription->billing_period; if ($subscription->billing_interval > 1) { $period .= 's'; // Pluralize } $enriched['billing_schedule'] = sprintf(__('Every %s%s', 'woonoow'), $interval, $period); return $enriched; } }