Skip to content

Instantly share code, notes, and snippets.

@goranefbl
Created March 13, 2026 13:30
Show Gist options
  • Select an option

  • Save goranefbl/6dd1f8c418af77cf21ec819f715a45b8 to your computer and use it in GitHub Desktop.

Select an option

Save goranefbl/6dd1f8c418af77cf21ec819f715a45b8 to your computer and use it in GitHub Desktop.
Auto apply coupon codes to renewals - loyalty plugin
<?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