mirror of
https://github.com/pronamic/woocommerce-subscriptions.git
synced 2025-10-07 10:04:03 +00:00
409 lines
16 KiB
PHP
409 lines
16 KiB
PHP
<?php
|
|
/**
|
|
* WooCommerce Subscriptions Product Functions
|
|
*
|
|
* Functions for managing renewal of a subscription.
|
|
*
|
|
* @author Prospress
|
|
* @category Core
|
|
* @package WooCommerce Subscriptions/Functions
|
|
* @version 2.2.0
|
|
*/
|
|
|
|
/**
|
|
* For a given product, and optionally price/qty, work out the sign-up with tax included, based on store settings.
|
|
*
|
|
* @since 2.2.0
|
|
* @param WC_Product $product
|
|
* @param array $args
|
|
* @return float
|
|
*/
|
|
function wcs_get_price_including_tax( $product, $args = array() ) {
|
|
|
|
$args = wp_parse_args( $args, array(
|
|
'qty' => 1,
|
|
'price' => $product->get_price(),
|
|
) );
|
|
|
|
if ( function_exists( 'wc_get_price_including_tax' ) ) { // WC 3.0+
|
|
$price = wc_get_price_including_tax( $product, $args );
|
|
$filter = 'woocommerce_product_get_price';
|
|
} else { // WC < 3.0
|
|
$price = $product->get_price_including_tax( $args['qty'], $args['price'] );
|
|
$filter = 'woocommerce_get_price';
|
|
}
|
|
|
|
return apply_filters( $filter, $price , $product );
|
|
}
|
|
|
|
/**
|
|
* For a given product, and optionally price/qty, work out the sign-up fee with tax excluded, based on store settings.
|
|
*
|
|
* @since 2.2.0
|
|
* @param WC_Product $product
|
|
* @param array $args
|
|
* @return float
|
|
*/
|
|
function wcs_get_price_excluding_tax( $product, $args = array() ) {
|
|
|
|
$args = wp_parse_args( $args, array(
|
|
'qty' => 1,
|
|
'price' => $product->get_price(),
|
|
) );
|
|
|
|
if ( function_exists( 'wc_get_price_excluding_tax' ) ) { // WC 3.0+
|
|
$price = wc_get_price_excluding_tax( $product, $args );
|
|
$filter = 'woocommerce_product_get_price';
|
|
} else { // WC < 3.0
|
|
$price = $product->get_price_excluding_tax( $args['qty'], $args['price'] );
|
|
$filter = 'woocommerce_get_price';
|
|
}
|
|
|
|
return apply_filters( $filter, $price , $product );
|
|
}
|
|
|
|
/**
|
|
* Returns a 'from' prefix if you want to show where prices start at.
|
|
*
|
|
* @since 2.2.0
|
|
* @return string
|
|
*/
|
|
function wcs_get_price_html_from_text( $product = '' ) {
|
|
|
|
if ( function_exists( 'wc_get_price_html_from_text' ) ) { // WC 3.0+
|
|
$price_html_from_text = wc_get_price_html_from_text();
|
|
} else { // WC < 3.0
|
|
$price_html_from_text = $product->get_price_html_from_text();
|
|
}
|
|
|
|
return $price_html_from_text;
|
|
}
|
|
|
|
/**
|
|
* Get an array of the prices, used to help determine min/max values.
|
|
*
|
|
* @since 2.2.0
|
|
*/
|
|
function wcs_get_variation_prices( $variation, $variable_product ) {
|
|
|
|
return array(
|
|
'price' => apply_filters( 'woocommerce_variation_prices_price', WC_Subscriptions_Product::get_price( $variation ), $variation, $variable_product ),
|
|
'regular_price' => apply_filters( 'woocommerce_variation_prices_regular_price', WC_Subscriptions_Product::get_regular_price( $variation, 'edit' ), $variation, $variable_product ),
|
|
'sale_price' => apply_filters( 'woocommerce_variation_prices_sale_price', WC_Subscriptions_Product::get_sale_price( $variation, 'edit' ), $variation, $variable_product ),
|
|
'sign_up_fee' => apply_filters( 'woocommerce_variation_prices_sign_up_fee', WC_Subscriptions_Product::get_sign_up_fee( $variation ), $variation, $variable_product ),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get an array of the minimum and maximum priced variations based on subscription billing terms.
|
|
*
|
|
* @param array $child_variation_ids the IDs of product variation children ids
|
|
* @return array() Array containing the min and max variation prices and billing data
|
|
* @since 2.2.0
|
|
*/
|
|
function wcs_get_min_max_variation_data( $variable_product, $child_variation_ids = array() ) {
|
|
|
|
if ( empty( $child_variation_ids ) ) {
|
|
$child_variation_ids = is_callable( array( $variable_product, 'get_visible_children' ) ) ? $variable_product->get_visible_children() : $variable_product->get_children( true );
|
|
}
|
|
|
|
$variations_data = array();
|
|
|
|
foreach ( $child_variation_ids as $variation_id ) {
|
|
|
|
if ( $variation = wc_get_product( $variation_id ) ) {
|
|
|
|
$prices = wcs_get_variation_prices( $variation, $variable_product );
|
|
|
|
foreach ( $prices as $price_key => $amount ) {
|
|
if ( '' !== $amount ) {
|
|
if ( 'incl' === get_option( 'woocommerce_tax_display_shop' ) ) {
|
|
$prices[ $price_key ] = wcs_get_price_including_tax( $variable_product, array( 'price' => $amount ) );
|
|
} else {
|
|
$prices[ $price_key ] = wcs_get_price_excluding_tax( $variable_product, array( 'price' => $amount ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
$variations_data[ $variation_id ] = array(
|
|
'price' => $prices['price'],
|
|
'regular_price' => $prices['regular_price'],
|
|
'sale_price' => $prices['sale_price'],
|
|
'subscription' => array(
|
|
'sign_up_fee' => $prices['sign_up_fee'],
|
|
'period' => WC_Subscriptions_Product::get_period( $variation ),
|
|
'interval' => WC_Subscriptions_Product::get_interval( $variation ),
|
|
'trial_length' => WC_Subscriptions_Product::get_trial_length( $variation ),
|
|
'trial_period' => WC_Subscriptions_Product::get_trial_period( $variation ),
|
|
'length' => WC_Subscriptions_Product::get_length( $variation ),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
return wcs_calculate_min_max_variations( $variations_data );
|
|
}
|
|
|
|
/**
|
|
* Determine the minimum and maximum values for a set of structured subscription
|
|
* price data in a form created by @see wcs_get_min_max_variation_data()
|
|
*
|
|
* @param array $child_variation_ids the IDs of product variation children ids
|
|
* @return array
|
|
* @since 2.2.0
|
|
*/
|
|
function wcs_calculate_min_max_variations( $variations_data ) {
|
|
|
|
$lowest_initial_amount = $highest_initial_amount = $lowest_price = $highest_price = '';
|
|
$shortest_initial_period = $longest_initial_period = $shortest_trial_period = $longest_trial_period = $shortest_trial_length = $longest_trial_length = '';
|
|
$longest_initial_interval = $shortest_initial_interval = $variable_subscription_period = $variable_subscription_period_interval = '';
|
|
$lowest_regular_price = $highest_regular_price = $lowest_sale_price = $highest_sale_price = $max_subscription_period = $max_subscription_period_interval = '';
|
|
$variable_subscription_sign_up_fee = $variable_subscription_trial_period = $variable_subscription_trial_length = $variable_subscription_length = $variable_subscription_sign_up_fee = $variable_subscription_trial_period = $variable_subscription_trial_length = $variable_subscription_length = '';
|
|
$min_variation_id = $max_variation_id = null;
|
|
|
|
foreach ( $variations_data as $variation_id => $variation_data ) {
|
|
|
|
$is_max = $is_min = false;
|
|
|
|
if ( '' === $variation_data['price'] && '' === $variation_data['subscription']['sign_up_fee'] ) {
|
|
continue;
|
|
}
|
|
|
|
$has_free_trial = ( '' !== $variation_data['subscription']['trial_length'] && $variation_data['subscription']['trial_length'] > 0 ) ? true : false;
|
|
|
|
// Determine some recurring price flags
|
|
$is_lowest_price = ( $variation_data['price'] < $lowest_price || '' === $lowest_price ) ? true : false;
|
|
$is_longest_period = ( WC_Subscriptions::get_longest_period( $variable_subscription_period, $variation_data['subscription']['period'] ) === $variation_data['subscription']['period'] ) ? true : false;
|
|
$is_longest_interval = ( $variation_data['subscription']['interval'] >= $variable_subscription_period_interval || '' === $variable_subscription_period_interval ) ? true : false;
|
|
|
|
// Find the amount the subscriber will have to pay up-front
|
|
if ( $has_free_trial ) {
|
|
$initial_amount = $variation_data['subscription']['sign_up_fee'];
|
|
$initial_period = $variation_data['subscription']['trial_period'];
|
|
$initial_interval = $variation_data['subscription']['trial_length'];
|
|
} else {
|
|
$initial_amount = $variation_data['price'] + $variation_data['subscription']['sign_up_fee'];
|
|
$initial_period = $variation_data['subscription']['period'];
|
|
$initial_interval = $variation_data['subscription']['interval'];
|
|
}
|
|
|
|
// We have a free trial & no sign-up fee, so need to choose the longest free trial (and maybe the shortest)
|
|
if ( $has_free_trial && 0 == $variation_data['subscription']['sign_up_fee'] ) {
|
|
|
|
// First variation
|
|
if ( '' === $longest_trial_period ) {
|
|
|
|
$is_min = true;
|
|
|
|
// If two variations have the same free trial, choose the variation with the lowest recurring price for the longest period
|
|
} elseif ( $variable_subscription_trial_period === $variation_data['subscription']['trial_period'] && $variation_data['subscription']['trial_length'] === $variable_subscription_trial_length ) {
|
|
|
|
// If the variation has the lowest recurring price, it's the cheapest
|
|
if ( $is_lowest_price ) {
|
|
|
|
$is_min = true;
|
|
|
|
// When current variation's free trial is the same as the lowest, it's the cheaper if it has a longer billing schedule
|
|
} elseif ( $variation_data['price'] === $lowest_price ) {
|
|
|
|
if ( $is_longest_period && $is_longest_interval ) {
|
|
|
|
$is_min = true;
|
|
|
|
// Longest with a new billing period
|
|
} elseif ( $is_longest_period && $variation_data['subscription']['period'] !== $variable_subscription_trial_period ) {
|
|
|
|
$is_min = true;
|
|
|
|
}
|
|
}
|
|
|
|
// Otherwise the cheapest variation is the one with the longer trial
|
|
} elseif ( $variable_subscription_trial_period === $variation_data['subscription']['trial_period'] ) {
|
|
|
|
$is_min = ( $variation_data['subscription']['trial_length'] > $variable_subscription_trial_length ) ? true : false;
|
|
|
|
// Otherwise just a longer trial period (that isn't equal to the longest period)
|
|
} elseif ( WC_Subscriptions::get_longest_period( $longest_trial_period, $variation_data['subscription']['trial_period'] ) === $variation_data['subscription']['trial_period'] ) {
|
|
|
|
$is_min = true;
|
|
|
|
}
|
|
|
|
if ( $is_min ) {
|
|
$longest_trial_period = $variation_data['subscription']['trial_period'];
|
|
$longest_trial_length = $variation_data['subscription']['trial_length'];
|
|
}
|
|
|
|
// If the current cheapest variation is also free, then the shortest trial period is the most expensive
|
|
if ( 0 == $lowest_price || '' === $lowest_price ) {
|
|
|
|
if ( '' === $shortest_trial_period ) {
|
|
|
|
$is_max = true;
|
|
|
|
// Need to check trial length
|
|
} elseif ( $shortest_trial_period === $variation_data['subscription']['trial_period'] ) {
|
|
|
|
$is_max = ( $variation_data['subscription']['trial_length'] < $shortest_trial_length ) ? true : false;
|
|
|
|
// Need to find shortest period
|
|
} elseif ( WC_Subscriptions::get_shortest_period( $shortest_trial_period, $variation_data['subscription']['trial_period'] ) === $variation_data['subscription']['trial_period'] ) {
|
|
|
|
$is_max = true;
|
|
|
|
}
|
|
|
|
if ( $is_max ) {
|
|
$shortest_trial_period = $variation_data['subscription']['trial_period'];
|
|
$shortest_trial_length = $variation_data['subscription']['trial_length'];
|
|
}
|
|
}
|
|
} else {
|
|
|
|
$longest_initial_period = WC_Subscriptions::get_longest_period( $longest_initial_period, $initial_period );
|
|
$shortest_initial_period = WC_Subscriptions::get_shortest_period( $shortest_initial_period, $initial_period );
|
|
|
|
$is_lowest_initial_amount = ( $initial_amount < $lowest_initial_amount || '' === $lowest_initial_amount ) ? true : false;
|
|
$is_longest_initial_period = ( $initial_period === $longest_initial_period ) ? true : false;
|
|
$is_longest_initial_interval = ( $initial_interval >= $longest_initial_interval || '' === $longest_initial_interval ) ? true : false;
|
|
|
|
$is_highest_initial = ( $initial_amount > $highest_initial_amount || '' === $highest_initial_amount ) ? true : false;
|
|
$is_shortest_period = ( $initial_period === $shortest_initial_period || '' === $shortest_initial_period ) ? true : false;
|
|
$is_shortest_interval = ( $initial_interval < $shortest_initial_interval || '' === $shortest_initial_interval ) ? true : false;
|
|
|
|
// If we're not dealing with the lowest initial access amount, then ignore this variation
|
|
if ( ! $is_lowest_initial_amount && $initial_amount !== $lowest_initial_amount ) {
|
|
continue;
|
|
}
|
|
|
|
// If the variation has the lowest price, it's the cheapest
|
|
if ( $is_lowest_initial_amount ) {
|
|
|
|
$is_min = true;
|
|
|
|
// When current variation's price is the same as the lowest, it's the cheapest only if it has a longer billing schedule
|
|
} elseif ( $initial_amount === $lowest_initial_amount ) {
|
|
|
|
// We need to check the recurring schedule when the sign-up fee & free trial periods are equal
|
|
if ( $has_free_trial && $initial_period == $longest_initial_period && $initial_interval == $longest_initial_interval ) {
|
|
|
|
// If the variation has the lowest recurring price, it's the cheapest
|
|
if ( $is_lowest_price ) {
|
|
|
|
$is_min = true;
|
|
|
|
// When current variation's price is the same as the lowest, it's the cheapest only if it has a longer billing schedule
|
|
} elseif ( $variation_data['price'] === $lowest_price ) {
|
|
|
|
if ( $is_longest_period && $is_longest_interval ) {
|
|
|
|
$is_min = true;
|
|
|
|
// Longest with a new billing period
|
|
} elseif ( $is_longest_period && $variation_data['subscription']['period'] !== $variable_subscription_period ) {
|
|
|
|
$is_min = true;
|
|
|
|
}
|
|
}
|
|
// Longest initial term is the cheapest
|
|
} elseif ( $is_longest_initial_period && $is_longest_initial_interval ) {
|
|
|
|
$is_min = true;
|
|
|
|
// Longest with a new billing period
|
|
} elseif ( $is_longest_initial_period && $initial_period !== $variable_subscription_period ) {
|
|
|
|
$is_min = true;
|
|
|
|
}
|
|
}
|
|
|
|
// If we have the highest price for the shortest period, we might have the maximum variation
|
|
if ( $is_highest_initial && $is_shortest_period && $is_shortest_interval ) {
|
|
|
|
$is_max = true;
|
|
|
|
// But only if its for the shortest billing period
|
|
} elseif ( $variation_data['price'] === $highest_price ) {
|
|
|
|
if ( $is_shortest_period && $is_shortest_interval ) {
|
|
|
|
$is_max = true;
|
|
|
|
} elseif ( $is_shortest_period ) {
|
|
|
|
$is_max = true;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// If it's the min subscription terms
|
|
if ( $is_min ) {
|
|
|
|
$min_variation_id = $variation_id;
|
|
|
|
$lowest_price = $variation_data['price'];
|
|
$lowest_regular_price = $variation_data['regular_price'];
|
|
$lowest_sale_price = $variation_data['sale_price'];
|
|
|
|
$lowest_regular_price = ( '' === $lowest_regular_price ) ? 0 : $lowest_regular_price;
|
|
$lowest_sale_price = ( '' === $lowest_sale_price ) ? 0 : $lowest_sale_price;
|
|
|
|
$lowest_initial_amount = $initial_amount;
|
|
$longest_initial_period = $initial_period;
|
|
$longest_initial_interval = $initial_interval;
|
|
|
|
$variable_subscription_sign_up_fee = $variation_data['subscription']['sign_up_fee'];
|
|
$variable_subscription_period = $variation_data['subscription']['period'];
|
|
$variable_subscription_period_interval = $variation_data['subscription']['interval'];
|
|
$variable_subscription_trial_length = $variation_data['subscription']['trial_length'];
|
|
$variable_subscription_trial_period = $variation_data['subscription']['trial_period'];
|
|
$variable_subscription_length = $variation_data['subscription']['length'];
|
|
}
|
|
|
|
if ( $is_max ) {
|
|
|
|
$max_variation_id = $variation_id;
|
|
|
|
$highest_price = $variation_data['price'];
|
|
$highest_regular_price = $variation_data['regular_price'];
|
|
$highest_sale_price = $variation_data['sale_price'];
|
|
$highest_initial_amount = $initial_amount;
|
|
|
|
$highest_regular_price = ( '' === $highest_regular_price ) ? 0 : $highest_regular_price;
|
|
$highest_sale_price = ( '' === $highest_sale_price ) ? 0 : $highest_sale_price;
|
|
|
|
$max_subscription_period = $variation_data['subscription']['period'];
|
|
$max_subscription_period_interval = $variation_data['subscription']['interval'];
|
|
}
|
|
}
|
|
|
|
return array(
|
|
'min' => array(
|
|
'variation_id' => $min_variation_id,
|
|
'price' => $lowest_price,
|
|
'regular_price' => $lowest_regular_price,
|
|
'sale_price' => $lowest_sale_price,
|
|
'period' => $variable_subscription_period,
|
|
'interval' => $variable_subscription_period_interval,
|
|
),
|
|
'max' => array(
|
|
'variation_id' => $max_variation_id,
|
|
'price' => $highest_price,
|
|
'regular_price' => $highest_regular_price,
|
|
'sale_price' => $highest_sale_price,
|
|
'period' => $max_subscription_period,
|
|
'interval' => $max_subscription_period_interval,
|
|
),
|
|
'subscription' => array(
|
|
'signup-fee' => $variable_subscription_sign_up_fee,
|
|
'trial_period' => $variable_subscription_trial_period,
|
|
'trial_length' => $variable_subscription_trial_length,
|
|
'length' => $variable_subscription_length,
|
|
),
|
|
);
|
|
}
|