mirror of
https://github.com/pronamic/woocommerce-subscriptions.git
synced 2025-10-07 10:04:03 +00:00
290 lines
12 KiB
PHP
290 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* WooCommerce Subscriptions Deprecated Functions
|
|
*
|
|
* Functions for handling backward compatibility with the Subscription 1.n
|
|
* data structure and reference system (i.e. $subscription_key instead of a
|
|
* post ID)
|
|
*
|
|
* @author Prospress
|
|
* @category Core
|
|
* @package WooCommerce Subscriptions/Functions
|
|
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit; // Exit if accessed directly
|
|
}
|
|
|
|
/**
|
|
* Wrapper for wc_doing_it_wrong.
|
|
*
|
|
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
|
* @param string $function
|
|
* @param string $message
|
|
* @param string $version
|
|
*/
|
|
function wcs_doing_it_wrong( $function, $message, $version ) {
|
|
|
|
if ( function_exists( 'wc_doing_it_wrong' ) ) {
|
|
wc_doing_it_wrong( $function, $message, $version );
|
|
} else {
|
|
// Reimplement wc_doing_it_wrong() when WC 3.0 is not active
|
|
if ( wp_doing_ajax() ) {
|
|
do_action( 'doing_it_wrong_run', $function, $message, $version );
|
|
error_log( "{$function} was called incorrectly. {$message}. This message was added in version {$version}." );
|
|
} else {
|
|
_doing_it_wrong( esc_attr( $function ), esc_attr( $message ), esc_attr( $version ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Wrapper for wcs_deprecated_function to improve handling of ajax requests, even when
|
|
* WooCommerce 3.0's wcs_deprecated_function method is not available.
|
|
*
|
|
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
|
* @param string $function
|
|
* @param string $version
|
|
* @param string $replacement
|
|
*/
|
|
function wcs_deprecated_function( $function, $version, $replacement = null ) {
|
|
|
|
if ( function_exists( 'wc_deprecated_function' ) ) {
|
|
wc_deprecated_function( $function, $version, $replacement );
|
|
} else {
|
|
// Reimplement wcs_deprecated_function() when WC 3.0 is not active
|
|
if ( wp_doing_ajax() ) {
|
|
do_action( 'deprecated_function_run', $function, $replacement, $version );
|
|
$log_string = "The {$function} function is deprecated since version {$version}.";
|
|
$log_string .= $replacement ? " Replace with {$replacement}." : '';
|
|
error_log( $log_string );
|
|
} else {
|
|
_deprecated_function( esc_attr( $function ), esc_attr( $version ), esc_attr( $replacement ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reimplement similar logic to wc_deprecated_argument() without the first parameter confusion.
|
|
*
|
|
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
|
* @param string $function
|
|
* @param string $version
|
|
* @param string $message
|
|
*/
|
|
function wcs_deprecated_argument( $function, $version, $message = null ) {
|
|
if ( wp_doing_ajax() ) {
|
|
do_action( 'deprecated_argument_run', $function, $message, $version );
|
|
error_log( "{$function} was called with an argument that is deprecated since version {$version}. {$message}" );
|
|
} else {
|
|
_deprecated_argument( esc_attr( $function ), esc_attr( $version ), esc_attr( $message ) );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the string key for a subscription used in Subscriptions prior to 2.0.
|
|
*
|
|
* Previously, a subscription key was made up of the ID of the order used to purchase the subscription, and
|
|
* the product to which the subscription relates; however, in Subscriptions 2.0, subscriptions can actually
|
|
* relate to multiple products (because they can contain multiple line items) and they also no longer need
|
|
* to have an original order associated with them, to make manually adding subscriptions more accurate.
|
|
*
|
|
* Therefore, although the return value of this method is a string matching the key form used inSubscriptions
|
|
* prior to 2.0, the actual value represented is not a perfect analogue. Specifically,
|
|
* - if the subscription contains more than one product, only the ID of the first line item will be used in the ID
|
|
* - if the subscription does not contain any products, the key still be missing that component of the
|
|
* - if the subscription does not have an initial order, then the order ID used will be the WC_Subscription object's ID
|
|
*
|
|
* @param WC_Subscription $subscription An instance of WC_Subscription
|
|
* @return string $subscription_key A subscription key in the deprecated form previously created by @see self::get_subscription_key()
|
|
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
|
*/
|
|
function wcs_get_old_subscription_key( WC_Subscription $subscription ) {
|
|
|
|
// Get an ID to use as the order ID
|
|
$order_id = ( false == $subscription->get_parent_id() ) ? $subscription->get_id() : $subscription->get_parent_id();
|
|
|
|
// Get an ID to use as the product ID
|
|
$subscription_items = $subscription->get_items();
|
|
$first_item = reset( $subscription_items );
|
|
|
|
return $order_id . '_' . WC_Subscriptions_Order::get_items_product_id( $first_item );
|
|
}
|
|
|
|
/**
|
|
* Return the post ID of a WC_Subscription object for the given subscription key (if one exists).
|
|
*
|
|
* @param string $subscription_key A subscription key in the deprecated form created by @see WC_Subscriptions_Manager::get_subscription_key()
|
|
* @return int|null The post ID for the subscription if it can be found (i.e. an order exists) or null if no order exists for the subscription.
|
|
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
|
*/
|
|
function wcs_get_subscription_id_from_key( $subscription_key ) {
|
|
global $wpdb;
|
|
|
|
// it can be either 8_13 or just 8. If it's 8, it'll be an integer
|
|
if ( ! is_string( $subscription_key ) && ! is_int( $subscription_key ) ) {
|
|
return null;
|
|
}
|
|
|
|
$order_and_product_id = explode( '_', $subscription_key );
|
|
$subscription_ids = array();
|
|
|
|
// If we have an order ID and product ID, query based on that
|
|
if ( ! empty( $order_and_product_id[0] ) && ! empty( $order_and_product_id[1] ) ) {
|
|
$subscription_ids = $wpdb->get_col( $wpdb->prepare( "
|
|
SELECT DISTINCT order_items.order_id FROM {$wpdb->prefix}woocommerce_order_items as order_items
|
|
LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS itemmeta ON order_items.order_item_id = itemmeta.order_item_id
|
|
LEFT JOIN {$wpdb->posts} AS posts ON order_items.order_id = posts.ID
|
|
WHERE posts.post_type = 'shop_subscription'
|
|
AND posts.post_parent = %d
|
|
AND itemmeta.meta_value = %d
|
|
AND itemmeta.meta_key IN ( '_variation_id', '_product_id' )",
|
|
$order_and_product_id[0], $order_and_product_id[1] ) );
|
|
|
|
} elseif ( ! empty( $order_and_product_id[0] ) ) {
|
|
// Not replacing this `get_posts` call with `wc_get_orders`. This is from when subscription object used to be an array of data stored in order meta ({$order_id}_{$product_id}, referred to as a "subscriptions key")
|
|
$subscription_ids = get_posts(
|
|
array(
|
|
'posts_per_page' => 1,
|
|
'post_parent' => $order_and_product_id[0],
|
|
'post_status' => 'any',
|
|
'post_type' => 'shop_subscription',
|
|
'fields' => 'ids',
|
|
)
|
|
);
|
|
}
|
|
|
|
return ( ! empty( $subscription_ids ) ) ? $subscription_ids[0] : null;
|
|
}
|
|
|
|
/**
|
|
* Return an instance of a WC_Subscription object for the given subscription key (if one exists).
|
|
*
|
|
* @param string $subscription_key A subscription key in the deprecated form created by @see self::get_subscription_key()
|
|
* @return WC_Subscription|null The subscription object if it can be found (i.e. an order exists) or null if no order exists for the subscription (i.e. it was manually created).
|
|
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
|
*/
|
|
function wcs_get_subscription_from_key( $subscription_key ) {
|
|
|
|
$subscription_id = wcs_get_subscription_id_from_key( $subscription_key );
|
|
|
|
if ( null !== $subscription_id && is_numeric( $subscription_id ) ) {
|
|
$subscription = wcs_get_subscription( $subscription_id );
|
|
}
|
|
|
|
// @phpstan-ignore variable.undefined
|
|
if ( ! is_object( $subscription ) ) {
|
|
// translators: placeholder is either subscription key or a subscription id, or, failing that, empty (e.g. "145_21" or "145")
|
|
throw new InvalidArgumentException( sprintf( __( 'Could not get subscription. Most likely the subscription key does not refer to a subscription. The key was: "%s".', 'woocommerce-subscriptions' ), $subscription_key ) );
|
|
}
|
|
|
|
return $subscription;
|
|
}
|
|
|
|
/**
|
|
* Return an associative array of a given subscriptions details (if it exists) in the pre v2.0 data structure.
|
|
*
|
|
* @param WC_Subscription $subscription An instance of WC_Subscription
|
|
* @return array Subscription details
|
|
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
|
*/
|
|
function wcs_get_subscription_in_deprecated_structure( WC_Subscription $subscription ) {
|
|
|
|
$completed_payments = array();
|
|
|
|
if ( $subscription->get_payment_count() ) {
|
|
|
|
$order = $subscription->get_parent();
|
|
|
|
if ( ! empty( $order ) ) {
|
|
$parent_order_created_date = wcs_get_objects_property( $order, 'date_created' );
|
|
|
|
if ( ! is_null( $parent_order_created_date ) ) {
|
|
$completed_payments[] = wcs_get_datetime_utc_string( $parent_order_created_date );
|
|
}
|
|
}
|
|
|
|
foreach ( $subscription->get_related_orders( 'all', 'renewal' ) as $renewal_order ) {
|
|
|
|
// Not all gateways would call $order->payment_complete() with WC < 3.0, so we need to find renewal orders with a paid status or a paid date (WC 3.0+ takes care of setting the paid date when payment_complete() wasn't called)
|
|
if ( null !== wcs_get_objects_property( $renewal_order, 'date_paid' ) || $renewal_order->has_status( $subscription->get_paid_order_statuses() ) ) {
|
|
|
|
$date_created = wcs_get_objects_property( $renewal_order, 'date_created' );
|
|
|
|
if ( ! is_null( $date_created ) ) {
|
|
$completed_payments[] = wcs_get_datetime_utc_string( $date_created );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$items = $subscription->get_items();
|
|
$item = array_pop( $items );
|
|
|
|
if ( ! empty( $item ) ) {
|
|
|
|
$deprecated_subscription_object = array(
|
|
'order_id' => $subscription->get_parent_id(),
|
|
'product_id' => isset( $item['product_id'] ) ? $item['product_id'] : 0,
|
|
'variation_id' => isset( $item['variation_id'] ) ? $item['variation_id'] : 0,
|
|
'status' => $subscription->get_status(),
|
|
|
|
// Subscription billing details
|
|
'period' => $subscription->get_billing_period(),
|
|
'interval' => $subscription->get_billing_interval(),
|
|
'length' => wcs_estimate_periods_between( ( 0 == $subscription->get_time( 'trial_end' ) ) ? $subscription->get_time( 'date_created' ) : $subscription->get_time( 'trial_end' ), $subscription->get_time( 'end' ) + 120, $subscription->get_billing_period(), 'floor' ) / $subscription->get_billing_interval(), // Since subscriptions no longer have a length, we need to calculate the length given the start and end dates and the period.
|
|
|
|
// Subscription dates
|
|
'start_date' => $subscription->get_date( 'start' ),
|
|
'expiry_date' => $subscription->get_date( 'end' ),
|
|
'end_date' => $subscription->has_status( wcs_get_subscription_ended_statuses() ) ? $subscription->get_date( 'end' ) : 0,
|
|
'trial_expiry_date' => $subscription->get_date( 'trial_end' ),
|
|
|
|
// Payment & status change history
|
|
'failed_payments' => $subscription->get_failed_payment_count(),
|
|
'completed_payments' => $completed_payments,
|
|
'suspension_count' => $subscription->get_suspension_count(),
|
|
'last_payment_date' => $subscription->get_date( 'last_order_date_created' ),
|
|
);
|
|
|
|
} else {
|
|
|
|
$deprecated_subscription_object = array();
|
|
|
|
}
|
|
|
|
return $deprecated_subscription_object;
|
|
}
|
|
|
|
/**
|
|
* Wrapper for wc_deprecated_hook to improve handling of ajax requests, even when
|
|
* WooCommerce 3.3.0's wc_deprecated_hook method is not available.
|
|
*
|
|
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.6.0
|
|
* @param string $hook The hook that was used.
|
|
* @param string $version The version that deprecated the hook.
|
|
* @param string $replacement The hook that should have been used.
|
|
* @param string $message A message regarding the change.
|
|
*/
|
|
function wcs_deprecated_hook( $hook, $version, $replacement = null, $message = null ) {
|
|
|
|
if ( function_exists( 'wc_deprecated_hook' ) ) {
|
|
wc_deprecated_hook( $hook, $version, $replacement, $message );
|
|
} else {
|
|
// Reimplement wcs_deprecated_function() when WC 3.0 is not active
|
|
if ( wp_doing_ajax() ) {
|
|
do_action( 'deprecated_hook_run', $hook, $replacement, $version, $message );
|
|
|
|
$message = empty( $message ) ? '' : ' ' . $message;
|
|
$log_string = "{$hook} is deprecated since version {$version}";
|
|
$log_string .= $replacement ? "! Use {$replacement} instead." : ' with no alternative available.';
|
|
|
|
error_log( $log_string . $message );
|
|
} else {
|
|
wc_deprecated_hook( $hook, $version, $replacement, $message );
|
|
}
|
|
}
|
|
}
|