Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save xlplugins/48419ffe61c1886d1592f247ba12c02c to your computer and use it in GitHub Desktop.

Select an option

Save xlplugins/48419ffe61c1886d1592f247ba12c02c to your computer and use it in GitHub Desktop.
Sublium : Order bump discount on the first payment only
/**
* Plugin Name: Sublium - Order bump discount on the first payment only
* Description: A Funnel Builder order bump discount on a subscription product applies to the first payment only. Every renewal, whatever the billing frequency, is charged at the full plan price.
* Version: 1.0.0
*
* Install as a must-use plugin (wp-content/mu-plugins/) or as a Code Snippets entry
* (everything below the opening tag, run everywhere).
*
* How it works
* - Sublium stores the discounted price on the subscription at purchase time and
* rebuilds every renewal order from it, so the bump discount repeats forever.
* - Funnel Builder tags the order line of a bump product with _bump_purchase = yes.
* - At checkout this snippet also records the full (undiscounted) recurring line total
* on that order line; Sublium copies the line meta onto the subscription item.
* - When any renewal order is built, the line is reset to the full price before
* WooCommerce calculates totals and taxes.
*
* Subscriptions bought before this snippet was installed have no recorded full price;
* for those the full price is read from the plan at renewal time instead.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Full recurring line total (excluding tax) of a plan product, ignoring any bump discount.
*
* @param int $product_id Product (or variation) ID.
* @param int $plan_id Sublium plan ID.
* @param int $quantity Line quantity.
*
* @return float|null Null when the price cannot be worked out.
*/
function sublium_bump_first_payment_full_total( $product_id, $plan_id, $quantity ) {
if ( ! class_exists( '\Sublium_WCS\Includes\Main\Plans' ) || empty( $plan_id ) ) {
return null;
}
// A fresh product object: the one in the cart carries the bump price.
$product = wc_get_product( $product_id );
if ( ! $product instanceof WC_Product ) {
return null;
}
try {
$plan = \Sublium_WCS\Includes\Main\Plans::get_plan_by_id( absint( $plan_id ), $product );
if ( empty( $plan ) || ! in_array( (int) $plan->get_type(), array( 1, 2, 3 ), true ) ) {
return null;
}
$unit = (float) $plan->get_recurring_cart_price( (float) $product->get_price(), $product );
} catch ( Throwable $e ) {
return null;
}
if ( $unit <= 0 ) {
return null;
}
return (float) wc_get_price_excluding_tax(
$product,
array(
'price' => $unit,
'qty' => max( 1, (int) $quantity ),
)
);
}
/**
* Remember the full recurring line total on the order line of a bump subscription product.
*
* @param WC_Order_Item_Product $item Order line.
* @param string $cart_item_key Cart item key.
* @param array $values Cart item.
*/
function sublium_bump_first_payment_record_full_total( $item, $cart_item_key, $values ) {
unset( $cart_item_key );
if ( empty( $values['_wfob_product'] ) || empty( $values['sublium_wcs_plan'] ) ) {
return;
}
$product_id = ! empty( $values['variation_id'] ) ? $values['variation_id'] : $values['product_id'];
$total = sublium_bump_first_payment_full_total( $product_id, $values['sublium_wcs_plan'], isset( $values['quantity'] ) ? $values['quantity'] : 1 );
if ( null !== $total ) {
$item->add_meta_data( '_sublium_bump_full_total', wc_format_decimal( $total ), true );
}
}
add_action( 'woocommerce_checkout_create_order_line_item', 'sublium_bump_first_payment_record_full_total', 20, 3 );
/**
* Charge bump lines at the full plan price on every renewal.
*
* @param WC_Order $order Renewal order, before totals are calculated.
*/
function sublium_bump_first_payment_restore_full_price( $order ) {
if ( ! $order instanceof WC_Order ) {
return;
}
foreach ( $order->get_items() as $item ) {
// Sublium writes the copied line meta straight to the database, so read it from there.
$item_id = $item->get_id();
if ( 'yes' !== wc_get_order_item_meta( $item_id, '_bump_purchase', true ) ) {
continue;
}
$full_total = wc_get_order_item_meta( $item_id, '_sublium_bump_full_total', true );
if ( '' === $full_total ) {
$product_id = $item->get_variation_id() ? $item->get_variation_id() : $item->get_product_id();
$full_total = sublium_bump_first_payment_full_total( $product_id, wc_get_order_item_meta( $item_id, '_sublium_wcs_plan', true ), $item->get_quantity() );
}
if ( null === $full_total || (float) $full_total <= 0 || (float) $full_total <= (float) $item->get_total() ) {
continue;
}
$item->set_subtotal( $full_total );
$item->set_total( $full_total );
$item->save();
wc_update_order_item_meta( $item_id, '_sublium_bump_discount_ended', 'yes' );
}
}
add_action( 'sublium_wcs_renewal_order_before_calculate_totals', 'sublium_bump_first_payment_restore_full_price' );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment