Subscription module: add gateway capability flow and UX fixes

This commit is contained in:
Dwindi Ramadhana
2026-06-02 00:38:42 +07:00
parent fec786daa6
commit df969b442d
15 changed files with 2375 additions and 138 deletions

View File

@@ -38,8 +38,15 @@ class SubscriptionModule
add_action('woocommerce_order_status_completed', [__CLASS__, 'maybe_create_subscription'], 10, 1);
add_action('woocommerce_order_status_processing', [__CLASS__, 'maybe_create_subscription'], 10, 1);
// Hook into order status change to handle manual renewal payments
// Hook into order status change to handle manual renewal payments and status sync
add_action('woocommerce_order_status_changed', [__CLASS__, 'on_order_status_changed'], 10, 3);
// Hook into entity deletions for cleanup and state sync
add_action('woocommerce_trash_order', [__CLASS__, 'on_order_deleted']);
add_action('woocommerce_delete_order', [__CLASS__, 'on_order_deleted']);
add_action('trashed_post', [__CLASS__, 'on_post_deleted']);
add_action('deleted_post', [__CLASS__, 'on_post_deleted']);
add_action('delete_user', [__CLASS__, 'on_user_deleted']);
// Modify add to cart button text for subscription products
add_filter('woocommerce_product_single_add_to_cart_text', [__CLASS__, 'subscription_add_to_cart_text'], 10, 2);
@@ -275,6 +282,14 @@ class SubscriptionModule
$product_id = $product->get_id();
if (get_post_meta($product_id, '_woonoow_subscription_enabled', true) === 'yes') {
// Guests cannot have subscriptions — create_from_order() rejects guest orders silently
// (H6). Show the standard add-to-cart text and let the regular checkout flow handle
// guest sign-up. The subscription will only be created if/when the customer converts
// to a user. We do NOT advertise a subscription capability the system cannot honor.
if (!is_user_logged_in()) {
return $text;
}
$settings = ModuleRegistry::get_settings('subscription');
return $settings['button_text_subscribe'] ?? __('Subscribe Now', 'woonoow');
}
@@ -532,7 +547,7 @@ class SubscriptionModule
}
/**
* Handle manual renewal payment completion
* Handle order status changes for both parent and renewal orders
*/
public static function on_order_status_changed($order_id, $old_status, $new_status)
{
@@ -540,24 +555,108 @@ class SubscriptionModule
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(
// Find if this order is linked to any subscription
$links = $wpdb->get_results($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);
if (empty($links)) {
return;
}
foreach ($links as $link) {
$subscription = SubscriptionManager::get($link->subscription_id);
if (!$subscription) continue;
if ($link->order_type === 'renewal') {
if (in_array($new_status, ['processing', 'completed'])) {
$order = wc_get_order($order_id);
if ($order) {
SubscriptionManager::handle_renewal_success($link->subscription_id, $order);
}
} elseif ($new_status === 'failed') {
SubscriptionManager::handle_renewal_failure($link->subscription_id);
} elseif ($new_status === 'cancelled') {
SubscriptionManager::update_status($link->subscription_id, 'cancelled', 'renewal_order_cancelled');
} elseif ($new_status === 'refunded') {
SubscriptionManager::update_status($link->subscription_id, 'on-hold', 'renewal_order_refunded');
}
} elseif ($link->order_type === 'parent') {
if (in_array($new_status, ['refunded', 'cancelled'])) {
SubscriptionManager::update_status($link->subscription_id, 'cancelled', 'parent_order_' . $new_status);
} elseif ($new_status === 'on-hold') {
SubscriptionManager::update_status($link->subscription_id, 'on-hold', 'parent_order_on_hold');
}
}
}
}
/**
* Handle order trashing/deletion
*/
public static function on_order_deleted($order_id)
{
global $wpdb;
$table_orders = $wpdb->prefix . 'woonoow_subscription_orders';
$links = $wpdb->get_results($wpdb->prepare(
"SELECT subscription_id, order_type FROM $table_orders WHERE order_id = %d",
$order_id
));
foreach ($links as $link) {
if ($link->order_type === 'parent') {
SubscriptionManager::update_status($link->subscription_id, 'cancelled', 'parent_order_deleted');
} elseif ($link->order_type === 'renewal') {
SubscriptionManager::update_status($link->subscription_id, 'on-hold', 'renewal_order_deleted');
}
}
}
/**
* Handle product trashing/deletion
*/
public static function on_post_deleted($post_id)
{
if (get_post_type($post_id) !== 'product') {
return;
}
global $wpdb;
$table_subs = $wpdb->prefix . 'woonoow_subscriptions';
// Find active/on-hold subscriptions for this product
$affected = $wpdb->get_col($wpdb->prepare(
"SELECT id FROM $table_subs WHERE product_id = %d AND status IN ('active', 'on-hold', 'pending')",
$post_id
));
foreach ($affected as $sub_id) {
SubscriptionManager::update_status($sub_id, 'on-hold', 'product_deleted');
// Fire an action so merchants can hook in and get alerted
do_action('woonoow/subscription/product_deleted_alert', $sub_id, $post_id);
}
}
/**
* Handle user deletion
*/
public static function on_user_deleted($user_id)
{
global $wpdb;
$table_subs = $wpdb->prefix . 'woonoow_subscriptions';
$affected = $wpdb->get_col($wpdb->prepare(
"SELECT id FROM $table_subs WHERE user_id = %d AND status != 'cancelled'",
$user_id
));
foreach ($affected as $sub_id) {
SubscriptionManager::update_status($sub_id, 'cancelled', 'user_deleted');
}
}
}