mirror of
https://github.com/pronamic/woocommerce-subscriptions.git
synced 2025-10-07 10:04:03 +00:00
361 lines
12 KiB
PHP
361 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* Variable Subscription Product Class
|
|
*
|
|
* This class extends the WC Variable product class to create variable products with recurring payments.
|
|
*
|
|
* @class WC_Product_Variable_Subscription
|
|
* @package WooCommerce Subscriptions
|
|
* @category Class
|
|
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.3
|
|
*
|
|
*/
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit; // Exit if accessed directly
|
|
}
|
|
|
|
class WC_Product_Variable_Subscription extends WC_Product_Variable {
|
|
|
|
/**
|
|
* A cache of the variable product's min and max data generated by @see wcs_get_min_max_variation_data().
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $min_max_variation_data = array();
|
|
|
|
/**
|
|
* A cache of the variable product's sorted variation prices.
|
|
*
|
|
* @var array
|
|
*/
|
|
private $sorted_variation_prices = array();
|
|
|
|
/**
|
|
* Get internal type.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_type() {
|
|
return 'variable-subscription';
|
|
}
|
|
|
|
/**
|
|
* Auto-load in-accessible properties on demand.
|
|
*
|
|
* @param mixed $key
|
|
* @return mixed
|
|
*/
|
|
public function __get( $key ) {
|
|
|
|
if ( wcs_is_woocommerce_pre( '3.0' ) ) {
|
|
$value = parent::__get( $key );
|
|
} else {
|
|
$value = wcs_product_deprecated_property_handler( $key, $this );
|
|
|
|
// No matching property found in wcs_product_deprecated_property_handler()
|
|
if ( is_null( $value ) ) {
|
|
$value = parent::__get( $key );
|
|
}
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
/**
|
|
* Get the add to cart button text for the single page
|
|
*
|
|
* @access public
|
|
* @return string
|
|
*/
|
|
public function single_add_to_cart_text() {
|
|
|
|
if ( $this->is_purchasable() && $this->is_in_stock() ) {
|
|
$text = WC_Subscriptions_Product::get_add_to_cart_text();
|
|
} else {
|
|
$text = parent::add_to_cart_text(); // translated "Read More"
|
|
}
|
|
|
|
return apply_filters( 'woocommerce_product_single_add_to_cart_text', $text, $this );
|
|
}
|
|
|
|
/**
|
|
* Returns the price in html format.
|
|
*
|
|
* @access public
|
|
* @param string $price (default: '')
|
|
* @return string
|
|
*/
|
|
public function get_price_html( $price = '' ) {
|
|
$prices = $this->get_variation_prices( true );
|
|
$min_price_variation_id = $this->get_meta( '_min_price_variation_id' );
|
|
|
|
if ( empty( $min_price_variation_id ) ) {
|
|
WC_Subscriptions_Product::variable_subscription_product_sync( $this );
|
|
$min_price_variation_id = $this->get_meta( '_min_price_variation_id' );
|
|
}
|
|
|
|
if ( empty( $prices['price'] ) || ! $min_price_variation_id ) {
|
|
return apply_filters( 'woocommerce_variable_empty_price_html', '', $this );
|
|
}
|
|
|
|
$tax_display_mode = get_option( 'woocommerce_tax_display_shop' );
|
|
|
|
$price = WC_Subscriptions_Product::get_price( $min_price_variation_id );
|
|
$price = 'incl' == $tax_display_mode ? wcs_get_price_including_tax( $this, array( 'price' => $price ) ) : wcs_get_price_excluding_tax( $this, array( 'price' => $price ) );
|
|
$price = $this->get_price_prefix( $prices ) . wc_price( $price ) . $this->get_price_suffix();
|
|
$price = apply_filters( 'woocommerce_variable_price_html', $price, $this );
|
|
$price = WC_Subscriptions_Product::get_price_string( $this, array( 'price' => $price ) );
|
|
|
|
return apply_filters( 'woocommerce_variable_subscription_price_html', apply_filters( 'woocommerce_get_price_html', $price, $this ), $this );
|
|
}
|
|
|
|
/**
|
|
* Checks if the store manager has requested the current product be limited to one purchase
|
|
* per customer, and if so, checks whether the customer already has an active subscription to
|
|
* the product.
|
|
*
|
|
* @access public
|
|
* @return bool
|
|
*/
|
|
function is_purchasable() {
|
|
$purchasable = WCS_Limiter::is_purchasable( parent::is_purchasable(), $this );
|
|
|
|
return apply_filters( 'woocommerce_subscription_is_purchasable', $purchasable, $this );
|
|
}
|
|
|
|
/**
|
|
* Checks the product type to see if it is either this product's type or the parent's
|
|
* product type.
|
|
*
|
|
* @access public
|
|
* @param mixed $type Array or string of types
|
|
* @return bool
|
|
*/
|
|
public function is_type( $type ) {
|
|
if ( 'variable' == $type || ( is_array( $type ) && in_array( 'variable', $type ) ) ) {
|
|
return true;
|
|
} else {
|
|
return parent::is_type( $type );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sort an associative array of $variation_id => $price pairs in order of min and max prices.
|
|
*
|
|
* @param array $prices Associative array of $variation_id => $price pairs
|
|
* @return array
|
|
*/
|
|
protected function sort_variation_prices( $prices ) {
|
|
|
|
// If we don't have any prices, there's nothing to sort.
|
|
if ( empty( $prices ) ) {
|
|
return $prices;
|
|
}
|
|
|
|
$prices_hash = md5( json_encode( $prices ) );
|
|
|
|
if ( empty( $this->sorted_variation_prices[ $prices_hash ] ) ) {
|
|
|
|
$min_max_variation_data = $this->get_min_and_max_variation_data( array_keys( $prices ) );
|
|
|
|
$min_variation_id = $min_max_variation_data['min']['variation_id'];
|
|
$max_variation_id = $min_max_variation_data['max']['variation_id'];
|
|
|
|
// Reorder the variable price arrays to reflect the min and max values so that WooCommerce will find them in the correct order
|
|
$min_price = $prices[ $min_variation_id ];
|
|
$max_price = $prices[ $max_variation_id ];
|
|
|
|
unset( $prices[ $min_variation_id ] );
|
|
unset( $prices[ $max_variation_id ] );
|
|
|
|
// Prepend the minimum variation and append the maximum variation
|
|
$prices = array( $min_variation_id => $min_price ) + $prices;
|
|
$prices += array( $max_variation_id => $max_price );
|
|
|
|
$this->sorted_variation_prices[ $prices_hash ] = $prices;
|
|
}
|
|
|
|
return $this->sorted_variation_prices[ $prices_hash ];
|
|
}
|
|
|
|
/**
|
|
* Set the product's min and max variation data.
|
|
*
|
|
* @param array $min_and_max_data The min and max variation data returned by @see wcs_get_min_max_variation_data(). Optional.
|
|
* @param array $variation_ids The child variation IDs. Optional. By default this value be generated by @see WC_Product_Variable->get_visible_children().
|
|
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.0
|
|
*/
|
|
public function set_min_and_max_variation_data( $min_and_max_data = array(), $variation_ids = array() ) {
|
|
|
|
if ( empty( $variation_ids ) ) {
|
|
$variation_ids = $this->get_visible_children();
|
|
}
|
|
|
|
if ( empty( $min_and_max_data ) ) {
|
|
$min_and_max_data = wcs_get_min_max_variation_data( $this, $variation_ids );
|
|
}
|
|
|
|
$this->add_meta_data( '_min_max_variation_data', $min_and_max_data, true );
|
|
$this->add_meta_data( '_min_max_variation_ids_hash', $this->get_variation_ids_hash( $variation_ids ), true );
|
|
|
|
do_action( 'wc_subscriptions_min_and_max_variation_data_set', $this, $min_and_max_data, $variation_ids );
|
|
}
|
|
|
|
/**
|
|
* Get the min and max variation data.
|
|
*
|
|
* This is a wrapper for @see wcs_get_min_max_variation_data() but to avoid calling
|
|
* that resource intensive function multiple times per request, check the value
|
|
* stored in meta or cached in memory before calling that function.
|
|
*
|
|
* @param array $variation_ids An array of variation IDs.
|
|
* @return array The variable product's min and max variation data.
|
|
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.0
|
|
*/
|
|
public function get_min_and_max_variation_data( $variation_ids ) {
|
|
$variation_ids_hash = $this->get_variation_ids_hash( $variation_ids );
|
|
|
|
if ( $variation_ids_hash === $this->get_meta( '_min_max_variation_ids_hash', true ) ) {
|
|
$min_and_max_variation_data = $this->get_meta( '_min_max_variation_data', true );
|
|
} elseif ( ! empty( $this->min_max_variation_data[ $variation_ids_hash ] ) ) {
|
|
$min_and_max_variation_data = $this->min_max_variation_data[ $variation_ids_hash ];
|
|
} else {
|
|
$min_and_max_variation_data = wcs_get_min_max_variation_data( $this, $variation_ids );
|
|
$this->min_max_variation_data[ $variation_ids_hash ] = $min_and_max_variation_data;
|
|
}
|
|
|
|
return $min_and_max_variation_data;
|
|
}
|
|
|
|
/**
|
|
* Generate a unique hash from an array of variation IDs.
|
|
*
|
|
* @param array $variation_ids
|
|
* @return string
|
|
*/
|
|
protected static function get_variation_ids_hash( $variation_ids ) {
|
|
// Sort the variation IDs so the hash isn't different for the same array of IDs
|
|
sort( $variation_ids );
|
|
|
|
return md5( json_encode( $variation_ids ) );
|
|
}
|
|
|
|
/* Deprecated Functions */
|
|
|
|
/**
|
|
* Return the sign-up fee for this product
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_sign_up_fee() {
|
|
wcs_deprecated_function( __METHOD__, '2.2.0', 'WC_Subscriptions_Product::get_sign_up_fee( $this )' );
|
|
return WC_Subscriptions_Product::get_sign_up_fee( $this );
|
|
}
|
|
|
|
/**
|
|
* Returns the sign up fee (including tax) by filtering the products price used in
|
|
* @see WC_Product::get_price_including_tax( $qty )
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_sign_up_fee_including_tax( $qty = 1 ) {
|
|
wcs_deprecated_function( __METHOD__, '2.2.0', 'wcs_get_price_including_tax( $product, array( "qty" => $qty, "price" => WC_Subscriptions_Product::get_sign_up_fee( $product ) ) )' );
|
|
return wcs_get_price_including_tax(
|
|
$this,
|
|
array(
|
|
'qty' => $qty,
|
|
'price' => WC_Subscriptions_Product::get_sign_up_fee( $this ),
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns the sign up fee (excluding tax) by filtering the products price used in
|
|
* @see WC_Product::get_price_excluding_tax( $qty )
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_sign_up_fee_excluding_tax( $qty = 1 ) {
|
|
wcs_deprecated_function( __METHOD__, '2.2.0', 'wcs_get_price_excluding_tax( $product, array( "qty" => $qty, "price" => WC_Subscriptions_Product::get_sign_up_fee( $product ) ) )' );
|
|
return wcs_get_price_excluding_tax(
|
|
$this,
|
|
array(
|
|
'qty' => $qty,
|
|
'price' => WC_Subscriptions_Product::get_sign_up_fee( $this ),
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Use WC core add-to-cart handlers for subscription products.
|
|
*
|
|
* @param string $handler The name of the handler to use when adding product to the cart
|
|
* @param WC_Product $product
|
|
*/
|
|
public function add_to_cart_handler( $handler, $product ) {
|
|
wcs_deprecated_function( __METHOD__, '2.2.0', 'WC_Subscriptions_Cart::add_to_cart_handler( $handler, $product )' );
|
|
return WC_Subscriptions_Cart::add_to_cart_handler( $handler, $product );
|
|
}
|
|
|
|
/**
|
|
* Sync variable product prices with the children lowest/highest prices.
|
|
*
|
|
* @param int $product_id The ID of the product to sync.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function variable_product_sync( $product_id = 0 ) {
|
|
wcs_deprecated_function( __METHOD__, '2.2,0', 'WC_Subscriptions_Product::variable_subscription_product_sync( $this )' );
|
|
|
|
if ( empty( $product_id ) ) {
|
|
$product_id = $this->get_id();
|
|
}
|
|
|
|
// Sync prices with children
|
|
self::sync( $product_id );
|
|
}
|
|
|
|
/**
|
|
* Get the suffix to display before prices.
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function get_price_prefix( $prices ) {
|
|
|
|
$child_variation_ids = array_keys( $prices['price'] );
|
|
$min_max_variation_data = $this->get_min_and_max_variation_data( $child_variation_ids );
|
|
|
|
// Are the subscription details of all variations identical?
|
|
if ( $min_max_variation_data['identical'] ) {
|
|
$prefix = '';
|
|
} else {
|
|
$prefix = wcs_get_price_html_from_text( $this );
|
|
}
|
|
|
|
return $prefix;
|
|
}
|
|
|
|
/**
|
|
* Gets an array of available variations.
|
|
*
|
|
* @param string $return Optional. The format to return the results in. Can be 'array' to return an array of variation data or 'objects' for the product objects. Default 'array'.
|
|
* @return array|WC_Product_Subscription_Variation[]
|
|
*/
|
|
public function get_available_variations( $return = 'array' ) {
|
|
$available_variations = parent::get_available_variations( $return );
|
|
|
|
// Add the variation first payment date if data is being prepared for the add to cart form.
|
|
if ( 'array' === $return ) {
|
|
foreach ( $available_variations as $index => $variation_data ) {
|
|
|
|
// Add the product's synced first payment date to the variation data if applicable.
|
|
if ( isset( $variation_data['variation_id'] ) ) {
|
|
$available_variations[ $index ]['first_payment_html'] = WC_Subscriptions_Synchroniser::get_products_first_payment_date( wc_get_product( $variation_data['variation_id'] ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
return $available_variations;
|
|
}
|
|
}
|