prefix . 'woonoow_subscriptions'; // Check if table exists if ($wpdb->get_var("SHOW TABLES LIKE '$table'") !== $table) { SubscriptionManager::create_tables(); } } /** * Handle module enable */ public static function on_module_enabled($module_id) { if ($module_id === 'subscription') { SubscriptionManager::create_tables(); } } /** * Add subscription fields to product edit page */ public static function add_product_subscription_fields() { global $post; if (!ModuleRegistry::is_enabled('subscription')) { return; } echo '
'; woocommerce_wp_checkbox([ 'id' => '_woonoow_subscription_enabled', 'label' => __('Enable Subscription', 'woonoow'), 'description' => __('Enable recurring subscription billing for this product', 'woonoow'), ]); echo ''; // .woonoow-subscription-options // Add inline script to show/hide options based on checkbox ?> '; // .options_group } /** * Save subscription fields */ public static function save_product_subscription_fields($post_id) { $subscription_enabled = isset($_POST['_woonoow_subscription_enabled']) ? 'yes' : 'no'; update_post_meta($post_id, '_woonoow_subscription_enabled', $subscription_enabled); if (isset($_POST['_woonoow_subscription_period'])) { update_post_meta($post_id, '_woonoow_subscription_period', sanitize_text_field($_POST['_woonoow_subscription_period'])); } if (isset($_POST['_woonoow_subscription_interval'])) { update_post_meta($post_id, '_woonoow_subscription_interval', absint($_POST['_woonoow_subscription_interval'])); } if (isset($_POST['_woonoow_subscription_trial_days'])) { update_post_meta($post_id, '_woonoow_subscription_trial_days', absint($_POST['_woonoow_subscription_trial_days'])); } if (isset($_POST['_woonoow_subscription_signup_fee'])) { update_post_meta($post_id, '_woonoow_subscription_signup_fee', wc_format_decimal($_POST['_woonoow_subscription_signup_fee'])); } if (isset($_POST['_woonoow_subscription_length'])) { update_post_meta($post_id, '_woonoow_subscription_length', absint($_POST['_woonoow_subscription_length'])); } } /** * Maybe create subscription from completed order */ public static function maybe_create_subscription($order_id) { if (!ModuleRegistry::is_enabled('subscription')) { return; } $order = wc_get_order($order_id); if (!$order) { return; } // Check if subscription already created for this order if ($order->get_meta('_woonoow_subscription_created')) { return; } foreach ($order->get_items() as $item) { $product_id = $item->get_product_id(); $variation_id = $item->get_variation_id(); // Check if product has subscription enabled if (get_post_meta($product_id, '_woonoow_subscription_enabled', true) !== 'yes') { continue; } // Create subscription for this product SubscriptionManager::create_from_order($order, $item); } // Mark order as processed $order->update_meta_data('_woonoow_subscription_created', 'yes'); $order->save(); } /** * Modify add to cart button text for subscription products */ public static function subscription_add_to_cart_text($text, $product) { if (!ModuleRegistry::is_enabled('subscription')) { return $text; } $product_id = $product->get_id(); if (get_post_meta($product_id, '_woonoow_subscription_enabled', true) === 'yes') { $settings = ModuleRegistry::get_settings('subscription'); return $settings['button_text_subscribe'] ?? __('Subscribe Now', 'woonoow'); } return $text; } /** * Register subscription notification events * * @param array $events Existing events * @return array Updated events */ public static function register_notification_events($events) { // Customer notifications $events['subscription_pending_cancel'] = [ 'id' => 'subscription_pending_cancel', 'label' => __('Subscription Pending Cancellation', 'woonoow'), 'description' => __('When a subscription is scheduled for cancellation at period end', 'woonoow'), 'category' => 'subscriptions', 'recipient_type' => 'customer', 'wc_email' => '', 'enabled' => true, 'variables' => self::get_subscription_variables(), ]; $events['subscription_cancelled'] = [ 'id' => 'subscription_cancelled', 'label' => __('Subscription Cancelled', 'woonoow'), 'description' => __('When a subscription is cancelled and access ends', 'woonoow'), 'category' => 'subscriptions', 'recipient_type' => 'customer', 'wc_email' => '', 'enabled' => true, 'variables' => self::get_subscription_variables(), ]; $events['subscription_expired'] = [ 'id' => 'subscription_expired', 'label' => __('Subscription Expired', 'woonoow'), 'description' => __('When a subscription expires due to end date or failed payments', 'woonoow'), 'category' => 'subscriptions', 'recipient_type' => 'customer', 'wc_email' => '', 'enabled' => true, 'variables' => self::get_subscription_variables(), ]; $events['subscription_paused'] = [ 'id' => 'subscription_paused', 'label' => __('Subscription Paused', 'woonoow'), 'description' => __('When a subscription is put on hold', 'woonoow'), 'category' => 'subscriptions', 'recipient_type' => 'customer', 'wc_email' => '', 'enabled' => true, 'variables' => self::get_subscription_variables(), ]; $events['subscription_resumed'] = [ 'id' => 'subscription_resumed', 'label' => __('Subscription Resumed', 'woonoow'), 'description' => __('When a subscription is resumed from pause', 'woonoow'), 'category' => 'subscriptions', 'recipient_type' => 'customer', 'wc_email' => '', 'enabled' => true, 'variables' => self::get_subscription_variables(), ]; $events['subscription_renewal_failed'] = [ 'id' => 'subscription_renewal_failed', 'label' => __('Subscription Renewal Failed', 'woonoow'), 'description' => __('When a renewal payment fails', 'woonoow'), 'category' => 'subscriptions', 'recipient_type' => 'customer', 'wc_email' => '', 'enabled' => true, 'variables' => self::get_subscription_variables(), ]; $events['subscription_renewal_payment_due'] = [ 'id' => 'subscription_renewal_payment_due', 'label' => __('Subscription Renewal Payment Due', 'woonoow'), 'description' => __('When a manual payment is required for subscription renewal', 'woonoow'), 'category' => 'subscriptions', 'recipient_type' => 'customer', 'wc_email' => '', 'enabled' => true, 'variables' => array_merge(self::get_subscription_variables(), [ '{payment_link}' => __('Link to payment page', 'woonoow'), ]), ]; $events['subscription_renewal_reminder'] = [ 'id' => 'subscription_renewal_reminder', 'label' => __('Subscription Renewal Reminder', 'woonoow'), 'description' => __('Reminder before subscription renewal', 'woonoow'), 'category' => 'subscriptions', 'recipient_type' => 'customer', 'wc_email' => '', 'enabled' => true, 'variables' => self::get_subscription_variables(), ]; // Staff notifications $events['subscription_cancelled_admin'] = [ 'id' => 'subscription_cancelled', 'label' => __('Subscription Cancelled', 'woonoow'), 'description' => __('When a customer cancels their subscription', 'woonoow'), 'category' => 'subscriptions', 'recipient_type' => 'staff', 'wc_email' => '', 'enabled' => true, 'variables' => self::get_subscription_variables(), ]; $events['subscription_renewal_failed_admin'] = [ 'id' => 'subscription_renewal_failed', 'label' => __('Subscription Renewal Failed', 'woonoow'), 'description' => __('When a subscription renewal payment fails', 'woonoow'), 'category' => 'subscriptions', 'recipient_type' => 'staff', 'wc_email' => '', 'enabled' => true, 'variables' => self::get_subscription_variables(), ]; return $events; } /** * Get subscription-specific template variables * * @return array */ private static function get_subscription_variables() { return [ '{subscription_id}' => __('Subscription ID', 'woonoow'), '{subscription_status}' => __('Subscription status', 'woonoow'), '{product_name}' => __('Product name', 'woonoow'), '{billing_period}' => __('Billing period (e.g., monthly)', 'woonoow'), '{recurring_amount}' => __('Recurring payment amount', 'woonoow'), '{next_payment_date}' => __('Next payment date', 'woonoow'), '{end_date}' => __('Subscription end date', 'woonoow'), '{cancel_reason}' => __('Cancellation reason', 'woonoow'), ]; } /** * Handle pending cancellation notification */ public static function on_pending_cancel($subscription_id, $reason = '') { self::send_subscription_notification('subscription_pending_cancel', $subscription_id, $reason); } /** * Handle cancellation notification */ public static function on_cancelled($subscription_id, $reason = '') { self::send_subscription_notification('subscription_cancelled', $subscription_id, $reason); } /** * Handle expiration notification */ public static function on_expired($subscription_id, $reason = '') { self::send_subscription_notification('subscription_expired', $subscription_id, $reason); } /** * Handle pause notification */ public static function on_paused($subscription_id) { self::send_subscription_notification('subscription_paused', $subscription_id); } /** * Handle resume notification */ public static function on_resumed($subscription_id) { self::send_subscription_notification('subscription_resumed', $subscription_id); } /** * Handle renewal failed notification */ public static function on_renewal_failed($subscription_id, $failed_count) { self::send_subscription_notification('subscription_renewal_failed', $subscription_id, '', $failed_count); } /** * Handle renewal payment due notification */ public static function on_renewal_payment_due($subscription_id, $order = null) { $payment_link = ''; if ($order && is_a($order, 'WC_Order')) { $payment_link = $order->get_checkout_payment_url(); } self::send_subscription_notification('subscription_renewal_payment_due', $subscription_id, '', 0, ['payment_link' => $payment_link]); } /** * Handle renewal reminder notification */ public static function on_renewal_reminder($subscription) { if (!$subscription || !isset($subscription->id)) { return; } self::send_subscription_notification('subscription_renewal_reminder', $subscription->id); } /** * Send subscription notification * * @param string $event_id Event ID * @param int $subscription_id Subscription ID * @param string $reason Optional reason * @param int $failed_count Optional failed payment count * @param array $extra_data Optional extra data variables */ private static function send_subscription_notification($event_id, $subscription_id, $reason = '', $failed_count = 0, $extra_data = []) { $subscription = SubscriptionManager::get($subscription_id); if (!$subscription) { return; } $user = get_user_by('id', $subscription->user_id); $product = wc_get_product($subscription->product_id); $data = [ 'subscription' => $subscription, 'customer' => $user, 'product' => $product, 'reason' => $reason, 'failed_count' => $failed_count, 'payment_link' => $extra_data['payment_link'] ?? '', ]; // Send via NotificationManager if (class_exists('\\WooNooW\\Core\\Notifications\\NotificationManager')) { \WooNooW\Core\Notifications\NotificationManager::send($event_id, 'email', $data); } } /** * Handle manual renewal payment completion */ public static function on_order_status_changed($order_id, $old_status, $new_status) { if (!ModuleRegistry::is_enabled('subscription')) { return; } if (!in_array($new_status, ['processing', 'completed'])) { return; } // Check if this is a subscription renewal order global $wpdb; $table_orders = $wpdb->prefix . 'woonoow_subscription_orders'; $link = $wpdb->get_row($wpdb->prepare( "SELECT subscription_id, order_type FROM $table_orders WHERE order_id = %d", $order_id )); if ($link && $link->order_type === 'renewal') { $order = wc_get_order($order_id); if ($order) { SubscriptionManager::handle_renewal_success($link->subscription_id, $order); } } } }