Created
March 13, 2026 13:30
-
-
Save goranefbl/6dd1f8c418af77cf21ec819f715a45b8 to your computer and use it in GitHub Desktop.
Auto apply coupon codes to renewals - loyalty plugin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Auto-apply loyalty coupons on WooCommerce Subscription renewals | |
| * | |
| * When a subscription renewal order is created, this snippet checks if the user | |
| * has any unused loyalty coupons (matching the configured coupon prefix) and | |
| * applies them as a discount fee on the renewal order. | |
| * | |
| * Works with both WooCommerce Subscriptions (official) and ThemeHigh Subscriptions. | |
| * | |
| * Add this snippet to your theme's functions.php or a custom plugin. | |
| */ | |
| add_filter('wcs_new_order_created', 'wpgens_loyalty_renewal_order_created', 10, 2); | |
| add_filter('wbte_subscription_renewal_order_created', 'wpgens_loyalty_renewal_order_created', 10, 2); | |
| function wpgens_loyalty_renewal_order_created($order, $subscription) | |
| { | |
| if (!$order instanceof WC_Order) { | |
| return $order; | |
| } | |
| $user_id = $order->get_user_id(); | |
| if (!$user_id) { | |
| return $order; | |
| } | |
| $user_info = get_userdata($user_id); | |
| $user_email = $user_info->user_email; | |
| if (empty($user_email)) { | |
| return $order; | |
| } | |
| // Get the loyalty coupon prefix from plugin settings | |
| $settings = WPGL_Points_Core::get_settings(); | |
| $prefix = $settings['couponPrefix'] ?? 'loyalty'; | |
| // Order total (excluding tax and shipping) | |
| $order_total = $order->get_total() - $order->get_total_tax(); | |
| $order_total = $order_total - $order->get_total_shipping() - $order->get_shipping_tax(); | |
| // Find unused loyalty coupons for this user | |
| $args = [ | |
| 'posts_per_page' => 999, | |
| 'post_type' => 'shop_coupon', | |
| 'post_status' => 'publish', | |
| 'meta_query' => [ | |
| 'relation' => 'AND', | |
| [ | |
| 'key' => 'customer_email', | |
| 'value' => $user_email, | |
| 'compare' => 'LIKE', | |
| ], | |
| [ | |
| 'key' => 'usage_count', | |
| 'value' => 1, | |
| 'type' => 'numeric', | |
| 'compare' => '<', | |
| ], | |
| ], | |
| ]; | |
| $coupons = get_posts($args); | |
| if (empty($coupons)) { | |
| return $order; | |
| } | |
| $available_coupons = []; | |
| $order_items = $order->get_items(); | |
| foreach ($coupons as $coupon_post) { | |
| // Check if coupon code starts with the loyalty prefix | |
| if (strpos($coupon_post->post_title, $prefix) !== 0) { | |
| continue; | |
| } | |
| $wc_coupon = new WC_Coupon($coupon_post->ID); | |
| // Check usage limit | |
| $usage_count = $wc_coupon->get_usage_count(); | |
| $usage_limit = $wc_coupon->get_usage_limit(); | |
| if ($usage_limit > 0 && $usage_count >= $usage_limit) { | |
| continue; | |
| } | |
| // Check expiry | |
| $expiry = $wc_coupon->get_date_expires(); | |
| if ($expiry && $expiry->getTimestamp() < time()) { | |
| continue; | |
| } | |
| // Check eligible items | |
| $eligible_items_total = 0; | |
| foreach ($order_items as $item) { | |
| $product = $item->get_product(); | |
| if ($wc_coupon->is_valid_for_product($product) || $wc_coupon->is_valid_for_cart()) { | |
| $eligible_items_total += $item->get_total(); | |
| } | |
| } | |
| if ($eligible_items_total > 0) { | |
| $available_coupons[] = [ | |
| 'coupon' => $wc_coupon, | |
| 'eligible_total' => $eligible_items_total, | |
| ]; | |
| } | |
| } | |
| if (empty($available_coupons)) { | |
| return $order; | |
| } | |
| // Calculate total discount from available coupons | |
| $total_value = 0; | |
| foreach ($available_coupons as $coupon_data) { | |
| $wc_coupon = $coupon_data['coupon']; | |
| $eligible_total = $coupon_data['eligible_total']; | |
| $coupon_amount = $wc_coupon->get_amount(); | |
| $type = strpos($wc_coupon->get_discount_type(), 'percent') !== false ? 'percent' : 'fixed'; | |
| if ($type === 'percent') { | |
| $coupon_amount = $eligible_total * ($coupon_amount / 100); | |
| } else { | |
| $coupon_amount = min($coupon_amount, $eligible_total); | |
| } | |
| $total_value += $coupon_amount; | |
| // Mark coupon as used | |
| $wc_coupon->set_usage_count($wc_coupon->get_usage_count() + 1); | |
| $wc_coupon->save(); | |
| if ($total_value >= $order_total) { | |
| break; | |
| } | |
| } | |
| // Cap discount to order total | |
| if ($total_value > $order_total) { | |
| $total_value = $order_total; | |
| } | |
| // Apply discount as negative fee | |
| if ($total_value > 0) { | |
| $item = new WC_Order_Item_Fee(); | |
| $item->set_props([ | |
| 'name' => __('Loyalty coupon applied', 'wpgens-loyalty-program'), | |
| 'tax_class' => null, | |
| 'total' => -$total_value, | |
| 'total_tax' => 0, | |
| 'tax_status' => 'none', | |
| 'order_id' => $order->get_id(), | |
| ]); | |
| $item->save(); | |
| $order->add_item($item); | |
| $order->update_taxes(); | |
| $order->calculate_totals(true); | |
| $order->add_order_note( | |
| sprintf('Auto-applied loyalty coupon discount (-%s) during subscription renewal.', wc_price($total_value)) | |
| ); | |
| } | |
| return $order; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment