- payment_method, $subscription->id ); ?>
+ get_payment_method(), $subscription->get_id() ); ?>
id ) ) {
+ } elseif ( ! current_user_can( 'edit_shop_subscription_payment_method', $subscription->get_id() ) ) {
WC_Subscriptions::add_notice( __( 'That doesn\'t appear to be one of your subscriptions.', 'woocommerce-subscriptions' ), 'error' );
@@ -213,17 +235,24 @@ class WC_Subscriptions_Change_Payment_Gateway {
WC_Subscriptions::add_notice( sprintf( __( 'Choose a new payment method.%s', 'woocommerce-subscriptions' ), $next_payment_string ), 'notice' );
WC_Subscriptions::print_notices();
- if ( $subscription->order_key == $_GET['key'] ) {
+ if ( $subscription->get_order_key() == $_GET['key'] ) {
+
+ $subscription_billing_country = $subscription->get_billing_country();
+ $subscription_billing_state = $subscription->get_billing_state();
+ $subscription_billing_postcode = $subscription->get_billing_postcode();
// Set customer location to order location
- if ( $subscription->billing_country ) {
- WC()->customer->set_country( $subscription->billing_country );
+ if ( $subscription_billing_country ) {
+ $setter = is_callable( array( WC()->customer, 'set_billing_country' ) ) ? 'set_billing_country' : 'set_country';
+ WC()->customer->$setter( $subscription_billing_country );
}
- if ( $subscription->billing_state ) {
- WC()->customer->set_state( $subscription->billing_state );
+ if ( $subscription_billing_state ) {
+ $setter = is_callable( array( WC()->customer, 'set_billing_state' ) ) ? 'set_billing_state' : 'set_state';
+ WC()->customer->$setter( $subscription_billing_state );
}
- if ( $subscription->billing_postcode ) {
- WC()->customer->set_postcode( $subscription->billing_postcode );
+ if ( $subscription_billing_postcode ) {
+ $setter = is_callable( array( WC()->customer, 'set_billing_postcode' ) ) ? 'set_billing_postcode' : 'set_postcode';
+ WC()->customer->$setter( $subscription_billing_postcode );
}
wc_get_template( 'checkout/form-change-payment-method.php', array( 'subscription' => $subscription ), '', plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/' );
@@ -255,7 +284,7 @@ class WC_Subscriptions_Change_Payment_Gateway {
if ( $subscription->can_be_updated_to( 'new-payment-method' ) ) {
$actions['change_payment_method'] = array(
- 'url' => wp_nonce_url( add_query_arg( array( 'change_payment_method' => $subscription->id ), $subscription->get_checkout_payment_url() ) ),
+ 'url' => wp_nonce_url( add_query_arg( array( 'change_payment_method' => $subscription->get_id() ), $subscription->get_checkout_payment_url() ) ),
'name' => _x( 'Change Payment', 'label on button, imperative', 'woocommerce-subscriptions' ),
);
@@ -283,20 +312,29 @@ class WC_Subscriptions_Change_Payment_Gateway {
ob_start();
- if ( $subscription->order_key == $_GET['key'] ) {
+ if ( $subscription->get_order_key() == $_GET['key'] ) {
+
+ $subscription_billing_country = $subscription->get_billing_country();
+ $subscription_billing_state = $subscription->get_billing_state();
+ $subscription_billing_postcode = $subscription->get_billing_postcode();
+ $subscription_billing_city = $subscription->get_billing_postcode();
// Set customer location to order location
- if ( $subscription->billing_country ) {
- WC()->customer->set_country( $subscription->billing_country );
+ if ( $subscription_billing_country ) {
+ $setter = is_callable( array( WC()->customer, 'set_billing_country' ) ) ? 'set_billing_country' : 'set_country';
+ WC()->customer->$setter( $subscription_billing_country );
}
- if ( $subscription->billing_state ) {
- WC()->customer->set_state( $subscription->billing_state );
+ if ( $subscription_billing_state ) {
+ $setter = is_callable( array( WC()->customer, 'set_billing_state' ) ) ? 'set_billing_state' : 'set_state';
+ WC()->customer->$setter( $subscription_billing_state );
}
- if ( $subscription->billing_postcode ) {
- WC()->customer->set_postcode( $subscription->billing_postcode );
+ if ( $subscription_billing_postcode ) {
+ $setter = is_callable( array( WC()->customer, 'set_billing_postcode' ) ) ? 'set_billing_postcode' : 'set_postcode';
+ WC()->customer->$setter( $subscription_billing_postcode );
}
- if ( $subscription->billing_city ) {
- WC()->customer->set_city( $subscription->billing_city );
+ if ( $subscription_billing_city ) {
+ $setter = is_callable( array( WC()->customer, 'set_billing_city' ) ) ? 'set_billing_city' : 'set_city';
+ WC()->customer->$setter( $subscription_billing_city );
}
// Update payment method
@@ -315,7 +353,7 @@ class WC_Subscriptions_Change_Payment_Gateway {
// Process payment for the new method (with a $0 order total)
if ( wc_notice_count( 'error' ) == 0 ) {
- $result = $available_gateways[ $new_payment_method ]->process_payment( $subscription->id );
+ $result = $available_gateways[ $new_payment_method ]->process_payment( $subscription->get_id() );
if ( 'success' == $result['result'] && wc_get_page_permalink( 'myaccount' ) == $result['redirect'] ) {
$result['redirect'] = $subscription->get_view_order_url();
@@ -342,8 +380,8 @@ class WC_Subscriptions_Change_Payment_Gateway {
*/
public static function update_payment_method( $subscription, $new_payment_method ) {
- $old_payment_method = $subscription->payment_method;
- $old_payment_method_title = $subscription->payment_method_title;
+ $old_payment_method = $subscription->get_payment_method();
+ $old_payment_method_title = $subscription->get_payment_method_title();
$available_gateways = WC()->payment_gateways->get_available_payment_gateways(); // Also inits all payment gateways to make sure that hooks are attached correctly
do_action( 'woocommerce_subscriptions_pre_update_payment_method', $subscription, $new_payment_method, $old_payment_method );
@@ -352,8 +390,8 @@ class WC_Subscriptions_Change_Payment_Gateway {
WC_Subscriptions_Payment_Gateways::trigger_gateway_status_updated_hook( $subscription, 'cancelled' );
// Update meta
- update_post_meta( $subscription->id, '_old_payment_method', $old_payment_method );
- update_post_meta( $subscription->id, '_payment_method', $new_payment_method );
+ update_post_meta( $subscription->get_id(), '_old_payment_method', $old_payment_method );
+ update_post_meta( $subscription->get_id(), '_payment_method', $new_payment_method );
if ( isset( $available_gateways[ $new_payment_method ] ) ) {
$new_payment_method_title = $available_gateways[ $new_payment_method ]->get_title();
@@ -361,8 +399,8 @@ class WC_Subscriptions_Change_Payment_Gateway {
$new_payment_method_title = '';
}
- update_post_meta( $subscription->id, '_old_payment_method_title', $old_payment_method_title );
- update_post_meta( $subscription->id, '_payment_method_title', $new_payment_method_title );
+ update_post_meta( $subscription->get_id(), '_old_payment_method_title', $old_payment_method_title );
+ update_post_meta( $subscription->get_id(), '_payment_method_title', $new_payment_method_title );
if ( empty( $old_payment_method_title ) ) {
$old_payment_method_title = $old_payment_method;
@@ -408,7 +446,7 @@ class WC_Subscriptions_Change_Payment_Gateway {
public static function maybe_zero_total( $total, $subscription ) {
global $wp;
- if ( ! empty( $_POST['_wcsnonce'] ) && wp_verify_nonce( $_POST['_wcsnonce'], 'wcs_change_payment_method' ) && isset( $_POST['woocommerce_change_payment'] ) && $subscription->order_key == $_GET['key'] && $subscription->id == absint( $_POST['woocommerce_change_payment'] ) ) {
+ if ( ! empty( $_POST['_wcsnonce'] ) && wp_verify_nonce( $_POST['_wcsnonce'], 'wcs_change_payment_method' ) && isset( $_POST['woocommerce_change_payment'] ) && $subscription->get_order_key() == $_GET['key'] && $subscription->get_id() == absint( $_POST['woocommerce_change_payment'] ) ) {
$total = 0;
} elseif ( ! self::$is_request_to_change_payment && isset( $wp->query_vars['order-pay'] ) && wcs_is_subscription( absint( $wp->query_vars['order-pay'] ) ) ) {
// if the request to pay for the order belongs to a subscription but there's no GET params for changing payment method, the receipt page is being used to collect credit card details so we still need to $0 the total
@@ -449,7 +487,7 @@ class WC_Subscriptions_Change_Payment_Gateway {
if ( ! empty( $_POST['_wcsnonce'] ) && wp_verify_nonce( $_POST['_wcsnonce'], 'wcs_change_payment_method' ) && isset( $_POST['payment_method'] ) ) {
$new_payment_method = wc_clean( $_POST['payment_method'] );
} else {
- $new_payment_method = $renewal_order->payment_method;
+ $new_payment_method = wcs_get_objects_property( $renewal_order, 'payment_method' );
}
self::update_payment_method( $subscription, $new_payment_method );
diff --git a/includes/class-wc-subscriptions-checkout.php b/includes/class-wc-subscriptions-checkout.php
index 50a2189..560266c 100644
--- a/includes/class-wc-subscriptions-checkout.php
+++ b/includes/class-wc-subscriptions-checkout.php
@@ -40,6 +40,9 @@ class WC_Subscriptions_Checkout {
// Force registration during checkout process
add_action( 'woocommerce_before_checkout_process', __CLASS__ . '::force_registration_during_checkout', 10 );
+
+ // When a line item is added to a subscription on checkout, ensure the backorder data added by WC is removed
+ add_action( 'woocommerce_checkout_create_order_line_item', __CLASS__ . '::remove_backorder_meta_from_subscription_line_item', 10, 4 );
}
/**
@@ -60,12 +63,12 @@ class WC_Subscriptions_Checkout {
$subscriptions = array();
// First clear out any subscriptions created for a failed payment to give us a clean slate for creating new subscriptions
- $subscriptions = wcs_get_subscriptions_for_order( $order->id, array( 'order_type' => 'parent' ) );
+ $subscriptions = wcs_get_subscriptions_for_order( wcs_get_objects_property( $order, 'id' ), array( 'order_type' => 'parent' ) );
if ( ! empty( $subscriptions ) ) {
remove_action( 'before_delete_post', 'WC_Subscriptions_Manager::maybe_cancel_subscription' );
foreach ( $subscriptions as $subscription ) {
- wp_delete_post( $subscription->id );
+ wp_delete_post( $subscription->get_id() );
}
add_action( 'before_delete_post', 'WC_Subscriptions_Manager::maybe_cancel_subscription' );
}
@@ -75,7 +78,7 @@ class WC_Subscriptions_Checkout {
// Create new subscriptions for each group of subscription products in the cart (that is not a renewal)
foreach ( WC()->cart->recurring_carts as $recurring_cart ) {
- $subscription = self::create_subscription( $order, $recurring_cart ); // Exceptions are caught by WooCommerce
+ $subscription = self::create_subscription( $order, $recurring_cart, $posted_data ); // Exceptions are caught by WooCommerce
if ( is_wp_error( $subscription ) ) {
throw new Exception( $subscription->get_error_message() );
@@ -97,7 +100,7 @@ class WC_Subscriptions_Checkout {
* @param WC_Cart $cart
* @since 2.0
*/
- public static function create_subscription( $order, $cart ) {
+ public static function create_subscription( $order, $cart, $posted_data ) {
global $wpdb;
try {
@@ -108,16 +111,13 @@ class WC_Subscriptions_Checkout {
$variation_id = wcs_cart_pluck( $cart, 'variation_id' );
$product_id = empty( $variation_id ) ? wcs_cart_pluck( $cart, 'product_id' ) : $variation_id;
- // We need to use the $order->order_date value because the post_date_gmt isn't always set
- $order_date_gmt = get_gmt_from_date( $order->order_date );
-
$subscription = wcs_create_subscription( array(
'start_date' => $cart->start_date,
- 'order_id' => $order->id,
+ 'order_id' => wcs_get_objects_property( $order, 'id' ),
'customer_id' => $order->get_user_id(),
'billing_period' => wcs_cart_pluck( $cart, 'subscription_period' ),
'billing_interval' => wcs_cart_pluck( $cart, 'subscription_period_interval' ),
- 'customer_note' => $order->customer_note,
+ 'customer_note' => wcs_get_objects_property( $order, 'customer_note' ),
) );
if ( is_wp_error( $subscription ) ) {
@@ -135,68 +135,91 @@ class WC_Subscriptions_Checkout {
// Store trial period for PayPal
if ( wcs_cart_pluck( $cart, 'subscription_trial_length' ) > 0 ) {
- update_post_meta( $subscription->id, '_trial_period', wcs_cart_pluck( $cart, 'subscription_trial_period' ) );
+ $subscription->set_trial_period( wcs_cart_pluck( $cart, 'subscription_trial_period' ) );
}
// Set the payment method on the subscription
- $available_gateways = WC()->payment_gateways->get_available_payment_gateways();
+ $available_gateways = WC()->payment_gateways->get_available_payment_gateways();
+ $order_payment_method = wcs_get_objects_property( $order, 'payment_method' );
- if ( $cart->needs_payment() && isset( $available_gateways[ $order->payment_method ] ) ) {
- $subscription->set_payment_method( $available_gateways[ $order->payment_method ] );
+ if ( $cart->needs_payment() && isset( $available_gateways[ $order_payment_method ] ) ) {
+ $subscription->set_payment_method( $available_gateways[ $order_payment_method ] );
}
if ( ! $cart->needs_payment() || 'yes' == get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no' ) ) {
- $subscription->update_manual( 'true' );
- } elseif ( ! isset( $available_gateways[ $order->payment_method ] ) || ! $available_gateways[ $order->payment_method ]->supports( 'subscriptions' ) ) {
- $subscription->update_manual( 'true' );
+ $subscription->set_requires_manual_renewal( true );
+ } elseif ( ! isset( $available_gateways[ $order_payment_method ] ) || ! $available_gateways[ $order_payment_method ]->supports( 'subscriptions' ) ) {
+ $subscription->set_requires_manual_renewal( true );
}
wcs_copy_order_meta( $order, $subscription, 'subscription' );
// Store the line items
- foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
- $item_id = self::add_cart_item( $subscription, $cart_item, $cart_item_key );
+ if ( is_callable( array( WC()->checkout, 'create_order_line_items' ) ) ) {
+ WC()->checkout->create_order_line_items( $subscription, $cart );
+ } else {
+ foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
+ $item_id = self::add_cart_item( $subscription, $cart_item, $cart_item_key );
+ }
}
// Store fees (although no fees recur by default, extensions may add them)
- foreach ( $cart->get_fees() as $fee_key => $fee ) {
- $item_id = $subscription->add_fee( $fee );
+ if ( is_callable( array( WC()->checkout, 'create_order_fee_lines' ) ) ) {
+ WC()->checkout->create_order_fee_lines( $subscription, $cart );
+ } else {
+ foreach ( $cart->get_fees() as $fee_key => $fee ) {
+ $item_id = $subscription->add_fee( $fee );
- if ( ! $item_id ) {
- // translators: placeholder is an internal error number
- throw new Exception( sprintf( __( 'Error %d: Unable to create subscription. Please try again.', 'woocommerce-subscriptions' ), 403 ) );
+ if ( ! $item_id ) {
+ // translators: placeholder is an internal error number
+ throw new Exception( sprintf( __( 'Error %d: Unable to create subscription. Please try again.', 'woocommerce-subscriptions' ), 403 ) );
+ }
+
+ // Allow plugins to add order item meta to fees
+ do_action( 'woocommerce_add_order_fee_meta', $subscription->get_id(), $item_id, $fee, $fee_key );
}
-
- // Allow plugins to add order item meta to fees
- do_action( 'woocommerce_add_order_fee_meta', $order->id, $item_id, $fee, $fee_key );
}
self::add_shipping( $subscription, $cart );
// Store tax rows
- foreach ( array_keys( $cart->taxes + $cart->shipping_taxes ) as $tax_rate_id ) {
- if ( $tax_rate_id && ! $subscription->add_tax( $tax_rate_id, $cart->get_tax_amount( $tax_rate_id ), $cart->get_shipping_tax_amount( $tax_rate_id ) ) && apply_filters( 'woocommerce_cart_remove_taxes_zero_rate_id', 'zero-rated' ) !== $tax_rate_id ) {
- // translators: placeholder is an internal error number
- throw new Exception( sprintf( __( 'Error %d: Unable to add tax to subscription. Please try again.', 'woocommerce-subscriptions' ), 405 ) );
+ if ( is_callable( array( WC()->checkout, 'create_order_tax_lines' ) ) ) {
+ WC()->checkout->create_order_tax_lines( $subscription, $cart );
+ } else {
+ foreach ( array_keys( $cart->taxes + $cart->shipping_taxes ) as $tax_rate_id ) {
+ if ( $tax_rate_id && ! $subscription->add_tax( $tax_rate_id, $cart->get_tax_amount( $tax_rate_id ), $cart->get_shipping_tax_amount( $tax_rate_id ) ) && apply_filters( 'woocommerce_cart_remove_taxes_zero_rate_id', 'zero-rated' ) !== $tax_rate_id ) {
+ // translators: placeholder is an internal error number
+ throw new Exception( sprintf( __( 'Error %d: Unable to add tax to subscription. Please try again.', 'woocommerce-subscriptions' ), 405 ) );
+ }
}
}
// Store coupons
- foreach ( $cart->get_coupons() as $code => $coupon ) {
- if ( ! $subscription->add_coupon( $code, $cart->get_coupon_discount_amount( $code ), $cart->get_coupon_discount_tax_amount( $code ) ) ) {
- // translators: placeholder is an internal error number
- throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce-subscriptions' ), 406 ) );
+ if ( is_callable( array( WC()->checkout, 'create_order_coupon_lines' ) ) ) {
+ WC()->checkout->create_order_coupon_lines( $subscription, $cart );
+ } else {
+ foreach ( $cart->get_coupons() as $code => $coupon ) {
+ if ( ! $subscription->add_coupon( $code, $cart->get_coupon_discount_amount( $code ), $cart->get_coupon_discount_tax_amount( $code ) ) ) {
+ // translators: placeholder is an internal error number
+ throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce-subscriptions' ), 406 ) );
+ }
}
}
// Set the recurring totals on the subscription
- $subscription->set_total( $cart->shipping_total, 'shipping' );
- $subscription->set_total( $cart->get_cart_discount_total(), 'cart_discount' );
- $subscription->set_total( $cart->get_cart_discount_tax_total(), 'cart_discount_tax' );
- $subscription->set_total( $cart->tax_total, 'tax' );
- $subscription->set_total( $cart->shipping_tax_total, 'shipping_tax' );
+ $subscription->set_shipping_total( $cart->shipping_total );
+ $subscription->set_discount_total( $cart->get_cart_discount_total() );
+ $subscription->set_discount_tax( $cart->get_cart_discount_tax_total() );
+ $subscription->set_cart_tax( $cart->tax_total );
+ $subscription->set_shipping_tax( $cart->shipping_tax_total );
$subscription->set_total( $cart->total );
+ // Hook to adjust subscriptions before saving with WC 3.0+ (matches WC 3.0's new 'woocommerce_checkout_create_order' hook)
+ do_action( 'woocommerce_checkout_create_subscription', $subscription, $posted_data );
+
+ // Save the subscription if using WC 3.0 & CRUD
+ $subscription->save();
+
// If we got here, the subscription was created without problems
$wpdb->query( 'COMMIT' );
@@ -238,27 +261,71 @@ class WC_Subscriptions_Checkout {
if ( isset( $package['rates'][ $shipping_method_id ] ) ) {
- $item_id = $subscription->add_shipping( $package['rates'][ $shipping_method_id ] );
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
- if ( ! $item_id ) {
- throw new Exception( __( 'Error: Unable to create subscription. Please try again.', 'woocommerce-subscriptions' ) );
+ $item_id = $subscription->add_shipping( $package['rates'][ $shipping_method_id ] );
+
+ // Allows plugins to add order item meta to shipping
+ do_action( 'woocommerce_add_shipping_order_item', $subscription->get_id(), $item_id, $package_key );
+ do_action( 'woocommerce_subscriptions_add_recurring_shipping_order_item', $subscription->get_id(), $item_id, $package_key );
+
+ } else { // WC 3.0+
+
+ $shipping_rate = $package['rates'][ $shipping_method_id ];
+ $item = new WC_Order_Item_Shipping();
+ $item->legacy_package_key = $package_key; // @deprecated For legacy actions.
+ $item->set_props( array(
+ 'method_title' => $shipping_rate->label,
+ 'method_id' => $shipping_rate->id,
+ 'total' => wc_format_decimal( $shipping_rate->cost ),
+ 'taxes' => array( 'total' => $shipping_rate->taxes ),
+ 'order_id' => $subscription->get_id(),
+ ) );
+
+ foreach ( $shipping_rate->get_meta_data() as $key => $value ) {
+ $item->add_meta_data( $key, $value, true );
+ }
+
+ $subscription->add_item( $item );
+
+ $item->save(); // We need the item ID for old hooks, this can be removed once support for WC < 3.0 is dropped
+ wc_do_deprecated_action( 'woocommerce_subscriptions_add_recurring_shipping_order_item', array( $subscription->get_id(), $item->get_id(), $package_key ), '2.2.0', 'CRUD and woocommerce_checkout_create_subscription_shipping_item action instead' );
+
+ do_action( 'woocommerce_checkout_create_order_shipping_item', $item, $package_key, $package ); // WC 3.0+ will also trigger the deprecated 'woocommerce_add_shipping_order_item' hook
+ do_action( 'woocommerce_checkout_create_subscription_shipping_item', $item, $package_key, $package );
}
-
- // Allows plugins to add order item meta to shipping
- do_action( 'woocommerce_add_shipping_order_item', $subscription->id, $item_id, $package_key );
- do_action( 'woocommerce_subscriptions_add_recurring_shipping_order_item', $subscription->id, $item_id, $package_key );
}
}
WC_Subscriptions_Cart::set_calculation_type( 'none' );
}
+ /**
+ * Remove the Backordered meta data from subscription line items added on the checkout.
+ *
+ * @param WC_Order_Item_Product $order_item
+ * @param string $cart_item_key The hash used to identify the item in the cart
+ * @param array $cart_item The cart item's data.
+ * @param WC_Order|WC_Subscription $subscription The order or subscription object to which the line item relates
+ * @since 2.2.0
+ */
+ public static function remove_backorder_meta_from_subscription_line_item( $item, $cart_item_key, $cart_item, $subscription ) {
+
+ if ( wcs_is_subscription( $subscription ) ) {
+ $item->delete_meta_data( apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce-subscriptions' ) ) );
+ }
+ }
+
/**
* Add a cart item to a subscription.
*
* @since 2.0
*/
public static function add_cart_item( $subscription, $cart_item, $cart_item_key ) {
+ if ( ! WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ _deprecated_function( __METHOD__, '2.2.0', 'WC_Checkout::create_order_line_items( $subscription, $cart )' );
+ }
+
$item_id = $subscription->add_product(
$cart_item['data'],
$cart_item['quantity'],
@@ -286,9 +353,11 @@ class WC_Subscriptions_Checkout {
}
// Allow plugins to add order item meta
- do_action( 'woocommerce_add_order_item_meta', $item_id, $cart_item, $cart_item_key );
-
- do_action( 'woocommerce_add_subscription_item_meta', $item_id, $cart_item, $cart_item_key );
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ do_action( 'woocommerce_add_subscription_item_meta', $item_id, $cart_item, $cart_item_key );
+ } else {
+ wc_do_deprecated_action( 'woocommerce_add_subscription_item_meta', array( $item_id, $cart_item, $cart_item_key ), '3.0', 'CRUD and woocommerce_checkout_create_order_line_item action instead' );
+ }
return $item_id;
}
diff --git a/includes/class-wc-subscriptions-coupon.php b/includes/class-wc-subscriptions-coupon.php
index 443c934..d443b14 100644
--- a/includes/class-wc-subscriptions-coupon.php
+++ b/includes/class-wc-subscriptions-coupon.php
@@ -43,6 +43,11 @@ class WC_Subscriptions_Coupon {
// Add our recurring product coupon types to the list of coupon types that apply to individual products
add_filter( 'woocommerce_product_coupon_types', __CLASS__ . '::filter_product_coupon_types', 10, 1 );
+
+ if ( ! is_admin() ) {
+ // WC 3.0 only sets a coupon type if it is a pre-defined supported type, so we need to temporarily add our pseudo types. We don't want to add these on admin pages.
+ add_filter( 'woocommerce_coupon_discount_types', __CLASS__ . '::add_pseudo_coupon_types' );
+ }
}
/**
@@ -70,19 +75,19 @@ class WC_Subscriptions_Coupon {
*/
public static function get_discount_amount( $discount, $discounting_amount, $cart_item, $single, $coupon ) {
+ $coupon_type = wcs_get_coupon_property( $coupon, 'type' );
+
// Only deal with subscriptions coupon types
- if ( ! in_array( $coupon->type, array( 'recurring_fee', 'recurring_percent', 'sign_up_fee', 'sign_up_fee_percent', 'renewal_fee', 'renewal_percent', 'renewal_cart' ) ) ) {
+ if ( ! in_array( $coupon_type, array( 'recurring_fee', 'recurring_percent', 'sign_up_fee', 'sign_up_fee_percent', 'renewal_fee', 'renewal_percent', 'renewal_cart' ) ) ) {
return $discount;
}
- $product_id = ( $cart_item['data']->is_type( array( 'subscription_variation' ) ) ) ? $cart_item['data']->variation_id : $cart_item['data']->id;
-
// If not a subscription product return the default discount
if ( ! wcs_cart_contains_renewal() && ! WC_Subscriptions_Product::is_subscription( $cart_item['data'] ) ) {
return $discount;
}
// But if cart contains a renewal, we need to handle both subscription products and manually added non-susbscription products that could be part of a subscription
- if ( wcs_cart_contains_renewal() && ! self::is_subsbcription_renewal_line_item( $product_id, $cart_item ) ) {
+ if ( wcs_cart_contains_renewal() && ! self::is_subsbcription_renewal_line_item( $cart_item['data'], $cart_item ) ) {
return $discount;
}
@@ -100,8 +105,8 @@ class WC_Subscriptions_Coupon {
// Check if we're applying any recurring discounts to recurring total calculations
if ( 'recurring_total' == $calculation_type ) {
- $apply_recurring_coupon = ( 'recurring_fee' == $coupon->type ) ? true : false;
- $apply_recurring_percent_coupon = ( 'recurring_percent' == $coupon->type ) ? true : false;
+ $apply_recurring_coupon = ( 'recurring_fee' == $coupon_type ) ? true : false;
+ $apply_recurring_percent_coupon = ( 'recurring_percent' == $coupon_type ) ? true : false;
}
// Check if we're applying any initial discounts
@@ -110,42 +115,42 @@ class WC_Subscriptions_Coupon {
// If all items have a free trial we don't need to apply recurring coupons to the initial total
if ( ! WC_Subscriptions_Cart::all_cart_items_have_free_trial() ) {
- if ( 'recurring_fee' == $coupon->type ) {
+ if ( 'recurring_fee' == $coupon_type ) {
$apply_initial_coupon = true;
}
- if ( 'recurring_percent' == $coupon->type ) {
+ if ( 'recurring_percent' == $coupon_type ) {
$apply_initial_percent_coupon = true;
}
}
// Apply sign-up discounts
- if ( ! empty( $cart_item['data']->subscription_sign_up_fee ) ) {
+ if ( WC_Subscriptions_Product::get_sign_up_fee( $cart_item['data'] ) > 0 ) {
- if ( 'sign_up_fee' == $coupon->type ) {
+ if ( 'sign_up_fee' == $coupon_type ) {
$apply_initial_coupon = true;
}
- if ( 'sign_up_fee_percent' == $coupon->type ) {
+ if ( 'sign_up_fee_percent' == $coupon_type ) {
$apply_initial_percent_coupon = true;
}
// Only Sign up fee coupons apply to sign up fees, adjust the discounting_amount accordingly
- if ( in_array( $coupon->type, array( 'sign_up_fee', 'sign_up_fee_percent' ) ) ) {
- $discounting_amount = $cart_item['data']->subscription_sign_up_fee;
+ if ( in_array( $coupon_type, array( 'sign_up_fee', 'sign_up_fee_percent' ) ) ) {
+ $discounting_amount = WC_Subscriptions_Product::get_sign_up_fee( $cart_item['data'] );
} else {
- $discounting_amount -= $cart_item['data']->subscription_sign_up_fee;
+ $discounting_amount -= WC_Subscriptions_Product::get_sign_up_fee( $cart_item['data'] );
}
}
// Apply renewal discounts
- if ( 'renewal_fee' == $coupon->type ) {
+ if ( 'renewal_fee' == $coupon_type ) {
$apply_recurring_coupon = true;
}
- if ( 'renewal_percent' == $coupon->type ) {
+ if ( 'renewal_percent' == $coupon_type ) {
$apply_recurring_percent_coupon = true;
}
- if ( 'renewal_cart' == $coupon->type ) {
+ if ( 'renewal_cart' == $coupon_type ) {
$apply_renewal_cart_coupon = true;
}
}
@@ -154,25 +159,25 @@ class WC_Subscriptions_Coupon {
if ( $apply_recurring_coupon || $apply_initial_coupon ) {
// Recurring coupons only apply when there is no free trial (carts can have a mix of free trial and non free trial items)
- if ( $apply_initial_coupon && 'recurring_fee' == $coupon->type && ! empty( $cart_item['data']->subscription_trial_length ) ) {
+ if ( $apply_initial_coupon && 'recurring_fee' == $coupon_type && WC_Subscriptions_Product::get_trial_length( $cart_item['data'] ) > 0 ) {
$discounting_amount = 0;
}
- $discount_amount = min( $coupon->coupon_amount, $discounting_amount );
+ $discount_amount = min( wcs_get_coupon_property( $coupon, 'amount' ), $discounting_amount );
$discount_amount = $single ? $discount_amount : $discount_amount * $cart_item_qty;
} elseif ( $apply_recurring_percent_coupon ) {
- $discount_amount = ( $discounting_amount / 100 ) * $coupon->amount;
+ $discount_amount = ( $discounting_amount / 100 ) * wcs_get_coupon_property( $coupon, 'amount' );
} elseif ( $apply_initial_percent_coupon ) {
// Recurring coupons only apply when there is no free trial (carts can have a mix of free trial and non free trial items)
- if ( 'recurring_percent' == $coupon->type && ! empty( $cart_item['data']->subscription_trial_length ) ) {
+ if ( 'recurring_percent' == $coupon_type && WC_Subscriptions_Product::get_trial_length( $cart_item['data'] ) > 0 ) {
$discounting_amount = 0;
}
- $discount_amount = ( $discounting_amount / 100 ) * $coupon->amount;
+ $discount_amount = ( $discounting_amount / 100 ) * wcs_get_coupon_property( $coupon, 'amount' );
} elseif ( $apply_renewal_cart_coupon ) {
@@ -182,9 +187,9 @@ class WC_Subscriptions_Coupon {
*
* BUT... we also need the subtotal to exclude non renewal products, so user the renewal subtotal
*/
- $discount_percent = ( $discounting_amount * $cart_item['quantity'] ) / self::get_renewal_subtotal( $coupon->code );
+ $discount_percent = ( $discounting_amount * $cart_item['quantity'] ) / self::get_renewal_subtotal( wcs_get_coupon_property( $coupon, 'code' ) );
- $discount_amount = ( $coupon->amount * $discount_percent ) / $cart_item_qty;
+ $discount_amount = ( wcs_get_coupon_property( $coupon, 'amount' ) * $discount_percent ) / $cart_item_qty;
}
// Round - consistent with WC approach
@@ -216,9 +221,10 @@ class WC_Subscriptions_Coupon {
foreach ( WC()->cart->applied_coupons as $code ) {
- $coupon = new WC_Coupon( $code );
+ $coupon = new WC_Coupon( $code );
+ $cart_coupon_type = wcs_get_coupon_property( $coupon, 'type' );
- if ( 'any' == $coupon_type || $coupon_type == $coupon->type || ( 'core' == $coupon_type && in_array( $coupon->type, $core_coupons ) ) ) {
+ if ( 'any' == $coupon_type || $coupon_type == $cart_coupon_type || ( 'core' == $coupon_type && in_array( $cart_coupon_type, $core_coupons ) ) ) {
$contains_discount = true;
break;
}
@@ -240,9 +246,10 @@ class WC_Subscriptions_Coupon {
}
self::$coupon_error = '';
+ $coupon_type = wcs_get_coupon_property( $coupon, 'type' );
// ignore non-subscription coupons
- if ( ! in_array( $coupon->type, array( 'recurring_fee', 'sign_up_fee', 'recurring_percent', 'sign_up_fee_percent', 'renewal_fee', 'renewal_percent', 'renewal_cart' ) ) ) {
+ if ( ! in_array( $coupon_type, array( 'recurring_fee', 'sign_up_fee', 'recurring_percent', 'sign_up_fee_percent', 'renewal_fee', 'renewal_percent', 'renewal_cart' ) ) ) {
// but make sure there is actually something for the coupon to be applied to (i.e. not a free trial)
if ( ( wcs_cart_contains_renewal() || WC_Subscriptions_Cart::cart_contains_subscription() ) && 0 == WC()->cart->subtotal ) {
@@ -251,7 +258,7 @@ class WC_Subscriptions_Coupon {
} else {
// prevent subscription coupons from being applied to renewal payments
- if ( wcs_cart_contains_renewal() && ! in_array( $coupon->type, array( 'renewal_fee', 'renewal_percent', 'renewal_cart' ) ) ) {
+ if ( wcs_cart_contains_renewal() && ! in_array( $coupon_type, array( 'renewal_fee', 'renewal_percent', 'renewal_cart' ) ) ) {
self::$coupon_error = __( 'Sorry, this coupon is only valid for new subscriptions.', 'woocommerce-subscriptions' );
}
@@ -261,13 +268,13 @@ class WC_Subscriptions_Coupon {
}
// prevent subscription renewal coupons from being applied to non renewal payments
- if ( ! wcs_cart_contains_renewal() && in_array( $coupon->type, array( 'renewal_fee', 'renewal_percent', 'renewal_cart' ) ) ) {
+ if ( ! wcs_cart_contains_renewal() && in_array( $coupon_type, array( 'renewal_fee', 'renewal_percent', 'renewal_cart' ) ) ) {
// translators: 1$: coupon code that is being removed
- self::$coupon_error = sprintf( __( 'Sorry, the "%1$s" coupon is only valid for renewals.', 'woocommerce-subscriptions' ), $coupon->code );
+ self::$coupon_error = sprintf( __( 'Sorry, the "%1$s" coupon is only valid for renewals.', 'woocommerce-subscriptions' ), wcs_get_coupon_property( $coupon, 'code' ) );
}
// prevent sign up fee coupons from being applied to subscriptions without a sign up fee
- if ( 0 == WC_Subscriptions_Cart::get_cart_subscription_sign_up_fee() && in_array( $coupon->type, array( 'sign_up_fee', 'sign_up_fee_percent' ) ) ) {
+ if ( 0 == WC_Subscriptions_Cart::get_cart_subscription_sign_up_fee() && in_array( $coupon_type, array( 'sign_up_fee', 'sign_up_fee_percent' ) ) ) {
self::$coupon_error = __( 'Sorry, this coupon is only valid for subscription products with a sign-up fee.', 'woocommerce-subscriptions' );
}
}
@@ -307,16 +314,16 @@ class WC_Subscriptions_Coupon {
$this_item_is_discounted = false;
// Specific products get the discount
- if ( sizeof( $coupon->product_ids ) > 0 ) {
+ if ( sizeof( $coupon_product_ids = wcs_get_coupon_property( $coupon, 'product_ids' ) ) > 0 ) {
- if ( in_array( wcs_get_canonical_product_id( $cart_item ), $coupon->product_ids ) || in_array( $cart_item['data']->get_parent(), $coupon->product_ids ) ) {
+ if ( in_array( wcs_get_canonical_product_id( $cart_item ), $coupon_product_ids ) || in_array( $cart_item['data']->get_parent(), $coupon_product_ids ) ) {
$this_item_is_discounted = true;
}
// Category discounts
- } elseif ( sizeof( $coupon->product_categories ) > 0 ) {
+ } elseif ( sizeof( $coupon_product_categories = wcs_get_coupon_property( $coupon, 'product_categories' ) ) > 0 ) {
- if ( sizeof( array_intersect( $product_cats, $coupon->product_categories ) ) > 0 ) {
+ if ( sizeof( array_intersect( $product_cats, $coupon_product_categories ) ) > 0 ) {
$this_item_is_discounted = true;
}
} else {
@@ -327,15 +334,15 @@ class WC_Subscriptions_Coupon {
}
// Specific product ID's excluded from the discount
- if ( sizeof( $coupon->exclude_product_ids ) > 0 ) {
- if ( in_array( wcs_get_canonical_product_id( $cart_item ), $coupon->exclude_product_ids ) || in_array( $cart_item['data']->get_parent(), $coupon->exclude_product_ids ) ) {
+ if ( sizeof( $coupon_excluded_product_ids = wcs_get_coupon_property( $coupon, 'exclude_product_ids' ) ) > 0 ) {
+ if ( in_array( wcs_get_canonical_product_id( $cart_item ), $coupon_excluded_product_ids ) || in_array( $cart_item['data']->get_parent(), $coupon_excluded_product_ids ) ) {
$this_item_is_discounted = false;
}
}
// Specific categories excluded from the discount
- if ( sizeof( $coupon->exclude_product_categories ) > 0 ) {
- if ( sizeof( array_intersect( $product_cats, $coupon->exclude_product_categories ) ) > 0 ) {
+ if ( sizeof( $coupon_excluded_product_categories = wcs_get_coupon_property( $coupon, 'exclude_product_categories' ) ) > 0 ) {
+ if ( sizeof( array_intersect( $product_cats, $coupon_excluded_product_categories ) ) > 0 ) {
$this_item_is_discounted = false;
}
}
@@ -371,9 +378,10 @@ class WC_Subscriptions_Coupon {
foreach ( $applied_coupons as $coupon_code ) {
- $coupon = new WC_Coupon( $coupon_code );
+ $coupon = new WC_Coupon( $coupon_code );
+ $coupon_type = wcs_get_coupon_property( $coupon, 'type' );
- if ( in_array( $coupon->type, array( 'recurring_fee', 'recurring_percent' ) ) ) { // always apply coupons to their specific calculation case
+ if ( in_array( $coupon_type, array( 'recurring_fee', 'recurring_percent' ) ) ) { // always apply coupons to their specific calculation case
if ( 'recurring_total' == $calculation_type ) {
$coupons_to_reapply[] = $coupon_code;
} elseif ( 'none' == $calculation_type && ! WC_Subscriptions_Cart::all_cart_items_have_free_trial() ) { // sometimes apply recurring coupons to initial total
@@ -381,7 +389,7 @@ class WC_Subscriptions_Coupon {
} else {
self::$removed_coupons[] = $coupon_code;
}
- } elseif ( ( 'none' == $calculation_type ) && ! in_array( $coupon->type, array( 'recurring_fee', 'recurring_percent' ) ) ) { // apply all coupons to the first payment
+ } elseif ( ( 'none' == $calculation_type ) && ! in_array( $coupon_type, array( 'recurring_fee', 'recurring_percent' ) ) ) { // apply all coupons to the first payment
$coupons_to_reapply[] = $coupon_code;
} else {
self::$removed_coupons[] = $coupon_code;
@@ -437,7 +445,7 @@ class WC_Subscriptions_Coupon {
foreach ( $coupons as $coupon ) {
- if ( $coupon->code == $code ) {
+ if ( wcs_get_coupon_property( $coupon, 'code' ) == $code ) {
if ( $subscription = wcs_get_subscription( $subscription_id ) ) {
$subtotal = $subscription->get_subtotal();
@@ -453,9 +461,9 @@ class WC_Subscriptions_Coupon {
/**
* Check if a product is a renewal order line item (rather than a "susbscription") - to pick up non-subsbcription products added a subscription manually
*
- * @param int $product_id
- * @param array $cart_item
- * @param WC_Cart $cart The WooCommerce cart object.
+ * @param int|WC_Product $product_id
+ * @param array $cart_item
+ * @param WC_Cart $cart The WooCommerce cart object.
* @return boolean whether a product is a renewal order line item
* @since 2.0.10
*/
@@ -464,16 +472,13 @@ class WC_Subscriptions_Coupon {
$is_subscription_line_item = false;
if ( is_object( $product_id ) ) {
- $product = $product_id;
- $product_id = $product->id;
- } elseif ( is_numeric( $product_id ) ) {
- $product = wc_get_product( $product_id );
+ $product_id = $product_id->get_id();
}
if ( ! empty( $cart_item['subscription_renewal'] ) ) {
if ( $subscription = wcs_get_subscription( $cart_item['subscription_renewal']['subscription_id'] ) ) {
foreach ( $subscription->get_items() as $item ) {
- $item_product_id = ( $item['variation_id'] ) ? $item['variation_id'] : $item['product_id'];
+ $item_product_id = wcs_get_canonical_product_id( $item );
if ( ! empty( $item_product_id ) && $item_product_id == $product_id ) {
$is_subscription_line_item = true;
}
@@ -484,6 +489,24 @@ class WC_Subscriptions_Coupon {
return apply_filters( 'woocommerce_is_subscription_renewal_line_item', $is_subscription_line_item, $product_id, $cart_item );
}
+ /**
+ * Add our pseudo renewal coupon types to the list of supported types.
+ *
+ * @param array $coupon_types
+ * @return array supported coupon types
+ * @since 2.2
+ */
+ public static function add_pseudo_coupon_types( $coupon_types ) {
+ return array_merge(
+ $coupon_types,
+ array(
+ 'renewal_percent' => __( 'Renewal % discount', 'woocommerce-subscriptions' ),
+ 'renewal_fee' => __( 'Renewal product discount', 'woocommerce-subscriptions' ),
+ 'renewal_cart' => __( 'Renewal cart discount', 'woocommerce-subscriptions' ),
+ )
+ );
+ }
+
/* Deprecated */
/**
@@ -494,9 +517,7 @@ class WC_Subscriptions_Coupon {
public static function apply_subscription_discount( $original_price, $cart_item, $cart ) {
_deprecated_function( __METHOD__, '2.0.10', 'Have moved to filtering on "woocommerce_coupon_get_discount_amount" to return discount amount. See: '. __CLASS__ .'::get_discount_amount()' );
- $product_id = ( $cart_item['data']->is_type( array( 'subscription_variation' ) ) ) ? $cart_item['data']->variation_id : $cart_item['data']->id;
-
- if ( ! WC_Subscriptions_Product::is_subscription( $product_id ) ) {
+ if ( ! WC_Subscriptions_Product::is_subscription( $cart_item['data'] ) ) {
return $original_price;
}
@@ -506,15 +527,17 @@ class WC_Subscriptions_Coupon {
if ( ! empty( $cart->applied_coupons ) ) {
- foreach ( $cart->applied_coupons as $code ) {
+ foreach ( $cart->applied_coupons as $coupon_code ) {
- $coupon = new WC_Coupon( $code );
+ $coupon = new WC_Coupon( $coupon_code );
+ $coupon_type = wcs_get_coupon_property( $coupon, 'type' );
+ $coupon_amount = wcs_get_coupon_property( $coupon, 'amount' );
// Pre 2.5 is_valid_for_product() does not use wc_get_product_coupon_types()
if ( WC_Subscriptions::is_woocommerce_pre( '2.5' ) ) {
$is_valid_for_product = true;
} else {
- $is_valid_for_product = $coupon->is_valid_for_product( wc_get_product( $product_id ), $cart_item );
+ $is_valid_for_product = $coupon->is_valid_for_product( $cart_item['data'], $cart_item );
}
if ( $coupon->apply_before_tax() && $coupon->is_valid() && $is_valid_for_product ) {
@@ -523,8 +546,8 @@ class WC_Subscriptions_Coupon {
// Apply recurring fee discounts to recurring total calculations
if ( 'recurring_total' == $calculation_type ) {
- $apply_recurring_coupon = ( 'recurring_fee' == $coupon->type ) ? true : false;
- $apply_recurring_percent_coupon = ( 'recurring_percent' == $coupon->type ) ? true : false;
+ $apply_recurring_coupon = ( 'recurring_fee' == $coupon_type ) ? true : false;
+ $apply_recurring_percent_coupon = ( 'recurring_percent' == $coupon_type ) ? true : false;
}
if ( 'none' == $calculation_type ) {
@@ -532,71 +555,71 @@ class WC_Subscriptions_Coupon {
// If all items have a free trial we don't need to apply recurring coupons to the initial total
if ( ! WC_Subscriptions_Cart::all_cart_items_have_free_trial() ) {
- if ( 'recurring_fee' == $coupon->type ) {
+ if ( 'recurring_fee' == $coupon_type ) {
$apply_initial_coupon = true;
}
- if ( 'recurring_percent' == $coupon->type ) {
+ if ( 'recurring_percent' == $coupon_type ) {
$apply_initial_percent_coupon = true;
}
}
// Apply sign-up discounts to initial total
- if ( ! empty( $cart_item['data']->subscription_sign_up_fee ) ) {
+ if ( WC_Subscriptions_Product::get_sign_up_fee( $cart_item['data'] ) > 0 ) {
- if ( 'sign_up_fee' == $coupon->type ) {
+ if ( 'sign_up_fee' == $coupon_type ) {
$apply_initial_coupon = true;
}
- if ( 'sign_up_fee_percent' == $coupon->type ) {
+ if ( 'sign_up_fee_percent' == $coupon_type ) {
$apply_initial_percent_coupon = true;
}
- $calculation_price = $cart_item['data']->subscription_sign_up_fee;
+ $calculation_price = WC_Subscriptions_Product::get_sign_up_fee( $cart_item['data'] );
}
}
if ( $apply_recurring_coupon || $apply_initial_coupon ) {
- $discount_amount = ( $calculation_price < $coupon->amount ) ? $calculation_price : $coupon->amount;
+ $discount_amount = ( $calculation_price < $coupon_amount ) ? $calculation_price : $coupon_amount;
// Recurring coupons only apply when there is no free trial (carts can have a mix of free trial and non free trial items)
- if ( $apply_initial_coupon && 'recurring_fee' == $coupon->type && ! empty( $cart_item['data']->subscription_trial_length ) ) {
+ if ( $apply_initial_coupon && 'recurring_fee' == $coupon_type && WC_Subscriptions_Product::get_trial_length( $cart_item['data'] ) > 0 ) {
$discount_amount = 0;
}
$cart->discount_cart = $cart->discount_cart + ( $discount_amount * $cart_item['quantity'] );
- $cart = self::increase_coupon_discount_amount( $cart, $coupon->code, $discount_amount * $cart_item['quantity'] );
+ $cart = self::increase_coupon_discount_amount( $cart, $coupon_code, $discount_amount * $cart_item['quantity'] );
$price = $price - $discount_amount;
} elseif ( $apply_recurring_percent_coupon ) {
- $discount_amount = round( ( $calculation_price / 100 ) * $coupon->amount, WC()->cart->dp );
+ $discount_amount = round( ( $calculation_price / 100 ) * $coupon_amount, WC()->cart->dp );
$cart->discount_cart = $cart->discount_cart + ( $discount_amount * $cart_item['quantity'] );
- $cart = self::increase_coupon_discount_amount( $cart, $coupon->code, $discount_amount * $cart_item['quantity'] );
+ $cart = self::increase_coupon_discount_amount( $cart, $coupon_code, $discount_amount * $cart_item['quantity'] );
$price = $price - $discount_amount;
} elseif ( $apply_initial_percent_coupon ) {
// Recurring coupons only apply when there is no free trial (carts can have a mix of free trial and non free trial items)
- if ( 'recurring_percent' == $coupon->type && empty( $cart_item['data']->subscription_trial_length ) ) {
- $amount_to_discount = $cart_item['data']->subscription_price;
+ if ( 'recurring_percent' == $coupon_type && 0 == WC_Subscriptions_Product::get_trial_length( $cart_item['data'] ) ) {
+ $amount_to_discount = WC_Subscriptions_Product::get_price( $cart_item['data'] );
} else {
$amount_to_discount = 0;
}
// Sign up fee coupons only apply to sign up fees
- if ( 'sign_up_fee_percent' == $coupon->type ) {
- $amount_to_discount = $cart_item['data']->subscription_sign_up_fee;
+ if ( 'sign_up_fee_percent' == $coupon_type ) {
+ $amount_to_discount = WC_Subscriptions_Product::get_sign_up_fee( $cart_item['data'] );
}
- $discount_amount = round( ( $amount_to_discount / 100 ) * $coupon->amount, WC()->cart->dp );
+ $discount_amount = round( ( $amount_to_discount / 100 ) * $coupon_amount, WC()->cart->dp );
$cart->discount_cart = $cart->discount_cart + $discount_amount * $cart_item['quantity'];
- $cart = self::increase_coupon_discount_amount( $cart, $coupon->code, $discount_amount * $cart_item['quantity'] );
+ $cart = self::increase_coupon_discount_amount( $cart, $coupon_code, $discount_amount * $cart_item['quantity'] );
$price = $price - $discount_amount;
}
diff --git a/includes/class-wc-subscriptions-email.php b/includes/class-wc-subscriptions-email.php
index 41e8d4c..57b5e40 100644
--- a/includes/class-wc-subscriptions-email.php
+++ b/includes/class-wc-subscriptions-email.php
@@ -104,7 +104,7 @@ class WC_Subscriptions_Email {
public static function send_cancelled_email( $subscription ) {
WC()->mailer();
- if ( $subscription->has_status( array( 'pending-cancel', 'cancelled' ) ) && 'true' !== get_post_meta( $subscription->id, '_cancelled_email_sent', true ) ) {
+ if ( $subscription->has_status( array( 'pending-cancel', 'cancelled' ) ) && 'true' !== get_post_meta( $subscription->get_id(), '_cancelled_email_sent', true ) ) {
do_action( 'cancelled_subscription_notification', $subscription );
}
}
@@ -157,7 +157,7 @@ class WC_Subscriptions_Email {
*/
public static function maybe_remove_woocommerce_email( $order_id ) {
if ( wcs_order_contains_renewal( $order_id ) || wcs_order_contains_switch( $order_id ) ) {
- remove_action( current_filter(), array( 'WC_Emails', 'send_transactional_email' ) );
+ self::detach_woocommerce_transactional_email();
}
}
@@ -170,7 +170,7 @@ class WC_Subscriptions_Email {
*/
public static function maybe_reattach_woocommerce_email( $order_id ) {
if ( wcs_order_contains_renewal( $order_id ) || wcs_order_contains_switch( $order_id ) ) {
- add_action( current_filter(), array( 'WC_Emails', 'send_transactional_email' ), 10, 10 );
+ self::attach_woocommerce_transactional_email();
}
}
@@ -185,7 +185,7 @@ class WC_Subscriptions_Email {
public static function renewal_order_emails_available( $available_emails ) {
global $theorder;
- if ( wcs_order_contains_renewal( $theorder->id ) ) {
+ if ( wcs_order_contains_renewal( wcs_get_objects_property( $theorder, 'id' ) ) ) {
$available_emails = array(
'new_renewal_order',
'customer_processing_renewal_order',
@@ -252,7 +252,11 @@ class WC_Subscriptions_Email {
add_filter( 'woocommerce_order_is_download_permitted', $show_download_links_callback );
add_filter( 'woocommerce_order_is_paid', $show_purchase_note_callback );
- $items_table = $order->email_order_items_table( $args );
+ if ( function_exists( 'wc_get_email_order_items' ) ) { // WC 3.0+
+ $items_table = wc_get_email_order_items( $order );
+ } else {
+ $items_table = $order->email_order_items_table( $args );
+ }
remove_filter( 'woocommerce_order_is_download_permitted', $show_download_links_callback );
remove_filter( 'woocommerce_order_is_paid', $show_purchase_note_callback );
@@ -300,6 +304,45 @@ class WC_Subscriptions_Email {
);
}
+ /**
+ * Detach WC transactional emails from a specific hook.
+ *
+ * @param string Optional. The action hook or filter to detach WC core's transactional emails from. Defaults to the current filter.
+ * @param int Optional. The priority the function runs on. Default 10.
+ * @since 2.2.3
+ */
+ public static function detach_woocommerce_transactional_email( $hook = '', $priority = 10 ) {
+
+ if ( '' === $hook ) {
+ $hook = current_filter();
+ }
+
+ // Emails might be queued or sent immediately so we need to remove both
+ remove_action( $hook, array( 'WC_Emails', 'queue_transactional_email' ), $priority );
+ remove_action( $hook, array( 'WC_Emails', 'send_transactional_email' ), $priority );
+ }
+
+ /**
+ * Attach WC transactional emails to a specific hook.
+ *
+ * @param string Optional. The action hook or filter to attach WC core's transactional emails to. Defaults to the current filter.
+ * @param int Optional. The priority the function should run on. Default 10.
+ * @param int Optional. The number of arguments the function accepts. Default 10.
+ * @since 2.2.3
+ */
+ public static function attach_woocommerce_transactional_email( $hook = '', $priority = 10, $accepted_args = 10 ) {
+
+ if ( '' === $hook ) {
+ $hook = current_filter();
+ }
+
+ if ( false === WC_Subscriptions::is_woocommerce_pre( '3.0' ) && apply_filters( 'woocommerce_defer_transactional_emails', true ) ) {
+ add_action( $hook, array( 'WC_Emails', 'queue_transactional_email' ), $priority, $accepted_args );
+ } else {
+ add_action( $hook, array( 'WC_Emails', 'send_transactional_email' ), $priority, $accepted_args );
+ }
+ }
+
/**
* Init the mailer and call the notifications for the current filter.
*
diff --git a/includes/class-wc-subscriptions-manager.php b/includes/class-wc-subscriptions-manager.php
index c61aa8f..9fa0a9e 100644
--- a/includes/class-wc-subscriptions-manager.php
+++ b/includes/class-wc-subscriptions-manager.php
@@ -88,7 +88,7 @@ class WC_Subscriptions_Manager {
}
// If the subscription is using manual payments, the gateway isn't active or it manages scheduled payments
- if ( 0 == $subscription->get_total() || $subscription->is_manual() || empty( $subscription->payment_method ) || ! $subscription->payment_method_supports( 'gateway_scheduled_payments' ) ) {
+ if ( 0 == $subscription->get_total() || $subscription->is_manual() || '' != $subscription->get_payment_method() || ! $subscription->payment_method_supports( 'gateway_scheduled_payments' ) ) {
// Always put the subscription on hold in case something goes wrong while trying to process renewal
$subscription->update_status( 'on-hold', _x( 'Subscription renewal payment due:', 'used in order note as reason for why subscription status changed', 'woocommerce-subscriptions' ) );
@@ -114,9 +114,13 @@ class WC_Subscriptions_Manager {
} else {
if ( $subscription->is_manual() ) {
- do_action( 'woocommerce_generated_manual_renewal_order', $renewal_order->id );
+ do_action( 'woocommerce_generated_manual_renewal_order', wcs_get_objects_property( $renewal_order, 'id' ) );
} else {
- $renewal_order->set_payment_method( $subscription->payment_gateway );
+ $renewal_order->set_payment_method( wc_get_payment_gateway_by_order( $subscription ) ); // We need to pass the payment gateway instance to be compatible with WC < 3.0, only WC 3.0+ supports passing the string name
+
+ if ( is_callable( array( $renewal_order, 'save' ) ) ) { // WC 3.0+ We need to save the payment method.
+ $renewal_order->save();
+ }
}
}
}
@@ -426,7 +430,7 @@ class WC_Subscriptions_Manager {
}
$args = wp_parse_args( $args, array(
- 'start_date' => get_gmt_from_date( $order->order_date ),
+ 'start_date' => wcs_get_datetime_utc_string( wcs_get_objects_property( $order, 'date_created' ) ), // get_date_created() can return null, but if it does, we have an error anyway
'expiry_date' => '',
) );
@@ -439,7 +443,7 @@ class WC_Subscriptions_Manager {
$product = wc_get_product( $product_id );
// Check if there is already a subscription for this product and order
- $subscriptions = wcs_get_subscriptions( array( 'order_id' => $order->id, 'product_id' => $product_id ) );
+ $subscriptions = wcs_get_subscriptions( array( 'order_id' => wcs_get_objects_property( $order, 'id' ), 'product_id' => $product_id ) );
if ( ! empty( $subscriptions ) ) {
@@ -447,7 +451,7 @@ class WC_Subscriptions_Manager {
// Make sure the subscription is pending and start date is set correctly
wp_update_post( array(
- 'ID' => $subscription->id,
+ 'ID' => $subscription->get_id(),
'post_status' => 'wc-' . apply_filters( 'woocommerce_default_subscription_status', 'pending' ),
'post_date' => get_date_from_gmt( $args['start_date'] ),
) );
@@ -456,11 +460,11 @@ class WC_Subscriptions_Manager {
$subscription = wcs_create_subscription( array(
'start_date' => get_date_from_gmt( $args['start_date'] ),
- 'order_id' => $order->id,
+ 'order_id' => wcs_get_objects_property( $order, 'id' ),
'customer_id' => $order->get_user_id(),
'billing_period' => $billing_period,
'billing_interval' => $billing_interval,
- 'customer_note' => $order->customer_note,
+ 'customer_note' => wcs_get_objects_property( $order, 'customer_note' ),
) );
if ( is_wp_error( $subscription ) ) {
@@ -488,8 +492,13 @@ class WC_Subscriptions_Manager {
}
// Make sure some of the meta is copied form the order rather than the store's defaults
- update_post_meta( $subscription->id, '_order_currency', $order->order_currency );
- update_post_meta( $subscription->id, '_prices_include_tax', $order->prices_include_tax );
+ if ( wcs_get_objects_property( $order, 'prices_include_tax' ) ) {
+ $prices_include_tax = 'yes';
+ } else {
+ $prices_include_tax = 'no';
+ }
+ update_post_meta( $subscription->get_id(), '_order_currency', wcs_get_objects_property( $order, 'currency' ) );
+ update_post_meta( $subscription->get_id(), '_prices_include_tax', $prices_include_tax );
// Adding a new subscription so set the expiry date/time from the order date
if ( ! empty( $args['expiry_date'] ) ) {
@@ -562,7 +571,7 @@ class WC_Subscriptions_Manager {
_deprecated_argument( __METHOD__, '1.2', 'The "suspend" status value is deprecated. Use "on-hold"' );
}
- foreach ( wcs_get_subscriptions_for_order( $order->id, array( 'order_type' => 'parent' ) ) as $subscription_id => $subscription ) {
+ foreach ( wcs_get_subscriptions_for_order( wcs_get_objects_property( $order, 'id' ), array( 'order_type' => 'parent' ) ) as $subscription_id => $subscription ) {
switch ( $status ) {
case 'cancelled' :
@@ -575,7 +584,7 @@ class WC_Subscriptions_Manager {
break;
case 'failed' :
_deprecated_argument( __METHOD__, '2.0', 'The "failed" status value is deprecated.' );
- self::failed_subscription_signup( $order->user_id, $subscription_id );
+ self::failed_subscription_signup( $order->get_user_id(), $subscription_id );
break;
case 'pending' :
_deprecated_argument( __METHOD__, '2.0', 'The "pending" status value is deprecated.' );
@@ -612,7 +621,7 @@ class WC_Subscriptions_Manager {
$subscription = wcs_get_subscription_from_key( $subscription_key );
if ( isset( $new_subscription_details['status'] ) && 'deleted' == $new_subscription_details['status'] ) {
- wp_delete_post( $subscription->id );
+ wp_delete_post( $subscription->get_id() );
} else {
// There is no direct analog for this in WC_Subscription, so we need to call the deprecated method
self::update_subscription( $subscription_key, $new_subscription_details );
@@ -647,14 +656,14 @@ class WC_Subscriptions_Manager {
if ( isset( $new_subscription_details['status'] ) && 'deleted' == $new_subscription_details['status'] ) {
- wp_delete_post( $subscription->id );
+ wp_delete_post( $subscription->get_id() );
} else {
foreach ( $new_subscription_details as $meta_key => $meta_value ) {
switch ( $meta_key ) {
case 'start_date' :
- $subscription->update_dates( array( 'start' => $meta_value ) );
+ $subscription->update_dates( array( 'date_created' => $meta_value ) );
break;
case 'trial_expiry_date' :
$subscription->update_dates( array( 'trial_end' => $meta_value ) );
@@ -669,7 +678,7 @@ class WC_Subscriptions_Manager {
_deprecated_argument( __METHOD__, '2.0', 'The "completed_payments" meta value is deprecated. Create a renewal order with completed payment instead.' );
break;
case 'suspension_count' :
- $subscription->update_suspension_count( $subscription->suspension_count + 1 );
+ $subscription->set_suspension_count( $subscription->get_suspension_count() + 1 );
break;
}
}
@@ -738,7 +747,7 @@ class WC_Subscriptions_Manager {
public static function clear_users_subscriptions_from_order( $order ) {
foreach ( wcs_get_subscriptions_for_order( $order, array( 'order_type' => 'parent' ) ) as $subscription_id => $subscription ) {
- wp_delete_post( $subscription->id );
+ wp_delete_post( $subscription->get_id() );
}
do_action( 'cleared_users_subscriptions_from_order', $order );
@@ -757,7 +766,7 @@ class WC_Subscriptions_Manager {
// delete subscription
foreach ( wcs_get_subscriptions_for_order( $post_id, array( 'order_type' => 'parent' ) ) as $subscription ) {
- wp_trash_post( $subscription->id );
+ wp_trash_post( $subscription->get_id() );
}
}
}
@@ -828,7 +837,7 @@ class WC_Subscriptions_Manager {
if ( ! empty( $subscriptions ) ) {
foreach ( $subscriptions as $subscription ) {
- wp_delete_post( $subscription->id );
+ wp_delete_post( $subscription->get_id() );
}
}
}
@@ -1253,7 +1262,7 @@ class WC_Subscriptions_Manager {
public static function get_last_payment_date( $subscription_key, $user_id = '', $type = 'mysql' ) {
_deprecated_function( __METHOD__, '2.0', 'WC_Subscription::get_date( "last_payment" )' );
$subscription = wcs_get_subscription_from_key( $subscription_key );
- $last_payment_date = ( 'mysql' == $type ) ? $subscription->get_date( 'last_payment' ) : $subscription->get_time( 'last_payment' );
+ $last_payment_date = ( 'mysql' == $type ) ? $subscription->get_date( 'last_order_date_created' ) : $subscription->get_time( 'last_order_date_created' );
return apply_filters( 'woocommerce_subscription_last_payment_date', $last_payment_date, $subscription_key, $user_id, $type );
}
@@ -1537,7 +1546,7 @@ class WC_Subscriptions_Manager {
$order = new WC_Order( $order );
}
- update_user_meta( $order->user_id, 'paying_customer', 1 );
+ update_user_meta( $order->get_user_id(), 'paying_customer', 1 );
}
/**
@@ -1557,8 +1566,8 @@ class WC_Subscriptions_Manager {
$order = new WC_Order( $order );
}
- if ( $order->user_id > 0 ) {
- update_user_meta( $order->user_id, 'paying_customer', 0 );
+ if ( $order->get_user_id() > 0 ) {
+ update_user_meta( $order->get_user_id(), 'paying_customer', 0 );
}
}
@@ -1822,7 +1831,7 @@ class WC_Subscriptions_Manager {
}
// If the subscription is using manual payments, the gateway isn't active or it manages scheduled payments
- if ( 0 == $subscription->get_total() || $subscription->is_manual() || empty( $subscription->payment_method ) || ! $subscription->payment_method_supports( 'gateway_scheduled_payments' ) ) {
+ if ( 0 == $subscription->get_total() || $subscription->is_manual() || '' != $subscription->get_payment_method() || ! $subscription->payment_method_supports( 'gateway_scheduled_payments' ) ) {
$subscription->update_status( 'on-hold', _x( 'Subscription renewal payment due:', 'used in order note as reason for why subscription status changed', 'woocommerce-subscriptions' ) );
}
}
@@ -2091,7 +2100,7 @@ class WC_Subscriptions_Manager {
// Log failure on order
// translators: placeholder is subscription ID
- $subscription->order->add_order_note( sprintf( __( 'Failed sign-up for subscription %s.', 'woocommerce-subscriptions' ), $subscription->id ) );
+ $subscription->get_parent()->add_order_note( sprintf( __( 'Failed sign-up for subscription %s.', 'woocommerce-subscriptions' ), $subscription->get_id() ) );
do_action( 'subscription_sign_up_failed', $user_id, $subscription_key );
}
@@ -2127,7 +2136,7 @@ class WC_Subscriptions_Manager {
$subscription->update_status( 'cancelled' );
}
- wp_trash_post( $subscription->id, true );
+ wp_trash_post( $subscription->get_id(), true );
do_action( 'subscription_trashed', $user_id, $subscription_key );
}
@@ -2160,7 +2169,7 @@ class WC_Subscriptions_Manager {
$subscription->update_status( 'cancelled' );
}
- wp_delete_post( $subscription->id, true );
+ wp_delete_post( $subscription->get_id(), true );
do_action( 'subscription_deleted', $user_id, $subscription_key, $subscription, $item );
}
diff --git a/includes/class-wc-subscriptions-order.php b/includes/class-wc-subscriptions-order.php
index 87cbb52..b986c20 100644
--- a/includes/class-wc-subscriptions-order.php
+++ b/includes/class-wc-subscriptions-order.php
@@ -238,7 +238,7 @@ class WC_Subscriptions_Order {
$item['name'] = $item['order_item_name'];
$item['type'] = $item['order_item_type'];
- $item['item_meta'] = $order->get_item_meta( $item['order_item_id'] );
+ $item['item_meta'] = wc_get_order_item_meta( $item['order_item_id'], '' );
// Put meta into item array
if ( is_array( $item['item_meta'] ) ) {
@@ -345,7 +345,7 @@ class WC_Subscriptions_Order {
} elseif ( is_array( $order->order_custom_fields ) && isset( $order->order_custom_fields[ '_' . $meta_key ][0] ) && $order->order_custom_fields[ '_' . $meta_key ][0] ) { // < WC 2.1+
$meta_value = maybe_unserialize( $order->order_custom_fields[ '_' . $meta_key ][0] );
} else {
- $meta_value = get_post_meta( $order->id, '_' . $meta_key, true );
+ $meta_value = get_post_meta( wcs_get_objects_property( $order, 'id' ), '_' . $meta_key, true );
if ( empty( $meta_value ) ) {
$meta_value = $default;
@@ -482,12 +482,12 @@ class WC_Subscriptions_Order {
// Do we need to activate a subscription?
if ( $order_completed && ! $subscription->has_status( wcs_get_subscription_ended_statuses() ) && ! $subscription->has_status( 'active' ) ) {
- $new_start_date_offset = current_time( 'timestamp', true ) - $subscription->get_time( 'start' );
+ $new_start_date_offset = current_time( 'timestamp', true ) - $subscription->get_time( 'date_created' );
// if the payment has been processed more than an hour after the order was first created, let's update the dates on the subscription to account for that, because it may have even been processed days after it was first placed
if ( $new_start_date_offset > HOUR_IN_SECONDS ) {
- $dates = array( 'start' => current_time( 'mysql', true ) );
+ $dates = array( 'date_created' => current_time( 'mysql', true ) );
if ( WC_Subscriptions_Synchroniser::subscription_contains_synced_product( $subscription ) ) {
@@ -495,15 +495,15 @@ class WC_Subscriptions_Order {
$next_payment = $subscription->get_time( 'next_payment' );
// if either there is a free trial date or a next payment date that falls before now, we need to recalculate all the sync'd dates
- if ( ( $trial_end > 0 && $trial_end < wcs_date_to_time( $dates['start'] ) ) || ( $next_payment > 0 && $next_payment < wcs_date_to_time( $dates['start'] ) ) ) {
+ if ( ( $trial_end > 0 && $trial_end < wcs_date_to_time( $dates['date_created'] ) ) || ( $next_payment > 0 && $next_payment < wcs_date_to_time( $dates['date_created'] ) ) ) {
foreach ( $subscription->get_items() as $item ) {
$product_id = wcs_get_canonical_product_id( $item );
if ( WC_Subscriptions_Synchroniser::is_product_synced( $product_id ) ) {
- $dates['trial_end'] = WC_Subscriptions_Product::get_trial_expiration_date( $product_id, $dates['start'] );
- $dates['next_payment'] = WC_Subscriptions_Synchroniser::calculate_first_payment_date( $product_id, 'mysql', $dates['start'] );
- $dates['end'] = WC_Subscriptions_Product::get_expiration_date( $product_id, $dates['start'] );
+ $dates['trial_end'] = WC_Subscriptions_Product::get_trial_expiration_date( $product_id, $dates['date_created'] );
+ $dates['next_payment'] = WC_Subscriptions_Synchroniser::calculate_first_payment_date( $product_id, 'mysql', $dates['date_created'] );
+ $dates['end'] = WC_Subscriptions_Product::get_expiration_date( $product_id, $dates['date_created'] );
break;
}
}
@@ -624,7 +624,7 @@ class WC_Subscriptions_Order {
*/
public static function order_needs_payment( $needs_payment, $order, $valid_order_statuses ) {
- if ( wcs_order_contains_subscription( $order ) && in_array( $order->status, $valid_order_statuses ) && 0 == $order->get_total() && false === $needs_payment && self::get_recurring_total( $order ) > 0 && 'yes' !== get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no' ) ) {
+ if ( false === $needs_payment && 0 == $order->get_total() && in_array( $order->get_status(), $valid_order_statuses ) && wcs_order_contains_subscription( $order ) && self::get_recurring_total( $order ) > 0 && 'yes' !== get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no' ) ) {
$needs_payment = true;
}
@@ -658,22 +658,6 @@ class WC_Subscriptions_Order {
}
}
- /**
- * Wrapper around @see WC_Order::get_order_currency() for versions of WooCommerce prior to 2.1.
- *
- * @since version 1.4.9
- */
- public static function get_order_currency( $order ) {
-
- if ( method_exists( $order, 'get_order_currency' ) ) {
- $order_currency = $order->get_order_currency();
- } else {
- $order_currency = get_woocommerce_currency();
- }
-
- return $order_currency;
- }
-
/**
* Add admin dropdown for order types to Woocommerce -> Orders screen
*
@@ -946,14 +930,14 @@ class WC_Subscriptions_Order {
if ( wcs_order_contains_subscription( $order, array( 'parent', 'renewal' ) ) ) {
- $subscriptions = wcs_get_subscriptions_for_order( $order->id, array( 'order_type' => array( 'parent', 'renewal' ) ) );
+ $subscriptions = wcs_get_subscriptions_for_order( wcs_get_objects_property( $order, 'id' ), array( 'order_type' => array( 'parent', 'renewal' ) ) );
foreach ( $subscriptions as $subscription ) {
$latest_order = $subscription->get_last_order();
- if ( $order->id == $latest_order && $subscription->has_status( 'pending-cancel' ) && $subscription->can_be_updated_to( 'cancelled' ) ) {
+ if ( wcs_get_objects_property( $order, 'id' ) == $latest_order && $subscription->has_status( 'pending-cancel' ) && $subscription->can_be_updated_to( 'cancelled' ) ) {
// translators: $1: opening link tag, $2: order number, $3: closing link tag
- $subscription->update_status( 'cancelled', wp_kses( sprintf( __( 'Subscription cancelled for refunded order %1$s#%2$s%3$s.', 'woocommerce-subscriptions' ), sprintf( '', esc_url( wcs_get_edit_post_link( $order->id ) ) ), $order->get_order_number(), '' ), array( 'a' => array( 'href' => true ) ) ) );
+ $subscription->update_status( 'cancelled', wp_kses( sprintf( __( 'Subscription cancelled for refunded order %1$s#%2$s%3$s.', 'woocommerce-subscriptions' ), sprintf( '', esc_url( wcs_get_edit_post_link( wcs_get_objects_property( $order, 'id' ) ) ) ), $order->get_order_number(), '' ), array( 'a' => array( 'href' => true ) ) ) );
}
}
}
@@ -1032,7 +1016,11 @@ class WC_Subscriptions_Order {
* @since 2.1.3
*/
public static function maybe_autocomplete_order( $new_order_status, $order_id ) {
+
+ // Guard against infinite loops in WC 3.0+ where woocommerce_payment_complete_order_status is called while instantiating WC_Order objects
+ remove_filter( 'woocommerce_payment_complete_order_status', __METHOD__, 10 );
$order = wc_get_order( $order_id );
+ add_filter( 'woocommerce_payment_complete_order_status', __METHOD__, 10, 2 );
if ( 'processing' == $new_order_status && $order->get_total() == 0 && wcs_order_contains_subscription( $order ) ) {
@@ -1350,22 +1338,24 @@ class WC_Subscriptions_Order {
public static function get_recurring_discount_total( $order, $product_id = '' ) {
_deprecated_function( __METHOD__, '2.0', 'the value for the subscription object rather than the value on the original order. The value is stored against the subscription since Subscriptions v2.0 as an order can be used to create multiple different subscriptions with different discounts, so use the subscription object' );
- $ex_tax = ( $order->tax_display_cart === 'excl' && $order->display_totals_ex_tax ) ? true : false;
+ $ex_tax = ( 'excl' === get_option( 'woocommerce_tax_display_cart' ) && wcs_get_objects_property( $order, 'display_totals_ex_tax' ) ) ? true : false;
$recurring_discount_cart = (double) self::get_recurring_discount_cart( $order );
$recurring_discount_cart_tax = (double) self::get_recurring_discount_cart_tax( $order );
$recurring_discount_total = 0;
- if ( ! $order->order_version || version_compare( $order->order_version, '2.3.7', '<' ) ) {
+ $order_version = wcs_get_objects_property( $order, 'version' );
+
+ if ( '' === $order_version || version_compare( $order_version, '2.3.7', '<' ) ) {
// Backwards compatible total calculation - totals were not stored consistently in old versions.
if ( $ex_tax ) {
- if ( $order->prices_include_tax ) {
+ if ( wcs_get_objects_property( $order, 'prices_include_tax' ) ) {
$recurring_discount_total = $recurring_discount_cart - $recurring_discount_cart_tax;
} else {
$recurring_discount_total = $recurring_discount_cart;
}
} else {
- if ( $order->prices_include_tax ) {
+ if ( wcs_get_objects_property( $order, 'prices_include_tax' ) ) {
$recurring_discount_total = $recurring_discount_cart;
} else {
$recurring_discount_total = $recurring_discount_cart + $recurring_discount_cart_tax;
@@ -1629,13 +1619,13 @@ class WC_Subscriptions_Order {
// Find the billing period discount for all recurring items
if ( empty( $product_id ) ) {
- $billing_period = $subscription->billing_period;
+ $billing_period = $subscription->get_billing_period();
break;
} else {
// We want the billing period for a specific item (so we need to find if this subscription contains that item)
foreach ( $subscription->get_items() as $line_item ) {
if ( wcs_get_canonical_product_id( $line_item ) == $product_id ) {
- $billing_period = $subscription->billing_period;
+ $billing_period = $subscription->get_billing_period();
break 2;
}
}
@@ -1664,13 +1654,13 @@ class WC_Subscriptions_Order {
// Find the billing interval for all recurring items
if ( empty( $product_id ) ) {
- $billing_interval = $subscription->billing_interval;
+ $billing_interval = $subscription->get_billing_interval();
break;
} else {
// We want the billing interval for a specific item (so we need to find if this subscription contains that item)
foreach ( $subscription->get_items() as $line_item ) {
if ( wcs_get_canonical_product_id( $line_item ) == $product_id ) {
- $billing_interval = $subscription->billing_interval;
+ $billing_interval = $subscription->get_billing_interval();
break 2;
}
}
@@ -1802,11 +1792,11 @@ class WC_Subscriptions_Order {
}
if ( $subscription = self::get_matching_subscription( $order, $product_id ) ) {
- $last_payment_date = $subscription->get_date( 'last_payment' );
- } elseif ( isset( $order->paid_date ) ) {
- $last_payment_date = get_gmt_from_date( $order->paid_date );
+ $last_payment_date = $subscription->get_date( 'last_order_date_created' );
+ } elseif ( null !== ( $last_payment_date = wcs_get_objects_property( $order, 'date_paid' ) ) ) {
+ $last_payment_date = $last_payment_date->date( 'Y-m-d H:i:s' );
} else {
- $last_payment_date = $order->post->post_date;
+ $last_payment_date = wcs_get_datetime_utc_string( wcs_get_objects_property( $order, 'date_created' ) ); // get_date_created() can return null, but if it does, we have an error anyway
}
return $last_payment_date;
@@ -2024,11 +2014,22 @@ class WC_Subscriptions_Order {
// No payments have been recorded yet
if ( 0 == $subscription->get_completed_payment_count() ) {
- $subscription->update_dates( array( 'start' => current_time( 'mysql', true ) ) );
+ $subscription->update_dates( array( 'date_created' => current_time( 'mysql', true ) ) );
$subscription->payment_complete();
}
}
}
}
+
+ /**
+ * Wrapper around @see WC_Order::get_order_currency() for versions of WooCommerce prior to 2.1.
+ *
+ * @since version 1.4.9
+ * @deprecated 2.2.0
+ */
+ public static function get_order_currency( $order ) {
+ _deprecated_function( __METHOD__, '2.2.0', 'wcs_get_objects_property( $order, "currency" ) or $order->get_currency()' );
+ return wcs_get_objects_property( $order, 'currency' );
+ }
}
WC_Subscriptions_Order::init();
diff --git a/includes/class-wc-subscriptions-product.php b/includes/class-wc-subscriptions-product.php
index a0f6301..4debda1 100644
--- a/includes/class-wc-subscriptions-product.php
+++ b/includes/class-wc-subscriptions-product.php
@@ -45,6 +45,9 @@ class WC_Subscriptions_Product {
// Make sure a subscriptions price is included in subscription variations when required
add_filter( 'woocommerce_available_variation', __CLASS__ . '::maybe_set_variations_price_html', 10, 3 );
+ // Sync variable product min/max prices with WC 3.0
+ add_action( 'woocommerce_variable_product_sync_data', __CLASS__ . '::variable_subscription_product_sync', 10 );
+
// Prevent users from deleting subscription products - it causes too many problems with WooCommerce and other plugins
add_filter( 'user_has_cap', __CLASS__ . '::user_can_not_delete_subscription', 10, 3 );
@@ -71,23 +74,6 @@ class WC_Subscriptions_Product {
add_action( 'wp_ajax_wcs_update_one_time_shipping', __CLASS__ . '::maybe_update_one_time_shipping_on_variation_edits' );
}
- /**
- * 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 static function get_sign_up_fee_including_tax( $product, $qty = 1 ) {
-
- add_filter( 'woocommerce_get_price', __CLASS__ . '::get_sign_up_fee_filter', 100, 2 );
-
- $sign_up_fee_including_tax = $product->get_price_including_tax( $qty );
-
- remove_filter( 'woocommerce_get_price', __CLASS__ . '::get_sign_up_fee_filter', 100, 2 );
-
- return $sign_up_fee_including_tax;
- }
-
/**
* Returns the raw sign up fee value (ignoring tax) by filtering the products price.
*
@@ -98,23 +84,6 @@ class WC_Subscriptions_Product {
return self::get_sign_up_fee( $product );
}
- /**
- * 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 static function get_sign_up_fee_excluding_tax( $product, $qty = 1 ) {
-
- add_filter( 'woocommerce_get_price', __CLASS__ . '::get_sign_up_fee_filter', 100, 2 );
-
- $sign_up_fee_excluding_tax = $product->get_price_excluding_tax( $qty );
-
- remove_filter( 'woocommerce_get_price', __CLASS__ . '::get_sign_up_fee_filter', 100, 2 );
-
- return $sign_up_fee_excluding_tax;
- }
-
/**
* Override the WooCommerce "Add to Cart" text with "Sign Up Now".
*
@@ -134,25 +103,20 @@ class WC_Subscriptions_Product {
* Checks a given product to determine if it is a subscription.
* When the received arg is a product object, make sure it is passed into the filter intact in order to retain any properties added on the fly.
*
- * @param int|WC_Product $product_id Either a product object or product's post ID.
+ * @param int|WC_Product $product Either a product object or product's post ID.
* @since 1.0
*/
- public static function is_subscription( $product_id ) {
+ public static function is_subscription( $product ) {
$is_subscription = false;
- if ( is_object( $product_id ) ) {
- $product = $product_id;
- $product_id = $product->id;
- } elseif ( is_numeric( $product_id ) ) {
- $product = wc_get_product( $product_id );
- }
+ $product = self::maybe_get_product_instance( $product );
if ( is_object( $product ) && $product->is_type( array( 'subscription', 'subscription_variation', 'variable-subscription' ) ) ) {
$is_subscription = true;
}
- return apply_filters( 'woocommerce_is_subscription', $is_subscription, $product_id, $product );
+ return apply_filters( 'woocommerce_is_subscription', $is_subscription, $product->get_id(), $product );
}
/**
@@ -174,9 +138,10 @@ class WC_Subscriptions_Product {
$child_product = wc_get_product( $child_product_id );
- $child_price = $child_product->get_price();
- $sign_up_fee = $child_product->get_sign_up_fee();
- $has_trial = ( self::get_trial_length( $child_product ) > 0 ) ? true : false;
+ $tax_display_mode = get_option( 'woocommerce_tax_display_shop' );
+ $child_price = 'incl' == $tax_display_mode ? wcs_get_price_including_tax( $child_product, array( 'price' => $child_product->get_price() ) ) : wcs_get_price_excluding_tax( $child_product, array( 'price' => $child_product->get_price() ) );
+ $sign_up_fee = 'incl' == $tax_display_mode ? wcs_get_price_including_tax( $child_product, array( 'price' => self::get_sign_up_fee( $child_product ) ) ) : wcs_get_price_excluding_tax( $child_product, array( 'price' => self::get_sign_up_fee( $child_product ) ) );
+ $has_trial = ( self::get_trial_length( $child_product ) > 0 ) ? true : false;
// Make sure we have the *real* price (i.e. total initial payment)
if ( $has_trial && $sign_up_fee > 0 ) {
@@ -209,7 +174,7 @@ class WC_Subscriptions_Product {
}
if ( sizeof( $child_prices ) > 1 ) {
- $price .= $grouped_product->get_price_html_from_text();
+ $price .= wcs_get_price_html_from_text( $grouped_product );
}
$price .= wc_price( $min_price );
@@ -247,9 +212,7 @@ class WC_Subscriptions_Product {
public static function get_price_string( $product, $include = array() ) {
global $wp_locale;
- if ( ! is_object( $product ) ) {
- $product = WC_Subscriptions::get_product( $product );
- }
+ $product = self::maybe_get_product_instance( $product );
if ( ! self::is_subscription( $product ) ) {
return;
@@ -284,22 +247,22 @@ class WC_Subscriptions_Product {
if ( isset( $include['price'] ) ) {
$price = $include['price'];
} else {
- $price = $product->get_price_excluding_tax( 1, $include['price'] );
+ $price = wcs_get_price_excluding_tax( $product, array( 'price' => $include['price'] ) );
}
if ( true === $include['sign_up_fee'] ) {
- $sign_up_fee = self::get_sign_up_fee_excluding_tax( $product );
+ $sign_up_fee = wcs_get_price_excluding_tax( $product, array( 'price' => WC_Subscriptions_Product::get_sign_up_fee( $product ) ) );
}
} else { // Add Tax
if ( isset( $include['price'] ) ) {
$price = $include['price'];
} else {
- $price = $product->get_price_including_tax();
+ $price = wcs_get_price_including_tax( $product );
}
if ( true === $include['sign_up_fee'] ) {
- $sign_up_fee = self::get_sign_up_fee_including_tax( $product );
+ $sign_up_fee = wcs_get_price_including_tax( $product, array( 'price' => WC_Subscriptions_Product::get_sign_up_fee( $product ) ) );
}
}
} else {
@@ -421,18 +384,43 @@ class WC_Subscriptions_Product {
* @since 1.0
*/
public static function get_price( $product ) {
+ return apply_filters( 'woocommerce_subscriptions_product_price', self::get_meta_data( $product, 'subscription_price', 0 ), self::maybe_get_product_instance( $product ) );
+ }
- if ( ! is_object( $product ) ) {
- $product = WC_Subscriptions::get_product( $product );
- }
+ /**
+ * Returns the sale price per period for a product if it is a subscription.
+ *
+ * @param mixed $product A WC_Product object or product ID
+ * @return float
+ * @since 2.2.0
+ */
+ public static function get_regular_price( $product, $context = 'view' ) {
- if ( ! self::is_subscription( $product ) || ( ! isset( $product->subscription_price ) && empty( $product->product_custom_fields['_subscription_price'][0] ) ) ) {
- $subscription_price = '';
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ $regular_price = $product->regular_price;
} else {
- $subscription_price = isset( $product->subscription_price ) ? $product->subscription_price : $product->product_custom_fields['_subscription_price'][0];
+ $regular_price = $product->get_regular_price( $context );
}
- return apply_filters( 'woocommerce_subscriptions_product_price', $subscription_price, $product );
+ return apply_filters( 'woocommerce_subscriptions_product_regular_price', $regular_price, $product );
+ }
+
+ /**
+ * Returns the regular price per period for a product if it is a subscription.
+ *
+ * @param mixed $product A WC_Product object or product ID
+ * @return float
+ * @since 2.2.0
+ */
+ public static function get_sale_price( $product, $context = 'view' ) {
+
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ $sale_price = $product->sale_price;
+ } else {
+ $sale_price = $product->get_sale_price( $context );
+ }
+
+ return apply_filters( 'woocommerce_subscriptions_product_sale_price', $sale_price, $product );
}
/**
@@ -443,18 +431,7 @@ class WC_Subscriptions_Product {
* @since 1.0
*/
public static function get_period( $product ) {
-
- if ( ! is_object( $product ) ) {
- $product = WC_Subscriptions::get_product( $product );
- }
-
- if ( ! self::is_subscription( $product ) || ( ! isset( $product->subscription_period ) && empty( $product->product_custom_fields['_subscription_period'][0] ) ) ) {
- $subscription_period = '';
- } else {
- $subscription_period = isset( $product->subscription_period ) ? $product->subscription_period : $product->product_custom_fields['_subscription_period'][0];
- }
-
- return apply_filters( 'woocommerce_subscriptions_product_period', $subscription_period, $product );
+ return apply_filters( 'woocommerce_subscriptions_product_period', self::get_meta_data( $product, 'subscription_period', '' ), self::maybe_get_product_instance( $product ) );
}
/**
@@ -465,18 +442,7 @@ class WC_Subscriptions_Product {
* @since 1.0
*/
public static function get_interval( $product ) {
-
- if ( ! is_object( $product ) ) {
- $product = WC_Subscriptions::get_product( $product );
- }
-
- if ( ! self::is_subscription( $product ) || ( ! isset( $product->subscription_period_interval ) && empty( $product->product_custom_fields['_subscription_period_interval'][0] ) ) ) {
- $subscription_period_interval = 1;
- } else {
- $subscription_period_interval = isset( $product->subscription_period_interval ) ? $product->subscription_period_interval : $product->product_custom_fields['_subscription_period_interval'][0];
- }
-
- return apply_filters( 'woocommerce_subscriptions_product_period_interval', $subscription_period_interval, $product );
+ return apply_filters( 'woocommerce_subscriptions_product_period_interval', self::get_meta_data( $product, 'subscription_period_interval', 0 ), self::maybe_get_product_instance( $product ) );
}
/**
@@ -487,18 +453,7 @@ class WC_Subscriptions_Product {
* @since 1.0
*/
public static function get_length( $product ) {
-
- if ( ! is_object( $product ) ) {
- $product = WC_Subscriptions::get_product( $product );
- }
-
- if ( ! self::is_subscription( $product ) || ( ! isset( $product->subscription_length ) && empty( $product->product_custom_fields['_subscription_length'][0] ) ) ) {
- $subscription_length = 0;
- } else {
- $subscription_length = isset( $product->subscription_length ) ? $product->subscription_length : $product->product_custom_fields['_subscription_length'][0];
- }
-
- return apply_filters( 'woocommerce_subscriptions_product_length', $subscription_length, $product );
+ return apply_filters( 'woocommerce_subscriptions_product_length', self::get_meta_data( $product, 'subscription_length', 0 ), self::maybe_get_product_instance( $product ) );
}
/**
@@ -509,18 +464,7 @@ class WC_Subscriptions_Product {
* @since 1.0
*/
public static function get_trial_length( $product ) {
-
- if ( ! is_object( $product ) ) {
- $product = WC_Subscriptions::get_product( $product );
- }
-
- if ( ! self::is_subscription( $product ) || ( ! isset( $product->subscription_trial_length ) && empty( $product->product_custom_fields['_subscription_trial_length'][0] ) ) ) {
- $subscription_trial_length = 0;
- } else {
- $subscription_trial_length = isset( $product->subscription_trial_length ) ? $product->subscription_trial_length : $product->product_custom_fields['_subscription_trial_length'][0];
- }
-
- return apply_filters( 'woocommerce_subscriptions_product_trial_length', $subscription_trial_length, $product );
+ return apply_filters( 'woocommerce_subscriptions_product_trial_length', self::get_meta_data( $product, 'subscription_trial_length', 0 ), self::maybe_get_product_instance( $product ) );
}
/**
@@ -531,20 +475,7 @@ class WC_Subscriptions_Product {
* @since 1.2
*/
public static function get_trial_period( $product ) {
-
- if ( ! is_object( $product ) ) {
- $product = WC_Subscriptions::get_product( $product );
- }
-
- if ( ! self::is_subscription( $product ) ) {
- $subscription_trial_period = '';
- } elseif ( ! isset( $product->subscription_trial_period ) && empty( $product->product_custom_fields['_subscription_trial_period'][0] ) ) { // Backward compatibility
- $subscription_trial_period = self::get_period( $product );
- } else {
- $subscription_trial_period = isset( $product->subscription_trial_period ) ? $product->subscription_trial_period : $product->product_custom_fields['_subscription_trial_period'][0];
- }
-
- return apply_filters( 'woocommerce_subscriptions_product_trial_period', $subscription_trial_period, $product );
+ return apply_filters( 'woocommerce_subscriptions_product_trial_period', self::get_meta_data( $product, 'subscription_trial_period', '' ), self::maybe_get_product_instance( $product ) );
}
/**
@@ -555,18 +486,7 @@ class WC_Subscriptions_Product {
* @since 1.0
*/
public static function get_sign_up_fee( $product ) {
-
- if ( ! is_object( $product ) ) {
- $product = WC_Subscriptions::get_product( $product );
- }
-
- if ( ! self::is_subscription( $product ) || ( ! isset( $product->subscription_sign_up_fee ) && empty( $product->product_custom_fields['_subscription_sign_up_fee'][0] ) ) ) {
- $subscription_sign_up_fee = 0;
- } else {
- $subscription_sign_up_fee = isset( $product->subscription_sign_up_fee ) ? $product->subscription_sign_up_fee : $product->product_custom_fields['_subscription_sign_up_fee'][0];
- }
-
- return apply_filters( 'woocommerce_subscriptions_product_sign_up_fee', $subscription_sign_up_fee, $product );
+ return apply_filters( 'woocommerce_subscriptions_product_sign_up_fee', self::get_meta_data( $product, 'subscription_sign_up_fee', 0 ), self::maybe_get_product_instance( $product ) );
}
/**
@@ -735,7 +655,7 @@ class WC_Subscriptions_Product {
*/
public static function maybe_set_variations_price_html( $variation_details, $variable_product, $variation ) {
- if ( 'variable-subscription' == $variable_product->product_type && empty( $variation_details['price_html'] ) ) {
+ if ( $variable_product->is_type( 'variable-subscription' ) && empty( $variation_details['price_html'] ) ) {
$variation_details['price_html'] = '' . $variation->get_price_html() . '';
}
@@ -759,9 +679,9 @@ class WC_Subscriptions_Product {
$post_id = $args[2];
$product = wc_get_product( $post_id );
- if ( false !== $product && 'trash' == $product->post->post_status && $product->is_type( array( 'subscription', 'variable-subscription', 'subscription_variation' ) ) ) {
+ if ( false !== $product && 'trash' == wcs_get_objects_property( $product, 'post_status' ) && $product->is_type( array( 'subscription', 'variable-subscription', 'subscription_variation' ) ) ) {
- $product_id = ( $product->is_type( 'subscription_variation' ) ) ? $product->post->ID : $post_id;
+ $product_id = ( $product->is_type( 'subscription_variation' ) ) ? $product->get_parent_id() : $post_id;
$subscription_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM `{$wpdb->prefix}woocommerce_order_itemmeta` WHERE `meta_key` = '_product_id' AND `meta_value` = %d", $product_id ) );
@@ -820,6 +740,17 @@ class WC_Subscriptions_Product {
return $actions;
}
+ /**
+ * Check whether a product has one-time shipping only.
+ *
+ * @param mixed $product A WC_Product object or product ID
+ * @return bool True if the product requires only one time shipping, false otherwise.
+ * @since 2.2.0
+ */
+ public static function needs_one_time_shipping( $product ) {
+ return apply_filters( 'woocommerce_subscriptions_product_needs_one_time_shipping', 'yes' === self::get_meta_data( $product, 'subscription_one_time_shipping', 'no' ), self::maybe_get_product_instance( $product ) );
+ }
+
/**
* Hooked to the @see 'wp_scheduled_delete' WP-Cron scheduled task to rename the '_wp_trash_meta_time' meta value
* as '_wc_trash_meta_time'. This is the flag used by WordPress to determine which posts should be automatically
@@ -965,14 +896,14 @@ class WC_Subscriptions_Product {
continue;
}
- $variable_product = wc_get_product( $variation_id );
+ $variation_product = wc_get_product( $variation_id );
- if ( $variable_product->subscription_trial_length > 0 ) {
+ if ( WC_Subscriptions_Product::get_trial_length( $variation_product ) ) {
$is_synced_or_has_trial = true;
break;
}
- if ( WC_Subscriptions_Synchroniser::is_syncing_enabled() && ( ( ! is_array( $variable_product->subscription_payment_sync_date ) && $variable_product->subscription_payment_sync_date > 0 ) || ( is_array( $variable_product->subscription_payment_sync_date ) && $variable_product->subscription_payment_sync_date['day'] > 0 ) ) ) {
+ if ( WC_Subscriptions_Synchroniser::is_product_synced( $variation_product ) ) {
$is_synced_or_has_trial = true;
break;
}
@@ -1008,6 +939,102 @@ class WC_Subscriptions_Product {
wp_send_json( array( 'one_time_shipping' => $subscription_one_time_shipping ) );
}
+ /**
+ * Wrapper to check whether we have a product ID or product and if we have the former, return the later.
+ *
+ * @param mixed $product A WC_Product object or product ID
+ * @return WC_Product
+ * @since 2.2.0
+ */
+ private static function maybe_get_product_instance( $product ) {
+
+ if ( ! is_object( $product ) || ! is_a( $product, 'WC_Product' ) ) {
+ $product = wc_get_product( $product );
+ }
+
+ return $product;
+ }
+
+ /**
+ * Get a piece of subscription related meta data for a product in a version compatible way.
+ *
+ * @param mixed $product A WC_Product object or product ID
+ * @param string $meta_key The string key for the meta data
+ * @return float The value of the sign-up fee, or 0 if the product is not a subscription or the subscription has no sign-up fee
+ * @since 2.2.0
+ */
+ public static function get_meta_data( $product, $meta_key, $default_value ) {
+
+ $product = self::maybe_get_product_instance( $product );
+
+ $meta_value = $default_value;
+
+ if ( self::is_subscription( $product ) ) {
+
+ if ( is_callable( array( $product, 'meta_exists' ) ) ) { // WC 3.0
+
+ $prefixed_key = wcs_maybe_prefix_key( $meta_key );
+
+ // Only set the meta value when the object has a meta value to workaround ambiguous default return values
+ if ( $product->meta_exists( $prefixed_key ) ) {
+ $meta_value = $product->get_meta( $prefixed_key, true );
+ }
+ } elseif ( isset( $product->{$meta_key} ) ) { // WC < 3.0
+ $meta_value = $product->{$meta_key};
+ }
+ }
+
+ return $meta_value;
+ }
+
+ /**
+ * sync variable product min/max prices with WC 3.0
+ *
+ * @param WC_Product_Variable $product
+ * @since 2.2.0
+ */
+ public static function variable_subscription_product_sync( $product ) {
+
+ if ( self::is_subscription( $product ) ) {
+
+ $child_variation_ids = $product->get_visible_children();
+
+ if ( $child_variation_ids ) {
+
+ $min_max_data = wcs_get_min_max_variation_data( $product, $child_variation_ids );
+
+ $product->add_meta_data( '_min_price_variation_id', $min_max_data['min']['variation_id'], true );
+ $product->add_meta_data( '_max_price_variation_id', $min_max_data['max']['variation_id'], true );
+
+ $product->add_meta_data( '_min_variation_price', $min_max_data['min']['price'], true );
+ $product->add_meta_data( '_max_variation_price', $min_max_data['max']['price'], true );
+ $product->add_meta_data( '_min_variation_regular_price', $min_max_data['min']['regular_price'], true );
+ $product->add_meta_data( '_max_variation_regular_price', $min_max_data['max']['regular_price'], true );
+ $product->add_meta_data( '_min_variation_sale_price', $min_max_data['min']['sale_price'], true );
+ $product->add_meta_data( '_max_variation_sale_price', $min_max_data['max']['sale_price'], true );
+
+ $product->add_meta_data( '_min_variation_period', $min_max_data['min']['period'], true );
+ $product->add_meta_data( '_max_variation_period', $min_max_data['max']['period'], true );
+ $product->add_meta_data( '_min_variation_period_interval', $min_max_data['min']['interval'], true );
+ $product->add_meta_data( '_max_variation_period_interval', $min_max_data['max']['interval'], true );
+
+ $product->add_meta_data( '_subscription_price', $min_max_data['min']['price'], true );
+ $product->add_meta_data( '_subscription_period', $min_max_data['min']['period'], true );
+ $product->add_meta_data( '_subscription_period_interval', $min_max_data['min']['interval'], true );
+ $product->add_meta_data( '_subscription_sign_up_fee', $min_max_data['subscription']['signup-fee'], true );
+ $product->add_meta_data( '_subscription_trial_period', $min_max_data['subscription']['trial_period'], true );
+ $product->add_meta_data( '_subscription_trial_length', $min_max_data['subscription']['trial_length'], true );
+ $product->add_meta_data( '_subscription_length', $min_max_data['subscription']['length'], true );
+ }
+ }
+
+ return $product;
+ }
+
+ /************************
+ * Deprecated Functions *
+ ************************/
+
/**
* If a product is being marked as not purchasable because it is limited and the customer has a subscription,
* but the current request is to resubscribe to the subscription, then mark it as purchasable.
@@ -1045,7 +1072,7 @@ class WC_Subscriptions_Product {
if ( $item['product_id'] == $product_id || $item['variation_id'] == $product_id ) {
$subscriptions = wcs_get_subscriptions( array(
- 'order_id' => $order->id,
+ 'order_id' => wcs_get_objects_property( $order, 'id' ),
'product_id' => $product_id,
) );
@@ -1065,6 +1092,28 @@ class WC_Subscriptions_Product {
return self::$order_awaiting_payment_for_product[ $product_id ];
}
+
+ /**
+ * 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 static function get_sign_up_fee_including_tax( $product, $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( $product, array( 'qty' => $qty, 'price' => WC_Subscriptions_Product::get_sign_up_fee( $product ) ) );
+ }
+
+ /**
+ * 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 static function get_sign_up_fee_excluding_tax( $product, $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( $product, array( 'qty' => $qty, 'price' => WC_Subscriptions_Product::get_sign_up_fee( $product ) ) );
+ }
}
WC_Subscriptions_Product::init();
diff --git a/includes/class-wc-subscriptions-renewal-order.php b/includes/class-wc-subscriptions-renewal-order.php
index ff8d775..5a10720 100644
--- a/includes/class-wc-subscriptions-renewal-order.php
+++ b/includes/class-wc-subscriptions-renewal-order.php
@@ -84,14 +84,21 @@ class WC_Subscriptions_Renewal_Order {
$order_needed_payment = in_array( $orders_old_status, apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'on-hold', 'failed' ), $order ) );
if ( $order_completed && $order_needed_payment ) {
- $update_post_data = array(
- 'ID' => $order_id,
- 'post_date' => current_time( 'mysql', 0 ),
- 'post_date_gmt' => current_time( 'mysql', 1 ),
- );
- wp_update_post( $update_post_data );
- update_post_meta( $order_id, '_paid_date', current_time( 'mysql', true ) );
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ $update_post_data = array(
+ 'ID' => $order_id,
+ 'post_date' => current_time( 'mysql', 0 ),
+ 'post_date_gmt' => current_time( 'mysql', 1 ),
+ );
+
+ wp_update_post( $update_post_data );
+ update_post_meta( $order_id, '_paid_date', current_time( 'mysql', true ) );
+ } else {
+ // In WC 3.0, only the paid date prop represents the paid date, the post date isn't used anymore, also the paid date is stored and referenced as a timestamp in site timezone, not a MySQL string
+ $order->set_date_paid( current_time( 'timestamp', 0 ) );
+ $order->save();
+ }
}
foreach ( $subscriptions as $subscription ) {
@@ -138,7 +145,7 @@ class WC_Subscriptions_Renewal_Order {
$order_number = sprintf( _x( '#%s', 'hash before order number', 'woocommerce-subscriptions' ), $renewal_order->get_order_number() );
// translators: placeholder is order ID
- $subscription->add_order_note( sprintf( __( 'Order %s created to record renewal.', 'woocommerce-subscriptions' ), sprintf( '%s ', esc_url( wcs_get_edit_post_link( $renewal_order->id ) ), $order_number ) ) );
+ $subscription->add_order_note( sprintf( __( 'Order %s created to record renewal.', 'woocommerce-subscriptions' ), sprintf( '%s ', esc_url( wcs_get_edit_post_link( wcs_get_objects_property( $renewal_order, 'id' ) ) ), $order_number ) ) );
}
return $renewal_order;
@@ -184,7 +191,13 @@ class WC_Subscriptions_Renewal_Order {
);
foreach ( $order_items as $order_item_id => $item ) {
- $order_items[ $order_item_id ]['item_meta'] = array_diff_key( $item['item_meta'], $switched_order_item_keys );
+ if ( is_callable( array( $item, 'delete_meta_data' ) ) ) { // WC 3.0+
+ foreach( $switched_order_item_keys as $switch_meta_key => $value ) {
+ $item->delete_meta_data( $switch_meta_key );
+ }
+ } else { // WC 2.6
+ $order_items[ $order_item_id ]['item_meta'] = array_diff_key( $item['item_meta'], $switched_order_item_keys );
+ }
}
return $order_items;
@@ -210,7 +223,7 @@ class WC_Subscriptions_Renewal_Order {
$subscription = wcs_get_subscription_from_key( $subscription_key );
$renewal_order = wcs_create_renewal_order( $subscription );
$renewal_order->payment_complete();
- return $renewal_order->id;
+ return wcs_get_objects_property( $renewal_order, 'id' );
}
/**
@@ -228,7 +241,7 @@ class WC_Subscriptions_Renewal_Order {
_deprecated_function( __METHOD__, '2.0', 'wcs_create_renewal_order( WC_Subscription $subscription )' );
$renewal_order = wcs_create_renewal_order( wcs_get_subscription_from_key( $subscription_key ) );
$renewal_order->update_status( 'failed' );
- return $renewal_order->id;
+ return wcs_get_objects_property( $renewal_order, 'id' );
}
/**
@@ -246,7 +259,7 @@ class WC_Subscriptions_Renewal_Order {
*/
public static function maybe_generate_manual_renewal_order( $user_id, $subscription_key ) {
_deprecated_function( __METHOD__, '2.0', __CLASS__ . '::maybe_create_manual_renewal_order( WC_Subscription $subscription )' );
- self::maybe_create_manual_renewal_order( wcs_get_subscription_from_key( $subscription_key ) )->id;
+ self::maybe_create_manual_renewal_order( wcs_get_subscription_from_key( $subscription_key ) );
}
/**
@@ -264,7 +277,7 @@ class WC_Subscriptions_Renewal_Order {
$parent_order = self::get_parent_order( $renewal_order );
- return ( null === $parent_order ) ? null : $parent_order->id;
+ return ( null === $parent_order ) ? null : wcs_get_objects_property( $parent_order, 'id' );
}
/**
@@ -287,10 +300,10 @@ class WC_Subscriptions_Renewal_Order {
$subscriptions = wcs_get_subscriptions_for_renewal_order( $renewal_order );
$subscription = array_pop( $subscriptions );
- if ( false === $subscription->order ) { // There is no original order
+ if ( false == $subscription->get_parent_id() ) { // There is no original order
$parent_order = null;
} else {
- $parent_order = $subscription->order;
+ $parent_order = $subscription->get_parent();
}
return apply_filters( 'woocommerce_subscriptions_parent_order', $parent_order, $renewal_order );
@@ -316,7 +329,7 @@ class WC_Subscriptions_Renewal_Order {
$renewal_order_count = count( $all_orders );
// Don't include the initial order (if any)
- if ( false !== $subscription->order ) {
+ if ( $subscription->get_parent_id() ) {
$renewal_order_count -= 1;
}
} else {
@@ -426,7 +439,7 @@ class WC_Subscriptions_Renewal_Order {
$new_order = wcs_create_renewal_order( $subscription );
}
- return $new_order->id;
+ return wcs_get_objects_property( $new_order, 'id' );
}
/**
diff --git a/includes/class-wc-subscriptions-switcher.php b/includes/class-wc-subscriptions-switcher.php
index 12214c5..ef62804 100644
--- a/includes/class-wc-subscriptions-switcher.php
+++ b/includes/class-wc-subscriptions-switcher.php
@@ -17,6 +17,9 @@ class WC_Subscriptions_Switcher {
*/
public static function init() {
+ // Attach hooks which depend on WooCommerce constants
+ add_action( 'woocommerce_loaded', __CLASS__ . '::attach_dependant_hooks' );
+
// Check if the current request is for switching a subscription and if so, start he switching process
add_filter( 'template_redirect', __CLASS__ . '::subscription_switch_handler', 100 );
@@ -36,12 +39,6 @@ class WC_Subscriptions_Switcher {
// When creating an order, add meta if it's for switching a subscription
add_action( 'woocommerce_checkout_update_order_meta', __CLASS__ . '::add_order_meta', 10, 2 );
- // For order items created as part of a switch, keep a record of the prorated amounts
- add_action( 'woocommerce_add_order_item_meta', __CLASS__ . '::add_order_item_meta', 10, 3 );
-
- // For subscription items created as part of a switch, keep a record of the relationship between the items
- add_action( 'woocommerce_add_subscription_item_meta', __CLASS__ . '::set_subscription_item_meta', 50, 3 );
-
// Add a renewal orders section to the Related Orders meta box
add_action( 'woocommerce_subscriptions_related_orders_meta_box_rows', __CLASS__ . '::switch_order_meta_box_rows', 10 );
@@ -125,6 +122,28 @@ class WC_Subscriptions_Switcher {
add_action( 'woocommerce_review_order_after_shipping', __CLASS__ . '::maybe_unset_free_trial' );
}
+ /**
+ * Attach WooCommerce version dependent hooks
+ *
+ * @since 2.2.0
+ */
+ public static function attach_dependant_hooks() {
+
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+
+ // For order items created as part of a switch, keep a record of the prorated amounts
+ add_action( 'woocommerce_add_order_item_meta', __CLASS__ . '::add_order_item_meta', 10, 3 );
+
+ // For subscription items created as part of a switch, keep a record of the relationship between the items
+ add_action( 'woocommerce_add_subscription_item_meta', __CLASS__ . '::set_subscription_item_meta', 50, 3 );
+
+ } else {
+
+ // For order items created as part of a switch, keep a record of the prorated amounts
+ add_action( 'woocommerce_checkout_create_order_line_item', __CLASS__ . '::add_line_item_meta', 10, 4 );
+ }
+ }
+
/**
* Handles the subscription upgrade/downgrade process.
*
@@ -206,7 +225,7 @@ class WC_Subscriptions_Switcher {
foreach ( $subscriptions as $subscription ) {
foreach ( $limited_switchable_products as $product ) {
- if ( ! $subscription->has_product( $product->id ) ) {
+ if ( ! $subscription->has_product( $product->get_id() ) ) {
continue;
}
@@ -233,7 +252,7 @@ class WC_Subscriptions_Switcher {
// Get the matching item
foreach ( $subscription->get_items() as $line_item_id => $line_item ) {
- if ( $line_item['product_id'] == $product->id || $line_item['variation_id'] == $product->id ) {
+ if ( $line_item['product_id'] == $product->get_id() || $line_item['variation_id'] == $product->get_id() ) {
$item_id = $line_item_id;
$item = $line_item;
break;
@@ -403,7 +422,7 @@ class WC_Subscriptions_Switcher {
*/
public static function print_switch_link( $item_id, $item, $subscription ) {
- if ( 'shop_subscription' !== $subscription->order_type || ! self::can_item_be_switched_by_user( $item, $subscription ) ) {
+ if ( wcs_is_order( $subscription ) || 'shop_subscription' !== $subscription->get_type() || ! self::can_item_be_switched_by_user( $item, $subscription ) ) {
return;
}
@@ -431,10 +450,10 @@ class WC_Subscriptions_Switcher {
$additional_query_args = array();
// Grouped product
- if ( 0 !== $product->post->post_parent ) {
- $switch_url = get_permalink( $product->post->post_parent );
+ if ( wcs_get_objects_property( $product, 'parent_id' ) ) {
+ $switch_url = get_permalink( wcs_get_objects_property( $product, 'parent_id' ) );
} else {
- $switch_url = get_permalink( $product->id );
+ $switch_url = get_permalink( $product->get_id() );
if ( ! empty( $_GET ) && is_product() ) {
$product_variations = $product->get_variation_attributes();
@@ -442,7 +461,7 @@ class WC_Subscriptions_Switcher {
}
}
- $switch_url = self::add_switch_query_args( $subscription->id, $item_id, $switch_url, $additional_query_args );
+ $switch_url = self::add_switch_query_args( $subscription->get_id(), $item_id, $switch_url, $additional_query_args );
return apply_filters( 'woocommerce_subscriptions_switch_url', $switch_url, $item_id, $item, $subscription );
}
@@ -487,7 +506,7 @@ class WC_Subscriptions_Switcher {
$is_product_switchable = false;
}
- if ( $subscription->has_status( 'active' ) && 0 !== $subscription->get_date( 'last_payment' ) ) {
+ if ( $subscription->has_status( 'active' ) && 0 !== $subscription->get_date( 'last_order_date_created' ) ) {
$is_subscription_switchable = true;
} else {
$is_subscription_switchable = false;
@@ -524,7 +543,7 @@ class WC_Subscriptions_Switcher {
$item_can_be_switched = false;
- if ( user_can( $user_id, 'switch_shop_subscription', $subscription->id ) && self::can_item_be_switched( $item, $subscription ) ) {
+ if ( user_can( $user_id, 'switch_shop_subscription', $subscription->get_id() ) && self::can_item_be_switched( $item, $subscription ) ) {
$item_can_be_switched = true;
}
@@ -541,14 +560,17 @@ class WC_Subscriptions_Switcher {
*/
public static function add_order_meta( $order_id, $posted ) {
+ $order = wc_get_order( $order_id );
+
// delete all the existing subscription switch links before adding new ones
- delete_post_meta( $order_id, '_subscription_switch' );
+ wcs_delete_objects_property( $order, 'subscription_switch' );
$switches = self::cart_contains_switches();
if ( false !== $switches ) {
+
foreach ( $switches as $switch_details ) {
- add_post_meta( $order_id, '_subscription_switch', $switch_details['subscription_id'] );
+ wcs_set_objects_property( $order, 'subscription_switch', $switch_details['subscription_id'] );
}
}
}
@@ -557,16 +579,23 @@ class WC_Subscriptions_Switcher {
* To prorate sign-up fee and recurring amounts correctly when the customer switches a subscription multiple times, keep a record of the
* amount for each on the order item.
*
+ * @param int $order_item_id The ID of a WC_Order_Item object.
+ * @param array $cart_item The cart item's data.
+ * @param string $cart_item_key The hash used to identify the item in the cart
* @since 2.0
*/
public static function add_order_item_meta( $order_item_id, $cart_item, $cart_item_key ) {
+ if ( false === WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ _deprecated_function( __METHOD__, '2.2.0 and WooCommerce 3.0.0', __CLASS__ . '::add_order_line_item_meta( $order_item, $cart_item_key, $cart_item )' );
+ }
+
if ( isset( $cart_item['subscription_switch'] ) ) {
if ( $switches = self::cart_contains_switches() ) {
foreach ( $switches as $switch_item_key => $switch_details ) {
if ( $cart_item_key == $switch_item_key ) {
- wc_add_order_item_meta( $order_item_id, '_switched_subscription_sign_up_fee_prorated', ( isset( WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_sign_up_fee_prorated ) ? WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_sign_up_fee_prorated : 0 ), true );
- wc_add_order_item_meta( $order_item_id, '_switched_subscription_price_prorated', ( isset( WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_price_prorated ) ? WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_price_prorated : 0 ), true );
+ wc_add_order_item_meta( $order_item_id, '_switched_subscription_sign_up_fee_prorated', wcs_get_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_sign_up_fee_prorated', 'single', 0 ), true );
+ wc_add_order_item_meta( $order_item_id, '_switched_subscription_price_prorated', wcs_get_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_price_prorated', 'single', 0 ), true );
}
}
}
@@ -582,14 +611,59 @@ class WC_Subscriptions_Switcher {
}
}
+ /**
+ * Store switch related data on the line item on the subscription and switch order.
+ *
+ * For subscriptions: items on a new billing schedule are left to be added as new subscriptions, but we also want
+ * to keep a record of them being a switch, so we do that here.
+ *
+ * For orders: to prorate sign-up fee and recurring amounts correctly when the customer switches a subscription
+ * multiple times, keep a record of the amount for each on the order item.
+ *
+ * Attached to WC 3.0+ hooks and uses WC 3.0 methods.
+ *
+ * @param WC_Order_Item_Product $order_item
+ * @param string $cart_item_key The hash used to identify the item in the cart
+ * @param array $cart_item The cart item's data.
+ * @param WC_Order $order The order or subscription object to which the line item relates
+ * @since 2.2.0
+ */
+ public static function add_line_item_meta( $order_item, $cart_item_key, $cart_item, $order ) {
+ if ( isset( $cart_item['subscription_switch'] ) ) {
+ if ( $switches = self::cart_contains_switches() ) {
+ foreach ( $switches as $switch_item_key => $switch_details ) {
+ if ( $cart_item_key == $switch_item_key ) {
+
+ if ( wcs_is_subscription( $order ) ) {
+ $order_item->add_meta_data( '_switched_subscription_item_id', $switch_details['item_id'] );
+ } else {
+ $sign_up_fee_prorated = WC()->cart->cart_contents[ $cart_item_key ]['data']->get_meta( 'subscription_sign_up_fee_prorated', true );
+ $price_prorated = WC()->cart->cart_contents[ $cart_item_key ]['data']->get_meta( 'subscription_price_prorated', true );
+
+ $order_item->add_meta_data( '_switched_subscription_sign_up_fee_prorated', empty( $sign_up_fee_prorated ) ? 0 : $sign_up_fee_prorated );
+ $order_item->add_meta_data( '_switched_subscription_price_prorated', empty( $price_prorated ) ? 0 : $price_prorated );
+ }
+ }
+ }
+ }
+ }
+ }
+
/**
* Subscription items on a new billing schedule are left to be added as new subscriptions, but we also
* want to keep a record of them being a switch, so we do that here.
*
+ * @param int $order_item_id The ID of a WC_Order_Item object.
+ * @param array $cart_item The cart item's data.
+ * @param string $cart_item_key The hash used to identify the item in the cart
* @since 2.0
*/
public static function set_subscription_item_meta( $item_id, $cart_item, $cart_item_key ) {
+ if ( ! WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ _deprecated_function( __METHOD__, '2.2.0', __CLASS__ . '::add_subscription_line_item_meta( $order_item, $cart_item_key, $cart_item )' );
+ }
+
if ( isset( $cart_item['subscription_switch'] ) ) {
if ( $switches = self::cart_contains_switches() ) {
foreach ( $switches as $switch_item_key => $switch_details ) {
@@ -643,7 +717,7 @@ class WC_Subscriptions_Switcher {
$next_payment_timestamp = $subscription->get_time( 'end' );
}
- if ( $cart_item['data']->subscription_period != $subscription->billing_period || $cart_item['data']->subscription_period_interval != $subscription->billing_interval ) {
+ if ( WC_Subscriptions_Product::get_period( $cart_item['data'] ) != $subscription->get_billing_period() || WC_Subscriptions_Product::get_interval( $cart_item['data'] ) != $subscription->get_billing_interval() ) {
$is_different_billing_schedule = true;
} else {
$is_different_billing_schedule = false;
@@ -651,7 +725,7 @@ class WC_Subscriptions_Switcher {
// If we haven't calculated a first payment date, fall back to the recurring cart's next payment date
if ( 0 == $cart_item['subscription_switch']['first_payment_timestamp'] ) {
- $cart_item['subscription_switch']['first_payment_timestamp'] = strtotime( $recurring_cart->next_payment_date );
+ $cart_item['subscription_switch']['first_payment_timestamp'] = wcs_date_to_time( $recurring_cart->next_payment_date );
}
if ( 0 !== $cart_item['subscription_switch']['first_payment_timestamp'] && $next_payment_timestamp !== $cart_item['subscription_switch']['first_payment_timestamp'] ) {
@@ -681,8 +755,45 @@ class WC_Subscriptions_Switcher {
if ( $is_single_item_subscription || ( false === $is_different_billing_schedule && false === $is_different_payment_date && false === $is_different_length ) ) {
// Add the new item
- $item_id = WC_Subscriptions_Checkout::add_cart_item( $subscription, $cart_item, $cart_item_key );
- wc_update_order_item( $item_id, array( 'order_item_type' => 'line_item_pending_switch' ) );
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ $item_id = WC_Subscriptions_Checkout::add_cart_item( $subscription, $cart_item, $cart_item_key );
+ wc_update_order_item( $item_id, array( 'order_item_type' => 'line_item_pending_switch' ) );
+ } else {
+ $item = new WC_Order_Item_Pending_Switch;
+ $item->legacy_values = $cart_item['data']; // @deprecated For legacy actions.
+ $item->legacy_cart_item_key = $cart_item_key; // @deprecated For legacy actions.
+ $item->set_props( array(
+ 'quantity' => $cart_item['quantity'],
+ 'variation' => $cart_item['variation'],
+ 'subtotal' => $cart_item['line_subtotal'],
+ 'total' => $cart_item['line_total'],
+ 'subtotal_tax' => $cart_item['line_subtotal_tax'],
+ 'total_tax' => $cart_item['line_tax'],
+ 'taxes' => $cart_item['line_tax_data'],
+ ) );
+
+ if ( ! empty( $cart_item['data'] ) ) {
+ $product = $cart_item['data'];
+ $item->set_props( array(
+ 'name' => $product->get_name(),
+ 'tax_class' => $product->get_tax_class(),
+ 'product_id' => $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id(),
+ 'variation_id' => $product->is_type( 'variation' ) ? $product->get_id() : 0,
+ ) );
+ }
+
+ if ( WC_Subscriptions_Product::get_trial_length( wcs_get_canonical_product_id( $cart_item ) ) > 0 ) {
+ $item->add_meta_data( '_has_trial', 'true' );
+ }
+
+ do_action( 'woocommerce_checkout_create_order_line_item', $item, $cart_item_key, $cart_item, $subscription );
+
+ $subscription->add_item( $item );
+
+ // The subscription is not saved automatically, we need to call 'save' becaused we added an item
+ $subscription->save();
+ $item_id = $item->get_id();
+ }
$switched_item_data['add_line_item'] = $item_id;
@@ -695,19 +806,19 @@ class WC_Subscriptions_Switcher {
}
}
- $switch_order_data[ $subscription->id ]['switches'][ $cart_item['subscription_switch']['order_line_item_id'] ] = $switched_item_data;
+ $switch_order_data[ $subscription->get_id() ]['switches'][ $cart_item['subscription_switch']['order_line_item_id'] ] = $switched_item_data;
// If the old subscription has just one item, we can safely update its billing schedule
if ( $is_single_item_subscription ) {
if ( $is_different_billing_schedule ) {
- $switch_order_data[ $subscription->id ]['billing_schedule']['_billing_period'] = $cart_item['data']->subscription_period;
- $switch_order_data[ $subscription->id ]['billing_schedule']['_billing_interval'] = absint( $cart_item['data']->subscription_period_interval );
+ $switch_order_data[ $subscription->get_id() ]['billing_schedule']['_billing_period'] = WC_Subscriptions_Product::get_period( $cart_item['data'] );
+ $switch_order_data[ $subscription->get_id() ]['billing_schedule']['_billing_interval'] = absint( WC_Subscriptions_Product::get_interval( $cart_item['data'] ) );
}
$updated_dates = array();
- if ( '1' == $cart_item['data']->subscription_length || ( 0 != $recurring_cart->end_date && gmdate( 'Y-m-d H:i:s', $cart_item['subscription_switch']['first_payment_timestamp'] ) >= $recurring_cart->end_date ) ) {
+ if ( '1' == WC_Subscriptions_Product::get_length( $cart_item['data'] ) || ( 0 != $recurring_cart->end_date && gmdate( 'Y-m-d H:i:s', $cart_item['subscription_switch']['first_payment_timestamp'] ) >= $recurring_cart->end_date ) ) {
// Delete the next payment date.
$updated_dates['next_payment'] = 0;
} else if ( $is_different_payment_date ) {
@@ -720,7 +831,7 @@ class WC_Subscriptions_Switcher {
if ( ! empty( $updated_dates ) ) {
$subscription->validate_date_updates( $updated_dates );
- $switch_order_data[ $subscription->id ]['dates']['update'] = $updated_dates;
+ $switch_order_data[ $subscription->get_id() ]['dates']['update'] = $updated_dates;
}
}
@@ -730,10 +841,16 @@ class WC_Subscriptions_Switcher {
$new_shipping_line_items = array();
// Keep a record of the subscription shipping total. Adding shipping methods will cause a new shipping total to be set, we'll need to set it back after.
- $subscription_shipping_total = $subscription->order_shipping;
+ $subscription_shipping_total = $subscription->get_total_shipping();
WC_Subscriptions_Checkout::add_shipping( $subscription, $recurring_cart );
+ if ( ! WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ // We must save the subscription, we need the Shipping method saved
+ // otherwise the ID is bogus (new:1) and we need it.
+ $subscription->save();
+ }
+
// Set all new shipping methods to shipping_pending_switch line items
foreach ( $subscription->get_shipping_methods() as $shipping_line_item_id => $shipping_meta ) {
@@ -743,9 +860,13 @@ class WC_Subscriptions_Switcher {
}
}
- $subscription->set_total( $subscription_shipping_total, 'shipping' );
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ $subscription->set_total( $subscription_shipping_total, 'shipping' );
+ } else {
+ $subscription->set_shipping_total( $subscription_shipping_total );
+ }
- $switch_order_data[ $subscription->id ]['shipping_line_items'] = $new_shipping_line_items;
+ $switch_order_data[ $subscription->get_id() ]['shipping_line_items'] = $new_shipping_line_items;
}
}
@@ -755,13 +876,13 @@ class WC_Subscriptions_Switcher {
$switch_orders = wcs_get_switch_orders_for_subscription( $subscription_id );
foreach ( $switch_orders as $switch_order_id => $switch_order ) {
- if ( $order->id !== $switch_order_id && in_array( $switch_order->get_status(), apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed', 'on-hold' ), $switch_order ) ) ) {
+ if ( wcs_get_objects_property( $order, 'id' ) !== $switch_order_id && in_array( $switch_order->get_status(), apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed', 'on-hold' ), $switch_order ) ) ) {
$switch_order->update_status( 'cancelled', sprintf( __( 'Switch order cancelled due to a new switch order being created #%s.', 'woocommerce-subscriptions' ), $order->get_order_number() ) );
}
}
}
- update_post_meta( $order_id, '_subscription_switch_data', $switch_order_data );
+ wcs_set_objects_property( $order, 'subscription_switch_data', $switch_order_data );
} catch ( Exception $e ) {
// There was an error updating the subscription, roll back and delete pending order for switch
@@ -786,12 +907,12 @@ class WC_Subscriptions_Switcher {
}
// Then zero the order_shipping total so we have a clean slate to add to
- $subscription->order_shipping = 0;
+ $subscription->set_total_shipping( 0 );
WC_Subscriptions_Checkout::add_shipping( $subscription, $recurring_cart );
// Now update subscription object order_shipping to reflect updated values so it doesn't stay 0
- $subscription->order_shipping = get_post_meta( $subscription->id, '_order_shipping', true );
+ $subscription->order_shipping = get_post_meta( $subscription->get_id(), '_order_shipping', true );
}
/**
@@ -842,24 +963,26 @@ class WC_Subscriptions_Switcher {
// Select the orders which switched item/s from this subscription
$orders = wcs_get_switch_orders_for_subscription( $post->ID );
- foreach ( $orders as $order ) {
- $orders[ $order->id ]->relationship = __( 'Switch Order', 'woocommerce-subscriptions' );
+ foreach ( $orders as $order_id => $order ) {
+ wcs_set_objects_property( $order, 'relationship', __( 'Switch Order', 'woocommerce-subscriptions' ), 'set_prop_only' );
}
// Select the subscriptions which had item/s switched to this subscription by its parent order
if ( ! empty( $post->post_parent ) ) {
- $switched_ids = get_post_meta( $post->post_parent, '_subscription_switch' );
+ $switched_ids = wcs_get_objects_property( wc_get_order( $post->post_parent ), 'subscription_switch', 'multiple' );
}
// On the Edit Order screen, show any subscriptions with items switched by this order
} else {
- $switched_ids = get_post_meta( $post->ID, '_subscription_switch', false );
+ $switched_ids = wcs_get_objects_property( wc_get_order( $post->ID ), 'subscription_switch', 'multiple' );
}
- foreach ( $switched_ids as $subscription_id ) {
- $subscription = wcs_get_subscription( $subscription_id );
- $subscription->relationship = __( 'Switched Subscription', 'woocommerce-subscriptions' );
- $orders[ $subscription_id ] = $subscription;
+ if ( is_array( $switched_ids ) ) {
+ foreach ( $switched_ids as $subscription_id ) {
+ $subscription = wcs_get_subscription( $subscription_id );
+ wcs_set_objects_property( $subscription, 'relationship', __( 'Switched Subscription', 'woocommerce-subscriptions' ), 'set_prop_only' );
+ $orders[ $subscription_id ] = $subscription;
+ }
}
foreach ( $orders as $order ) {
@@ -908,7 +1031,7 @@ class WC_Subscriptions_Switcher {
*/
public static function cart_contains_switch_for_product( $product ) {
- $product_id = ( is_object( $product ) ) ? $product->id : $product;
+ $product_id = ( is_object( $product ) ) ? $product->get_id() : $product;
$switch_items = self::cart_contains_switches();
$switch_product_ids = array();
@@ -920,10 +1043,12 @@ class WC_Subscriptions_Switcher {
$switch_product = wc_get_product( wcs_get_order_items_product_id( $switch_item_details['item_id'] ) );
// If the switch is for a grouped product, we need to check the other products grouped with this one
- if ( 0 !== $product->post->post_parent ) {
- $switch_product_ids = array_unique( array_merge( $switch_product_ids, wc_get_product( $product->post->post_parent )->get_children() ) );
+ if ( wcs_get_objects_property( $product, 'parent_id' ) ) {
+ $switch_product_ids = array_unique( array_merge( $switch_product_ids, wc_get_product( wcs_get_objects_property( $product, 'parent_id' ) )->get_children() ) );
+ } elseif ( $switch_product->is_type( 'subscription_variation' ) ) {
+ $switch_product_ids[] = $switch_product->get_parent_id();
} else {
- $switch_product_ids[] = $switch_product->id;
+ $switch_product_ids[] = $switch_product->get_id();
}
}
}
@@ -1031,7 +1156,7 @@ class WC_Subscriptions_Switcher {
$subscription = wcs_get_subscription( $_GET['switch-subscription'] );
// Requesting a switch for someone elses subscription
- if ( ! current_user_can( 'switch_shop_subscription', $subscription->id ) ) {
+ if ( ! current_user_can( 'switch_shop_subscription', $subscription->get_id() ) ) {
WC_Subscriptions::add_notice( __( 'You can not switch this subscription. It appears you do not own the subscription.', 'woocommerce-subscriptions' ), 'error' );
WC()->cart->empty_cart( true );
wp_redirect( get_permalink( $subscription['product_id'] ) );
@@ -1043,7 +1168,7 @@ class WC_Subscriptions_Switcher {
// Else it's a valid switch
$product = wc_get_product( $item['product_id'] );
- $child_products = ( 0 !== $product->post->post_parent ) ? wc_get_product( $product->post->post_parent )->get_children() : array();
+ $child_products = ( wcs_get_objects_property( $product, 'parent_id' ) ) ? wc_get_product( wcs_get_objects_property( $product, 'parent_id' ) )->get_children() : array();
if ( $product_id != $item['product_id'] && ! in_array( $item['product_id'], $child_products ) ) {
return $cart_item_data;
@@ -1057,7 +1182,7 @@ class WC_Subscriptions_Switcher {
}
$cart_item_data['subscription_switch'] = array(
- 'subscription_id' => $subscription->id,
+ 'subscription_id' => $subscription->get_id(),
'item_id' => absint( $_GET['item'] ),
'next_payment_timestamp' => $next_payment_timestamp,
'upgraded_or_downgraded' => '',
@@ -1107,7 +1232,7 @@ class WC_Subscriptions_Switcher {
// Default tax inclusive or exclusive to the value set on the subscription. This is for backwards compatibility
if ( empty( $tax_inclusive_or_exclusive ) ) {
- $tax_inclusive_or_exclusive = ( 'yes' == $subscription->prices_include_tax ) ? 'inclusive_of_tax' : 'exclusive_of_tax';
+ $tax_inclusive_or_exclusive = ( $subscription->get_prices_include_tax() ) ? 'inclusive_of_tax' : 'exclusive_of_tax';
}
foreach ( $switched_line_items as $switched_line_item_id => $switched_line_item ) {
@@ -1118,7 +1243,7 @@ class WC_Subscriptions_Switcher {
}
// Now add any sign-up fees paid in switch orders
- foreach ( wcs_get_switch_orders_for_subscription( $subscription->id ) as $order ) {
+ foreach ( wcs_get_switch_orders_for_subscription( $subscription->get_id() ) as $order ) {
foreach ( $order->get_items() as $order_item_id => $order_item ) {
if ( wcs_get_canonical_product_id( $line_item ) == wcs_get_canonical_product_id( $order_item ) ) {
@@ -1135,7 +1260,7 @@ class WC_Subscriptions_Switcher {
$order_total = $order_item['line_total'];
- if ( 'inclusive_of_tax' == $tax_inclusive_or_exclusive && 'yes' == $order->prices_include_tax ) {
+ if ( 'inclusive_of_tax' == $tax_inclusive_or_exclusive && wcs_get_objects_property( $order, 'prices_include_tax' ) ) {
$order_total += $order_item['line_tax'];
}
@@ -1184,13 +1309,18 @@ class WC_Subscriptions_Switcher {
// Set when the first payment and end date for the new subscription should occur
WC()->cart->cart_contents[ $cart_item_key ]['subscription_switch']['first_payment_timestamp'] = $cart_item['subscription_switch']['next_payment_timestamp'];
- WC()->cart->cart_contents[ $cart_item_key ]['subscription_switch']['end_timestamp'] = $end_timestamp = wcs_date_to_time( WC_Subscriptions_Product::get_expiration_date( $product_id, $subscription->get_date( 'last_payment' ) ) );
+ WC()->cart->cart_contents[ $cart_item_key ]['subscription_switch']['end_timestamp'] = $end_timestamp = wcs_date_to_time( WC_Subscriptions_Product::get_expiration_date( $product_id, $subscription->get_date( 'last_order_date_created' ) ) );
// Add any extra sign up fees required to switch to the new subscription
if ( 'yes' == $apportion_sign_up_fee ) {
+ // With WC 3.0, make sure we get a fresh copy of the product's meta to avoid prorating an already prorated sign-up fee
+ if ( is_callable( array( $product, 'read_meta_data' ) ) ) {
+ $product->read_meta_data( true );
+ }
+
// Because product add-ons etc. don't apply to sign-up fees, it's safe to use the product's sign-up fee value rather than the cart item's
- $sign_up_fee_due = $product->subscription_sign_up_fee;
+ $sign_up_fee_due = WC_Subscriptions_Product::get_sign_up_fee( $product );
$sign_up_fee_paid = $subscription->get_items_sign_up_fee( $existing_item, 'inclusive_of_tax' );
// Make sure total prorated sign-up fee is prorated across total amount of sign-up fee so that customer doesn't get extra discounts
@@ -1198,26 +1328,26 @@ class WC_Subscriptions_Switcher {
$sign_up_fee_paid = ( $sign_up_fee_paid * $existing_item['qty'] ) / $cart_item['quantity'];
}
- WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_sign_up_fee = max( $sign_up_fee_due - $sign_up_fee_paid, 0 );
- WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_sign_up_fee_prorated = WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_sign_up_fee;
+ wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_sign_up_fee', max( $sign_up_fee_due - $sign_up_fee_paid, 0 ), 'set_prop_only' );
+ wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_sign_up_fee_prorated', WC_Subscriptions_Product::get_sign_up_fee( WC()->cart->cart_contents[ $cart_item_key ]['data'] ), 'set_prop_only' );
} elseif ( 'no' == $apportion_sign_up_fee ) { // $0 the initial sign-up fee
- WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_sign_up_fee = 0;
+ wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_sign_up_fee', 0, 'set_prop_only' );
}
// Get the current subscription's last payment date
- $last_payment_timestamp = $subscription->get_time( 'last_payment' );
- $days_since_last_payment = floor( ( gmdate( 'U' ) - $last_payment_timestamp ) / ( 60 * 60 * 24 ) );
+ $last_order_time_created = $subscription->get_time( 'last_order_date_created' );
+ $days_since_last_payment = floor( ( gmdate( 'U' ) - $last_order_time_created ) / ( 60 * 60 * 24 ) );
// Get the current subscription's next payment date
$next_payment_timestamp = $cart_item['subscription_switch']['next_payment_timestamp'];
$days_until_next_payment = ceil( ( $next_payment_timestamp - gmdate( 'U' ) ) / ( 60 * 60 * 24 ) );
// If the subscription contains a synced product and the next payment is actually the first payment, determine the days in the "old" cycle from the subscription object
- if ( WC_Subscriptions_Synchroniser::subscription_contains_synced_product( $subscription->id ) && WC_Subscriptions_Synchroniser::calculate_first_payment_date( $product, 'timestamp', $subscription->get_date( 'start' ) ) == $next_payment_timestamp ) {
- $days_in_old_cycle = wcs_get_days_in_cycle( $subscription->billing_period, $subscription->billing_interval );
+ if ( WC_Subscriptions_Synchroniser::subscription_contains_synced_product( $subscription->get_id() ) && WC_Subscriptions_Synchroniser::calculate_first_payment_date( $product, 'timestamp', $subscription->get_date( 'date_created' ) ) == $next_payment_timestamp ) {
+ $days_in_old_cycle = wcs_get_days_in_cycle( $subscription->get_billing_period(), $subscription->get_billing_interval() );
} else {
// Find the number of days between the two
$days_in_old_cycle = $days_until_next_payment + $days_since_last_payment;
@@ -1226,7 +1356,7 @@ class WC_Subscriptions_Switcher {
// Find the actual recurring amount charged for the old subscription (we need to use the '_recurring_line_total' meta here rather than '_subscription_recurring_amount' because we want the recurring amount to include extra from extensions, like Product Add-ons etc.)
$old_recurring_total = $existing_item['line_total'];
- if ( 'yes' == $subscription->prices_include_tax || true === $subscription->prices_include_tax ) { // WC_Abstract_Order::$prices_include_tax can be set to true in __construct() or to 'yes' in populate()
+ if ( $subscription->get_prices_include_tax() ) {
$old_recurring_total += $existing_item['line_tax'];
}
@@ -1235,18 +1365,18 @@ class WC_Subscriptions_Switcher {
// Find the price per day for the new subscription's recurring total
// If the subscription uses the same billing interval & cycle as the old subscription,
- if ( $item_data->subscription_period == $subscription->billing_period && $item_data->subscription_period_interval == $subscription->billing_interval ) {
+ if ( WC_Subscriptions_Product::get_period( $item_data ) == $subscription->get_billing_period() && WC_Subscriptions_Product::get_interval( $item_data ) == $subscription->get_billing_interval() ) {
$days_in_new_cycle = $days_in_old_cycle; // Use $days_in_old_cycle to make sure they're consistent
} else {
// We need to figure out the price per day for the new subscription based on its billing schedule
- $days_in_new_cycle = wcs_get_days_in_cycle( $item_data->subscription_period, $item_data->subscription_period_interval );
+ $days_in_new_cycle = wcs_get_days_in_cycle( WC_Subscriptions_Product::get_period( $item_data ), WC_Subscriptions_Product::get_interval( $item_data ) );
}
// We need to use the cart items price to ensure we include extras added by extensions like Product Add-ons
- $new_price_per_day = ( $item_data->price * $cart_item['quantity'] ) / $days_in_new_cycle;
+ $new_price_per_day = ( WC_Subscriptions_Product::get_price( $item_data ) * $cart_item['quantity'] ) / $days_in_new_cycle;
if ( $old_price_per_day < $new_price_per_day ) {
@@ -1279,7 +1409,7 @@ class WC_Subscriptions_Switcher {
// If the total amount the customer has paid entitles her to more days at the new price than she has received, there is no gap payment, just shorten the pre-paid term the appropriate number of days
if ( $days_since_last_payment < $pre_paid_days ) {
- WC()->cart->cart_contents[ $cart_item_key ]['subscription_switch']['first_payment_timestamp'] = $last_payment_timestamp + ( $pre_paid_days * 60 * 60 * 24 );
+ WC()->cart->cart_contents[ $cart_item_key ]['subscription_switch']['first_payment_timestamp'] = $last_order_time_created + ( $pre_paid_days * 60 * 60 * 24 );
// If the total amount the customer has paid entitles her to the same or less days at the new price then start the new subscription from today
} else {
@@ -1292,7 +1422,7 @@ class WC_Subscriptions_Switcher {
$extra_to_pay = $days_until_next_payment * ( $new_price_per_day - $old_price_per_day );
// when calculating a subscription with one length (no more next payment date and the end date may have been pushed back) we need to pay for those extra days at the new price per day between the old next payment date and new end date
- if ( 1 == $item_data->subscription_length ) {
+ if ( 1 == WC_Subscriptions_Product::get_length( $item_data ) ) {
$days_to_new_end = floor( ( $end_timestamp - $next_payment_timestamp ) / ( 60 * 60 * 24 ) );
if ( $days_to_new_end > 0 ) {
@@ -1304,10 +1434,10 @@ class WC_Subscriptions_Switcher {
$extra_to_pay = $extra_to_pay / $cart_item['quantity'];
// Keep a record of the two separate amounts so we store these and calculate future switch amounts correctly
- WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_sign_up_fee_prorated = WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_sign_up_fee;
- WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_price_prorated = round( $extra_to_pay, wc_get_price_decimals() );
- WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_sign_up_fee += round( $extra_to_pay, wc_get_price_decimals() );
-
+ $existing_sign_up_fee = WC_Subscriptions_Product::get_sign_up_fee( WC()->cart->cart_contents[ $cart_item_key ]['data'] );
+ wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_sign_up_fee_prorated', $existing_sign_up_fee, 'set_prop_only' );
+ wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_price_prorated', round( $extra_to_pay, wc_get_price_decimals() ), 'set_prop_only' );
+ wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_sign_up_fee', round( $existing_sign_up_fee + $extra_to_pay, wc_get_price_decimals() ), 'set_prop_only' );
}
// If the customer is downgrading, set the next payment date and maybe extend it if downgrades are prorated
@@ -1349,7 +1479,7 @@ class WC_Subscriptions_Switcher {
$length_remaining = $base_length;
}
- WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_length = $length_remaining;
+ wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_length', $length_remaining, 'set_prop_only' );
}
}
}
@@ -1364,7 +1494,7 @@ class WC_Subscriptions_Switcher {
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
if ( isset( $cart_item['subscription_switch']['first_payment_timestamp'] ) && 0 != $cart_item['subscription_switch']['first_payment_timestamp'] ) {
- $first_renewal_date = ( '1' != $cart_item['data']->subscription_length ) ? gmdate( 'Y-m-d H:i:s', $cart_item['subscription_switch']['first_payment_timestamp'] ) : 0;
+ $first_renewal_date = ( '1' != WC_Subscriptions_Product::get_length( $cart_item['data'] ) ) ? gmdate( 'Y-m-d H:i:s', $cart_item['subscription_switch']['first_payment_timestamp'] ) : 0;
}
}
@@ -1386,19 +1516,19 @@ class WC_Subscriptions_Switcher {
$end_timestamp = WC()->cart->cart_contents[ $cart_item_key ]['subscription_switch']['end_timestamp'];
// if the subscription is length 1 and prorated, we want to use the prorated the next payment date as the end date
- if ( 1 == $cart_item['data']->subscription_length && 0 !== $next_payment_time && isset( $cart_item['subscription_switch']['recurring_payment_prorated'] ) ) {
+ if ( 1 == WC_Subscriptions_Product::get_length( $cart_item['data'] ) && 0 !== $next_payment_time && isset( $cart_item['subscription_switch']['recurring_payment_prorated'] ) ) {
$end_date = gmdate( 'Y-m-d H:i:s', $next_payment_time );
// if the subscription is more than 1 (and not 0) and we have a next payment date (prorated or not) we want to calculate the new end date from that
- } elseif ( 0 !== $next_payment_time && $cart_item['data']->subscription_length > 1 ) {
+ } elseif ( 0 !== $next_payment_time && WC_Subscriptions_Product::get_length( $cart_item['data'] ) > 1 ) {
// remove trial period on the switched subscription when calculating the new end date
- $trial_length = $cart_item['data']->subscription_trial_length;
- $cart_item['data']->subscription_trial_length = 0;
+ $trial_length = wcs_get_objects_property( $cart_item['data'], 'subscription_trial_length' );
+ wcs_set_objects_property( $cart_item['data'], 'subscription_trial_length', 0, 'set_prop_only' );
$end_date = WC_Subscriptions_Product::get_expiration_date( $cart_item['data'], gmdate( 'Y-m-d H:i:s', $next_payment_time ) );
// add back the trial length if it has been spoofed
- $cart_item['data']->subscription_trial_length = $trial_length;
+ wcs_set_objects_property( $cart_item['data'], 'subscription_trial_length', $trial_length, 'set_prop_only' );
// elseif fallback to using the end date set on the cart item
} elseif ( ! empty( $end_timestamp ) ) {
@@ -1509,10 +1639,10 @@ class WC_Subscriptions_Switcher {
public static function process_subscription_switches( $order_id, $order_old_status, $order_new_status ) {
global $wpdb;
- $switch_processed = get_post_meta( $order_id, '_completed_subscription_switch', true );
$order = wc_get_order( $order_id );
+ $switch_processed = wcs_get_objects_property( $order, 'completed_subscription_switch' );
- if ( ! wcs_order_contains_switch( $order_id ) || 'true' == $switch_processed ) {
+ if ( ! wcs_order_contains_switch( $order ) || 'true' == $switch_processed ) {
return;
}
@@ -1525,7 +1655,7 @@ class WC_Subscriptions_Switcher {
self::complete_subscription_switches( $order );
- update_post_meta( $order_id, '_completed_subscription_switch', 'true' );
+ wcs_set_objects_property( $order, 'completed_subscription_switch', 'true' );
$wpdb->query( 'COMMIT' );
@@ -1551,7 +1681,7 @@ class WC_Subscriptions_Switcher {
$switch_setting = get_option( WC_Subscriptions_Admin::$option_prefix . '_allow_switching', 'no' );
// does the current switch setting allow switching for variable or variable_grouped
- if ( 'variable_grouped' == $switch_setting || ( $product->is_type( array( 'variable-subscription', 'subscription_variation' ) ) && 'variable' == $switch_setting ) || ( 'grouped' == $switch_setting && ( $product->is_type( 'grouped' ) || 0 !== $product->post->post_parent ) ) ) {
+ if ( 'variable_grouped' == $switch_setting || ( $product->is_type( array( 'variable-subscription', 'subscription_variation' ) ) && 'variable' == $switch_setting ) || ( 'grouped' == $switch_setting && ( $product->is_type( 'grouped' ) || wcs_get_objects_property( $product, 'parent_id' ) ) ) ) {
$allow_switching = true;
}
@@ -1618,7 +1748,7 @@ class WC_Subscriptions_Switcher {
if ( in_array( $order_type, array( 'all', 'switch' ) ) ) {
- $switch_orders = wcs_get_switch_orders_for_subscription( $subscription->id );
+ $switch_orders = wcs_get_switch_orders_for_subscription( $subscription->get_id() );
if ( 'all' == $return_fields ) {
$related_orders += $switch_orders;
@@ -1710,7 +1840,7 @@ class WC_Subscriptions_Switcher {
}
$product_id = wcs_get_canonical_product_id( $old_item );
- WCS_Download_Handler::revoke_downloadable_file_permission( $product_id, $subscription->id, $subscription->customer_user );
+ WCS_Download_Handler::revoke_downloadable_file_permission( $product_id, $subscription->get_id(), $subscription->get_user_id() );
}
@@ -1726,7 +1856,7 @@ class WC_Subscriptions_Switcher {
public static function complete_subscription_switches( $order ) {
// Get the switch meta
- $switch_order_data = get_post_meta( $order->id, '_subscription_switch_data', true );
+ $switch_order_data = wcs_get_objects_property( $order, 'subscription_switch_data' );
// if we don't have an switch data, there is nothing to do here. Switch orders created prior to v2.1 won't have any data to process.
if ( empty( $switch_order_data ) || ! is_array( $switch_order_data ) ) {
@@ -1752,7 +1882,6 @@ class WC_Subscriptions_Switcher {
// If we are adding a line item to an existing subscription
if ( isset( $switched_item_data['add_line_item'] ) ) {
wc_update_order_item( $switched_item_data['add_line_item'], array( 'order_item_type' => 'line_item' ) );
-
do_action( 'woocommerce_subscription_item_switched', $order, $subscription, $switched_item_data['add_line_item'], $switched_item_data['remove_line_item'] );
}
@@ -1774,17 +1903,25 @@ class WC_Subscriptions_Switcher {
wc_update_order_item( $switched_item_data['remove_line_item'], array( 'order_item_type' => 'line_item_switched' ) );
// translators: 1$: old item, 2$: new item when switching
- $subscription->add_order_note( sprintf( _x( 'Customer switched from: %1$s to %2$s.', 'used in order notes', 'woocommerce-subscriptions' ), $old_item_name, $new_item_name ) );
+ $add_note = sprintf( _x( 'Customer switched from: %1$s to %2$s.', 'used in order notes', 'woocommerce-subscriptions' ), $old_item_name, $new_item_name );
}
}
}
}
+ if ( ! empty( $add_note ) ) {
+ $subscription->add_order_note( $add_note );
+ }
+
if ( ! empty( $switch_data['billing_schedule'] ) ) {
// Update the billing schedule
- foreach ( $switch_data['billing_schedule'] as $meta_key => $value ) {
- update_post_meta( $subscription_id, $meta_key, $value );
+ if ( ! empty( $switch_data['billing_schedule']['_billing_period'] ) ) {
+ $subscription->set_billing_period( $switch_data['billing_schedule']['_billing_period'] );
+ }
+
+ if ( ! empty( $switch_data['billing_schedule']['_billing_interval'] ) ) {
+ $subscription->set_billing_interval( $switch_data['billing_schedule']['_billing_interval'] );
}
}
@@ -1798,7 +1935,7 @@ class WC_Subscriptions_Switcher {
}
if ( ! empty( $switch_data['dates']['update'] ) ) {
- $subscription->update_dates( $switch_order_data[ $subscription->id ]['dates']['update'] );
+ $subscription->update_dates( $switch_order_data[ $subscription->get_id() ]['dates']['update'] );
}
}
@@ -1821,7 +1958,11 @@ class WC_Subscriptions_Switcher {
// Update the subscription address
self::maybe_update_subscription_address( $order, $subscription );
- $subscription->calculate_totals();
+ // Save every change
+ $subscription->save();
+
+ // We just changed above the type of some items related to this subscription, so we need to reload it to get the newest items
+ wcs_get_subscription( $subscription->get_id() )->calculate_totals();
}
}
@@ -1917,21 +2058,23 @@ class WC_Subscriptions_Switcher {
return;
}
- foreach ( wcs_get_subscriptions_for_switch_order( $order->id ) as $subscription ) {
+ foreach ( wcs_get_subscriptions_for_switch_order( $order ) as $subscription ) {
if ( false === $subscription->is_manual() ) {
continue;
}
- if ( $subscription->payment_method !== $order->payment_method ) {
+ if ( $subscription->get_payment_method() !== wcs_get_objects_property( $order, 'payment_method' ) ) {
// Set the new payment method on the subscription
- $available_gateways = WC()->payment_gateways->get_available_payment_gateways();
- $payment_method = isset( $available_gateways[ $order->payment_method ] ) ? $available_gateways[ $order->payment_method ] : false;
+ $available_gateways = WC()->payment_gateways->get_available_payment_gateways();
+ $order_payment_method = wcs_get_objects_property( $order, 'payment_method' );
+ $payment_method = '' != $order_payment_method && isset( $available_gateways[ $order_payment_method ] ) ? $available_gateways[ $order_payment_method ] : false;
if ( $payment_method && $payment_method->supports( 'subscriptions' ) ) {
$subscription->set_payment_method( $payment_method );
- $subscription->update_manual( false );
+ $subscription->set_requires_manual_renewal( false );
+ $subscription->save();
}
}
}
@@ -2001,7 +2144,7 @@ class WC_Subscriptions_Switcher {
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if ( isset( $cart_item['subscription_switch']['first_payment_timestamp'] ) && 0 != $cart_item['subscription_switch']['first_payment_timestamp'] ) {
- WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_trial_length = 1;
+ wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_trial_length', 1, 'set_prop_only' );
}
}
@@ -2017,7 +2160,7 @@ class WC_Subscriptions_Switcher {
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if ( isset( $cart_item['subscription_switch']['first_payment_timestamp'] ) && 0 != $cart_item['subscription_switch']['first_payment_timestamp'] ) {
- WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_trial_length = 0;
+ wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_trial_length', 0, 'set_prop_only' );
}
}
return $total;
@@ -2094,7 +2237,7 @@ class WC_Subscriptions_Switcher {
// Add the new shipping line item
foreach ( $shipping_methods as $shipping_line_item ) {
- $item_id = wc_add_order_item( $subscription->id, array(
+ $item_id = wc_add_order_item( $subscription->get_id(), array(
'order_item_name' => $shipping_line_item['name'],
'order_item_type' => 'shipping',
) );
@@ -2258,7 +2401,7 @@ class WC_Subscriptions_Switcher {
*/
public static function calculate_first_payment_date( $next_payment_date, $order, $product_id, $type ) {
_deprecated_function( __METHOD__, '2.0' );
- return self::get_first_payment_date( $next_payment_date, WC_Subscriptions_Manager::get_subscription_key( $order->id, $product_id ), $order->user_id, $type );
+ return self::get_first_payment_date( $next_payment_date, WC_Subscriptions_Manager::get_subscription_key( wcs_get_objects_property( $order, 'id' ), $product_id ), $order->get_user_id(), $type );
}
/**
@@ -2275,9 +2418,9 @@ class WC_Subscriptions_Switcher {
$subscription = wcs_get_subscription_from_key( $subscription_key );
- if ( $subscription->has_status( 'active' ) && ! empty( $subscription->order ) && wcs_order_contains_switch( $subscription->order->id ) && 1 >= $subscription->get_completed_payment_count() ) {
+ if ( $subscription->has_status( 'active' ) && $subscription->get_parent_id() && wcs_order_contains_switch( $subscription->get_parent_id() ) && 1 >= $subscription->get_completed_payment_count() ) {
- $first_payment_timestamp = get_post_meta( $subscription->order->id, '_switched_subscription_first_payment_timestamp', true );
+ $first_payment_timestamp = get_post_meta( $subscription->get_parent_id(), '_switched_subscription_first_payment_timestamp', true );
if ( 0 != $first_payment_timestamp ) {
$next_payment_date = ( 'mysql' == $type ) ? gmdate( 'Y-m-d H:i:s', $first_payment_timestamp ) : $first_payment_timestamp;
@@ -2348,5 +2491,34 @@ class WC_Subscriptions_Switcher {
_deprecated_function( __METHOD__, '2.0', 'wcs_order_contains_switch( $order_id )' );
return wcs_order_contains_switch( $order_id );
}
+
+ /**
+ * Store the order line item id so it can be retrieved when we're processing the switch on checkout
+ *
+ * @param int $order_id
+ * @param array $checkout_posted_data
+ * @since 2.2.0
+ */
+ public static function set_switch_order_item_id( $order_id, $posted_checkout_data ) {
+ _deprecated_function( __METHOD__, '2.2.1', 'WCS_Cart_Switch::set_cart_item_order_item_id()' );
+
+ $order = wc_get_order( $order_id );
+
+ foreach ( $order->get_items( 'line_item' ) as $order_item_id => $order_item ) {
+
+ $cart_item_key = $order_item->get_meta( '_switched_cart_item_key' );
+
+ if ( ! empty( $cart_item_key ) ) {
+ foreach ( WC()->cart->recurring_carts as $recurring_cart_key => $recurring_cart ) {
+
+ // If this cart item belongs to this recurring cart
+ if ( in_array( $cart_item_key, array_keys( $recurring_cart->cart_contents ) ) && isset( WC()->cart->recurring_carts[ $recurring_cart_key ]->cart_contents[ $cart_item_key ]['subscription_switch'] ) ) {
+ WC()->cart->recurring_carts[ $recurring_cart_key ]->cart_contents[ $cart_item_key ]['subscription_switch']['order_line_item_id'] = $order_item_id;
+ wc_add_order_item_meta( WC()->cart->recurring_carts[ $recurring_cart_key ]->cart_contents[ $cart_item_key ]['subscription_switch']['item_id'], '_switched_subscription_new_item_id', $order_item_id, true );
+ }
+ }
+ }
+ }
+ }
}
WC_Subscriptions_Switcher::init();
diff --git a/includes/class-wc-subscriptions-synchroniser.php b/includes/class-wc-subscriptions-synchroniser.php
index a309583..d4b6c5b 100644
--- a/includes/class-wc-subscriptions-synchroniser.php
+++ b/includes/class-wc-subscriptions-synchroniser.php
@@ -96,7 +96,12 @@ class WC_Subscriptions_Synchroniser {
// When adding an item to a subscription, check if it is for a synced product to make sure the sync meta is set on the subscription. We can't attach to just the 'woocommerce_new_order_item' here because the '_product_id' and '_variation_id' meta are not set before it fires
add_action( 'woocommerce_ajax_add_order_item_meta', __CLASS__ . '::ajax_maybe_add_meta_for_item', 10, 2 );
- add_action( 'woocommerce_order_add_product', __CLASS__ . '::maybe_add_meta_for_new_product', 10, 3 );
+
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ add_action( 'woocommerce_order_add_product', __CLASS__ . '::maybe_add_meta_for_new_product', 10, 3 );
+ } else {
+ add_action( 'woocommerce_new_order_item', __CLASS__ . '::maybe_add_meta_for_new_line_item', 10, 3 );
+ }
// Make sure the sign-up fee for a synchronised subscription is correct
add_filter( 'woocommerce_subscriptions_sign_up_fee', __CLASS__ . '::get_synced_sign_up_fee', 1, 3 );
@@ -259,14 +264,16 @@ class WC_Subscriptions_Synchroniser {
if ( self::is_syncing_enabled() ) {
// Set month as the default billing period
- if ( ! $subscription_period = get_post_meta( $variation->ID, '_subscription_period', true ) ) {
+ $subscription_period = WC_Subscriptions_Product::get_period( $variation );
+
+ if ( empty( $subscription_period ) ) {
$subscription_period = 'month';
}
$display_week_month_select = ( ! in_array( $subscription_period, array( 'month', 'week' ) ) ) ? 'display: none;' : '';
$display_annual_select = ( 'year' != $subscription_period ) ? 'display: none;' : '';
- $payment_day = self::get_products_payment_day( $variation->ID );
+ $payment_day = self::get_products_payment_day( $variation );
// An annual sync date is already set in the form: array( 'day' => 'nn', 'month' => 'nn' ), create a MySQL string from those values (year and time are irrelvent as they are ignored)
if ( is_array( $payment_day ) ) {
@@ -400,7 +407,7 @@ class WC_Subscriptions_Synchroniser {
$product = wc_get_product( $product );
}
- if ( ! is_object( $product ) || ! self::is_syncing_enabled() || 'day' == $product->subscription_period || ! WC_Subscriptions_Product::is_subscription( $product ) ) {
+ if ( ! is_object( $product ) || ! self::is_syncing_enabled() || 'day' == WC_Subscriptions_Product::get_period( $product ) || ! WC_Subscriptions_Product::is_subscription( $product ) ) {
return false;
}
@@ -441,15 +448,11 @@ class WC_Subscriptions_Synchroniser {
if ( ! self::is_syncing_enabled() ) {
$payment_date = 0;
- } elseif ( ! is_object( $product ) ) {
- $payment_date = get_post_meta( $product, self::$post_meta_key, true );
- } elseif ( isset( $product->subscription_payment_sync_date ) ) {
- $payment_date = $product->subscription_payment_sync_date;
} else {
- $payment_date = 0;
+ $payment_date = WC_Subscriptions_Product::get_meta_data( $product, 'subscription_payment_sync_date', 0 );
}
- return $payment_date;
+ return apply_filters( 'woocommerce_subscriptions_product_sync_date', $payment_date, $product );
}
/**
@@ -654,7 +657,7 @@ class WC_Subscriptions_Synchroniser {
$first_payment_date = '';
if ( self::is_product_synced( $product ) ) {
- $first_payment_timestamp = self::calculate_first_payment_date( $product->id, 'timestamp' );
+ $first_payment_timestamp = self::calculate_first_payment_date( $product->get_id(), 'timestamp' );
if ( 0 != $first_payment_timestamp ) {
@@ -713,7 +716,9 @@ class WC_Subscriptions_Synchroniser {
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if ( self::is_product_synced( $cart_item['data'] ) && ! self::is_product_prorated( $cart_item['data'] ) && ! self::is_today( self::calculate_first_payment_date( $cart_item['data'], 'timestamp' ) ) ) {
- WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_trial_length = ( WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_trial_length > 1 ) ? WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_trial_length : 1;
+ $current_trial_length = WC_Subscriptions_Product::get_trial_length( WC()->cart->cart_contents[ $cart_item_key ]['data'] );
+ $new_trial_length = ( $current_trial_length > 1 ) ? $current_trial_length : 1;
+ wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_trial_length', $new_trial_length, 'set_prop_only' );
}
}
@@ -729,7 +734,7 @@ class WC_Subscriptions_Synchroniser {
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if ( self::is_product_synced( $cart_item['data'] ) ) {
- WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_trial_length = WC_Subscriptions_Product::get_trial_length( wcs_get_canonical_product_id( $cart_item ) );
+ wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_trial_length', WC_Subscriptions_Product::get_trial_length( wcs_get_canonical_product_id( $cart_item ) ), 'set_prop_only' );
}
}
return $total;
@@ -748,7 +753,7 @@ class WC_Subscriptions_Synchroniser {
if ( self::is_syncing_enabled() && ! empty( $cart ) && ! wcs_cart_contains_renewal() ) {
foreach ( $cart->cart_contents as $cart_item_key => $cart_item ) {
- if ( ( ! is_array( $cart_item['data']->subscription_payment_sync_date ) && $cart_item['data']->subscription_payment_sync_date > 0 ) || ( is_array( $cart_item['data']->subscription_payment_sync_date ) && $cart_item['data']->subscription_payment_sync_date['day'] > 0 ) ) {
+ if ( self::is_product_synced( $cart_item['data'] ) ) {
$contains_synced = $cart_item;
break;
}
@@ -781,7 +786,7 @@ class WC_Subscriptions_Synchroniser {
if ( $trial_expiration_date > 0 && self::is_product_synced( $product_id ) ) {
- $trial_expiration_timestamp = strtotime( $trial_expiration_date );
+ $trial_expiration_timestamp = wcs_date_to_time( $trial_expiration_date );
remove_filter( 'woocommerce_subscriptions_product_trial_expiration_date', __METHOD__ ); // avoid infinite loop
$first_payment_timestamp = self::calculate_first_payment_date( $product_id, 'timestamp' );
add_filter( 'woocommerce_subscriptions_product_trial_expiration_date', __METHOD__, 10, 2 ); // avoid infinite loop
@@ -842,7 +847,7 @@ class WC_Subscriptions_Synchroniser {
*/
public static function get_synced_sign_up_fee( $sign_up_fee, $subscription, $product_id ) {
- if ( wcs_is_subscription( $subscription ) && self::subscription_contains_synced_product( $subscription ) && count( wcs_get_line_items_with_a_trial( $subscription->id ) ) < 0 ) {
+ if ( wcs_is_subscription( $subscription ) && self::subscription_contains_synced_product( $subscription ) && count( wcs_get_line_items_with_a_trial( $subscription->get_id() ) ) < 0 ) {
$sign_up_fee = max( $subscription->get_total_initial_payment() - $subscription->get_total(), 0 );
}
@@ -864,15 +869,15 @@ class WC_Subscriptions_Synchroniser {
return $price;
}
- switch ( $product->subscription_period ) {
+ switch ( WC_Subscriptions_Product::get_period( $product ) ) {
case 'week' :
- $days_in_cycle = 7 * $product->subscription_period_interval;
+ $days_in_cycle = 7 * WC_Subscriptions_Product::get_interval( $product );
break;
case 'month' :
- $days_in_cycle = gmdate( 't' ) * $product->subscription_period_interval;
+ $days_in_cycle = gmdate( 't' ) * WC_Subscriptions_Product::get_interval( $product );
break;
case 'year' :
- $days_in_cycle = ( 365 + gmdate( 'L' ) ) * $product->subscription_period_interval;
+ $days_in_cycle = ( 365 + gmdate( 'L' ) ) * WC_Subscriptions_Product::get_interval( $product );
break;
}
@@ -963,7 +968,7 @@ class WC_Subscriptions_Synchroniser {
$product_id = wcs_get_canonical_product_id( $item );
if ( self::is_product_synced( $product_id ) ) {
- update_post_meta( $subscription->id, '_contains_synced_subscription', 'true' );
+ update_post_meta( $subscription->get_id(), '_contains_synced_subscription', 'true' );
break;
}
}
@@ -1012,7 +1017,7 @@ class WC_Subscriptions_Synchroniser {
public static function subscription_contains_synced_product( $subscription_id ) {
if ( is_object( $subscription_id ) ) {
- $subscription_id = $subscription_id->id;
+ $subscription_id = $subscription_id->get_id();
}
return ( 'true' == get_post_meta( $subscription_id, '_contains_synced_subscription', true ) ) ? true : false;
@@ -1033,6 +1038,23 @@ class WC_Subscriptions_Synchroniser {
return $cart_key;
}
+ /**
+ * When adding a product line item to an order/subscription via the WC_Abstract_Order::add_product() method, check if we should be setting
+ * the sync meta on the subscription.
+ *
+ * Attached to WC 3.0+ hooks and uses WC 3.0 methods.
+ *
+ * @param int The new line item id
+ * @param WC_Order_Item
+ * @param int The post ID of a WC_Subscription
+ * @since 2.2.3
+ */
+ public static function maybe_add_meta_for_new_line_item( $item_id, $item, $subscription_id ) {
+ if ( is_callable( array( $item, 'get_product_id' ) ) && self::is_product_synced( $item->get_product_id() ) ) {
+ self::maybe_add_subscription_meta( $subscription_id );
+ }
+ }
+
/* Deprecated Functions */
/**
@@ -1059,7 +1081,7 @@ class WC_Subscriptions_Synchroniser {
$cart_item = self::cart_contains_synced_subscription();
- if ( false !== $cart_item && isset( $cart_item['data']->subscription_period ) && ( 'year' != $cart_item['data']->subscription_period || $cart_item['data']->subscription_trial_length > 0 ) ) {
+ if ( false !== $cart_item && '' !== WC_Subscriptions_Product::get_period( $cart_item['data'] ) && ( 'year' != WC_Subscriptions_Product::get_period( $cart_item['data'] ) || WC_Subscriptions_Product::get_trial_length( $cart_item['data'] ) > 0 ) ) {
$first_payment_date = self::get_products_first_payment_date( $cart_item['data'] );
@@ -1154,17 +1176,16 @@ class WC_Subscriptions_Synchroniser {
* @deprecated 2.0
*/
public static function get_first_payment_date( $first_payment_date, $order, $product_id, $type ) {
-
_deprecated_function( __METHOD__, '2.0' );
$subscription = wcs_get_subscription_from_key( $order . '_' . $product_id );
- if ( self::order_contains_synced_subscription( $order->id ) && 1 >= $subscription->get_completed_payment_count() ) {
+ if ( self::order_contains_synced_subscription( wcs_get_objects_property( $order, 'id' ) ) && 1 >= $subscription->get_completed_payment_count() ) {
// Don't prematurely set the first payment date when manually adding a subscription from the admin
if ( ! is_admin() || 'active' == $subscription->get_status() ) {
- $first_payment_timestamp = self::calculate_first_payment_date( $product_id, 'timestamp', $order->order_date );
+ $first_payment_timestamp = self::calculate_first_payment_date( $product_id, 'timestamp', wcs_get_datetime_utc_string( wcs_get_objects_property( $order, 'date_created' ) ) );
if ( 0 != $first_payment_timestamp ) {
$first_payment_date = ( 'mysql' == $type ) ? gmdate( 'Y-m-d H:i:s', $first_payment_timestamp ) : $first_payment_timestamp;
@@ -1210,7 +1231,7 @@ class WC_Subscriptions_Synchroniser {
_deprecated_function( __METHOD__, '2.0', __CLASS__ . '::subscription_contains_synced_product()' );
if ( is_object( $order_id ) ) {
- $order_id = $order_id->id;
+ $order_id = wcs_get_objects_property( $order_id, 'id' );
}
return ( 'true' == get_post_meta( $order_id, '_order_contains_synced_subscription', true ) ) ? true : false;
@@ -1262,7 +1283,7 @@ class WC_Subscriptions_Synchroniser {
public static function get_sign_up_fee( $sign_up_fee, $order, $product_id, $non_subscription_total ) {
_deprecated_function( __METHOD__, '2.0', __CLASS__ . '::get_synced_sign_up_fee' );
- if ( 'shop_order' == get_post_type( $order ) && self::order_contains_synced_subscription( $order->id ) && WC_Subscriptions_Order::get_subscription_trial_length( $order ) < 1 ) {
+ if ( 'shop_order' == get_post_type( $order ) && self::order_contains_synced_subscription( wcs_get_objects_property( $order, 'id' ) ) && WC_Subscriptions_Order::get_subscription_trial_length( $order ) < 1 ) {
$sign_up_fee = max( WC_Subscriptions_Order::get_total_initial_payment( $order ) - $non_subscription_total, 0 );
}
diff --git a/includes/class-wcs-action-scheduler.php b/includes/class-wcs-action-scheduler.php
index c6d69b6..3b2038d 100644
--- a/includes/class-wcs-action-scheduler.php
+++ b/includes/class-wcs-action-scheduler.php
@@ -22,7 +22,7 @@ class WCS_Action_Scheduler extends WCS_Scheduler {
* Maybe set a schedule action if the new date is in the future
*
* @param object $subscription An instance of a WC_Subscription object
- * @param string $date_type Can be 'start', 'trial_end', 'next_payment', 'payment_retry', 'last_payment', 'end', 'end_of_prepaid_term' or a custom date type
+ * @param string $date_type Can be 'trial_end', 'next_payment', 'payment_retry', 'end', 'end_of_prepaid_term' or a custom date type
* @param string $datetime A MySQL formated date/time string in the GMT/UTC timezone.
*/
public function update_date( $subscription, $date_type, $datetime ) {
@@ -55,7 +55,7 @@ class WCS_Action_Scheduler extends WCS_Scheduler {
* Delete a date from the action scheduler queue
*
* @param object $subscription An instance of a WC_Subscription object
- * @param string $date_type Can be 'start', 'trial_end', 'next_payment', 'last_payment', 'end', 'end_of_prepaid_term' or a custom date type
+ * @param string $date_type Can be 'trial_end', 'next_payment', 'end', 'end_of_prepaid_term' or a custom date type
*/
public function delete_date( $subscription, $date_type ) {
$this->update_date( $subscription, $date_type, 0 );
@@ -65,7 +65,7 @@ class WCS_Action_Scheduler extends WCS_Scheduler {
* When a subscription's status is updated, maybe schedule an event
*
* @param object $subscription An instance of a WC_Subscription object
- * @param string $date_type Can be 'start', 'trial_end', 'next_payment', 'last_payment', 'end', 'end_of_prepaid_term' or a custom date type
+ * @param string $date_type Can be 'trial_end', 'next_payment', 'end', 'end_of_prepaid_term' or a custom date type
* @param string $datetime A MySQL formated date/time string in the GMT/UTC timezone.
*/
public function update_status( $subscription, $new_status, $old_status ) {
@@ -126,7 +126,7 @@ class WCS_Action_Scheduler extends WCS_Scheduler {
* Get the hook to use in the action scheduler for the date type
*
* @param object $subscription An instance of WC_Subscription to get the hook for
- * @param string $date_type Can be 'start', 'trial_end', 'next_payment', 'last_payment', 'expiration', 'end_of_prepaid_term' or a custom date type
+ * @param string $date_type Can be 'trial_end', 'next_payment', 'expiration', 'end_of_prepaid_term' or a custom date type
*/
protected function get_scheduled_action_hook( $subscription, $date_type ) {
@@ -158,7 +158,7 @@ class WCS_Action_Scheduler extends WCS_Scheduler {
/**
* Get the args to set on the scheduled action.
*
- * @param string $date_type Can be 'start', 'trial_end', 'next_payment', 'last_payment', 'expiration', 'end_of_prepaid_term' or a custom date type
+ * @param string $date_type Can be 'trial_end', 'next_payment', 'expiration', 'end_of_prepaid_term' or a custom date type
* @param object $subscription An instance of WC_Subscription to get the hook for
* @return array Array of name => value pairs stored against the scheduled action.
*/
@@ -170,7 +170,7 @@ class WCS_Action_Scheduler extends WCS_Scheduler {
$action_args = array( 'order_id' => $last_order_id );
} else {
- $action_args = array( 'subscription_id' => $subscription->id );
+ $action_args = array( 'subscription_id' => $subscription->get_id() );
}
return apply_filters( 'woocommerce_subscriptions_scheduled_action_args', $action_args, $date_type, $subscription );
diff --git a/includes/class-wcs-api.php b/includes/class-wcs-api.php
index 1eebb91..1e1ce13 100644
--- a/includes/class-wcs-api.php
+++ b/includes/class-wcs-api.php
@@ -54,8 +54,13 @@ class WCS_API {
return;
}
- require_once( 'api/class-wc-rest-subscriptions-controller.php' );
- require_once( 'api/class-wc-rest-subscription-notes-controller.php' );
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ require_once( 'api/legacy/class-wc-rest-subscriptions-controller.php' );
+ require_once( 'api/legacy/class-wc-rest-subscription-notes-controller.php' );
+ } else {
+ require_once( 'api/class-wc-rest-subscriptions-controller.php' );
+ require_once( 'api/class-wc-rest-subscription-notes-controller.php' );
+ }
foreach ( array( 'WC_REST_Subscriptions_Controller', 'WC_REST_Subscription_Notes_Controller' ) as $api_class ) {
$controller = new $api_class();
diff --git a/includes/class-wcs-cache-manager-tlc.php b/includes/class-wcs-cache-manager-tlc.php
index 49c4b3a..0a4ee8b 100644
--- a/includes/class-wcs-cache-manager-tlc.php
+++ b/includes/class-wcs-cache-manager-tlc.php
@@ -97,9 +97,9 @@ class WCS_Cache_Manager_TLC extends WCS_Cache_Manager {
}
$subscription = array_shift( $subscription );
- $this->log( 'Got subscription, calling wcs_clear_related_order_cache for ' . $subscription->id );
+ $this->log( 'Got subscription, calling wcs_clear_related_order_cache for ' . $subscription->get_id() );
- $this->wcs_clear_related_order_cache( $subscription->id );
+ $this->wcs_clear_related_order_cache( $subscription->get_id() );
}
}
@@ -158,7 +158,7 @@ class WCS_Cache_Manager_TLC extends WCS_Cache_Manager {
// if it's not a Subscription, we don't deal with it
if ( is_object( $id ) && $id instanceof WC_Subscription ) {
- $id = $id->id;
+ $id = $id->get_id();
} elseif ( is_numeric( $id ) ) {
$id = absint( $id );
} else {
diff --git a/includes/class-wcs-cached-data-manager.php b/includes/class-wcs-cached-data-manager.php
index 2c1733a..9b0834c 100644
--- a/includes/class-wcs-cached-data-manager.php
+++ b/includes/class-wcs-cached-data-manager.php
@@ -75,9 +75,9 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager {
return;
}
- foreach ( wcs_get_subscriptions_for_order( $post_id, array( 'order_type' => 'any' ) ) as $linked_subscription ) {
- $this->log( 'Calling purge delete on ' . current_filter() . ' for ' . $linked_subscription->id );
- $this->clear_related_order_cache( $linked_subscription );
+ foreach ( wcs_get_subscriptions_for_order( $post_id, array( 'order_type' => 'any' ) ) as $subscription ) {
+ $this->log( 'Calling purge delete on ' . current_filter() . ' for ' . $subscription->get_id() );
+ $this->clear_related_order_cache( $subscription );
}
}
@@ -108,7 +108,7 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager {
// if it's not a Subscription, we don't deal with it
if ( is_object( $subscription_id ) && $subscription_id instanceof WC_Subscription ) {
- $subscription_id = $subscription_id->id;
+ $subscription_id = $subscription_id->get_id();
} elseif ( is_numeric( $subscription_id ) ) {
$subscription_id = absint( $subscription_id );
} else {
@@ -169,7 +169,7 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager {
$this->log( 'No subscriptions for this ID: ' . $post_id );
} else {
foreach ( $subscriptions as $subscription ) {
- $this->log( 'Got subscription, calling clear_related_order_cache for ' . $subscription->id );
+ $this->log( 'Got subscription, calling clear_related_order_cache for ' . $subscription->get_id() );
$this->clear_related_order_cache( $subscription );
}
}
diff --git a/includes/class-wcs-cart-initial-payment.php b/includes/class-wcs-cart-initial-payment.php
index 3f6b08b..8d5ec43 100644
--- a/includes/class-wcs-cart-initial-payment.php
+++ b/includes/class-wcs-cart-initial-payment.php
@@ -39,7 +39,7 @@ class WCS_Cart_Initial_Payment extends WCS_Cart_Renewal {
$order_id = ( isset( $wp->query_vars['order-pay'] ) ) ? $wp->query_vars['order-pay'] : absint( $_GET['order_id'] );
$order = wc_get_order( $wp->query_vars['order-pay'] );
- if ( $order->order_key == $order_key && $order->has_status( array( 'pending', 'failed' ) ) && wcs_order_contains_subscription( $order, 'parent' ) && ! wcs_order_contains_subscription( $order, 'resubscribe' ) ) {
+ if ( wcs_get_objects_property( $order, 'order_key' ) == $order_key && $order->has_status( array( 'pending', 'failed' ) ) && wcs_order_contains_subscription( $order, 'parent' ) && ! wcs_order_contains_subscription( $order, 'resubscribe' ) ) {
if ( ! is_user_logged_in() ) {
diff --git a/includes/class-wcs-cart-renewal.php b/includes/class-wcs-cart-renewal.php
index b390cec..6359701 100644
--- a/includes/class-wcs-cart-renewal.php
+++ b/includes/class-wcs-cart-renewal.php
@@ -26,6 +26,9 @@ class WCS_Cart_Renewal {
$this->setup_hooks();
+ // Attach hooks which depend on WooCommerce constants
+ add_action( 'woocommerce_loaded', array( &$this, 'attach_dependant_hooks' ), 10 );
+
// Set URL parameter for manual subscription renewals
add_filter( 'woocommerce_get_checkout_payment_url', array( &$this, 'get_checkout_payment_url' ), 10, 2 );
@@ -44,15 +47,37 @@ class WCS_Cart_Renewal {
// When a user is prevented from paying for a failed/pending renewal order because they aren't logged in, redirect them back after login
add_filter( 'woocommerce_login_redirect', array( &$this, 'maybe_redirect_after_login' ), 10 , 1 );
- // When a renewal order's line items are being updated, update the line item IDs stored in cart data.
- add_action( 'woocommerce_add_order_item_meta', array( &$this, 'update_line_item_cart_data' ), 10, 3 );
-
// Once we have finished updating the renewal order on checkout, update the session cart so the cart changes are honoured.
add_action( 'woocommerce_checkout_order_processed', array( &$this, 'update_session_cart_after_updating_renewal_order' ), 10 );
add_filter( 'wc_dynamic_pricing_apply_cart_item_adjustment', array( &$this, 'prevent_compounding_dynamic_discounts' ), 10, 2 );
}
+ /**
+ * Attach WooCommerce version dependent hooks
+ *
+ * @since 2.2.0
+ */
+ public function attach_dependant_hooks() {
+
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+
+ // When a renewal order's line items are being updated, update the line item IDs stored in cart data.
+ add_action( 'woocommerce_add_order_item_meta', array( &$this, 'update_line_item_cart_data' ), 10, 3 );
+
+ } else {
+
+ // For order items created as part of a renewal, keep a record of the cart item key so that we can match it later once the order item has been saved and has an ID
+ add_action( 'woocommerce_checkout_create_order_line_item', array( &$this, 'add_line_item_meta' ), 10, 3 );
+
+ // After order meta is saved, get the order line item ID for the renewal so we can update it later
+ add_action( 'woocommerce_checkout_update_order_meta', array( &$this, 'set_order_item_id' ), 10, 2 );
+
+ // Don't display cart item key meta stored above on the Edit Order screen
+ add_action( 'woocommerce_hidden_order_itemmeta', array( &$this, 'hidden_order_itemmeta' ), 10 );
+ }
+ }
+
/**
* Bootstraps the class and hooks required actions & filters.
*
@@ -111,7 +136,7 @@ class WCS_Cart_Renewal {
$order_id = ( isset( $wp->query_vars['order-pay'] ) ) ? $wp->query_vars['order-pay'] : absint( $_GET['order_id'] );
$order = wc_get_order( $wp->query_vars['order-pay'] );
- if ( $order->order_key == $order_key && $order->has_status( array( 'pending', 'failed' ) ) && wcs_order_contains_renewal( $order ) ) {
+ if ( wcs_get_objects_property( $order, 'order_key' ) == $order_key && $order->has_status( array( 'pending', 'failed' ) ) && wcs_order_contains_renewal( $order ) ) {
// If a user isn't logged in, allow them to login first and then redirect back
if ( ! is_user_logged_in() ) {
@@ -142,7 +167,7 @@ class WCS_Cart_Renewal {
// Add the existing subscription items to the cart
$this->setup_cart( $order, array(
- 'subscription_id' => $subscription->id,
+ 'subscription_id' => $subscription->get_id(),
'renewal_order_id' => $order_id,
) );
@@ -243,7 +268,8 @@ class WCS_Cart_Renewal {
if ( wcs_is_subscription( $subscription ) ) {
- $used_coupons = $subscription->get_used_coupons();
+ $used_coupons = $subscription->get_used_coupons();
+ $subscription_discount = wcs_get_objects_property( $subscription, 'cart_discount' );
// Add any used coupon discounts to the cart (as best we can) using our pseudo renewal coupons
if ( ! empty( $used_coupons ) ) {
@@ -252,34 +278,34 @@ class WCS_Cart_Renewal {
foreach ( $coupon_items as $coupon_item ) {
- $coupon = new WC_Coupon( $coupon_item['name'] );
-
+ $coupon = new WC_Coupon( $coupon_item['name'] );
+ $coupon_type = wcs_get_coupon_property( $coupon, 'type' );
$coupon_code = '';
// If the coupon still exists we can use the existing/available coupon properties
- if ( true === $coupon->exists ) {
+ if ( true === wcs_get_coupon_property( $coupon, 'exists' ) ) {
// But we only want to handle recurring coupons that have been applied to the subscription
- if ( in_array( $coupon->type, array( 'recurring_percent', 'recurring_fee' ) ) ) {
+ if ( in_array( $coupon_type, array( 'recurring_percent', 'recurring_fee' ) ) ) {
// Set the coupon type to be a renewal equivalent for correct validation and calculations
- if ( 'recurring_percent' == $coupon->type ) {
- $coupon->type = 'renewal_percent';
- } elseif ( 'recurring_fee' == $coupon->type ) {
- $coupon->type = 'renewal_fee';
+ if ( 'recurring_percent' == $coupon_type ) {
+ wcs_set_coupon_property( $coupon, 'type', 'renewal_percent' );
+ } elseif ( 'recurring_fee' == $coupon_type ) {
+ wcs_set_coupon_property( $coupon, 'type', 'renewal_fee' );
}
// Adjust coupon code to reflect that it is being applied to a renewal
- $coupon_code = $coupon->code;
+ $coupon_code = wcs_get_coupon_property( $coupon, 'code' );
}
} else {
// If the coupon doesn't exist we can only really apply the discount amount we know about - so we'll apply a cart style pseudo coupon and then set the amount
- $coupon->type = 'renewal_cart';
- $coupon->amount = $coupon_item['item_meta']['discount_amount']['0'];
+ wcs_set_coupon_property( $coupon, 'type', 'renewal_cart' );
+ wcs_set_coupon_property( $coupon, 'amount', $coupon_item['item_meta']['discount_amount']['0'] );
// Adjust coupon code to reflect that it is being applied to a renewal
- $coupon_code = $coupon->code;
+ $coupon_code = wcs_get_coupon_property( $coupon, 'code' );
}
// Now that we have a coupon we know we want to apply
@@ -287,11 +313,11 @@ class WCS_Cart_Renewal {
// Set renewal order products as the product ids on the coupon
if ( ! WC_Subscriptions::is_woocommerce_pre( '2.5' ) ) {
- $coupon->product_ids = $this->get_products( $subscription );
+ wcs_set_coupon_property( $coupon, 'product_ids', $this->get_products( $subscription ) );
}
// Store the coupon info for later
- $this->store_coupon( $subscription->id, $coupon );
+ $this->store_coupon( $subscription->get_id(), $coupon );
// Add the coupon to the cart - the actually coupon values / data are grabbed when needed later
if ( WC()->cart && ! WC()->cart->has_discount( $coupon_code ) ) {
@@ -300,21 +326,22 @@ class WCS_Cart_Renewal {
}
}
// If there are no coupons but there is still a discount (i.e. it might have been manually added), we need to account for that as well
- } elseif ( ! empty( $subscription->cart_discount ) ) {
+ } elseif ( ! empty( $subscription_discount ) ) {
$coupon = new WC_Coupon( 'discount_renewal' );
// Apply our cart style pseudo coupon and the set the amount
- $coupon->type = 'renewal_cart';
- $coupon->amount = $subscription->cart_discount;
+ wcs_set_coupon_property( $coupon, 'type', 'renewal_cart' );
+
+ wcs_set_coupon_property( $coupon, 'amount', $subscription_discount );
// Set renewal order products as the product ids on the coupon
if ( ! WC_Subscriptions::is_woocommerce_pre( '2.5' ) ) {
- $coupon->product_ids = $this->get_products( $subscription );
+ wcs_set_coupon_property( $coupon, 'product_ids', $this->get_products( $subscription ) );
}
// Store the coupon info for later
- $this->store_coupon( $subscription->id, $coupon );
+ $this->store_coupon( $subscription->get_id(), $coupon );
// Add the coupon to the cart
if ( WC()->cart && ! WC()->cart->has_discount( 'discount_renewal' ) ) {
@@ -390,21 +417,22 @@ class WCS_Cart_Renewal {
if ( wc_prices_include_tax() ) {
if ( apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) ) {
- $base_tax_rates = WC_Tax::get_base_tax_rates( $_product->tax_class );
+ $base_tax_rates = WC_Tax::get_base_tax_rates( wcs_get_objects_property( $_product, 'tax_class' ) );
} else {
- $base_tax_rates = WC_Tax::get_rates( $_product->tax_class );
+ $base_tax_rates = WC_Tax::get_rates( wcs_get_objects_property( $_product, 'tax_class' ) );
}
$base_taxes_on_item = WC_Tax::calc_tax( $price, $base_tax_rates, false, false );
$price += array_sum( $base_taxes_on_item );
}
- $_product->price = $price / $item_to_renew['qty'];
+ $_product->set_price( $price / $item_to_renew['qty'] );
// Don't carry over any sign up fee
- $_product->subscription_sign_up_fee = 0;
+ wcs_set_objects_property( $_product, 'subscription_sign_up_fee', 0, 'set_prop_only' );
- $_product->post->post_title = apply_filters( 'woocommerce_subscriptions_renewal_product_title', $_product->get_title(), $_product );
+ // Allow plugins to add additional strings to the product name for renewals
+ wcs_set_objects_property( $_product, 'name', apply_filters( 'woocommerce_subscriptions_renewal_product_title', $_product->get_title(), $_product ), 'set_prop_only' );
// Make sure the same quantity is renewed
$cart_item_session_data['quantity'] = $item_to_renew['qty'];
@@ -424,12 +452,16 @@ class WCS_Cart_Renewal {
public function checkout_get_value( $value, $key ) {
// Only hook in after WC()->checkout() has been initialised
- if ( did_action( 'woocommerce_checkout_init' ) > 0 ) {
+ if ( $this->cart_contains() && did_action( 'woocommerce_checkout_init' ) > 0 ) {
// Guard against the fake WC_Checkout singleton, see https://github.com/woocommerce/woocommerce-subscriptions/issues/427#issuecomment-260763250
remove_filter( 'woocommerce_checkout_get_value', array( &$this, 'checkout_get_value' ), 10, 2 );
- $address_fields = array_merge( WC()->checkout()->checkout_fields['billing'], WC()->checkout()->checkout_fields['shipping'] );
+ if ( is_callable( array( WC()->checkout(), 'get_checkout_fields' ) ) ) { // WC 3.0+
+ $address_fields = array_merge( WC()->checkout()->get_checkout_fields( 'billing' ), WC()->checkout()->get_checkout_fields( 'shipping' ) );
+ } else {
+ $address_fields = array_merge( WC()->checkout()->checkout_fields['billing'], WC()->checkout()->checkout_fields['shipping'] );
+ }
add_filter( 'woocommerce_checkout_get_value', array( &$this, 'checkout_get_value' ), 10, 2 );
@@ -438,8 +470,8 @@ class WCS_Cart_Renewal {
// Get the most specific order object, which will be the renewal order for renewals, initial order for initial payments, or a subscription for switches/resubscribes
$order = $this->get_order( $item );
- if ( isset( $order->$key ) ) {
- $value = $order->$key;
+ if ( ( $order_value = wcs_get_objects_property( $order, $key ) ) ) {
+ $value = $order_value;
}
}
}
@@ -582,13 +614,18 @@ class WCS_Cart_Renewal {
*/
public function maybe_preserve_order_status( $order_status ) {
- if ( null !== WC()->session ) {
+ if ( null !== WC()->session && 'failed' !== $order_status ) {
$order_id = absint( WC()->session->order_awaiting_payment );
+ // Guard against infinite loops in WC 3.0+ where default order staus is set in WC_Abstract_Order::__construct()
+ remove_filter( 'woocommerce_default_order_status', array( &$this, __FUNCTION__ ), 10 );
+
if ( $order_id > 0 && ( $order = wc_get_order( $order_id ) ) && wcs_order_contains_renewal( $order ) && $order->has_status( 'failed' ) ) {
$order_status = 'failed';
}
+
+ add_filter( 'woocommerce_default_order_status', array( &$this, __FUNCTION__ ) );
}
return $order_status;
@@ -710,28 +747,59 @@ class WCS_Cart_Renewal {
foreach ( $coupons as $coupon ) {
// Tweak the coupon data for renewal coupons
- if ( $code == $coupon->code ) {
+ if ( wcs_get_coupon_property( $coupon, 'code' ) == $code ) {
$data = array(
- 'discount_type' => $coupon->type,
- 'coupon_amount' => $coupon->amount,
- 'individual_use' => ( $coupon->individual_use ) ? $coupon->individual_use : 'no',
- 'product_ids' => ( $coupon->product_ids ) ? $coupon->product_ids : array(),
- 'exclude_product_ids' => ( $coupon->exclude_product_ids ) ? $coupon->exclude_product_ids : array(),
- 'usage_limit' => '',
- 'usage_count' => '',
- 'expiry_date' => '',
- 'free_shipping' => ( $coupon->free_shipping ) ? $coupon->free_shipping : '',
- 'product_categories' => ( $coupon->product_categories ) ? $coupon->product_categories : array(),
- 'exclude_product_categories' => ( $coupon->exclude_product_categories ) ? $coupon->exclude_product_categories : array(),
- 'exclude_sale_items' => ( $coupon->exclude_sale_items ) ? $coupon->exclude_sale_items : 'no',
- 'minimum_amount' => ( $coupon->minimum_amount ) ? $coupon->minimum_amount : '',
- 'maximum_amount' => ( $coupon->maximum_amount ) ? $coupon->maximum_amount : '',
- 'customer_email' => ( $coupon->customer_email ) ? $coupon->customer_email : array(),
+ 'id' => true,
+ 'discount_type' => wcs_get_coupon_property( $coupon, 'type' ),
+ 'amount' => wcs_get_coupon_property( $coupon, 'amount' ),
+ 'individual_use' => ( $individual_use = wcs_get_coupon_property( $coupon, 'individual_use' ) ) ? $individual_use : false,
+ 'product_ids' => ( $product_ids = wcs_get_coupon_property( $coupon, 'product_ids' ) ) ? $product_ids : array(),
+ 'excluded_product_ids' => ( $excluded_product_ids = wcs_get_coupon_property( $coupon, 'exclude_product_ids' ) ) ? $excluded_product_ids : array(),
+ 'usage_limit' => '',
+ 'usage_count' => '',
+ 'date_expires' => '',
+ 'free_shipping' => ( $free_shipping = wcs_get_coupon_property( $coupon, 'free_shipping' ) ) ? $free_shipping : false,
+ 'product_categories' => ( $product_categories = wcs_get_coupon_property( $coupon, 'product_categories' ) ) ? $product_categories : array(),
+ 'excluded_product_categories' => ( $excluded_product_categories = wcs_get_coupon_property( $coupon, 'exclude_product_categories' ) ) ? $excluded_product_categories : array(),
+ 'exclude_sale_items' => ( $exclude_sale_items = wcs_get_coupon_property( $coupon, 'exclude_sale_items' ) ) ? $exclude_sale_items : false,
+ 'minimum_amount' => ( $minimum_amount = wcs_get_coupon_property( $coupon, 'minimum_amount' ) ) ? $minimum_amount : '',
+ 'maximum_amount' => ( $maximum_amount = wcs_get_coupon_property( $coupon, 'maximum_amount' ) ) ? $maximum_amount : '',
+ 'customer_email' => ( $customer_email = wcs_get_coupon_property( $coupon, 'customer_email' ) ) ? $customer_email : array(),
);
+
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+
+ // Pre 3.0 we don't need to pass the id.
+ unset( $data['id'] );
+
+ // Some keys have changed between WC 2.6.x and WC 3.0. This array holds those changes in a 2.6 => 3.0 format.
+ $property_changes = array(
+ 'coupon_amount' => 'amount',
+ 'exclude_product_ids' => 'excluded_product_ids',
+ 'expiry_date' => 'date_expires',
+ 'exclude_product_categories' => 'excluded_product_categories',
+ 'customer_email' => 'email_restrictions',
+ );
+
+ foreach ( $data as $key => $value ) {
+
+ // Switch the 3.0 key out for the 2.6 equivalent
+ if ( in_array( $key, $property_changes ) ) {
+ $data[ array_search( $key, $property_changes ) ] = $value;
+ unset( $data[ $key ] );
+ }
+
+ // Some coupon properties have changed from accepting 'no' and 'yes' to true and false args. We need to change them into the correct format
+ if ( is_bool( $value ) && in_array( $key, array( 'individual_use', 'free_shipping', 'exclude_sale_items' ) ) ) {
+ $data[ $key ] = ( true == $value ) ? 'yes' : 'no';
+ }
+ }
+ }
}
}
}
+
return $data;
}
@@ -794,7 +862,7 @@ class WCS_Cart_Renewal {
if ( ! empty( $renewal_coupons ) ) {
foreach ( $renewal_coupons as $subscription_id => $coupons ) {
foreach ( $coupons as $coupon ) {
- WC()->cart->remove_coupons( $coupon->code );
+ WC()->cart->remove_coupons( wcs_get_coupon_property( $coupon, 'code' ) );
}
}
}
@@ -868,7 +936,8 @@ class WCS_Cart_Renewal {
* @since 2.0.14
*/
protected function set_cart_hash( $order_id ) {
- update_post_meta( $order_id, '_cart_hash', md5( json_encode( wc_clean( WC()->cart->get_cart_for_session() ) ) . WC()->cart->total ) );
+ $order = wc_get_order( $order_id );
+ wcs_set_objects_property( $order, 'cart_hash', md5( json_encode( wc_clean( WC()->cart->get_cart_for_session() ) ) . WC()->cart->total ) );
}
/**
@@ -907,24 +976,12 @@ class WCS_Cart_Renewal {
return $redirect;
}
- /**
- * After updating renewal order line items, update the values stored in cart item data
- * which would now reference old line item IDs.
- *
- * @since 2.1.3
- */
- public function update_line_item_cart_data( $item_id, $cart_item_data, $cart_item_key ) {
-
- if ( isset( $cart_item_data[ $this->cart_item_key ] ) ) {
- // Update the line_item_id to the new corresponding item_id
- WC()->cart->cart_contents[ $cart_item_key ][ $this->cart_item_key ]['line_item_id'] = $item_id;
- }
- }
-
/**
* Force an update to the session cart after updating renewal order line items.
- * This is required so that changes made by @see WCS_Cart_Renewal->update_line_item_cart_data()
- * are also reflected in the session cart.
+ *
+ * This is required so that changes made by @see WCS_Cart_Renewal->add_line_item_meta() (or @see
+ * WCS_Cart_Renewal->update_line_item_cart_data() for WC < 3.0), are also reflected
+ * in the session cart.
*
* @since 2.1.3
*/
@@ -954,6 +1011,76 @@ class WCS_Cart_Renewal {
return $adjust_price;
}
+ /**
+ * For order items created as part of a renewal, keep a record of the cart item key so that we can match it
+ * later in @see this->set_order_item_id() once the order item has been saved and has an ID.
+ *
+ * Attached to WC 3.0+ hooks and uses WC 3.0 methods.
+ *
+ * @param WC_Order_Item_Product $order_item
+ * @param string $cart_item_key The hash used to identify the item in the cart
+ * @param array $cart_item The cart item's data.
+ * @since 2.2.0
+ */
+ public function add_line_item_meta( $order_item, $cart_item_key, $cart_item ) {
+ if ( isset( $cart_item[ $this->cart_item_key ] ) ) {
+ // Store the cart item key on the line item so that we can link it later on to the order line item ID
+ $order_item->add_meta_data( '_cart_item_key_' . $this->cart_item_key, $cart_item_key );
+ }
+ }
+
+ /**
+ * After order meta is saved, get the order line item ID for this renewal and keep a record of it in
+ * the cart so we can update it later.
+ *
+ * @param int $order_id
+ * @param array $checkout_posted_data
+ * @since 2.2.1
+ */
+ public function set_order_item_id( $order_id, $posted_checkout_data ) {
+
+ $order = wc_get_order( $order_id );
+
+ foreach ( $order->get_items( 'line_item' ) as $order_item_id => $order_item ) {
+
+ $cart_item_key = $order_item->get_meta( '_cart_item_key_' . $this->cart_item_key );
+
+ if ( ! empty( $cart_item_key ) ) {
+ // Update the line_item_id to the new corresponding item_id
+ $this->set_cart_item_order_item_id( $cart_item_key, $order_item_id );
+ }
+ }
+ }
+
+ /**
+ * After updating renewal order line items, update the values stored in cart item data
+ * which would now reference old line item IDs.
+ *
+ * Used when WC 3.0 or newer is active. When prior versions are active,
+ * @see WCS_Cart_Renewal->update_line_item_cart_data()
+ *
+ * @param string $cart_item_key
+ * @param int $order_item_id
+ * @since 2.2.1
+ */
+ protected function set_cart_item_order_item_id( $cart_item_key, $order_item_id ) {
+ WC()->cart->cart_contents[ $cart_item_key ][ $this->cart_item_key ]['line_item_id'] = $order_item_id;
+ }
+
+ /**
+ * Do not display cart item key order item meta keys unless Subscriptions is in debug mode.
+ *
+ * @since 2.2.1
+ */
+ public function hidden_order_itemmeta( $hidden_meta_keys ) {
+
+ if ( apply_filters( 'woocommerce_subscriptions_hide_itemmeta', ! defined( 'WCS_DEBUG' ) || true !== WCS_DEBUG ) ) {
+ $hidden_meta_keys[] = '_cart_item_key_' . $this->cart_item_key;
+ }
+
+ return $hidden_meta_keys;
+ }
+
/* Deprecated */
/**
@@ -985,5 +1112,38 @@ class WCS_Cart_Renewal {
public function maybe_add_subscription_fees( $cart ) {
_deprecated_function( __METHOD__, '2.0.13', __CLASS__ .'::maybe_add_fees()' );
}
+
+ /**
+ * After updating renewal order line items, update the values stored in cart item data
+ * which would now reference old line item IDs.
+ *
+ * @since 2.1.3
+ */
+ public function update_line_item_cart_data( $item_id, $cart_item_data, $cart_item_key ) {
+
+ if ( false === WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ _deprecated_function( __METHOD__, '2.2.0 and WooCommerce 3.0', __CLASS__ . '::add_line_item_meta( $order_item, $cart_item_key, $cart_item )' );
+ }
+
+ if ( isset( $cart_item_data[ $this->cart_item_key ] ) ) {
+ // Update the line_item_id to the new corresponding item_id
+ WC()->cart->cart_contents[ $cart_item_key ][ $this->cart_item_key ]['line_item_id'] = $item_id;
+ }
+ }
+
+ /**
+ * After updating renewal order line items, update the values stored in cart item data
+ * which would now reference old line item IDs.
+ *
+ * Used when WC 3.0 or newer is active. When prior versions are active,
+ * @see WCS_Cart_Renewal->update_line_item_cart_data()
+ *
+ * @deprecated 2.2.1
+ * @since 2.2.0
+ */
+ public function update_order_item_data_in_cart( $order_item, $cart_item_key, $cart_item ) {
+ _deprecated_function( __METHOD__, '2.2.1', __CLASS__ . '::add_line_item_meta( $order_item, $cart_item_key, $cart_item )' );
+ $this->add_line_item_meta( $order_item, $cart_item_key, $cart_item );
+ }
}
new WCS_Cart_Renewal();
diff --git a/includes/class-wcs-cart-resubscribe.php b/includes/class-wcs-cart-resubscribe.php
index 1280239..8bc0b2b 100644
--- a/includes/class-wcs-cart-resubscribe.php
+++ b/includes/class-wcs-cart-resubscribe.php
@@ -65,7 +65,7 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal {
$subscription = wcs_get_subscription( $_GET['resubscribe'] );
$redirect_to = get_permalink( wc_get_page_id( 'myaccount' ) );
- if ( wp_verify_nonce( $_GET['_wpnonce'], $subscription->id ) === false ) {
+ if ( wp_verify_nonce( $_GET['_wpnonce'], $subscription->get_id() ) === false ) {
wc_add_notice( __( 'There was an error with your request to resubscribe. Please try again.', 'woocommerce-subscriptions' ), 'error' );
@@ -73,7 +73,7 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal {
wc_add_notice( __( 'That subscription does not exist. Has it been deleted?', 'woocommerce-subscriptions' ), 'error' );
- } elseif ( ! current_user_can( 'subscribe_again', $subscription->id ) ) {
+ } elseif ( ! current_user_can( 'subscribe_again', $subscription->get_id() ) ) {
wc_add_notice( __( 'That doesn\'t appear to be one of your subscriptions.', 'woocommerce-subscriptions' ), 'error' );
@@ -84,7 +84,7 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal {
} else {
$this->setup_cart( $subscription, array(
- 'subscription_id' => $subscription->id,
+ 'subscription_id' => $subscription->get_id(),
) );
if ( WC()->cart->get_cart_contents_count() != 0 ) {
@@ -103,7 +103,7 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal {
$order = wc_get_order( $wp->query_vars['order-pay'] );
$order_key = $_GET['key'];
- if ( $order->order_key == $order_key && $order->has_status( array( 'pending', 'failed' ) ) && wcs_order_contains_resubscribe( $order ) ) {
+ if ( wcs_get_objects_property( $order, 'order_key' ) == $order_key && $order->has_status( array( 'pending', 'failed' ) ) && wcs_order_contains_resubscribe( $order ) ) {
if ( ! is_user_logged_in() ) {
@@ -121,9 +121,9 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal {
$subscriptions = wcs_get_subscriptions_for_resubscribe_order( $order );
foreach ( $subscriptions as $subscription ) {
- if ( current_user_can( 'subscribe_again', $subscription->id ) ) {
+ if ( current_user_can( 'subscribe_again', $subscription->get_id() ) ) {
$this->setup_cart( $subscription, array(
- 'subscription_id' => $subscription->id,
+ 'subscription_id' => $subscription->get_id(),
) );
} else {
wc_add_notice( __( 'That doesn\'t appear to be one of your subscriptions.', 'woocommerce-subscriptions' ), 'error' );
@@ -150,8 +150,9 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal {
$cart_item = $this->cart_contains( $recurring_cart );
if ( false !== $cart_item ) {
- update_post_meta( $order->id, '_subscription_resubscribe', $cart_item[ $this->cart_item_key ]['subscription_id'], true );
- update_post_meta( $new_subscription->id, '_subscription_resubscribe', $cart_item[ $this->cart_item_key ]['subscription_id'], true );
+ wcs_set_objects_property( $order, 'subscription_resubscribe', $cart_item[ $this->cart_item_key ]['subscription_id'] );
+ $new_subscription->update_meta_data( '_subscription_resubscribe', $cart_item[ $this->cart_item_key ]['subscription_id'] );
+ $new_subscription->save();
}
}
@@ -170,12 +171,12 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal {
$subscription = wcs_get_subscription( $cart_item[ $this->cart_item_key ]['subscription_id'] );
if ( $subscription ) {
// Make sure the original subscription terms perisist
- $_product = $cart_item_session_data['data'];
- $_product->subscription_period = $subscription->billing_period;
- $_product->subscription_period_interval = $subscription->billing_interval;
+ $_product = $cart_item_session_data['data'];
+ wcs_set_objects_property( $_product, 'subscription_period', $subscription->get_billing_period(), 'set_prop_only' );
+ wcs_set_objects_property( $_product, 'subscription_period_interval', $subscription->get_billing_interval(), 'set_prop_only' );
// And don't give another free trial period
- $_product->subscription_trial_length = 0;
+ wcs_set_objects_property( $_product, 'subscription_trial_length', 0, 'set_prop_only' );
}
}
@@ -254,7 +255,7 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal {
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$subscription = $this->get_order( $cart_item );
if ( false !== $subscription && $subscription->has_status( 'pending-cancel' ) ) {
- $first_renewal_date = ( '1' != $cart_item['data']->subscription_length ) ? $subscription->get_date( 'end' ) : 0;
+ $first_renewal_date = ( '1' != WC_Subscriptions_Product::get_length( $cart_item['data'] ) ) ? $subscription->get_date( 'end' ) : 0;
break;
}
}
@@ -271,7 +272,7 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal {
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$subscription = $this->get_order( $cart_item );
if ( false !== $subscription && $subscription->has_status( 'pending-cancel' ) ) {
- WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_trial_length = 1;
+ wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_trial_length', 1, 'set_prop_only' );
break;
}
}
@@ -289,7 +290,7 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal {
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$subscription = $this->get_order( $cart_item );
if ( false !== $subscription && $subscription->has_status( 'pending-cancel' ) ) {
- WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_trial_length = 0;
+ wcs_set_objects_property( WC()->cart->cart_contents[ $cart_item_key ]['data'], 'subscription_trial_length', 0, 'set_prop_only' );
break;
}
}
diff --git a/includes/class-wcs-cart-switch.php b/includes/class-wcs-cart-switch.php
index 453f219..2c6b56c 100644
--- a/includes/class-wcs-cart-switch.php
+++ b/includes/class-wcs-cart-switch.php
@@ -2,11 +2,13 @@
/**
* Subscriptions switching cart
*
- *
* @author Prospress
* @since 2.1
*/
-class WCS_Cart_Switch extends WCS_Cart_Renewal{
+class WCS_Cart_Switch extends WCS_Cart_Renewal {
+
+ /* The flag used to indicate if a cart item is a renewal */
+ public $cart_item_key = 'subscription_switch';
/**
* Initialise class hooks & filters when the file is loaded
@@ -15,6 +17,9 @@ class WCS_Cart_Switch extends WCS_Cart_Renewal{
*/
public function __construct() {
+ // Attach hooks which depend on WooCommerce constants
+ add_action( 'woocommerce_loaded', array( &$this, 'attach_dependant_hooks' ), 10 );
+
// Set checkout payment URL parameter for subscription switch orders
add_filter( 'woocommerce_get_checkout_payment_url', array( &$this, 'get_checkout_payment_url' ), 10, 2 );
@@ -30,7 +35,7 @@ class WCS_Cart_Switch extends WCS_Cart_Renewal{
public function get_checkout_payment_url( $pay_url, $order ) {
if ( wcs_order_contains_switch( $order ) ) {
- $switch_order_data = get_post_meta( $order->id, '_subscription_switch_data', true );
+ $switch_order_data = wcs_get_objects_property( $order, 'subscription_switch_data' );
if ( ! empty( $switch_order_data ) ) {
$pay_url = add_query_arg( array(
@@ -51,7 +56,6 @@ class WCS_Cart_Switch extends WCS_Cart_Renewal{
* @since 2.1
*/
public function maybe_setup_cart() {
-
global $wp;
if ( isset( $_GET['pay_for_order'] ) && isset( $_GET['key'] ) && isset( $wp->query_vars['order-pay'] ) && isset( $_GET['subscription_switch'] ) ) {
@@ -61,10 +65,10 @@ class WCS_Cart_Switch extends WCS_Cart_Renewal{
$order_id = ( isset( $wp->query_vars['order-pay'] ) ) ? $wp->query_vars['order-pay'] : absint( $_GET['order_id'] );
$order = wc_get_order( $wp->query_vars['order-pay'] );
- if ( $order->order_key == $order_key && $order->has_status( array( 'pending', 'failed' ) ) && wcs_order_contains_switch( $order ) ) {
+ if ( wcs_get_objects_property( $order, 'order_key' ) == $order_key && $order->has_status( array( 'pending', 'failed' ) ) && wcs_order_contains_switch( $order ) ) {
WC()->cart->empty_cart( true );
- $switch_order_data = get_post_meta( $order_id, '_subscription_switch_data', true );
+ $switch_order_data = wcs_get_objects_property( $order, 'subscription_switch_data' );
foreach ( $order->get_items() as $item_id => $line_item ) {
@@ -88,28 +92,28 @@ class WCS_Cart_Switch extends WCS_Cart_Renewal{
$order_item = wcs_get_order_item( $item_id, $order );
$product = WC_Subscriptions::get_product( wcs_get_canonical_product_id( $order_item ) );
+ $product_id = $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id();
$order_product_data = array(
- '_qty' => 0,
- '_variation_id' => '',
+ '_qty' => (int) $line_item['qty'],
+ '_variation_id' => (int) $line_item['variation_id'],
);
$variations = array();
foreach ( $order_item['item_meta'] as $meta_key => $meta_value ) {
+ $meta_value = is_array( $meta_value ) ? $meta_value[0] : $meta_value; // In WC 3.0 the meta values are no longer arrays
- if ( taxonomy_is_product_attribute( $meta_key ) || meta_is_product_attribute( $meta_key, $meta_value[0], $product->id ) ) {
- $variations[ $meta_key ] = $meta_value[0];
- $_POST[ 'attribute_' . $meta_key ] = $meta_value[0];
- } else if ( array_key_exists( $meta_key, $order_product_data ) ) {
- $order_product_data[ $meta_key ] = (int) $meta_value[0];
+ if ( taxonomy_is_product_attribute( $meta_key ) || meta_is_product_attribute( $meta_key, $meta_value, $product_id ) ) {
+ $variations[ $meta_key ] = $meta_value;
+ $_POST[ 'attribute_' . $meta_key ] = $meta_value;
}
}
- $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product->id, $order_product_data['_qty'], $order_product_data['_variation_id'] );
+ $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $order_product_data['_qty'], $order_product_data['_variation_id'] );
if ( $passed_validation ) {
- $cart_item_key = WC()->cart->add_to_cart( $product->id, $order_product_data['_qty'], $order_product_data['_variation_id'], $variations, array() );
+ $cart_item_key = WC()->cart->add_to_cart( $product_id, $order_product_data['_qty'], $order_product_data['_variation_id'], $variations, array() );
}
}
}
@@ -121,5 +125,26 @@ class WCS_Cart_Switch extends WCS_Cart_Renewal{
exit;
}
}
+
+ /**
+ * Store the order line item id so it can be retrieved when we're processing the switch on checkout.
+ *
+ * @param string $cart_item_key
+ * @param int $order_item_id
+ * @since 2.2.1
+ */
+ protected function set_cart_item_order_item_id( $cart_item_key, $order_item_id ) {
+
+ foreach ( WC()->cart->recurring_carts as $recurring_cart_key => $recurring_cart ) {
+
+ // If this cart item belongs to this recurring cart
+ if ( in_array( $cart_item_key, array_keys( $recurring_cart->cart_contents ) ) && isset( WC()->cart->recurring_carts[ $recurring_cart_key ]->cart_contents[ $cart_item_key ][ $this->cart_item_key ] ) ) {
+
+ WC()->cart->recurring_carts[ $recurring_cart_key ]->cart_contents[ $cart_item_key ][ $this->cart_item_key ]['order_line_item_id'] = $order_item_id;
+
+ wc_add_order_item_meta( WC()->cart->recurring_carts[ $recurring_cart_key ]->cart_contents[ $cart_item_key ][ $this->cart_item_key ]['item_id'], '_switched_subscription_new_item_id', $order_item_id, true );
+ }
+ }
+ }
}
new WCS_Cart_Switch();
diff --git a/includes/class-wcs-change-payment-method-admin.php b/includes/class-wcs-change-payment-method-admin.php
index 7bd8e95..67aabfc 100644
--- a/includes/class-wcs-change-payment-method-admin.php
+++ b/includes/class-wcs-change-payment-method-admin.php
@@ -19,7 +19,7 @@ class WCS_Change_Payment_Method_Admin {
*/
public static function display_fields( $subscription ) {
- $payment_method = ! empty( $subscription->payment_method ) ? $subscription->payment_method : '';
+ $payment_method = $subscription->get_payment_method();
$valid_payment_methods = self::get_valid_payment_methods( $subscription );
if ( ! $subscription->is_manual() && ! isset( $valid_payment_methods[ $payment_method ] ) ) {
@@ -129,7 +129,7 @@ class WCS_Change_Payment_Method_Admin {
$payment_gateway = ( 'manual' != $payment_method ) ? $payment_gateways[ $payment_method ] : '';
- if ( ! $subscription->is_manual() && property_exists( $subscription->payment_gateway, 'id' ) && ( '' == $payment_gateway || ( $subscription->payment_gateway->id != $payment_gateway->id ) ) ) {
+ if ( ! $subscription->is_manual() && ( '' == $payment_gateway || $subscription->get_payment_method() != $payment_gateway->id ) ) {
// Before updating to a new payment gateway make sure the subscription status is updated with the current gateway
$gateway_status = apply_filters( 'wcs_gateway_status_payment_changed', 'cancelled', $subscription, $payment_gateway );
@@ -137,6 +137,7 @@ class WCS_Change_Payment_Method_Admin {
}
$subscription->set_payment_method( $payment_gateway, $payment_method_meta );
+ $subscription->save();
}
/**
@@ -158,7 +159,7 @@ class WCS_Change_Payment_Method_Admin {
foreach ( $available_gateways as $gateway_id => $gateway ) {
- if ( $gateway->supports( 'subscription_payment_method_change_admin' ) && 'no' == get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no' ) || ( ! $subscription->is_manual() && $gateway_id == $subscription->payment_method ) ) {
+ if ( $gateway->supports( 'subscription_payment_method_change_admin' ) && 'no' == get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no' ) || ( ! $subscription->is_manual() && $gateway_id == $subscription->get_payment_method() ) ) {
$valid_gateways[ $gateway_id ] = $gateway->get_title();
}
diff --git a/includes/class-wcs-download-handler.php b/includes/class-wcs-download-handler.php
index 3b7eb82..d031fb3 100644
--- a/includes/class-wcs-download-handler.php
+++ b/includes/class-wcs-download-handler.php
@@ -50,7 +50,7 @@ class WCS_Download_Handler {
*/
public static function maybe_revoke_immediate_access( $grant_access, $download_id, $product_id, $order ) {
- if ( 'yes' == get_option( WC_Subscriptions_Admin::$option_prefix . '_drip_downloadable_content_on_renewal', 'no' ) && ( wcs_is_subscription( $order->id ) || wcs_order_contains_subscription( $order, 'any' ) ) ) {
+ if ( 'yes' == get_option( WC_Subscriptions_Admin::$option_prefix . '_drip_downloadable_content_on_renewal', 'no' ) && ( wcs_is_subscription( wcs_get_objects_property( $order, 'id' ) ) || wcs_order_contains_subscription( $order, 'any' ) ) ) {
$grant_access = false;
}
return $grant_access;
@@ -79,20 +79,20 @@ class WCS_Download_Handler {
$_product = $subscription->get_product_from_item( $item );
if ( $_product && $_product->exists() && $_product->is_downloadable() ) {
- $downloads = $_product->get_files();
+ $downloads = wcs_get_objects_property( $_product, 'downloads' );
$product_id = wcs_get_canonical_product_id( $item );
foreach ( array_keys( $downloads ) as $download_id ) {
// grant access on subscription if it does not already exist
- if ( ! $wpdb->get_var( $wpdb->prepare( "SELECT download_id FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE `order_id` = %d AND `product_id` = %d AND `download_id` = '%s'", $subscription->id, $product_id, $download_id ) ) ) {
+ if ( ! $wpdb->get_var( $wpdb->prepare( "SELECT download_id FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE `order_id` = %d AND `product_id` = %d AND `download_id` = '%s'", $subscription->get_id(), $product_id, $download_id ) ) ) {
wc_downloadable_file_permission( $download_id, $product_id, $subscription, $item['qty'] );
}
- self::revoke_downloadable_file_permission( $product_id, $order_id, $order->user_id );
+ self::revoke_downloadable_file_permission( $product_id, $order_id, $order->get_user_id() );
}
}
}
}
- update_post_meta( $subscription->id, '_download_permissions_granted', 1 );
+ update_post_meta( $subscription->get_id(), '_download_permissions_granted', 1 );
}
}
@@ -147,7 +147,11 @@ class WCS_Download_Handler {
foreach ( $subscriptions as $subscription ) {
foreach ( $subscription->get_items() as $subscription_item ) {
if ( wcs_get_canonical_product_id( $subscription_item ) === $product_id ) {
- $files = $subscription->get_item_downloads( $subscription_item );
+ if ( is_callable( array( $subscription_item, 'get_item_downloads' ) ) ) { // WC 3.0+
+ $files = $subscription_item->get_item_downloads( $subscription_item );
+ } else { // WC < 3.0
+ $files = $subscription->get_item_downloads( $subscription_item );
+ }
}
}
}
@@ -195,7 +199,7 @@ class WCS_Download_Handler {
/**
* Grant downloadable file access to any newly added files on any existing subscriptions
- * which don't have existing permissions.
+ * which don't have existing permissions pre WC3.0 and all subscriptions post WC3.0.
*
* @param int $product_id
* @param int $variation_id
@@ -207,7 +211,7 @@ class WCS_Download_Handler {
$product_id = ( $variation_id ) ? $variation_id : $product_id;
$product = wc_get_product( $product_id );
- $existing_download_ids = array_keys( (array) $product->get_files() );
+ $existing_download_ids = array_keys( (array) wcs_get_objects_property( $product, 'downloads' ) );
$downloadable_ids = array_keys( (array) $downloadable_files );
$new_download_ids = array_filter( array_diff( $downloadable_ids, $existing_download_ids ) );
@@ -218,8 +222,8 @@ class WCS_Download_Handler {
foreach ( $subscriptions as $subscription_id ) {
- // only grant permissions to subscriptions which have no permissions for this product
- if ( ! in_array( $subscription_id, $existing_permissions ) ) {
+ // Grant permissions to subscriptions which have no permissions for this product, pre WC3.0, or all subscriptions, post WC3.0, as WC doesn't grant them retrospectively anymore.
+ if ( ! in_array( $subscription_id, $existing_permissions ) || false === WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
$subscription = wcs_get_subscription( $subscription_id );
foreach ( $new_download_ids as $download_id ) {
diff --git a/includes/class-wcs-limiter.php b/includes/class-wcs-limiter.php
index e6249bc..8bb8716 100644
--- a/includes/class-wcs-limiter.php
+++ b/includes/class-wcs-limiter.php
@@ -75,9 +75,11 @@ class WCS_Limiter {
}
break;
case 'subscription_variation' :
- if ( 'no' != wcs_get_product_limitation( $product->parent ) && ! empty( WC()->cart->cart_contents ) && ! wcs_is_order_received_page() && ! wcs_is_paypal_api_page() ) {
+ $variable_product = wc_get_product( $product->get_parent_id() );
+ if ( 'no' != wcs_get_product_limitation( $variable_product ) && ! empty( WC()->cart->cart_contents ) && ! wcs_is_order_received_page() && ! wcs_is_paypal_api_page() ) {
foreach ( WC()->cart->cart_contents as $cart_item ) {
- if ( $product->id == $cart_item['data']->id && $product->variation_id != $cart_item['data']->variation_id ) {
+ // If the variable product is limited, it can't be purchased if its the same variation
+ if ( $product->get_parent_id() == wcs_get_objects_property( $cart_item['data'], 'parent_id' ) && $product->get_id() != $cart_item['data']->get_id() ) {
$purchasable = false;
break;
}
@@ -98,21 +100,21 @@ class WCS_Limiter {
public static function is_purchasable_product( $is_purchasable, $product ) {
//Set up cache
- if ( ! isset( self::$is_purchasable_cache[ $product->id ] ) ) {
- self::$is_purchasable_cache[ $product->id ] = array();
+ if ( ! isset( self::$is_purchasable_cache[ $product->get_id() ] ) ) {
+ self::$is_purchasable_cache[ $product->get_id() ] = array();
}
- if ( ! isset( self::$is_purchasable_cache[ $product->id ]['standard'] ) ) {
- self::$is_purchasable_cache[ $product->id ]['standard'] = $is_purchasable;
+ if ( ! isset( self::$is_purchasable_cache[ $product->get_id() ]['standard'] ) ) {
+ self::$is_purchasable_cache[ $product->get_id() ]['standard'] = $is_purchasable;
- if ( WC_Subscriptions_Product::is_subscription( $product->id ) && 'no' != wcs_get_product_limitation( $product ) && ! wcs_is_order_received_page() && ! wcs_is_paypal_api_page() ) {
+ if ( WC_Subscriptions_Product::is_subscription( $product->get_id() ) && 'no' != wcs_get_product_limitation( $product ) && ! wcs_is_order_received_page() && ! wcs_is_paypal_api_page() ) {
- if ( wcs_is_product_limited_for_user( $product ) && ! self::order_awaiting_payment_for_product( $product->id ) ) {
- self::$is_purchasable_cache[ $product->id ]['standard'] = false;
+ if ( wcs_is_product_limited_for_user( $product ) && ! self::order_awaiting_payment_for_product( $product->get_id() ) ) {
+ self::$is_purchasable_cache[ $product->get_id() ]['standard'] = false;
}
}
}
- return self::$is_purchasable_cache[ $product->id ]['standard'];
+ return self::$is_purchasable_cache[ $product->get_id() ]['standard'];
}
@@ -132,7 +134,7 @@ class WCS_Limiter {
if ( ! isset( self::$is_purchasable_cache[ $product_key ]['switch'] ) ) {
- if ( false === $is_purchasable && wcs_is_product_switchable_type( $product ) && WC_Subscriptions_Product::is_subscription( $product->id ) && 'no' != wcs_get_product_limitation( $product ) && is_user_logged_in() && wcs_user_has_subscription( 0, $product->id, wcs_get_product_limitation( $product ) ) ) {
+ if ( false === $is_purchasable && wcs_is_product_switchable_type( $product ) && WC_Subscriptions_Product::is_subscription( $product->get_id() ) && 'no' != wcs_get_product_limitation( $product ) && is_user_logged_in() && wcs_user_has_subscription( 0, $product->get_id(), wcs_get_product_limitation( $product ) ) ) {
//Adding to cart
if ( isset( $_GET['switch-subscription'] ) ) {
@@ -146,7 +148,7 @@ class WCS_Limiter {
} elseif ( isset( WC()->session->cart ) ) {
foreach ( WC()->session->cart as $cart_item_key => $cart_item ) {
- if ( $product->id == $cart_item['product_id'] && isset( $cart_item['subscription_switch'] ) ) {
+ if ( $product->get_id() == $cart_item['product_id'] && isset( $cart_item['subscription_switch'] ) ) {
$is_purchasable = true;
break;
}
@@ -172,7 +174,7 @@ class WCS_Limiter {
$subscription_id = ( isset( $_GET['resubscribe'] ) ) ? absint( $_GET['resubscribe'] ) : $resubscribe_cart_item['subscription_resubscribe']['subscription_id'];
$subscription = wcs_get_subscription( $subscription_id );
- if ( false != $subscription && $subscription->has_product( $product->id ) && wcs_can_user_resubscribe_to( $subscription ) ) {
+ if ( false != $subscription && $subscription->has_product( $product->get_id() ) && wcs_can_user_resubscribe_to( $subscription ) ) {
$is_purchasable = true;
}
@@ -183,7 +185,7 @@ class WCS_Limiter {
// Restoring cart from session, so need to check the cart in the session (wcs_cart_contains_renewal() only checks the cart)
} elseif ( WC()->session->cart ) {
foreach ( WC()->session->cart as $cart_item_key => $cart_item ) {
- if ( $product->id == $cart_item['product_id'] && ( isset( $cart_item['subscription_renewal'] ) || isset( $cart_item['subscription_resubscribe'] ) ) ) {
+ if ( $product->get_id() == $cart_item['product_id'] && ( isset( $cart_item['subscription_renewal'] ) || isset( $cart_item['subscription_resubscribe'] ) ) ) {
$is_purchasable = true;
break;
}
@@ -216,7 +218,7 @@ class WCS_Limiter {
if ( $item['product_id'] == $product_id || $item['variation_id'] == $product_id ) {
$subscriptions = wcs_get_subscriptions( array(
- 'order_id' => $order->id,
+ 'order_id' => wcs_get_objects_property( $order, 'id' ),
'product_id' => $product_id,
) );
diff --git a/includes/class-wcs-remove-item.php b/includes/class-wcs-remove-item.php
index 86e0c67..fcf5e4e 100644
--- a/includes/class-wcs-remove-item.php
+++ b/includes/class-wcs-remove-item.php
@@ -76,7 +76,7 @@ class WCS_Remove_Item {
// handle undo request
$removed_item = WC()->session->get( 'removed_subscription_items', array() );
- if ( ! empty( $removed_item[ $item_id ] ) && $subscription->id == $removed_item[ $item_id ] ) {
+ if ( ! empty( $removed_item[ $item_id ] ) && $subscription->get_id() == $removed_item[ $item_id ] ) {
// restore the item
wc_update_order_item( $item_id, array( 'order_item_type' => 'line_item' ) );
@@ -85,6 +85,7 @@ class WCS_Remove_Item {
WC()->session->set( 'removed_subscription_items', $removed_item );
// restore download permissions for this item
+ $subscription = wcs_get_subscription( $subscription->get_id() );
$line_items = $subscription->get_items();
$line_item = $line_items[ $item_id ];
$_product = $subscription->get_product_from_item( $line_item );
@@ -92,7 +93,7 @@ class WCS_Remove_Item {
if ( $_product && $_product->exists() && $_product->is_downloadable() ) {
- $downloads = $_product->get_files();
+ $downloads = wcs_get_objects_property( $_product, 'downloads' );
foreach ( array_keys( $downloads ) as $download_id ) {
wc_downloadable_file_permission( $download_id, $product_id, $subscription, $line_item['qty'] );
@@ -108,14 +109,14 @@ class WCS_Remove_Item {
} else {
// handle remove item requests
- WC()->session->set( 'removed_subscription_items', array( $item_id => $subscription->id ) );
+ WC()->session->set( 'removed_subscription_items', array( $item_id => $subscription->get_id() ) );
// remove download access for the item
$line_items = $subscription->get_items();
$line_item = $line_items[ $item_id ];
$product_id = wcs_get_canonical_product_id( $line_item );
- WCS_Download_Handler::revoke_downloadable_file_permission( $product_id, $subscription->id, $subscription->get_user_id() );
+ WCS_Download_Handler::revoke_downloadable_file_permission( $product_id, $subscription->get_id(), $subscription->get_user_id() );
// remove the line item from subscription but preserve its data in the DB
wc_update_order_item( $item_id, array( 'order_item_type' => 'line_item_removed' ) );
@@ -124,10 +125,15 @@ class WCS_Remove_Item {
$subscription->add_order_note( sprintf( _x( 'Customer removed "%1$s" (Product ID: #%2$d) via the My Account page.', 'used in order note', 'woocommerce-subscriptions' ), wcs_get_line_item_name( $line_item ), $product_id ) );
// translators: placeholders are 1$: item name, and, 2$: opening and, 3$: closing link tags
- wc_add_notice( sprintf( __( 'You have successfully removed "%1$s" from your subscription. %2$sUndo?%3$s', 'woocommerce-subscriptions' ), $line_item['name'], '', '' ) );
+ wc_add_notice( sprintf( __( 'You have successfully removed "%1$s" from your subscription. %2$sUndo?%3$s', 'woocommerce-subscriptions' ), $line_item['name'], '', '' ) );
}
}
+ /**
+ * In WooCommerce 3.0 the subscription object and its items override the database with their current content,
+ * so we lost the changes we just did with `wc_update_order_item`. Re-reading the object fixes this problem.
+ */
+ $subscription = wcs_get_subscription( $subscription->get_id() );
$subscription->calculate_totals();
wp_safe_redirect( $subscription->get_view_order_url() );
exit;
@@ -155,7 +161,7 @@ class WCS_Remove_Item {
wc_add_notice( __( 'Security error. Please contact us if you need assistance.', 'woocommerce-subscriptions' ), 'error' );
- } elseif ( ! current_user_can( 'edit_shop_subscription_line_items', $subscription->id ) ) {
+ } elseif ( ! current_user_can( 'edit_shop_subscription_line_items', $subscription->get_id() ) ) {
wc_add_notice( __( 'You cannot modify a subscription that does not belong to you.', 'woocommerce-subscriptions' ), 'error' );
diff --git a/includes/class-wcs-retry-manager.php b/includes/class-wcs-retry-manager.php
index 907cdb1..b5b12ec 100644
--- a/includes/class-wcs-retry-manager.php
+++ b/includes/class-wcs-retry-manager.php
@@ -134,7 +134,7 @@ class WCS_Retry_Manager {
if ( $subscription->get_date( 'payment_retry' ) > 0 ) {
$last_order = $subscription->get_last_order( 'all' );
- $last_retry = ( $last_order ) ? self::store()->get_last_retry_for_order( $last_order->id ) : null;
+ $last_retry = ( $last_order ) ? self::store()->get_last_retry_for_order( wcs_get_objects_property( $last_order, 'id' ) ) : null;
if ( null !== $last_retry && 'cancelled' !== $last_retry->get_status() && null !== ( $last_retry_rule = $last_retry->get_rule() ) ) {
@@ -206,17 +206,17 @@ class WCS_Retry_Manager {
return;
}
- $retry_count = self::store()->get_retry_count_for_order( $last_order->id );
+ $retry_count = self::store()->get_retry_count_for_order( wcs_get_objects_property( $last_order, 'id' ) );
- if ( self::rules()->has_rule( $retry_count, $last_order->id ) ) {
+ if ( self::rules()->has_rule( $retry_count, wcs_get_objects_property( $last_order, 'id' ) ) ) {
- $retry_rule = self::rules()->get_rule( $retry_count, $last_order->id );
+ $retry_rule = self::rules()->get_rule( $retry_count, wcs_get_objects_property( $last_order, 'id' ) );
do_action( 'woocommerce_subscriptions_before_apply_retry_rule', $retry_rule, $last_order, $subscription );
$retry_id = self::store()->save( new WCS_Retry( array(
'status' => 'pending',
- 'order_id' => $last_order->id,
+ 'order_id' => wcs_get_objects_property( $last_order, 'id' ),
'date_gmt' => gmdate( 'Y-m-d H:i:s', gmdate( 'U' ) + $retry_rule->get_retry_interval() ),
'rule_raw' => $retry_rule->get_raw_data(),
) ) );
@@ -257,7 +257,7 @@ class WCS_Retry_Manager {
}
$subscriptions = wcs_get_subscriptions_for_renewal_order( $last_order );
- $last_retry = self::store()->get_last_retry_for_order( $last_order->id );
+ $last_retry = self::store()->get_last_retry_for_order( wcs_get_objects_property( $last_order, 'id' ) );
// we only need to retry the payment if we have applied a retry rule for the order and it still needs payment
if ( null !== $last_retry && 'pending' === $last_retry->get_status() ) {
@@ -302,7 +302,7 @@ class WCS_Retry_Manager {
WC_Subscriptions_Payment_Gateways::trigger_gateway_renewal_payment_hook( $last_order );
// Now that we've attempted to process the payment, refresh the order
- $last_order = wc_get_order( $last_order->id );
+ $last_order = wc_get_order( wcs_get_objects_property( $last_order, 'id' ) );
// if the order still needs payment, payment failed
if ( $last_order->needs_payment() ) {
diff --git a/includes/class-wcs-select2.php b/includes/class-wcs-select2.php
new file mode 100644
index 0000000..a0ca10e
--- /dev/null
+++ b/includes/class-wcs-select2.php
@@ -0,0 +1,123 @@
+ 'hidden',
+ 'placeholder' => '',
+ 'class' => '',
+ );
+
+ protected $attributes = array();
+
+ /**
+ * Constructor.
+ *
+ * @param array $attributes The attributes that make up the Select2 element
+ * @since 2.2
+ */
+ public function __construct( array $attributes ) {
+ $this->attributes = array_merge( $this->default_attributes, $attributes );
+ }
+
+ /**
+ * Render a select2 element given an array of attributes.
+ *
+ * @param array $attributes Select2 attributes
+ * @since 2.2
+ */
+ public static function render( array $attributes ) {
+ $select2 = new self( $attributes );
+ $select2->print_html();
+ }
+
+ /**
+ * Get a property name.
+ *
+ * @param string $property
+ * @return string class, name, id or data-$property;
+ * @since 2.2
+ */
+ protected function get_property_name( $property ) {
+ $data_properties = WC_Subscriptions::is_woocommerce_pre( '3.0' ) ? array( 'placeholder', 'selected', 'allow_clear' ) : array( 'placeholder', 'allow_clear' );
+ return in_array( $property, $data_properties ) ? 'data-' . $property : $property;
+ }
+
+ /**
+ * Returns a list of properties/values (HTML) from an array. All the values
+ * are escaped.
+ *
+ * @param $attributes List of HTML attributes with values
+ * @return string
+ * @since 2.2
+ */
+ protected function attributes_to_html( array $attributes ) {
+
+ $html = array();
+
+ foreach ( $attributes as $property => $value ) {
+ if ( ! is_scalar( $value ) ) {
+ $value = wcs_json_encode( $value );
+ }
+
+ $html[] = $this->get_property_name( $property ) . '="' . esc_attr( $value, 'woocommerce-subscriptions' ) . '"';
+ }
+
+ return implode( ' ', $html );
+ }
+
+ /**
+ * Prints the HTML to show the Select2 field.
+ *
+ * @since 2.2
+ */
+ public function print_html() {
+ $allowed_attributes = array_map( array( $this, 'get_property_name' ), array_keys( $this->attributes ) );
+ $allowed_attributes = array_fill_keys( $allowed_attributes, array() );
+
+ echo wp_kses( $this->get_html(), array( 'input' => $allowed_attributes, 'select' => $allowed_attributes, 'option' => $allowed_attributes ) );
+ }
+
+ /**
+ * Returns the HTML needed to show the Select2 field
+ *
+ * @return string
+ * @since 2.2
+ */
+ public function get_html() {
+ $html = "\n\n";
+
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ $html .= 'attributes_to_html( $this->attributes );
+ $html .= '/>';
+ } else {
+ $attributes = $this->attributes;
+ $selected_value = isset( $attributes['selected'] ) ? $attributes['selected'] : '';
+ $attributes['selected'] = 'selected';
+
+ $option_attributes = array_intersect_key( $attributes, array_flip( array( 'value', 'selected' ) ) );
+ $select_attributes = array_diff_key( $attributes, $option_attributes );
+
+ $html .= '';
+ }
+
+ $html .= "\n\n";
+
+ return $html;
+ }
+}
diff --git a/includes/class-wcs-user-change-status-handler.php b/includes/class-wcs-user-change-status-handler.php
index fbbdad0..2161b50 100644
--- a/includes/class-wcs-user-change-status-handler.php
+++ b/includes/class-wcs-user-change-status-handler.php
@@ -95,11 +95,11 @@ class WCS_User_Change_Status_Handler {
WC_Subscriptions::add_notice( __( 'That subscription does not exist. Please contact us if you need assistance.', 'woocommerce-subscriptions' ), 'error' );
return false;
- } elseif ( ! empty( $wpnonce ) && wp_verify_nonce( $wpnonce, $subscription->id . $subscription->get_status() ) === false ) {
+ } elseif ( ! empty( $wpnonce ) && wp_verify_nonce( $wpnonce, $subscription->get_id() . $subscription->get_status() ) === false ) {
WC_Subscriptions::add_notice( __( 'Security error. Please contact us if you need assistance.', 'woocommerce-subscriptions' ), 'error' );
return false;
- } elseif ( ! user_can( $user_id, 'edit_shop_subscription_status', $subscription->id ) ) {
+ } elseif ( ! user_can( $user_id, 'edit_shop_subscription_status', $subscription->get_id() ) ) {
WC_Subscriptions::add_notice( __( 'That doesn\'t appear to be one of your subscriptions.', 'woocommerce-subscriptions' ), 'error' );
return false;
diff --git a/includes/class-wcs-webhooks.php b/includes/class-wcs-webhooks.php
index 132ce51..070a7e0 100644
--- a/includes/class-wcs-webhooks.php
+++ b/includes/class-wcs-webhooks.php
@@ -104,16 +104,31 @@ class WCS_Webhooks {
public static function create_payload( $payload, $resource, $resource_id, $id ) {
if ( 'subscription' == $resource && empty( $payload ) && wcs_is_subscription( $resource_id ) ) {
-
$webhook = new WC_Webhook( $id );
$event = $webhook->get_event();
$current_user = get_current_user_id();
wp_set_current_user( $webhook->get_user_id() );
- WC()->api->WC_API_Subscriptions->register_routes( array() );
+ $webhook_api_version = ( method_exists( $webhook, 'get_api_version' ) ) ? $webhook->get_api_version() : 'legacy_v3';
- $payload = WC()->api->WC_API_Subscriptions->get_subscription( $resource_id );
+ switch ( $webhook_api_version ) {
+ case 'legacy_v3':
+ WC()->api->WC_API_Subscriptions->register_routes( array() );
+ $payload = WC()->api->WC_API_Subscriptions->get_subscription( $resource_id );
+ break;
+ case 'wp_api_v1':
+ case 'wp_api_v2':
+ require_once( 'api/class-wc-rest-subscriptions-controller.php' );
+
+ $request = new WP_REST_Request( 'GET' );
+ $controller = new WC_REST_Subscriptions_Controller;
+
+ $request->set_param( 'id', $resource_id );
+ $result = $controller->get_item( $request );
+ $payload = isset( $result->data ) ? $result->data : array();
+ break;
+ }
wp_set_current_user( $current_user );
}
@@ -154,7 +169,7 @@ class WCS_Webhooks {
* @since 2.0
*/
public static function add_subscription_created_callback( $subscription ) {
- do_action( 'wcs_webhook_subscription_created', $subscription->id );
+ do_action( 'wcs_webhook_subscription_created', $subscription->get_id() );
}
/**
@@ -163,7 +178,7 @@ class WCS_Webhooks {
* @since 2.0
*/
public static function add_subscription_updated_callback( $subscription ) {
- do_action( 'wcs_webhook_subscription_updated', $subscription->id );
+ do_action( 'wcs_webhook_subscription_updated', $subscription->get_id() );
}
/**
diff --git a/includes/data-stores/class-wcs-subscription-data-store-cpt.php b/includes/data-stores/class-wcs-subscription-data-store-cpt.php
new file mode 100644
index 0000000..cd3c799
--- /dev/null
+++ b/includes/data-stores/class-wcs-subscription-data-store-cpt.php
@@ -0,0 +1,262 @@
+ prop_key
+ *
+ * Used to read/update props on the subscription.
+ *
+ * @since 2.2.0
+ * @var array
+ */
+ protected $subscription_meta_keys_to_props = array(
+ '_billing_period' => 'billing_period',
+ '_billing_interval' => 'billing_interval',
+ '_suspension_count' => 'suspension_count',
+ '_cancelled_email_sent' => 'cancelled_email_sent',
+ '_requires_manual_renewal' => 'requires_manual_renewal',
+ '_trial_period' => 'trial_period',
+
+ '_schedule_trial_end' => 'schedule_trial_end',
+ '_schedule_next_payment' => 'schedule_next_payment',
+ '_schedule_cancelled' => 'schedule_cancelled',
+ '_schedule_end' => 'schedule_end',
+ '_schedule_payment_retry' => 'schedule_payment_retry',
+
+ '_subscription_switch_data' => 'switch_data',
+ );
+
+ /**
+ * Constructor.
+ */
+ public function __construct() {
+ // Exclude the subscription related meta data we set and manage manually from the objects "meta" data
+ $this->internal_meta_keys = array_merge( $this->internal_meta_keys, $this->subscription_internal_meta_keys );
+ }
+
+ /**
+ * Create a new subscription in the database.
+ *
+ * @param WC_Subscription $subscription
+ * @since 2.2.0
+ */
+ public function create( &$subscription ) {
+ parent::create( $subscription );
+ do_action( 'woocommerce_new_subscription', $subscription->get_id() );
+ }
+
+ /**
+ * Read subscription data.
+ *
+ * @param WC_Subscription $subscription
+ * @param object $post_object
+ * @since 2.2.0
+ */
+ protected function read_order_data( &$subscription, $post_object ) {
+
+ // Set all order meta data, as well as data defined by WC_Subscription::$extra_keys which has corresponding setter methods
+ parent::read_order_data( $subscription, $post_object );
+
+ $props_to_set = $dates_to_set = array();
+
+ foreach ( $this->subscription_meta_keys_to_props as $meta_key => $prop_key ) {
+ if ( 0 === strpos( $prop_key, 'schedule' ) || in_array( $meta_key, $this->subscription_internal_meta_keys ) ) {
+
+ $meta_value = get_post_meta( $subscription->get_id(), $meta_key, true );
+
+ // Dates are set via update_dates() to make sure relationships between dates are validated
+ if ( 0 === strpos( $prop_key, 'schedule' ) ) {
+ $date_type = str_replace( 'schedule_', '', $prop_key );
+ $dates_to_set[ $date_type ] = ( false == $meta_value ) ? 0 : $meta_value;
+ } else {
+ $props_to_set[ $prop_key ] = $meta_value;
+ }
+ }
+ }
+
+ $subscription->update_dates( $dates_to_set );
+ $subscription->set_props( $props_to_set );
+ }
+
+ /**
+ * Update subscription in the database.
+ *
+ * @param WC_Subscription $subscription
+ * @since 2.2.0
+ */
+ public function update( &$subscription ) {
+ parent::update( $subscription );
+ do_action( 'woocommerce_update_subscription', $subscription->get_id() );
+ }
+
+ /**
+ * Update post meta for a subscription based on it's settings in the WC_Subscription class.
+ *
+ * @param WC_Subscription $subscription
+ * @since 2.2.0
+ */
+ protected function update_post_meta( &$subscription ) {
+
+ $updated_props = array();
+
+ foreach ( $this->get_props_to_update( $subscription, $this->subscription_meta_keys_to_props ) as $meta_key => $prop ) {
+ $meta_value = ( 'schedule_' == substr( $prop, 0, 9 ) ) ? $subscription->get_date( $prop ) : $subscription->{"get_$prop"}( 'edit' );
+
+ // Store as a string of the boolean for backward compatibility (yep, it's gross)
+ if ( 'requires_manual_renewal' === $prop ) {
+ $meta_value = $meta_value ? 'true' : 'false';
+ }
+
+ update_post_meta( $subscription->get_id(), $meta_key, $meta_value );
+ $updated_props[] = $prop;
+ }
+
+ do_action( 'woocommerce_subscription_object_updated_props', $subscription, $updated_props );
+
+ parent::update_post_meta( $subscription );
+ }
+
+ /**
+ * Get amount refunded for all related orders.
+ *
+ * @param WC_Subscription $subscription
+ * @return string
+ * @since 2.2.0
+ */
+ public function get_total_refunded( $subscription ) {
+
+ $total = 0;
+
+ foreach ( $subscription->get_related_orders( 'all' ) as $order ) {
+ $total += parent::get_total_refunded( $order );
+ }
+
+ return $total;
+ }
+
+ /**
+ * Get the total tax refunded for all related orders.
+ *
+ * @param WC_Subscription $subscription
+ * @return float
+ * @since 2.2.0
+ */
+ public function get_total_tax_refunded( $subscription ) {
+
+ $total = 0;
+
+ foreach ( $subscription->get_related_orders() as $order ) {
+ $total += parent::get_total_tax_refunded( $order );
+ }
+
+ return abs( $total );
+ }
+
+ /**
+ * Get the total shipping refunded for all related orders.
+ *
+ * @param WC_Subscription $subscription
+ * @return float
+ * @since 2.2.0
+ */
+ public function get_total_shipping_refunded( $subscription ) {
+
+ $total = 0;
+
+ foreach ( $subscription->get_related_orders( 'all' ) as $order ) {
+ $total += parent::get_total_shipping_refunded( $order );
+ }
+
+ return abs( $total );
+ }
+
+ /**
+ * Return count of subscriptions with type.
+ *
+ * @param string $type
+ * @return int
+ * @since 2.2.0
+ */
+ public function get_order_count( $status ) {
+ global $wpdb;
+ return absint( $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM {$wpdb->posts} WHERE post_type = 'shop_subscription' AND post_status = %s", $status ) ) );
+ }
+
+ /**
+ * Get all subscriptions matching the passed in args.
+ *
+ * @see wc_get_orders()
+ * @param array $args
+ * @return array of orders
+ * @since 2.2.0
+ */
+ public function get_orders( $args = array() ) {
+
+ $parent_args = $args = wp_parse_args( $args, array(
+ 'type' => 'shop_subscription',
+ 'return' => 'objects',
+ ) );
+
+ // We only want IDs from the parent method
+ $parent_args['return'] = 'ids';
+
+ $subscriptions = parent::get_orders( $parent_args );
+
+ if ( $args['paginate'] ) {
+
+ if ( 'objects' === $args['return'] ) {
+ $return = array_map( 'wcs_get_subscription', $subscriptions->orders );
+ } else {
+ $return = $subscriptions->orders;
+ }
+
+ return (object) array(
+ 'orders' => $return,
+ 'total' => $subscriptions->total,
+ 'max_num_pages' => $subscriptions->max_num_pages,
+ );
+
+ } else {
+
+ if ( 'objects' === $args['return'] ) {
+ $return = array_map( 'wcs_get_subscription', $subscriptions );
+ } else {
+ $return = $subscriptions;
+ }
+
+ return $return;
+ }
+ }
+}
diff --git a/includes/deprecated/class-wcs-deprecated-filter-hooks.php b/includes/deprecated/class-wcs-deprecated-filter-hooks.php
new file mode 100644
index 0000000..051f2b4
--- /dev/null
+++ b/includes/deprecated/class-wcs-deprecated-filter-hooks.php
@@ -0,0 +1,55 @@
+ old_hook )
+ *
+ * @var array
+ */
+ protected $deprecated_hooks = array(
+ 'woocommerce_subscription_get_currency' => 'woocommerce_get_currency',
+ 'woocommerce_subscription_get_discount_total' => 'woocommerce_order_amount_discount_total',
+ 'woocommerce_subscription_get_discount_tax' => 'woocommerce_order_amount_discount_tax',
+ 'woocommerce_subscription_get_shipping_total' => 'woocommerce_order_amount_shipping_total',
+ 'woocommerce_subscription_get_shipping_tax' => 'woocommerce_order_amount_shipping_tax',
+ 'woocommerce_subscription_get_cart_tax' => 'woocommerce_order_amount_cart_tax',
+ 'woocommerce_subscription_get_total' => 'woocommerce_order_amount_total',
+ 'woocommerce_subscription_get_total_tax' => 'woocommerce_order_amount_total_tax',
+ 'woocommerce_subscription_get_total_discount' => 'woocommerce_order_amount_total_discount',
+ 'woocommerce_subscription_get_subtotal' => 'woocommerce_order_amount_subtotal',
+ 'woocommerce_subscription_get_tax_totals' => 'woocommerce_order_tax_totals',
+ );
+
+ /**
+ * Display a deprecated notice for old hooks.
+ *
+ * @param string $old_hook
+ * @param string $new_hook
+ * @since 2.2.0
+ */
+ protected function display_notice( $old_hook, $new_hook ) {
+ wcs_deprecated_function( sprintf( 'The "%s" hook uses out of date data structures and', esc_html( $old_hook ) ), '2.2.0', esc_html( $new_hook ) . ' to filter subscription properties' );
+ }
+}
+new WCS_Deprecated_Filter_Hooks();
diff --git a/includes/deprecated/class-wcs-filter-deprecator.php b/includes/deprecated/class-wcs-filter-deprecator.php
index d3259bb..e5354e7 100644
--- a/includes/deprecated/class-wcs-filter-deprecator.php
+++ b/includes/deprecated/class-wcs-filter-deprecator.php
@@ -132,7 +132,7 @@ class WCS_Filter_Deprecator extends WCS_Hook_Deprecator {
// Old arg spec: $next_payment_date, $order, $product_id, $type, $from_date, $from_date_arg
case 'woocommerce_subscriptions_calculated_next_payment_date' :
$subscription = $new_callback_args[1];
- $last_payment = $subscription->get_date( 'last_payment' );
+ $last_payment = $subscription->get_date( 'last_order_date_created' );
$return_value = apply_filters( $old_hook, $return_value, self::get_order( $subscription ), self::get_product_id( $subscription ), 'mysql', $last_payment, $last_payment );
break;
@@ -168,10 +168,10 @@ class WCS_Filter_Deprecator extends WCS_Hook_Deprecator {
// Old arg spec: $order_items, $original_order_id, $renewal_order_id, $product_id, $new_order_role
if ( 'woocommerce_subscriptions_renewal_order_items' == $old_hook ) {
- $return_value = apply_filters( $old_hook, $return_value, $original_id, $renewal_order->id, self::get_product_id( $subscription ), $order_role );
+ $return_value = apply_filters( $old_hook, $return_value, $original_id, wcs_get_objects_property( $renewal_order, 'id' ), self::get_product_id( $subscription ), $order_role );
} else {
// Old arg spec: $order_meta_query, $original_order_id, $renewal_order_id, $new_order_role
- $return_value = apply_filters( $old_hook, $return_value, $original_id, $renewal_order->id, $order_role );
+ $return_value = apply_filters( $old_hook, $return_value, $original_id, wcs_get_objects_property( $renewal_order, 'id' ), $order_role );
}
break;
@@ -202,7 +202,7 @@ class WCS_Filter_Deprecator extends WCS_Hook_Deprecator {
$renewal_order_id = apply_filters( $old_hook, $return_value->id, self::get_order( $subscription ), self::get_product_id( $subscription ), $order_role );
// Only change the return value if a new filter was returned by the hook
- if ( $renewal_order_id !== $renewal_order->id ) {
+ if ( wcs_get_objects_property( $renewal_order, 'id' ) !== $renewal_order_id ) {
$return_value = wc_get_order( $renewal_order_id );
}
break;
@@ -326,7 +326,7 @@ class WCS_Filter_Deprecator extends WCS_Hook_Deprecator {
$args->subscription = wcs_get_subscription_in_deprecated_structure( $subscription );
$args->user_id = $subscription->get_user_id();
$args->order = self::get_order( $subscription );
- $args->payment_gateway = $subscription->payment_method;
+ $args->payment_gateway = $subscription->get_payment_method();
$args->order_uses_manual_payments = $subscription->is_manual();
$return_value = apply_filters( $old_hook, $return_value, $args );
break;
diff --git a/includes/emails/class-wcs-email-cancelled-subscription.php b/includes/emails/class-wcs-email-cancelled-subscription.php
index 283407f..e9827ed 100644
--- a/includes/emails/class-wcs-email-cancelled-subscription.php
+++ b/includes/emails/class-wcs-email-cancelled-subscription.php
@@ -64,7 +64,7 @@ class WCS_Email_Cancelled_Subscription extends WC_Email {
return;
}
- update_post_meta( $subscription->id, '_cancelled_email_sent', 'true' );
+ update_post_meta( $subscription->get_id(), '_cancelled_email_sent', 'true' );
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
}
diff --git a/includes/emails/class-wcs-email-customer-completed-renewal-order.php b/includes/emails/class-wcs-email-customer-completed-renewal-order.php
index 0e797ab..9821d43 100644
--- a/includes/emails/class-wcs-email-customer-completed-renewal-order.php
+++ b/includes/emails/class-wcs-email-customer-completed-renewal-order.php
@@ -55,24 +55,24 @@ class WCS_Email_Completed_Renewal_Order extends WC_Email_Customer_Completed_Orde
* @access public
* @return void
*/
- function trigger( $order_id ) {
+ function trigger( $order_id, $order = null ) {
if ( $order_id ) {
$this->object = new WC_Order( $order_id );
- $this->recipient = $this->object->billing_email;
+ $this->recipient = wcs_get_objects_property( $this->object, 'billing_email' );
$order_date_index = array_search( '{order_date}', $this->find );
if ( false === $order_date_index ) {
- $this->find[] = '{order_date}';
- $this->replace[] = date_i18n( wc_date_format(), wcs_date_to_time( $this->object->order_date ) );
+ $this->find['order_date'] = '{order_date}';
+ $this->replace['order_date'] = wcs_format_datetime( wcs_get_objects_property( $this->object, 'date_created' ) );
} else {
- $this->replace[ $order_date_index ] = date_i18n( wc_date_format(), wcs_date_to_time( $this->object->order_date ) );
+ $this->replace[ $order_date_index ] = wcs_format_datetime( wcs_get_objects_property( $this->object, 'date_created' ) );
}
$order_number_index = array_search( '{order_number}', $this->find );
if ( false === $order_number_index ) {
- $this->find[] = '{order_number}';
- $this->replace[] = $this->object->get_order_number();
+ $this->find['order_number'] = '{order_number}';
+ $this->replace['order_number'] = $this->object->get_order_number();
} else {
$this->replace[ $order_number_index ] = $this->object->get_order_number();
}
diff --git a/includes/emails/class-wcs-email-customer-completed-switch-order.php b/includes/emails/class-wcs-email-customer-completed-switch-order.php
index cf2a612..d04d30c 100644
--- a/includes/emails/class-wcs-email-customer-completed-switch-order.php
+++ b/includes/emails/class-wcs-email-customer-completed-switch-order.php
@@ -54,24 +54,24 @@ class WCS_Email_Completed_Switch_Order extends WC_Email_Customer_Completed_Order
* @access public
* @return void
*/
- function trigger( $order_id ) {
+ function trigger( $order_id, $order = null ) {
if ( $order_id ) {
$this->object = new WC_Order( $order_id );
- $this->recipient = $this->object->billing_email;
+ $this->recipient = wcs_get_objects_property( $this->object, 'billing_email' );
$order_date_index = array_search( '{order_date}', $this->find );
if ( false === $order_date_index ) {
- $this->find[] = '{order_date}';
- $this->replace[] = date_i18n( wc_date_format(), wcs_date_to_time( $this->object->order_date ) );
+ $this->find['order_date'] = '{order_date}';
+ $this->replace['order_date'] = wcs_format_datetime( wcs_get_objects_property( $this->object, 'date_created' ) );
} else {
- $this->replace[ $order_date_index ] = date_i18n( wc_date_format(), wcs_date_to_time( $this->object->order_date ) );
+ $this->replace[ $order_date_index ] = wcs_format_datetime( wcs_get_objects_property( $this->object, 'date_created' ) );
}
$order_number_index = array_search( '{order_number}', $this->find );
if ( false === $order_number_index ) {
- $this->find[] = '{order_number}';
- $this->replace[] = $this->object->get_order_number();
+ $this->find['order_number'] = '{order_number}';
+ $this->replace['order_number'] = $this->object->get_order_number();
} else {
$this->replace[ $order_number_index ] = $this->object->get_order_number();
}
diff --git a/includes/emails/class-wcs-email-customer-payment-retry.php b/includes/emails/class-wcs-email-customer-payment-retry.php
index f98391e..68fc5dc 100644
--- a/includes/emails/class-wcs-email-customer-payment-retry.php
+++ b/includes/emails/class-wcs-email-customer-payment-retry.php
@@ -49,19 +49,19 @@ class WCS_Email_Customer_Payment_Retry extends WCS_Email_Customer_Renewal_Invoic
* @access public
* @return void
*/
- function trigger( $order ) {
+ function trigger( $order_id, $order = null ) {
- $this->retry = WCS_Retry_Manager::store()->get_last_retry_for_order( $order->id );
+ $this->retry = WCS_Retry_Manager::store()->get_last_retry_for_order( $order_id );
$retry_time_index = array_search( '{retry_time}', $this->find );
if ( false === $retry_time_index ) {
- $this->find[] = '{retry_time}';
- $this->replace[] = strtolower( wcs_get_human_time_diff( $this->retry->get_time() ) );
+ $this->find['retry_time'] = '{retry_time}';
+ $this->replace['retry_time'] = strtolower( wcs_get_human_time_diff( $this->retry->get_time() ) );
} else {
$this->replace[ $retry_time_index ] = strtolower( wcs_get_human_time_diff( $this->retry->get_time() ) );
}
- parent::trigger( $order );
+ parent::trigger( $order_id, $order );
}
/**
diff --git a/includes/emails/class-wcs-email-customer-processing-renewal-order.php b/includes/emails/class-wcs-email-customer-processing-renewal-order.php
index 35c2830..70c6899 100644
--- a/includes/emails/class-wcs-email-customer-processing-renewal-order.php
+++ b/includes/emails/class-wcs-email-customer-processing-renewal-order.php
@@ -49,24 +49,24 @@ class WCS_Email_Processing_Renewal_Order extends WC_Email_Customer_Processing_Or
* @access public
* @return void
*/
- function trigger( $order_id ) {
+ function trigger( $order_id, $order = null ) {
if ( $order_id ) {
$this->object = new WC_Order( $order_id );
- $this->recipient = $this->object->billing_email;
+ $this->recipient = wcs_get_objects_property( $this->object, 'billing_email' );
$order_date_index = array_search( '{order_date}', $this->find );
if ( false === $order_date_index ) {
- $this->find[] = '{order_date}';
- $this->replace[] = date_i18n( wc_date_format(), wcs_date_to_time( $this->object->order_date ) );
+ $this->find['order_date'] = '{order_date}';
+ $this->replace['order_date'] = wcs_format_datetime( wcs_get_objects_property( $this->object, 'date_created' ) );
} else {
- $this->replace[ $order_date_index ] = date_i18n( wc_date_format(), wcs_date_to_time( $this->object->order_date ) );
+ $this->replace[ $order_date_index ] = wcs_format_datetime( wcs_get_objects_property( $this->object, 'date_created' ) );
}
$order_number_index = array_search( '{order_number}', $this->find );
if ( false === $order_number_index ) {
- $this->find[] = '{order_number}';
- $this->replace[] = $this->object->get_order_number();
+ $this->find['order_number'] = '{order_number}';
+ $this->replace['order_number'] = $this->object->get_order_number();
} else {
$this->replace[ $order_number_index ] = $this->object->get_order_number();
}
diff --git a/includes/emails/class-wcs-email-customer-renewal-invoice.php b/includes/emails/class-wcs-email-customer-renewal-invoice.php
index 2c4cdc3..d17fb1e 100644
--- a/includes/emails/class-wcs-email-customer-renewal-invoice.php
+++ b/includes/emails/class-wcs-email-customer-renewal-invoice.php
@@ -56,28 +56,28 @@ class WCS_Email_Customer_Renewal_Invoice extends WC_Email_Customer_Invoice {
* @access public
* @return void
*/
- function trigger( $order ) {
+ function trigger( $order_id, $order = null ) {
- if ( ! is_object( $order ) ) {
- $order = new WC_Order( absint( $order ) );
+ if ( $order_id && ! is_a( $order, 'WC_Order' ) ) {
+ $order = wc_get_order( $order_id );
}
- if ( $order ) {
+ if ( is_a( $order, 'WC_Order' ) ) {
$this->object = $order;
- $this->recipient = $this->object->billing_email;
+ $this->recipient = wcs_get_objects_property( $this->object, 'billing_email' );
$order_date_index = array_search( '{order_date}', $this->find );
if ( false === $order_date_index ) {
- $this->find[] = '{order_date}';
- $this->replace[] = date_i18n( wc_date_format(), wcs_date_to_time( $this->object->order_date ) );
+ $this->find['order_date'] = '{order_date}';
+ $this->replace['order_date'] = wcs_format_datetime( wcs_get_objects_property( $this->object, 'date_created' ) );
} else {
- $this->replace[ $order_date_index ] = date_i18n( wc_date_format(), wcs_date_to_time( $this->object->order_date ) );
+ $this->replace[ $order_date_index ] = wcs_format_datetime( wcs_get_objects_property( $this->object, 'date_created' ) );
}
$order_number_index = array_search( '{order_number}', $this->find );
if ( false === $order_number_index ) {
- $this->find[] = '{order_number}';
- $this->replace[] = $this->object->get_order_number();
+ $this->find['order_number'] = '{order_number}';
+ $this->replace['order_number'] = $this->object->get_order_number();
} else {
$this->replace[ $order_number_index ] = $this->object->get_order_number();
}
diff --git a/includes/emails/class-wcs-email-new-renewal-order.php b/includes/emails/class-wcs-email-new-renewal-order.php
index 2a7d2eb..ecd3869 100644
--- a/includes/emails/class-wcs-email-new-renewal-order.php
+++ b/includes/emails/class-wcs-email-new-renewal-order.php
@@ -57,23 +57,23 @@ class WCS_Email_New_Renewal_Order extends WC_Email_New_Order {
* @access public
* @return void
*/
- function trigger( $order_id ) {
+ function trigger( $order_id, $order = null ) {
if ( $order_id ) {
$this->object = new WC_Order( $order_id );
$order_date_index = array_search( '{order_date}', $this->find );
if ( false === $order_date_index ) {
- $this->find[] = '{order_date}';
- $this->replace[] = date_i18n( wc_date_format(), wcs_date_to_time( $this->object->order_date ) );
+ $this->find['order-date'] = '{order_date}';
+ $this->replace['order-date'] = wcs_format_datetime( wcs_get_objects_property( $this->object, 'date_created' ) );
} else {
- $this->replace[ $order_date_index ] = date_i18n( wc_date_format(), wcs_date_to_time( $this->object->order_date ) );
+ $this->replace[ $order_date_index ] = wcs_format_datetime( wcs_get_objects_property( $this->object, 'date_created' ) );
}
$order_number_index = array_search( '{order_number}', $this->find );
if ( false === $order_number_index ) {
- $this->find[] = '{order_number}';
- $this->replace[] = $this->object->get_order_number();
+ $this->find['order-number'] = '{order_number}';
+ $this->replace['order-number'] = $this->object->get_order_number();
} else {
$this->replace[ $order_number_index ] = $this->object->get_order_number();
}
diff --git a/includes/emails/class-wcs-email-new-switch-order.php b/includes/emails/class-wcs-email-new-switch-order.php
index 0ff791d..6e8b31d 100644
--- a/includes/emails/class-wcs-email-new-switch-order.php
+++ b/includes/emails/class-wcs-email-new-switch-order.php
@@ -52,23 +52,23 @@ class WCS_Email_New_Switch_Order extends WC_Email_New_Order {
* @access public
* @return void
*/
- function trigger( $order_id ) {
+ function trigger( $order_id, $order = null ) {
if ( $order_id ) {
$this->object = new WC_Order( $order_id );
$order_date_index = array_search( '{order_date}', $this->find );
if ( false === $order_date_index ) {
- $this->find[] = '{order_date}';
- $this->replace[] = date_i18n( wc_date_format(), wcs_date_to_time( $this->object->order_date ) );
+ $this->find['order_date'] = '{order_date}';
+ $this->replace['order_date'] = wcs_format_datetime( wcs_get_objects_property( $this->object, 'date_created' ) );
} else {
- $this->replace[ $order_date_index ] = date_i18n( wc_date_format(), wcs_date_to_time( $this->object->order_date ) );
+ $this->replace[ $order_date_index ] = wcs_format_datetime( wcs_get_objects_property( $this->object, 'date_created' ) );
}
$order_number_index = array_search( '{order_number}', $this->find );
if ( false === $order_number_index ) {
- $this->find[] = '{order_number}';
- $this->replace[] = $this->object->get_order_number();
+ $this->find['order_number'] = '{order_number}';
+ $this->replace['order_number'] = $this->object->get_order_number();
} else {
$this->replace[ $order_number_index ] = $this->object->get_order_number();
}
diff --git a/includes/emails/class-wcs-email-payment-retry.php b/includes/emails/class-wcs-email-payment-retry.php
index 65bfbe7..d1cd514 100644
--- a/includes/emails/class-wcs-email-payment-retry.php
+++ b/includes/emails/class-wcs-email-payment-retry.php
@@ -45,13 +45,13 @@ class WCS_Email_Payment_Retry extends WC_Email_Failed_Order {
*
* @param int $order_id
*/
- public function trigger( $order ) {
+ public function trigger( $order_id, $order = null ) {
$this->object = $order;
- $this->retry = WCS_Retry_Manager::store()->get_last_retry_for_order( $order->id );;
+ $this->retry = WCS_Retry_Manager::store()->get_last_retry_for_order( wcs_get_objects_property( $order, 'id' ) );;
$this->find['order-date'] = '{order_date}';
$this->find['order-number'] = '{order_number}';
$this->find['retry-time'] = '{retry_time}';
- $this->replace['order-date'] = date_i18n( wc_date_format(), strtotime( $this->object->order_date ) );
+ $this->replace['order-date'] = wcs_format_datetime( wcs_get_objects_property( $this->object, 'date_created' ) );
$this->replace['order-number'] = $this->object->get_order_number();
$this->replace['retry-time'] = strtolower( wcs_get_human_time_diff( $this->retry->get_time() ) );
diff --git a/includes/gateways/class-wc-subscriptions-payment-gateways.php b/includes/gateways/class-wc-subscriptions-payment-gateways.php
index e8346c6..a3a501f 100644
--- a/includes/gateways/class-wc-subscriptions-payment-gateways.php
+++ b/includes/gateways/class-wc-subscriptions-payment-gateways.php
@@ -161,7 +161,7 @@ class WC_Subscriptions_Payment_Gateways {
break;
}
- do_action( $hook_prefix . $subscription->payment_method, $subscription );
+ do_action( $hook_prefix . $subscription->get_payment_method(), $subscription );
}
/**
@@ -170,12 +170,15 @@ class WC_Subscriptions_Payment_Gateways {
* @since 2.1.0
*/
public static function trigger_gateway_renewal_payment_hook( $renewal_order ) {
- if ( ! empty( $renewal_order ) && $renewal_order->get_total() > 0 && ! empty( $renewal_order->payment_method ) ) {
+
+ $renewal_order_payment_method = wcs_get_objects_property( $renewal_order, 'payment_method' );
+
+ if ( ! empty( $renewal_order ) && $renewal_order->get_total() > 0 && ! empty( $renewal_order_payment_method ) ) {
// Make sure gateways are setup
WC()->payment_gateways();
- do_action( 'woocommerce_scheduled_subscription_payment_' . $renewal_order->payment_method, $renewal_order->get_total(), $renewal_order );
+ do_action( 'woocommerce_scheduled_subscription_payment_' . $renewal_order_payment_method, $renewal_order->get_total(), $renewal_order );
}
}
diff --git a/includes/gateways/paypal/class-wcs-paypal.php b/includes/gateways/paypal/class-wcs-paypal.php
index cd5d215..3cf5530 100644
--- a/includes/gateways/paypal/class-wcs-paypal.php
+++ b/includes/gateways/paypal/class-wcs-paypal.php
@@ -234,7 +234,7 @@ class WCS_PayPal {
foreach ( wcs_get_subscriptions_for_order( $order, array( 'order_type' => 'any' ) ) as $subscription ) {
$subscription->set_payment_method( $payment_method );
- wcs_set_paypal_id( $subscription, $billing_agreement_response->get_billing_agreement_id() );
+ wcs_set_paypal_id( $subscription, $billing_agreement_response->get_billing_agreement_id() ); // Also saves the subscription
}
if ( ! wcs_is_subscription( $order ) ) {
@@ -330,7 +330,7 @@ class WCS_PayPal {
public static function process_subscription_payment( $amount, $order ) {
// If the subscription is using reference transactions, we can process the payment ourselves
- $paypal_profile_id = wcs_get_paypal_id( $order->id );
+ $paypal_profile_id = wcs_get_paypal_id( wcs_get_objects_property( $order, 'id' ) );
if ( wcs_is_paypal_profile_a( $paypal_profile_id, 'billing_agreement' ) ) {
@@ -414,7 +414,7 @@ class WCS_PayPal {
);
foreach ( $post_meta_keys as $post_meta_key ) {
- delete_post_meta( $resubscribe_order->id, $post_meta_key );
+ delete_post_meta( wcs_get_objects_property( $resubscribe_order, 'id' ), $post_meta_key );
}
return $resubscribe_order;
@@ -433,9 +433,9 @@ class WCS_PayPal {
global $post;
$subscription = wcs_get_subscription( $post );
- if ( 'paypal' === $subscription->payment_method ) {
+ if ( 'paypal' === $subscription->get_payment_method() ) {
- $paypal_profile_id = wcs_get_paypal_id( $subscription->id );
+ $paypal_profile_id = wcs_get_paypal_id( $subscription->get_id() );
$is_paypal_standard = ! wcs_is_paypal_profile_a( $paypal_profile_id, 'billing_agreement' );
if ( $is_paypal_standard ) {
diff --git a/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php b/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php
index 87c1b6d..57bcbf1 100644
--- a/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php
+++ b/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php
@@ -244,7 +244,7 @@ class WCS_PayPal_Admin {
* @param WC_Subscription $subscription
*/
public static function profile_link( $subscription ) {
- if ( wcs_is_subscription( $subscription ) && 'paypal' == $subscription->payment_method ) {
+ if ( wcs_is_subscription( $subscription ) && 'paypal' == $subscription->get_payment_method() ) {
$paypal_profile_id = wcs_get_paypal_id( $subscription );
diff --git a/includes/gateways/paypal/includes/admin/class-wcs-paypal-change-payment-method-admin.php b/includes/gateways/paypal/includes/admin/class-wcs-paypal-change-payment-method-admin.php
index 4b66f20..bdc150c 100644
--- a/includes/gateways/paypal/includes/admin/class-wcs-paypal-change-payment-method-admin.php
+++ b/includes/gateways/paypal/includes/admin/class-wcs-paypal-change-payment-method-admin.php
@@ -41,7 +41,7 @@ class WCS_PayPal_Change_Payment_Method_Admin {
* @since 2.0
*/
public static function add_payment_meta_details( $payment_meta, $subscription ) {
- $subscription_id = get_post_meta( $subscription->id, '_paypal_subscription_id', true );
+ $subscription_id = get_post_meta( $subscription->get_id(), '_paypal_subscription_id', true );
if ( wcs_is_paypal_profile_a( $subscription_id, 'billing_agreement' ) || empty( $subscription_id ) ) {
$label = 'PayPal Billing Agreement ID';
@@ -76,8 +76,8 @@ class WCS_PayPal_Change_Payment_Method_Admin {
public static function validate_payment_meta( $payment_meta, $subscription ) {
if ( empty( $payment_meta['post_meta']['_paypal_subscription_id']['value'] ) ) {
throw new Exception( 'A valid PayPal Billing Agreement ID value is required.' );
- } elseif ( $subscription->paypal_subscription_id !== $payment_meta['post_meta']['_paypal_subscription_id']['value'] && 0 !== strpos( $payment_meta['post_meta']['_paypal_subscription_id']['value'], 'B-' ) ) {
- throw new Exception( 'Invalid Billing Agreemend ID. A valid PayPal Billing Agreement ID must begin with "B-".' );
+ } elseif ( 0 !== strpos( $payment_meta['post_meta']['_paypal_subscription_id']['value'], 'B-' ) && wcs_get_paypal_id( $subscription ) !== $payment_meta['post_meta']['_paypal_subscription_id']['value'] ) {
+ throw new Exception( 'Invalid Billing Agreement ID. A valid PayPal Billing Agreement ID must begin with "B-".' );
}
}
diff --git a/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php b/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php
index 70c6c9e..60c299b 100644
--- a/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php
+++ b/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php
@@ -206,7 +206,7 @@ class WCS_PayPal_Reference_Transaction_API_Request {
'return_fraud_filters' => 1,
'notify_url' => WC()->api_request_url( 'WC_Gateway_Paypal' ),
'invoice_number' => WCS_PayPal::get_option( 'invoice_prefix' ) . wcs_str_to_ascii( ltrim( $order->get_order_number(), _x( '#', 'hash before the order number. Used as a character to remove from the actual order number', 'woocommerce-subscriptions' ) ) ),
- 'custom' => wcs_json_encode( array( 'order_id' => $order->id, 'order_key' => $order->order_key ) ),
+ 'custom' => wcs_json_encode( array( 'order_id' => wcs_get_objects_property( $order, 'id' ), 'order_key' => wcs_get_objects_property( $order, 'order_key' ) ) ),
);
$args = wp_parse_args( $args, $defaults );
@@ -310,24 +310,24 @@ class WCS_PayPal_Reference_Transaction_API_Request {
if ( $use_deprecated_params ) {
$this->add_parameters( array(
'AMT' => $total_amount,
- 'CURRENCYCODE' => $order->get_order_currency(),
+ 'CURRENCYCODE' => wcs_get_objects_property( $order, 'currency' ),
'ITEMAMT' => $this->round( $order_subtotal + $order->get_cart_tax() ),
'SHIPPINGAMT' => $this->round( $order->get_total_shipping() + $order->get_shipping_tax() ),
'INVNUM' => WCS_PayPal::get_option( 'invoice_prefix' ) . wcs_str_to_ascii( ltrim( $order->get_order_number(), _x( '#', 'hash before the order number. Used as a character to remove from the actual order number', 'woocommerce-subscriptions' ) ) ),
'PAYMENTACTION' => $type,
- 'PAYMENTREQUESTID' => $order->id,
- 'CUSTOM' => json_encode( array( 'order_id' => $order->id, 'order_key' => $order->order_key ) ),
+ 'PAYMENTREQUESTID' => wcs_get_objects_property( $order, 'id' ),
+ 'CUSTOM' => json_encode( array( 'order_id' => wcs_get_objects_property( $order, 'id' ), 'order_key' => wcs_get_objects_property( $order, 'order_key' ) ) ),
) );
} else {
$this->add_payment_parameters( array(
'AMT' => $total_amount,
- 'CURRENCYCODE' => $order->get_order_currency(),
+ 'CURRENCYCODE' => wcs_get_objects_property( $order, 'currency' ),
'ITEMAMT' => $this->round( $order_subtotal + $order->get_cart_tax() ),
'SHIPPINGAMT' => $this->round( $order->get_total_shipping() + $order->get_shipping_tax() ),
'INVNUM' => WCS_PayPal::get_option( 'invoice_prefix' ) . wcs_str_to_ascii( ltrim( $order->get_order_number(), _x( '#', 'hash before the order number. Used as a character to remove from the actual order number', 'woocommerce-subscriptions' ) ) ),
'PAYMENTACTION' => $type,
- 'PAYMENTREQUESTID' => $order->id,
- 'CUSTOM' => json_encode( array( 'order_id' => $order->id, 'order_key' => $order->order_key ) ),
+ 'PAYMENTREQUESTID' => wcs_get_objects_property( $order, 'id' ),
+ 'CUSTOM' => json_encode( array( 'order_id' => wcs_get_objects_property( $order, 'id' ), 'order_key' => wcs_get_objects_property( $order, 'order_key' ) ) ),
) );
}
} else {
@@ -348,26 +348,26 @@ class WCS_PayPal_Reference_Transaction_API_Request {
if ( $use_deprecated_params ) {
$this->add_parameters( array(
'AMT' => $total_amount,
- 'CURRENCYCODE' => $order->get_order_currency(),
+ 'CURRENCYCODE' => wcs_get_objects_property( $order, 'currency' ),
'ITEMAMT' => $this->round( $order_subtotal ),
'SHIPPINGAMT' => $this->round( $order->get_total_shipping() ),
'TAXAMT' => $this->round( $order->get_total_tax() ),
'INVNUM' => WCS_PayPal::get_option( 'invoice_prefix' ) . wcs_str_to_ascii( ltrim( $order->get_order_number(), _x( '#', 'hash before the order number. Used as a character to remove from the actual order number', 'woocommerce-subscriptions' ) ) ),
'PAYMENTACTION' => $type,
- 'PAYMENTREQUESTID' => $order->id,
- 'CUSTOM' => json_encode( array( 'order_id' => $order->id, 'order_key' => $order->order_key ) ),
+ 'PAYMENTREQUESTID' => wcs_get_objects_property( $order, 'id' ),
+ 'CUSTOM' => json_encode( array( 'order_id' => wcs_get_objects_property( $order, 'id' ), 'order_key' => wcs_get_objects_property( $order, 'order_key' ) ) ),
) );
} else {
$this->add_payment_parameters( array(
'AMT' => $total_amount,
- 'CURRENCYCODE' => $order->get_order_currency(),
+ 'CURRENCYCODE' => wcs_get_objects_property( $order, 'currency' ),
'ITEMAMT' => $this->round( $order_subtotal ),
'SHIPPINGAMT' => $this->round( $order->get_total_shipping() ),
'TAXAMT' => $this->round( $order->get_total_tax() ),
'INVNUM' => WCS_PayPal::get_option( 'invoice_prefix' ) . wcs_str_to_ascii( ltrim( $order->get_order_number(), _x( '#', 'hash before the order number. Used as a character to remove from the actual order number', 'woocommerce-subscriptions' ) ) ),
'PAYMENTACTION' => $type,
- 'PAYMENTREQUESTID' => $order->id,
- 'CUSTOM' => json_encode( array( 'order_id' => $order->id, 'order_key' => $order->order_key ) ),
+ 'PAYMENTREQUESTID' => wcs_get_objects_property( $order, 'id' ),
+ 'CUSTOM' => json_encode( array( 'order_id' => wcs_get_objects_property( $order, 'id' ), 'order_key' => wcs_get_objects_property( $order, 'order_key' ) ) ),
) );
}
@@ -484,27 +484,32 @@ class WCS_PayPal_Reference_Transaction_API_Request {
*/
private function get_item_description( $item, $product ) {
- if ( empty( $item['item_meta'] ) ) {
-
+ if ( ! empty( WC()->cart ) && is_array( $item ) && empty( $item['item_meta'] ) ) {
// cart item
$item_desc = WC()->cart->get_item_data( $item, true );
$item_desc = str_replace( "\n", ', ', rtrim( $item_desc ) );
} else {
-
// order item
- $item_meta = new WC_Order_Item_Meta( $item );
- $item_meta = $item_meta->get_formatted();
+ $item_desc = array();
- if ( ! empty( $item_meta ) ) {
+ if ( is_callable( array( $item, 'get_formatted_meta_data' ) ) ) { // WC 3.0+
- $item_desc = array();
+ foreach ( $item->get_formatted_meta_data() as $meta ) {
+ $item_desc[] = sprintf( '%s: %s', $meta->display_key, $meta->display_value );
+ }
+ } else { // WC < 3.0
- foreach ( $item_meta as $meta ) {
+ $item_meta = new WC_Order_Item_Meta( $item );
+
+ foreach ( $item_meta->get_formatted() as $meta ) {
$item_desc[] = sprintf( '%s: %s', $meta['label'], $meta['value'] );
}
+ }
+
+ if ( ! empty( $item_desc ) ) {
$item_desc = implode( ', ', $item_desc );
@@ -525,7 +530,7 @@ class WCS_PayPal_Reference_Transaction_API_Request {
* @since 2.0
*/
public function to_string() {
- return http_build_query( $this->get_parameters() );
+ return http_build_query( $this->get_parameters(), '', '&' );
}
/**
@@ -630,11 +635,7 @@ class WCS_PayPal_Reference_Transaction_API_Request {
*/
private function skip_line_items( $order = null ) {
- if ( isset( $order->prices_include_tax ) ) {
- $skip_line_items = $order->prices_include_tax;
- } else {
- $skip_line_items = wc_prices_include_tax();
- }
+ $skip_line_items = wcs_get_objects_property( $order, 'prices_include_tax' );
/**
* Filter whether line items should be skipped or not
diff --git a/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-ipn-handler.php b/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-ipn-handler.php
index 59d917e..62237c2 100644
--- a/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-ipn-handler.php
+++ b/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-ipn-handler.php
@@ -64,7 +64,7 @@ class WCS_PayPal_Reference_Transaction_IPN_Handler extends WCS_PayPal_Standard_I
$transaction_details['payment_status'] = 'completed';
}
- WC_Gateway_Paypal::log( 'Found order #' . $order->id );
+ WC_Gateway_Paypal::log( 'Found order #' . wcs_get_objects_property( $order, 'id' ) );
WC_Gateway_Paypal::log( 'Payment status: ' . $transaction_details['payment_status'] );
if ( method_exists( $this, 'payment_status_' . $transaction_details['payment_status'] ) ) {
diff --git a/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php b/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php
index ce960c2..d07dce0 100644
--- a/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php
+++ b/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php
@@ -84,7 +84,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
remove_filter( 'woocommerce_subscription_payment_gateway_supports', 'WCS_PayPal_Supports::add_feature_support_for_subscription', 10 );
// We have an invalid $subscription, probably because invoice_prefix has changed since the subscription was first created, so get the subscription by order key
- if ( ! isset( $subscription->id ) ) {
+ if ( ! is_callable( array( $subscription, 'get_id' ) ) ) {
$subscription = wcs_get_subscription( wc_get_order_id_by_order_key( $subscription_key ) );
}
@@ -98,7 +98,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
exit;
}
- if ( $subscription->order_key != $subscription_key ) {
+ if ( $subscription->get_order_key() != $subscription_key ) {
WC_Gateway_Paypal::log( 'Subscription IPN Error: Subscription Key does not match invoice.' );
exit;
}
@@ -106,7 +106,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
if ( isset( $transaction_details['ipn_track_id'] ) ) {
// Make sure the IPN request has not already been handled
- $handled_ipn_requests = get_post_meta( $subscription->id, '_paypal_ipn_tracking_ids', true );
+ $handled_ipn_requests = get_post_meta( $subscription->get_id(), '_paypal_ipn_tracking_ids', true );
if ( empty( $handled_ipn_requests ) ) {
$handled_ipn_requests = array();
@@ -140,7 +140,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
if ( isset( $transaction_details['txn_id'] ) ) {
// Make sure the IPN request has not already been handled
- $handled_transactions = get_post_meta( $subscription->id, '_paypal_transaction_ids', true );
+ $handled_transactions = get_post_meta( $subscription->get_id(), '_paypal_transaction_ids', true );
if ( empty( $handled_transactions ) ) {
$handled_transactions = array();
@@ -171,7 +171,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
$renewal_order = wc_get_order( substr( $transaction_details['invoice'], strrpos( $transaction_details['invoice'], '-' ) + 1 ) );
// check if the failed signup has been previously recorded
- if ( $renewal_order->id != get_post_meta( $subscription->id, '_paypal_failed_sign_up_recorded', true ) ) {
+ if ( wcs_get_objects_property( $renewal_order, 'id' ) != get_post_meta( $subscription->get_id(), '_paypal_failed_sign_up_recorded', true ) ) {
$is_renewal_sign_up_after_failure = true;
}
}
@@ -184,7 +184,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
}
// Ignore IPN messages when the payment method isn't PayPal
- if ( 'paypal' != $subscription->payment_method ) {
+ if ( 'paypal' != $subscription->get_payment_method() ) {
// The 'recurring_payment_suspended' transaction is actually an Express Checkout transaction type, but PayPal also send it for PayPal Standard Subscriptions suspended by admins at PayPal, so we need to handle it *if* the subscription has PayPal as the payment method, or leave it if the subscription is using a different payment method (because it might be using PayPal Express Checkout or PayPal Digital Goods)
if ( 'recurring_payment_suspended' == $transaction_details['txn_type'] ) {
@@ -206,8 +206,8 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
$existing_profile_id = wcs_get_paypal_id( $subscription );
if ( empty( $existing_profile_id ) || $existing_profile_id !== $transaction_details['subscr_id'] ) {
- update_post_meta( $subscription->id, '_old_paypal_subscriber_id', $existing_profile_id );
- update_post_meta( $subscription->id, '_old_payment_method', $subscription->payment_method );
+ update_post_meta( $subscription->get_id(), '_old_paypal_subscriber_id', $existing_profile_id );
+ update_post_meta( $subscription->get_id(), '_old_payment_method', $subscription->get_payment_method() );
}
}
@@ -232,13 +232,13 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
// Store PayPal Details on Subscription and Order
$this->save_paypal_meta_data( $subscription, $transaction_details );
- $this->save_paypal_meta_data( $subscription->order, $transaction_details );
+ $this->save_paypal_meta_data( $subscription->get_parent(), $transaction_details );
// When there is a free trial & no initial payment amount, we need to mark the order as paid and activate the subscription
- if ( ! $is_payment_change && ! $is_renewal_sign_up_after_failure && 0 == $subscription->order->get_total() ) {
+ if ( ! $is_payment_change && ! $is_renewal_sign_up_after_failure && 0 == $subscription->get_parent()->get_total() ) {
// Safe to assume the subscription has an order here because otherwise we wouldn't get a 'subscr_signup' IPN
- $subscription->order->payment_complete(); // No 'txn_id' value for 'subscr_signup' IPN messages
- update_post_meta( $subscription->id, '_paypal_first_ipn_ignored_for_pdt', 'true' );
+ $subscription->get_parent()->payment_complete(); // No 'txn_id' value for 'subscr_signup' IPN messages
+ update_post_meta( $subscription->get_id(), '_paypal_first_ipn_ignored_for_pdt', 'true' );
}
// Payment completed
@@ -248,8 +248,8 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
WC_Subscriptions_Change_Payment_Gateway::update_payment_method( $subscription, 'paypal' );
// We need to cancel the subscription now that the method has been changed successfully
- if ( 'paypal' == get_post_meta( $subscription->id, '_old_payment_method', true ) ) {
- self::cancel_subscription( $subscription, get_post_meta( $subscription->id, '_old_paypal_subscriber_id', true ) );
+ if ( 'paypal' == get_post_meta( $subscription->get_id(), '_old_payment_method', true ) ) {
+ self::cancel_subscription( $subscription, get_post_meta( $subscription->get_id(), '_old_paypal_subscriber_id', true ) );
}
$this->add_order_note( _x( 'IPN subscription payment method changed to PayPal.', 'when it is a payment change, and there is a subscr_signup message, this will be a confirmation message that PayPal accepted it being the new payment method', 'woocommerce-subscriptions' ), $subscription, $transaction_details );
@@ -261,9 +261,9 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
}
if ( $is_payment_change ) {
- WC_Gateway_Paypal::log( 'IPN subscription payment method changed for subscription ' . $subscription->id );
+ WC_Gateway_Paypal::log( 'IPN subscription payment method changed for subscription ' . $subscription->get_id() );
} else {
- WC_Gateway_Paypal::log( 'IPN subscription sign up completed for subscription ' . $subscription->id );
+ WC_Gateway_Paypal::log( 'IPN subscription sign up completed for subscription ' . $subscription->get_id() );
}
break;
@@ -301,37 +301,37 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
// Subscription Payment completed
$this->add_order_note( __( 'IPN subscription payment completed.', 'woocommerce-subscriptions' ), $subscription, $transaction_details );
- WC_Gateway_Paypal::log( 'IPN subscription payment completed for subscription ' . $subscription->id );
+ WC_Gateway_Paypal::log( 'IPN subscription payment completed for subscription ' . $subscription->get_id() );
// First payment on order, process payment & activate subscription
if ( $is_first_payment ) {
- $subscription->order->payment_complete( $transaction_details['txn_id'] );
+ $subscription->get_parent()->payment_complete( $transaction_details['txn_id'] );
// Store PayPal Details on Order
- $this->save_paypal_meta_data( $subscription->order, $transaction_details );
+ $this->save_paypal_meta_data( $subscription->get_parent(), $transaction_details );
// IPN got here first or PDT will never arrive. Normally PDT would have arrived, so the first IPN would not be the first payment. In case the the first payment is an IPN, we need to make sure to not ignore the second one
- update_post_meta( $subscription->id, '_paypal_first_ipn_ignored_for_pdt', 'true' );
+ update_post_meta( $subscription->get_id(), '_paypal_first_ipn_ignored_for_pdt', 'true' );
// Ignore the first IPN message if the PDT should have handled it (if it didn't handle it, it will have been dealt with as first payment), but set a flag to make sure we only ignore it once
- } elseif ( $subscription->get_completed_payment_count() == 1 && '' !== WCS_PayPal::get_option( 'identity_token' ) && 'true' != get_post_meta( $subscription->id, '_paypal_first_ipn_ignored_for_pdt', true ) && false === $is_renewal_sign_up_after_failure ) {
+ } elseif ( $subscription->get_completed_payment_count() == 1 && '' !== WCS_PayPal::get_option( 'identity_token' ) && 'true' != get_post_meta( $subscription->get_id(), '_paypal_first_ipn_ignored_for_pdt', true ) && false === $is_renewal_sign_up_after_failure ) {
- WC_Gateway_Paypal::log( 'IPN subscription payment ignored for subscription ' . $subscription->id . ' due to PDT previously handling the payment.' );
+ WC_Gateway_Paypal::log( 'IPN subscription payment ignored for subscription ' . $subscription->get_id() . ' due to PDT previously handling the payment.' );
- update_post_meta( $subscription->id, '_paypal_first_ipn_ignored_for_pdt', 'true' );
+ update_post_meta( $subscription->get_id(), '_paypal_first_ipn_ignored_for_pdt', 'true' );
// Process the payment if the subscription is active
} elseif ( ! $subscription->has_status( array( 'cancelled', 'expired', 'switched', 'trash' ) ) ) {
if ( true === $is_renewal_sign_up_after_failure && is_object( $renewal_order ) ) {
- update_post_meta( $subscription->id, '_paypal_failed_sign_up_recorded', $renewal_order->id );
+ update_post_meta( $subscription->get_id(), '_paypal_failed_sign_up_recorded', wcs_get_objects_property( $renewal_order, 'id' ) );
// We need to cancel the old subscription now that the method has been changed successfully
- if ( 'paypal' == get_post_meta( $subscription->id, '_old_payment_method', true ) ) {
+ if ( 'paypal' == get_post_meta( $subscription->get_id(), '_old_payment_method', true ) ) {
- $profile_id = get_post_meta( $subscription->id, '_old_paypal_subscriber_id', true );
+ $profile_id = get_post_meta( $subscription->get_id(), '_old_paypal_subscriber_id', true );
// Make sure we don't cancel the current profile
if ( $profile_id !== $transaction_details['subscr_id'] ) {
@@ -349,23 +349,23 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
if ( $subscription->get_time( 'trial_end' ) > gmdate( 'U' ) ) {
$update_dates['trial_end'] = gmdate( 'Y-m-d H:i:s', gmdate( 'U' ) - 1 );
- WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment for subscription %d: trial_end is in futute (date: %s) setting to %s.', $subscription->id, $subscription->get_date( 'trial_end' ), $update_dates['trial_end'] ) );
+ WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment for subscription %d: trial_end is in futute (date: %s) setting to %s.', $subscription->get_id(), $subscription->get_date( 'trial_end' ), $update_dates['trial_end'] ) );
} else {
- WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment for subscription %d: trial_end is in past (date: %s).', $subscription->id, $subscription->get_date( 'trial_end' ) ) );
+ WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment for subscription %d: trial_end is in past (date: %s).', $subscription->get_id(), $subscription->get_date( 'trial_end' ) ) );
}
if ( $subscription->get_time( 'next_payment' ) > gmdate( 'U' ) ) {
$update_dates['next_payment'] = gmdate( 'Y-m-d H:i:s', gmdate( 'U' ) - 1 );
- WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment for subscription %d: next_payment is in future (date: %s) setting to %s.', $subscription->id, $subscription->get_date( 'next_payment' ), $update_dates['next_payment'] ) );
+ WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment for subscription %d: next_payment is in future (date: %s) setting to %s.', $subscription->get_id(), $subscription->get_date( 'next_payment' ), $update_dates['next_payment'] ) );
} else {
- WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment for subscription %d: next_payment is in past (date: %s).', $subscription->id, $subscription->get_date( 'next_payment' ) ) );
+ WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment for subscription %d: next_payment is in past (date: %s).', $subscription->get_id(), $subscription->get_date( 'next_payment' ) ) );
}
if ( ! empty( $update_dates ) ) {
$subscription->update_dates( $update_dates );
}
} catch ( Exception $e ) {
- WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment exception subscription %d: %s.', $subscription->id, $e->getMessage() ) );
+ WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment exception subscription %d: %s.', $subscription->get_id(), $e->getMessage() ) );
}
remove_action( 'woocommerce_subscription_activated_paypal', 'WCS_PayPal_Status_Manager::reactivate_subscription' );
@@ -373,7 +373,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
try {
$renewal_order->payment_complete( $transaction_details['txn_id'] );
} catch ( Exception $e ) {
- WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment exception calling $renewal_order->payment_complete() for subscription %d: %s.', $subscription->id, $e->getMessage() ) );
+ WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment exception calling $renewal_order->payment_complete() for subscription %d: %s.', $subscription->get_id(), $e->getMessage() ) );
}
$this->add_order_note( __( 'IPN subscription payment completed.', 'woocommerce-subscriptions' ), $renewal_order, $transaction_details );
@@ -390,7 +390,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
if ( ! $is_first_payment ) {
- update_post_meta( $renewal_order->id, '_transaction_id', $transaction_details['txn_id'] );
+ wcs_set_objects_property( $renewal_order, 'transaction_id', $transaction_details['txn_id'] );
if ( 'failed' == strtolower( $transaction_details['payment_status'] ) ) {
$subscription->payment_failed();
@@ -403,10 +403,10 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
}
}
- WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment %s for subscription %d ', $transaction_details['payment_status'], $subscription->id ) );
+ WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment %s for subscription %d ', $transaction_details['payment_status'], $subscription->get_id() ) );
} else {
- WC_Gateway_Paypal::log( 'IPN subscription payment notification received for subscription ' . $subscription->id . ' with status ' . $transaction_details['payment_status'] );
+ WC_Gateway_Paypal::log( 'IPN subscription payment notification received for subscription ' . $subscription->get_id() . ' with status ' . $transaction_details['payment_status'] );
}
@@ -429,11 +429,11 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
add_action( 'woocommerce_subscription_on-hold_paypal', 'WCS_PayPal_Status_Manager::suspend_subscription' );
- WC_Gateway_Paypal::log( 'IPN subscription suspended for subscription ' . $subscription->id );
+ WC_Gateway_Paypal::log( 'IPN subscription suspended for subscription ' . $subscription->get_id() );
} else {
- WC_Gateway_Paypal::log( sprintf( 'IPN "recurring_payment_suspended" ignored for subscription %d. Subscription already %s.', $subscription->id, $subscription->get_status() ) );
+ WC_Gateway_Paypal::log( sprintf( 'IPN "recurring_payment_suspended" ignored for subscription %d. Subscription already %s.', $subscription->get_id(), $subscription->get_status() ) );
}
@@ -444,13 +444,13 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
// Make sure the subscription hasn't been linked to a new payment method
if ( wcs_get_paypal_id( $subscription ) != $transaction_details['subscr_id'] ) {
- WC_Gateway_Paypal::log( 'IPN subscription cancellation request ignored - new PayPal Profile ID linked to this subscription, for subscription ' . $subscription->id );
+ WC_Gateway_Paypal::log( 'IPN subscription cancellation request ignored - new PayPal Profile ID linked to this subscription, for subscription ' . $subscription->get_id() );
} else {
$subscription->cancel_order( __( 'IPN subscription cancelled.', 'woocommerce-subscriptions' ) );
- WC_Gateway_Paypal::log( 'IPN subscription cancelled for subscription ' . $subscription->id );
+ WC_Gateway_Paypal::log( 'IPN subscription cancelled for subscription ' . $subscription->get_id() );
}
@@ -458,7 +458,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
case 'subscr_eot': // Subscription ended, either due to failed payments or expiration
- WC_Gateway_Paypal::log( 'IPN EOT request ignored for subscription ' . $subscription->id );
+ WC_Gateway_Paypal::log( 'IPN EOT request ignored for subscription ' . $subscription->get_id() );
break;
case 'subscr_failed': // Subscription sign up failed
@@ -476,7 +476,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
$this->add_order_note( $ipn_failure_note, $renewal_order, $transaction_details );
}
- WC_Gateway_Paypal::log( 'IPN subscription payment failure for subscription ' . $subscription->id );
+ WC_Gateway_Paypal::log( 'IPN subscription payment failure for subscription ' . $subscription->get_id() );
// Subscription Payment completed
$this->add_order_note( $ipn_failure_note, $subscription, $transaction_details );
@@ -493,12 +493,12 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
// Store the transaction IDs to avoid handling requests duplicated by PayPal
if ( isset( $transaction_details['ipn_track_id'] ) ) {
$handled_ipn_requests[] = $ipn_id;
- update_post_meta( $subscription->id, '_paypal_ipn_tracking_ids', $handled_ipn_requests );
+ update_post_meta( $subscription->get_id(), '_paypal_ipn_tracking_ids', $handled_ipn_requests );
}
if ( isset( $transaction_details['txn_id'] ) ) {
$handled_transactions[] = $transaction_id;
- update_post_meta( $subscription->id, '_paypal_transaction_ids', $handled_transactions );
+ update_post_meta( $subscription->get_id(), '_paypal_transaction_ids', $handled_transactions );
}
// And delete the transient that's preventing other IPN's being processed
@@ -507,7 +507,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
}
// Log completion
- $log_message = 'IPN subscription request processed for ' . $subscription->id;
+ $log_message = 'IPN subscription request processed for ' . $subscription->get_id();
if ( isset( $ipn_id ) && ! empty( $ipn_id ) ) {
$log_message .= sprintf( ' (%s)', $ipn_id );
@@ -592,8 +592,8 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
if ( ! empty( $subscriptions ) ) {
$subscription = array_pop( $subscriptions );
- $order_id = $subscription->id;
- $order_key = $subscription->order_key;
+ $order_id = $subscription->get_id();
+ $order_key = $subscription->get_order_key();
}
}
} elseif ( preg_match( '/^a:2:{/', $args['custom'] ) && ! preg_match( '/[CO]:\+?[0-9]+:"/', $args['custom'] ) && ( $order_details = maybe_unserialize( $args['custom'] ) ) ) { // WC 2.0 - WC 2.3.11, only allow serialized data in the expected format, do not allow objects or anything nasty to sneak in
@@ -608,8 +608,8 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
if ( ! empty( $subscriptions ) ) {
$subscription = array_pop( $subscriptions );
- $order_id = $subscription->id;
- $order_key = $subscription->order_key;
+ $order_id = $subscription->get_id();
+ $order_key = $subscription->get_order_key();
}
}
} else { // WC 1.6.5 - WC 2.0 or invalid data
@@ -641,7 +641,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
return;
}
- $current_profile_id = wcs_get_paypal_id( $subscription->id );
+ $current_profile_id = wcs_get_paypal_id( $subscription->get_id() );
// Update the subscription using the old profile ID
wcs_set_paypal_id( $subscription, $old_paypal_subscriber_id );
diff --git a/includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php b/includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php
index 1f92780..db055a2 100644
--- a/includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php
+++ b/includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php
@@ -33,9 +33,9 @@ class WCS_PayPal_Standard_Request {
// Payment method changes act on the subscription not the original order
if ( $is_payment_change ) {
- $subscriptions = array( wcs_get_subscription( $order->id ) );
+ $subscriptions = array( wcs_get_subscription( wcs_get_objects_property( $order, 'id' ) ) );
$subscription = array_pop( $subscriptions );
- $order = $subscription->order;
+ $order = $subscription->get_parent();
// We need the subscription's total
remove_filter( 'woocommerce_order_amount_total', 'WC_Subscriptions_Change_Payment_Gateway::maybe_zero_total', 11, 2 );
@@ -43,7 +43,7 @@ class WCS_PayPal_Standard_Request {
} else {
// Otherwise the order is the $order
- if ( $cart_item = wcs_cart_contains_failed_renewal_order_payment() || false !== WC_Subscriptions_Renewal_Order::get_failed_order_replaced_by( $order->id ) ) {
+ if ( $cart_item = wcs_cart_contains_failed_renewal_order_payment() || false !== WC_Subscriptions_Renewal_Order::get_failed_order_replaced_by( wcs_get_objects_property( $order, 'id' ) ) ) {
$subscriptions = wcs_get_subscriptions_for_renewal_order( $order );
$order_contains_failed_renewal = true;
} else {
@@ -60,7 +60,7 @@ class WCS_PayPal_Standard_Request {
$paypal_args['cmd'] = '_xclick-subscriptions';
// Store the subscription ID in the args sent to PayPal so we can access them later
- $paypal_args['custom'] = wcs_json_encode( array( 'order_id' => $order->id, 'order_key' => $order->order_key, 'subscription_id' => $subscription->id, 'subscription_key' => $subscription->order_key ) );
+ $paypal_args['custom'] = wcs_json_encode( array( 'order_id' => wcs_get_objects_property( $order, 'id' ), 'order_key' => wcs_get_objects_property( $order, 'order_key' ), 'subscription_id' => $subscription->get_id(), 'subscription_key' => $subscription->get_order_key() ) );
foreach ( $subscription->get_items() as $item ) {
if ( $item['qty'] > 1 ) {
@@ -74,8 +74,8 @@ class WCS_PayPal_Standard_Request {
$paypal_args['item_name'] = wcs_get_paypal_item_name( sprintf( _x( 'Subscription %1$s (Order %2$s) - %3$s', 'item name sent to paypal', 'woocommerce-subscriptions' ), $subscription->get_order_number(), $order->get_order_number(), implode( ', ', $item_names ) ) );
$unconverted_periods = array(
- 'billing_period' => $subscription->billing_period,
- 'trial_period' => $subscription->trial_period,
+ 'billing_period' => $subscription->get_billing_period(),
+ 'trial_period' => $subscription->get_trial_period(),
);
$converted_periods = array();
@@ -100,12 +100,12 @@ class WCS_PayPal_Standard_Request {
}
$price_per_period = $subscription->get_total();
- $subscription_interval = $subscription->billing_interval;
- $start_timestamp = $subscription->get_time( 'start' );
+ $subscription_interval = $subscription->get_billing_interval();
+ $start_timestamp = $subscription->get_time( 'date_created' );
$trial_end_timestamp = $subscription->get_time( 'trial_end' );
$next_payment_timestamp = $subscription->get_time( 'next_payment' );
- $is_synced_subscription = WC_Subscriptions_Synchroniser::subscription_contains_synced_product( $subscription->id );
+ $is_synced_subscription = WC_Subscriptions_Synchroniser::subscription_contains_synced_product( $subscription->get_id() );
if ( $is_synced_subscription ) {
$length_from_timestamp = $next_payment_timestamp;
@@ -115,7 +115,7 @@ class WCS_PayPal_Standard_Request {
$length_from_timestamp = $start_timestamp;
}
- $subscription_length = wcs_estimate_periods_between( $length_from_timestamp, $subscription->get_time( 'end' ), $subscription->billing_period );
+ $subscription_length = wcs_estimate_periods_between( $length_from_timestamp, $subscription->get_time( 'end' ), $subscription->get_billing_period() );
$subscription_installments = $subscription_length / $subscription_interval;
@@ -128,24 +128,24 @@ class WCS_PayPal_Standard_Request {
$suffix = '-wcscpm-' . wp_create_nonce();
} else {
// Failed renewal order, append a descriptor and renewal order's ID
- $suffix = '-wcsfrp-' . $order->id;
+ $suffix = '-wcsfrp-' . wcs_get_objects_property( $order, 'id' );
}
+ $parent_order = $subscription->get_parent();
+
// Change the 'invoice' and the 'custom' values to be for the original order (if there is one)
- if ( false === $subscription->order ) {
+ if ( false === $parent_order ) {
// No original order so we need to use the subscriptions values instead
$order_number = ltrim( $subscription->get_order_number(), _x( '#', 'hash before the order number. Used as a character to remove from the actual order number', 'woocommerce-subscriptions' ) ) . '-subscription';
- $order_id_key = array( 'order_id' => $subscription->id, 'order_key' => $subscription->order_key );
+ $order_id_key = array( 'order_id' => $subscription->get_id(), 'order_key' => $subscription->get_order_key() );
} else {
- $order_number = ltrim( $subscription->order->get_order_number(), _x( '#', 'hash before the order number. Used as a character to remove from the actual order number', 'woocommerce-subscriptions' ) );
- $order_id_key = array( 'order_id' => $subscription->order->id, 'order_key' => $subscription->order->order_key );
+ $order_number = ltrim( $parent_order->get_order_number(), _x( '#', 'hash before the order number. Used as a character to remove from the actual order number', 'woocommerce-subscriptions' ) );
+ $order_id_key = array( 'order_id' => wcs_get_objects_property( $parent_order, 'id' ), 'order_key' => wcs_get_objects_property( $parent_order, 'order_key' ) );
}
- $order_details = ( false !== $subscription->order ) ? $subscription->order : $subscription;
-
// Set the invoice details to the original order's invoice but also append a special string and this renewal orders ID so that we can match it up as a failed renewal order payment later
$paypal_args['invoice'] = WCS_PayPal::get_option( 'invoice_prefix' ) . $order_number . $suffix;
- $paypal_args['custom'] = wcs_json_encode( array_merge( $order_id_key, array( 'subscription_id' => $subscription->id, 'subscription_key' => $subscription->order_key ) ) );
+ $paypal_args['custom'] = wcs_json_encode( array_merge( $order_id_key, array( 'subscription_id' => $subscription->get_id(), 'subscription_key' => $subscription->get_order_key() ) ) );
}
@@ -182,7 +182,7 @@ class WCS_PayPal_Standard_Request {
}
} else {
- $subscription_trial_length = wcs_estimate_periods_between( $start_timestamp, $trial_end_timestamp, $subscription->trial_period );
+ $subscription_trial_length = wcs_estimate_periods_between( $start_timestamp, $trial_end_timestamp, $subscription->get_trial_period() );
}
diff --git a/includes/gateways/paypal/includes/class-wcs-paypal-standard-switcher.php b/includes/gateways/paypal/includes/class-wcs-paypal-standard-switcher.php
index bf017b9..8531830 100644
--- a/includes/gateways/paypal/includes/class-wcs-paypal-standard-switcher.php
+++ b/includes/gateways/paypal/includes/class-wcs-paypal-standard-switcher.php
@@ -56,9 +56,9 @@ class WCS_PayPal_Standard_Switcher {
*/
public static function can_item_be_switched( $item_can_be_switch, $item, $subscription ) {
- if ( false === $item_can_be_switch && 'paypal' === $subscription->payment_method && WCS_PayPal::are_reference_transactions_enabled() ) {
+ if ( false === $item_can_be_switch && 'paypal' === $subscription->get_payment_method() && WCS_PayPal::are_reference_transactions_enabled() ) {
- $is_billing_agreement = wcs_is_paypal_profile_a( wcs_get_paypal_id( $subscription->id ), 'billing_agreement' );
+ $is_billing_agreement = wcs_is_paypal_profile_a( wcs_get_paypal_id( $subscription->get_id() ), 'billing_agreement' );
if ( 'line_item' == $item['type'] && wcs_is_product_switchable_type( $item['product_id'] ) ) {
$is_product_switchable = true;
@@ -66,7 +66,7 @@ class WCS_PayPal_Standard_Switcher {
$is_product_switchable = false;
}
- if ( $subscription->has_status( 'active' ) && 0 !== $subscription->get_date( 'last_payment' ) ) {
+ if ( $subscription->has_status( 'active' ) && 0 !== $subscription->get_date( 'last_order_date_created' ) ) {
$is_subscription_switchable = true;
} else {
$is_subscription_switchable = false;
@@ -99,7 +99,7 @@ class WCS_PayPal_Standard_Switcher {
$subscription = wcs_get_subscription( $cart_switch_details['subscription_id'] );
- if ( 'paypal' === $subscription->payment_method && ! wcs_is_paypal_profile_a( wcs_get_paypal_id( $subscription->id ), 'billing_agreement' ) ) {
+ if ( 'paypal' === $subscription->get_payment_method() && ! wcs_is_paypal_profile_a( wcs_get_paypal_id( $subscription->get_id() ), 'billing_agreement' ) ) {
$needs_payment = true;
break;
}
@@ -127,13 +127,16 @@ class WCS_PayPal_Standard_Switcher {
foreach ( wcs_get_subscriptions_for_switch_order( $order_id ) as $subscription ) {
- if ( 'paypal' === $subscription->payment_method && $subscription->payment_method !== $order->payment_method && false === wcs_is_paypal_profile_a( wcs_get_paypal_id( $subscription->id ), 'billing_agreement' ) ) {
+ $order_payment_method = wcs_get_objects_property( $order, 'payment_method' );
+
+ if ( 'paypal' === $subscription->get_payment_method() && $subscription->get_payment_method() !== $order_payment_method && false === wcs_is_paypal_profile_a( wcs_get_paypal_id( $subscription->get_id() ), 'billing_agreement' ) ) {
// Set the new payment method on the subscription
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
- if ( isset( $available_gateways[ $order->payment_method ] ) ) {
- $subscription->set_payment_method( $available_gateways[ $order->payment_method ] );
+ if ( isset( $available_gateways[ $order_payment_method ] ) ) {
+ $subscription->set_payment_method( $available_gateways[ $order_payment_method ] );
+ $subscription->save();
}
}
}
@@ -158,9 +161,9 @@ class WCS_PayPal_Standard_Switcher {
foreach ( $subscriptions as $subscription ) {
- if ( 'paypal' === $subscription->payment_method ) {
+ if ( 'paypal' === $subscription->get_payment_method() ) {
- $paypal_id = wcs_get_paypal_id( $subscription->id );
+ $paypal_id = wcs_get_paypal_id( $subscription->get_id() );
if ( ! wcs_is_paypal_profile_a( $paypal_id, 'billing_agreement' ) ) {
update_post_meta( $order_id, '_old_payment_method', 'paypal_standard' );
@@ -179,29 +182,29 @@ class WCS_PayPal_Standard_Switcher {
*/
public static function cancel_paypal_standard_after_switch( $order ) {
- if ( 'paypal_standard' == get_post_meta( $order->id, '_old_payment_method', true ) ) {
+ if ( 'paypal_standard' == get_post_meta( wcs_get_objects_property( $order, 'id' ), '_old_payment_method', true ) ) {
- $old_profile_id = get_post_meta( $order->id, '_old_paypal_subscription_id', true );
+ $old_profile_id = get_post_meta( wcs_get_objects_property( $order, 'id' ), '_old_paypal_subscription_id', true );
if ( ! empty( $old_profile_id ) ) {
- $subscriptions = wcs_get_subscriptions_for_order( $order->id, array( 'order_type' => 'switch' ) );
+ $subscriptions = wcs_get_subscriptions_for_order( wcs_get_objects_property( $order, 'id' ), array( 'order_type' => 'switch' ) );
foreach ( $subscriptions as $subscription ) {
if ( ! wcs_is_paypal_profile_a( $old_profile_id, 'billing_agreement' ) ) {
- $new_payment_method = $subscription->payment_method;
- $new_profile_id = get_post_meta( $subscription->id, '_paypal_subscription_id', true ); // grab the current paypal subscription id in case it's a billing agreement
+ $new_payment_method = $subscription->get_payment_method();
+ $new_profile_id = get_post_meta( $subscription->get_id(), '_paypal_subscription_id', true ); // grab the current paypal subscription id in case it's a billing agreement
- update_post_meta( $subscription->id, '_payment_method', 'paypal' );
- update_post_meta( $subscription->id, '_paypal_subscription_id', $old_profile_id );
+ update_post_meta( $subscription->get_id(), '_payment_method', 'paypal' );
+ update_post_meta( $subscription->get_id(), '_paypal_subscription_id', $old_profile_id );
WCS_PayPal_Status_Manager::suspend_subscription( $subscription );
// restore payment meta to the new data
- update_post_meta( $subscription->id, '_payment_method', $new_payment_method );
- update_post_meta( $subscription->id, '_paypal_subscription_id', $new_profile_id );
+ update_post_meta( $subscription->get_id(), '_payment_method', $new_payment_method );
+ update_post_meta( $subscription->get_id(), '_paypal_subscription_id', $new_profile_id );
}
}
}
diff --git a/includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php b/includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php
index 87100aa..7be77b8 100644
--- a/includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php
+++ b/includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php
@@ -38,7 +38,7 @@ class WCS_PayPal_Status_Manager extends WCS_PayPal {
* @since 2.0
*/
public static function cancel_subscription( $subscription ) {
- if ( ! wcs_is_paypal_profile_a( wcs_get_paypal_id( $subscription->id ), 'billing_agreement' ) && self::update_subscription_status( $subscription, 'Cancel' ) ) {
+ if ( ! wcs_is_paypal_profile_a( wcs_get_paypal_id( $subscription->get_id() ), 'billing_agreement' ) && self::update_subscription_status( $subscription, 'Cancel' ) ) {
$subscription->add_order_note( __( 'Subscription cancelled with PayPal', 'woocommerce-subscriptions' ) );
}
}
@@ -49,7 +49,7 @@ class WCS_PayPal_Status_Manager extends WCS_PayPal {
* @since 2.0
*/
public static function suspend_subscription( $subscription ) {
- if ( ! wcs_is_paypal_profile_a( wcs_get_paypal_id( $subscription->id ), 'billing_agreement' ) && self::update_subscription_status( $subscription, 'Suspend' ) ) {
+ if ( ! wcs_is_paypal_profile_a( wcs_get_paypal_id( $subscription->get_id() ), 'billing_agreement' ) && self::update_subscription_status( $subscription, 'Suspend' ) ) {
$subscription->add_order_note( __( 'Subscription suspended with PayPal', 'woocommerce-subscriptions' ) );
}
}
@@ -62,7 +62,7 @@ class WCS_PayPal_Status_Manager extends WCS_PayPal {
* @since 2.0
*/
public static function reactivate_subscription( $subscription ) {
- if ( ! wcs_is_paypal_profile_a( wcs_get_paypal_id( $subscription->id ), 'billing_agreement' ) && self::update_subscription_status( $subscription, 'Reactivate' ) ) {
+ if ( ! wcs_is_paypal_profile_a( wcs_get_paypal_id( $subscription->get_id() ), 'billing_agreement' ) && self::update_subscription_status( $subscription, 'Reactivate' ) ) {
$subscription->add_order_note( __( 'Subscription reactivated with PayPal', 'woocommerce-subscriptions' ) );
}
}
@@ -77,7 +77,7 @@ class WCS_PayPal_Status_Manager extends WCS_PayPal {
*/
public static function update_subscription_status( $subscription, $new_status ) {
- $profile_id = wcs_get_paypal_id( $subscription->id );
+ $profile_id = wcs_get_paypal_id( $subscription->get_id() );
if ( wcs_is_paypal_profile_a( $profile_id, 'billing_agreement' ) ) {
@@ -129,7 +129,7 @@ class WCS_PayPal_Status_Manager extends WCS_PayPal {
* @since 2.0
*/
public static function suspend_subscription_on_payment_changed( $status, $subscription ) {
- return ( 'paypal' == $subscription->payment_gateway->id ) ? 'on-hold' : $status;
+ return ( 'paypal' == $subscription->get_payment_method() ) ? 'on-hold' : $status;
}
}
diff --git a/includes/gateways/paypal/includes/class-wcs-paypal-supports.php b/includes/gateways/paypal/includes/class-wcs-paypal-supports.php
index 7541f67..3a88e1d 100644
--- a/includes/gateways/paypal/includes/class-wcs-paypal-supports.php
+++ b/includes/gateways/paypal/includes/class-wcs-paypal-supports.php
@@ -78,9 +78,9 @@ class WCS_PayPal_Supports {
*/
public static function add_feature_support_for_subscription( $is_supported, $feature, $subscription ) {
- if ( 'paypal' === $subscription->payment_method && WCS_PayPal::are_credentials_set() ) {
+ if ( 'paypal' === $subscription->get_payment_method() && WCS_PayPal::are_credentials_set() ) {
- $paypal_profile_id = wcs_get_paypal_id( $subscription->id );
+ $paypal_profile_id = wcs_get_paypal_id( $subscription->get_id() );
$is_billing_agreement = wcs_is_paypal_profile_a( $paypal_profile_id, 'billing_agreement' );
if ( 'gateway_scheduled_payments' === $feature && $is_billing_agreement ) {
diff --git a/includes/gateways/paypal/includes/wcs-paypal-functions.php b/includes/gateways/paypal/includes/wcs-paypal-functions.php
index aedc39c..7b116c0 100644
--- a/includes/gateways/paypal/includes/wcs-paypal-functions.php
+++ b/includes/gateways/paypal/includes/wcs-paypal-functions.php
@@ -20,13 +20,13 @@ if ( ! defined( 'ABSPATH' ) ) {
* @param int The ID of a WC_Order or WC_Subscription object
* @since 2.0
*/
-function wcs_get_paypal_id( $order_id ) {
+function wcs_get_paypal_id( $order ) {
- if ( is_object( $order_id ) ) {
- $order_id = $order_id->id;
+ if ( ! is_object( $order ) ) {
+ $order = wc_get_order( $order );
}
- return get_post_meta( $order_id, '_paypal_subscription_id', true );
+ return wcs_get_objects_property( $order, '_paypal_subscription_id' );
}
/**
@@ -48,7 +48,7 @@ function wcs_set_paypal_id( $order, $paypal_subscription_id ) {
}
}
- return update_post_meta( $order->id, '_paypal_subscription_id', $paypal_subscription_id );
+ wcs_set_objects_property( $order, 'paypal_subscription_id', $paypal_subscription_id );
}
/**
diff --git a/includes/legacy/class-wc-product-subscription-legacy.php b/includes/legacy/class-wc-product-subscription-legacy.php
new file mode 100644
index 0000000..d2cfbda
--- /dev/null
+++ b/includes/legacy/class-wc-product-subscription-legacy.php
@@ -0,0 +1,79 @@
+product_type = 'subscription';
+
+ // Load all meta fields
+ $this->product_custom_fields = get_post_meta( $this->id );
+
+ // Convert selected subscription meta fields for easy access
+ if ( ! empty( $this->product_custom_fields['_subscription_price'][0] ) ) {
+ $this->subscription_price = $this->product_custom_fields['_subscription_price'][0];
+ }
+
+ if ( ! empty( $this->product_custom_fields['_subscription_sign_up_fee'][0] ) ) {
+ $this->subscription_sign_up_fee = $this->product_custom_fields['_subscription_sign_up_fee'][0];
+ }
+
+ if ( ! empty( $this->product_custom_fields['_subscription_period'][0] ) ) {
+ $this->subscription_period = $this->product_custom_fields['_subscription_period'][0];
+ }
+
+ if ( ! empty( $this->product_custom_fields['_subscription_period_interval'][0] ) ) {
+ $this->subscription_period_interval = $this->product_custom_fields['_subscription_period_interval'][0];
+ }
+
+ if ( ! empty( $this->product_custom_fields['_subscription_length'][0] ) ) {
+ $this->subscription_length = $this->product_custom_fields['_subscription_length'][0];
+ }
+
+ if ( ! empty( $this->product_custom_fields['_subscription_trial_length'][0] ) ) {
+ $this->subscription_trial_length = $this->product_custom_fields['_subscription_trial_length'][0];
+ }
+
+ if ( ! empty( $this->product_custom_fields['_subscription_trial_period'][0] ) ) {
+ $this->subscription_trial_period = $this->product_custom_fields['_subscription_trial_period'][0];
+ }
+
+ $this->subscription_payment_sync_date = ( ! isset( $this->product_custom_fields['_subscription_payment_sync_date'][0] ) ) ? 0 : maybe_unserialize( $this->product_custom_fields['_subscription_payment_sync_date'][0] );
+ $this->subscription_one_time_shipping = ( ! isset( $this->product_custom_fields['_subscription_one_time_shipping'][0] ) ) ? 'no' : $this->product_custom_fields['_subscription_one_time_shipping'][0];
+ $this->subscription_limit = ( ! isset( $this->product_custom_fields['_subscription_limit'][0] ) ) ? 'no' : $this->product_custom_fields['_subscription_limit'][0];
+ }
+}
diff --git a/includes/legacy/class-wc-product-subscription-variation-legacy.php b/includes/legacy/class-wc-product-subscription-variation-legacy.php
new file mode 100644
index 0000000..e128843
--- /dev/null
+++ b/includes/legacy/class-wc-product-subscription-variation-legacy.php
@@ -0,0 +1,101 @@
+parent_product_type = $this->product_type;
+
+ $this->product_type = 'subscription_variation';
+
+ $this->subscription_variation_level_meta_data = array(
+ 'subscription_price' => 0,
+ 'subscription_period' => '',
+ 'subscription_period_interval' => 'day',
+ 'subscription_length' => 0,
+ 'subscription_trial_length' => 0,
+ 'subscription_trial_period' => 'day',
+ 'subscription_sign_up_fee' => 0,
+ 'subscription_payment_sync_date' => 0,
+ );
+
+ $this->variation_level_meta_data = array_merge( $this->variation_level_meta_data, $this->subscription_variation_level_meta_data );
+ }
+
+ /* Copied from WC 2.6 WC_Product_Variation */
+
+ /**
+ * __isset function.
+ *
+ * @param mixed $key
+ * @return bool
+ */
+ public function __isset( $key ) {
+ if ( in_array( $key, array( 'variation_data', 'variation_has_stock' ) ) ) {
+ return true;
+ } elseif ( in_array( $key, array_keys( $this->variation_level_meta_data ) ) ) {
+ return metadata_exists( 'post', $this->variation_id, '_' . $key );
+ } elseif ( in_array( $key, array_keys( $this->variation_inherited_meta_data ) ) ) {
+ return metadata_exists( 'post', $this->variation_id, '_' . $key ) || metadata_exists( 'post', $this->id, '_' . $key );
+ } else {
+ return metadata_exists( 'post', $this->id, '_' . $key );
+ }
+ }
+
+ /**
+ * Get method returns variation meta data if set, otherwise in most cases the data from the parent.
+ *
+ * We need to use the WC_Product_Variation's __get() method, not the one in WC_Product_Subscription_Variation,
+ * which handles deprecation notices.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function __get( $key ) {
+ return WC_Product_Variation::__get( $key );
+ }
+
+ /**
+ * Provide a WC 3.0 method for variations.
+ *
+ * WC < 3.0 products have a get_parent() method, but this is not equivalent to the get_parent_id() method
+ * introduced in WC 3.0, because it derives the parent from $this->post->post_parent, but for variations,
+ * $this->post refers to the parent variable object's post, so $this->post->post_parent will be 0 under
+ * normal circumstances. Becuase of that, we can rely on wcs_get_objects_property( $this, 'parent_id' )
+ * and define this get_parent_id() method for variations even when WC 3.0 is not active.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function get_parent_id() {
+ return $this->id; // When WC < 3.0 is active, the ID property is the parent variable product's ID
+ }
+}
diff --git a/includes/legacy/class-wc-product-variable-subscription-legacy.php b/includes/legacy/class-wc-product-variable-subscription-legacy.php
new file mode 100644
index 0000000..8438aca
--- /dev/null
+++ b/includes/legacy/class-wc-product-variable-subscription-legacy.php
@@ -0,0 +1,381 @@
+parent_product_type = $this->product_type;
+
+ $this->product_type = 'variable-subscription';
+
+ // Load all meta fields
+ $this->product_custom_fields = get_post_meta( $this->id );
+
+ // Convert selected subscription meta fields for easy access
+ if ( ! empty( $this->product_custom_fields['_subscription_price'][0] ) ) {
+ $this->subscription_price = $this->product_custom_fields['_subscription_price'][0];
+ }
+
+ if ( ! empty( $this->product_custom_fields['_subscription_sign_up_fee'][0] ) ) {
+ $this->subscription_sign_up_fee = $this->product_custom_fields['_subscription_sign_up_fee'][0];
+ }
+
+ if ( ! empty( $this->product_custom_fields['_subscription_period'][0] ) ) {
+ $this->subscription_period = $this->product_custom_fields['_subscription_period'][0];
+ }
+
+ if ( ! empty( $this->product_custom_fields['_subscription_period_interval'][0] ) ) {
+ $this->subscription_period_interval = $this->product_custom_fields['_subscription_period_interval'][0];
+ }
+
+ if ( ! empty( $this->product_custom_fields['_subscription_length'][0] ) ) {
+ $this->subscription_length = $this->product_custom_fields['_subscription_length'][0];
+ }
+
+ if ( ! empty( $this->product_custom_fields['_subscription_trial_length'][0] ) ) {
+ $this->subscription_trial_length = $this->product_custom_fields['_subscription_trial_length'][0];
+ }
+
+ if ( ! empty( $this->product_custom_fields['_subscription_trial_period'][0] ) ) {
+ $this->subscription_trial_period = $this->product_custom_fields['_subscription_trial_period'][0];
+ }
+
+ $this->subscription_payment_sync_date = 0;
+ $this->subscription_one_time_shipping = ( ! isset( $this->product_custom_fields['_subscription_one_time_shipping'][0] ) ) ? 'no' : $this->product_custom_fields['_subscription_one_time_shipping'][0];
+ $this->subscription_limit = ( ! isset( $this->product_custom_fields['_subscription_limit'][0] ) ) ? 'no' : $this->product_custom_fields['_subscription_limit'][0];
+ }
+
+
+ /**
+ * Get the min or max variation (active) price.
+ *
+ * This is a copy of WooCommerce < 2.4's get_variation_price() method, because 2.4.0 introduced a new
+ * transient caching system which assumes asort() on prices yields correct results for min/max prices
+ * (which it does for prices alone, but that's not the full story for subscription prices). Unfortunately,
+ * the new caching system is also hard to hook into so we'll just use the old system instead as the
+ * @see self::variable_product_sync() uses the old method also.
+ *
+ * @param string $min_or_max - min or max
+ * @param boolean $display Whether the value is going to be displayed
+ * @return string
+ */
+ public function get_variation_price( $min_or_max = 'min', $display = false ) {
+ $variation_id = get_post_meta( $this->id, '_' . $min_or_max . '_price_variation_id', true );
+
+ if ( $display ) {
+ if ( $variation = wc_get_product( $variation_id ) ) {
+ if ( 'incl' == get_option( 'woocommerce_tax_display_shop' ) ) {
+ $price = wcs_get_price_including_tax( $variation );
+ } else {
+ $price = wcs_get_price_excluding_tax( $variation );
+ }
+ } else {
+ $price = '';
+ }
+ } else {
+ $price = get_post_meta( $variation_id, '_price', true );
+ }
+
+ return apply_filters( 'woocommerce_get_variation_price', $price, $this, $min_or_max, $display );
+ }
+
+ /**
+ * Get an array of all sale and regular prices from all variations re-ordered after WC has done a standard sort, to reflect subscription terms.
+ * The first and last element for each price type is the least and most expensive, respectively.
+ *
+ * @see WC_Product_Variable::get_variation_prices()
+ * @param bool $include_taxes Should taxes be included in the prices.
+ * @return array() Array of RAW prices, regular prices, and sale prices with keys set to variation ID.
+ * @since 2.2.0
+ */
+ public function get_variation_prices( $display = false ) {
+
+ $price_hash = $this->get_price_hash( $this, $display );
+
+ $this->prices_array[ $price_hash ] = parent::get_variation_prices( $display );
+
+ $children = array_keys( $this->prices_array[ $price_hash ]['price'] );
+ sort( $children );
+
+ $min_max_data = wcs_get_min_max_variation_data( $this, $children );
+
+ $min_variation_id = $min_max_data['min']['variation_id'];
+ $max_variation_id = $min_max_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
+ foreach ( $this->prices_array as $price_hash => $prices ) {
+
+ // Loop over sale_price, regular_price & price values to update them on main array
+ foreach ( $prices as $price_key => $variation_prices ) {
+
+ $min_price = $prices[ $price_key ][ $min_variation_id ];
+ $max_price = $prices[ $price_key ][ $max_variation_id ];
+
+ unset( $prices[ $price_key ][ $min_variation_id ] );
+ unset( $prices[ $price_key ][ $max_variation_id ] );
+
+ // append the minimum variation and prepend the maximum variation
+ $prices[ $price_key ] = array( $min_variation_id => $min_price ) + $prices[ $price_key ];
+ $prices[ $price_key ] += array( $max_variation_id => $max_price );
+
+ $this->prices_array[ $price_hash ][ $price_key ] = $prices[ $price_key ];
+ }
+ }
+
+ $this->subscription_price = $min_max_data['min']['price'];
+ $this->subscription_period = $min_max_data['min']['period'];
+ $this->subscription_period_interval = $min_max_data['min']['interval'];
+
+ $this->max_variation_price = $min_max_data['max']['price'];
+ $this->max_variation_period = $min_max_data['max']['period'];
+ $this->max_variation_period_interval = $min_max_data['max']['interval'];
+
+ $this->min_variation_price = $min_max_data['min']['price'];
+ $this->min_variation_regular_price = $min_max_data['min']['regular_price'];
+
+ return $this->prices_array[ $price_hash ];
+ }
+
+ /**
+ * Create unique cache key based on the tax location (affects displayed/cached prices), product version and active price filters.
+ * DEVELOPERS should filter this hash if offering conditonal pricing to keep it unique.
+ *
+ * @since 2.2.0
+ * @param WC_Product
+ * @param bool $display Are prices for display? If so, taxes will be calculated.
+ * @return string
+ */
+ protected function get_price_hash( $display = false ) {
+ global $wp_filter;
+
+ if ( $display ) {
+ $price_hash = array( get_option( 'woocommerce_tax_display_shop', 'excl' ), WC_Tax::get_rates() );
+ } else {
+ $price_hash = array( false );
+ }
+
+ $filter_names = array( 'woocommerce_variation_prices_price', 'woocommerce_variation_prices_regular_price', 'woocommerce_variation_prices_sale_price' );
+
+ foreach ( $filter_names as $filter_name ) {
+ if ( ! empty( $wp_filter[ $filter_name ] ) ) {
+ $price_hash[ $filter_name ] = array();
+
+ foreach ( $wp_filter[ $filter_name ] as $priority => $callbacks ) {
+ $price_hash[ $filter_name ][] = array_values( wp_list_pluck( $callbacks, 'function' ) );
+ }
+ }
+ }
+
+ $price_hash = md5( json_encode( apply_filters( 'woocommerce_get_variation_prices_hash', $price_hash, $this, $display ) ) );
+
+ return $price_hash;
+ }
+
+ /**
+ * Sync variable product prices with the childs lowest/highest prices.
+ *
+ * @access public
+ * @return void
+ */
+ public function variable_product_sync( $product_id = '' ) {
+
+ WC_Product_Variable::variable_product_sync( $product_id );
+
+ $child_variation_ids = $this->get_children( true );
+
+ if ( $child_variation_ids ) {
+
+ $min_max_data = wcs_get_min_max_variation_data( $this, $child_variation_ids );
+
+ update_post_meta( $this->id, '_min_price_variation_id', $min_max_data['min']['variation_id'] );
+ update_post_meta( $this->id, '_max_price_variation_id', $min_max_data['max']['variation_id'] );
+
+ update_post_meta( $this->id, '_price', $min_max_data['min']['price'] );
+ update_post_meta( $this->id, '_min_variation_price', $min_max_data['min']['price'] );
+ update_post_meta( $this->id, '_max_variation_price', $min_max_data['max']['price'] );
+ update_post_meta( $this->id, '_min_variation_regular_price', $min_max_data['min']['regular_price'] );
+ update_post_meta( $this->id, '_max_variation_regular_price', $min_max_data['max']['regular_price'] );
+ update_post_meta( $this->id, '_min_variation_sale_price', $min_max_data['min']['sale_price'] );
+ update_post_meta( $this->id, '_max_variation_sale_price', $min_max_data['max']['sale_price'] );
+
+ update_post_meta( $this->id, '_min_variation_period', $min_max_data['min']['period'] );
+ update_post_meta( $this->id, '_max_variation_period', $min_max_data['max']['period'] );
+ update_post_meta( $this->id, '_min_variation_period_interval', $min_max_data['min']['interval'] );
+ update_post_meta( $this->id, '_max_variation_period_interval', $min_max_data['max']['interval'] );
+
+ update_post_meta( $this->id, '_subscription_price', $min_max_data['min']['price'] );
+ update_post_meta( $this->id, '_subscription_sign_up_fee', $min_max_data['subscription']['signup-fee'] );
+ update_post_meta( $this->id, '_subscription_period', $min_max_data['min']['period'] );
+ update_post_meta( $this->id, '_subscription_period_interval', $min_max_data['min']['interval'] );
+ update_post_meta( $this->id, '_subscription_trial_period', $min_max_data['subscription']['trial_period'] );
+ update_post_meta( $this->id, '_subscription_trial_length', $min_max_data['subscription']['trial_length'] );
+ update_post_meta( $this->id, '_subscription_length', $min_max_data['subscription']['length'] );
+
+ $this->subscription_price = $min_max_data['min']['price'];
+ $this->subscription_period = $min_max_data['min']['period'];
+ $this->subscription_period_interval = $min_max_data['min']['interval'];
+ $this->subscription_sign_up_fee = $min_max_data['subscription']['signup-fee'];
+ $this->subscription_trial_period = $min_max_data['subscription']['trial_period'];
+ $this->subscription_trial_length = $min_max_data['subscription']['trial_length'];
+ $this->subscription_length = $min_max_data['subscription']['length'];
+
+ if ( function_exists( 'wc_delete_product_transients' ) ) {
+ wc_delete_product_transients( $this->id );
+ } else {
+ WC()->clear_product_transients( $this->id );
+ }
+ } else { // No variations yet
+
+ $this->subscription_price = '';
+ $this->subscription_sign_up_fee = '';
+ $this->subscription_period = 'day';
+ $this->subscription_period_interval = 1;
+ $this->subscription_trial_period = 'day';
+ $this->subscription_trial_length = 1;
+ $this->subscription_length = 0;
+
+ }
+ }
+
+ /**
+ * Returns the price in html format.
+ *
+ * @access public
+ * @param string $price (default: '')
+ * @return string
+ */
+ public function get_price_html( $price = '' ) {
+
+ if ( ! isset( $this->subscription_period ) || ! isset( $this->subscription_period_interval ) || ! isset( $this->max_variation_period ) || ! isset( $this->max_variation_period_interval ) ) {
+ $this->variable_product_sync();
+ }
+
+ // Only create the subscription price string when a price has been set
+ if ( $this->subscription_price !== '' ) {
+
+ $price = '';
+
+ if ( $this->is_on_sale() && isset( $this->min_variation_price ) && $this->min_variation_regular_price !== $this->get_price() ) {
+
+ if ( ! $this->min_variation_price || $this->min_variation_price !== $this->max_variation_price ) {
+ $price .= wcs_get_price_html_from_text( $this );
+ }
+
+ $variation_id = get_post_meta( $this->id, '_min_price_variation_id', true );
+ $variation = wc_get_product( $variation_id );
+ $tax_display_mode = get_option( 'woocommerce_tax_display_shop' );
+
+ $sale_price_args = array( 'qty' => 1, 'price' => $variation->get_sale_price() );
+ $regular_price_args = array( 'qty' => 1, 'price' => $variation->get_regular_price() );
+
+ if ( 'incl' == $tax_display_mode ) {
+ $sale_price = wcs_get_price_including_tax( $variation, $sale_price_args );
+ $regular_price = wcs_get_price_including_tax( $variation, $regular_price_args );
+ } else {
+ $sale_price = wcs_get_price_excluding_tax( $variation, $sale_price_args );
+ $regular_price = wcs_get_price_excluding_tax( $variation, $regular_price_args );
+ }
+
+ $price .= $this->get_price_html_from_to( $regular_price, $sale_price );
+
+ } else {
+
+ if ( $this->min_variation_price !== $this->max_variation_price ) {
+ $price .= wcs_get_price_html_from_text( $this );
+ }
+
+ $price .= wc_price( $this->get_variation_price( 'min', true ) );
+
+ }
+
+ // Make sure the price contains "From:" when billing schedule differs between variations
+ if ( false === strpos( $price, wcs_get_price_html_from_text( $this ) ) ) {
+ if ( $this->subscription_period !== $this->max_variation_period ) {
+ $price = wcs_get_price_html_from_text( $this ) . $price;
+ } elseif ( $this->subscription_period_interval !== $this->max_variation_period_interval ) {
+ $price = wcs_get_price_html_from_text( $this ) . $price;
+ }
+ }
+
+ $price .= $this->get_price_suffix();
+
+ $price = WC_Subscriptions_Product::get_price_string( $this, array( 'price' => $price ) );
+ }
+
+ return apply_filters( 'woocommerce_variable_subscription_price_html', $price, $this );
+ }
+
+ /**
+ * Provide the WC_Data::get_meta() function when WC < 3.0 is active.
+ *
+ * @param string $meta_key
+ * @param bool $single
+ * @param string $context
+ * @return object WC_Product_Subscription or WC_Product_Subscription_Variation
+ */
+ function get_meta( $meta_key = '', $single = true, $context = 'view' ) {
+ return get_post_meta( $this->get_id(), $meta_key, $single );
+ }
+
+ /**
+ * get_child function.
+ *
+ * @access public
+ * @param mixed $child_id
+ * @return object WC_Product_Subscription or WC_Product_Subscription_Variation
+ */
+ public function get_child( $child_id ) {
+ return wc_get_product( $child_id, array(
+ 'product_type' => 'Subscription_Variation',
+ 'parent_id' => $this->id,
+ 'parent' => $this,
+ ) );
+ }
+
+ /**
+ * Get default attributes.
+ *
+ * @since 2.2.0
+ * @param string $context
+ * @return array
+ */
+ public function get_default_attributes( $context = 'view' ) {
+ return $this->get_variation_default_attributes();
+ }
+}
diff --git a/includes/legacy/class-wc-subscription-legacy.php b/includes/legacy/class-wc-subscription-legacy.php
new file mode 100644
index 0000000..78e62c3
--- /dev/null
+++ b/includes/legacy/class-wc-subscription-legacy.php
@@ -0,0 +1,749 @@
+order_type = 'shop_subscription';
+
+ $this->schedule = new stdClass();
+ }
+
+ /**
+ * Populates a subscription from the loaded post data.
+ *
+ * @param mixed $result
+ */
+ public function populate( $result ) {
+ parent::populate( $result );
+
+ if ( $this->post->post_parent > 0 ) {
+ $this->order = wc_get_order( $this->post->post_parent );
+ }
+ }
+
+ /**
+ * Returns the unique ID for this object.
+ *
+ * @return int
+ */
+ public function get_id() {
+ return $this->id;
+ }
+
+ /**
+ * Get parent order ID.
+ *
+ * @since 2.2.0
+ * @return int
+ */
+ public function get_parent_id() {
+ return $this->post->post_parent;
+ }
+
+ /**
+ * Gets order currency.
+ *
+ * @return string
+ */
+ public function get_currency() {
+ return $this->get_order_currency();
+ }
+
+ /**
+ * Get customer_note.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_customer_note( $context = 'view' ) {
+ return $this->customer_note;
+ }
+
+ /**
+ * Get prices_include_tax.
+ *
+ * @param string $context
+ * @return bool
+ */
+ public function get_prices_include_tax( $context = 'view' ) {
+ return $this->prices_include_tax;
+ }
+
+ /**
+ * Get the payment method.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_payment_method( $context = 'view' ) {
+ return $this->payment_method;
+ }
+
+ /**
+ * Get the payment method's title.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_payment_method_title( $context = 'view' ) {
+ return $this->payment_method_title;
+ }
+
+ /** Address Getters **/
+
+ /**
+ * Get billing_first_name.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_billing_first_name( $context = 'view' ) {
+ return $this->billing_first_name;
+ }
+
+ /**
+ * Get billing_last_name.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_billing_last_name( $context = 'view' ) {
+ return $this->billing_last_name;
+ }
+
+ /**
+ * Get billing_company.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_billing_company( $context = 'view' ) {
+ return $this->billing_company;
+ }
+
+ /**
+ * Get billing_address_1.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_billing_address_1( $context = 'view' ) {
+ return $this->billing_address_1;
+ }
+
+ /**
+ * Get billing_address_2.
+ *
+ * @param string $context
+ * @return string $value
+ */
+ public function get_billing_address_2( $context = 'view' ) {
+ return $this->billing_address_2;
+ }
+
+ /**
+ * Get billing_city.
+ *
+ * @param string $context
+ * @return string $value
+ */
+ public function get_billing_city( $context = 'view' ) {
+ return $this->billing_city;
+ }
+
+ /**
+ * Get billing_state.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_billing_state( $context = 'view' ) {
+ return $this->billing_state;
+ }
+
+ /**
+ * Get billing_postcode.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_billing_postcode( $context = 'view' ) {
+ return $this->billing_postcode;
+ }
+
+ /**
+ * Get billing_country.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_billing_country( $context = 'view' ) {
+ return $this->billing_country;
+ }
+
+ /**
+ * Get billing_email.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_billing_email( $context = 'view' ) {
+ return $this->billing_email;
+ }
+
+ /**
+ * Get billing_phone.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_billing_phone( $context = 'view' ) {
+ return $this->billing_phone;
+ }
+
+ /**
+ * Get shipping_first_name.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_shipping_first_name( $context = 'view' ) {
+ return $this->shipping_first_name;
+ }
+
+ /**
+ * Get shipping_last_name.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_shipping_last_name( $context = 'view' ) {
+ return $this->shipping_last_name;
+ }
+
+ /**
+ * Get shipping_company.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_shipping_company( $context = 'view' ) {
+ return $this->shipping_company;
+ }
+
+ /**
+ * Get shipping_address_1.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_shipping_address_1( $context = 'view' ) {
+ return $this->shipping_address_1;
+ }
+
+ /**
+ * Get shipping_address_2.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_shipping_address_2( $context = 'view' ) {
+ return $this->shipping_address_2;
+ }
+
+ /**
+ * Get shipping_city.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_shipping_city( $context = 'view' ) {
+ return $this->shipping_city;
+ }
+
+ /**
+ * Get shipping_state.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_shipping_state( $context = 'view' ) {
+ return $this->shipping_state;
+ }
+
+ /**
+ * Get shipping_postcode.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_shipping_postcode( $context = 'view' ) {
+ return $this->shipping_postcode;
+ }
+
+ /**
+ * Get shipping_country.
+ *
+ * @param string $context
+ * @return string
+ */
+ public function get_shipping_country( $context = 'view' ) {
+ return $this->shipping_country;
+ }
+
+ /**
+ * Get order key.
+ *
+ * @since 2.2.0
+ * @param string $context
+ * @return string
+ */
+ public function get_order_key( $context = 'view' ) {
+ return $this->order_key;
+ }
+
+ /**
+ * Get date_created.
+ *
+ * Used by parent::get_date()
+ *
+ * @throws WC_Data_Exception
+ * @return DateTime|NULL object if the date is set or null if there is no date.
+ */
+ public function get_date_created( $context = 'view' ) {
+
+ if ( '0000-00-00 00:00:00' != $this->post->post_date_gmt ) {
+ $datetime = new WC_DateTime( $this->post->post_date_gmt, new DateTimeZone( 'UTC' ) );
+ $datetime->setTimezone( new DateTimeZone( wc_timezone_string() ) );
+ } else {
+ $datetime = new WC_DateTime( $this->post->post_date, new DateTimeZone( wc_timezone_string() ) );
+ }
+
+ // Cache it in $this->schedule for backward compatibility
+ if ( ! isset( $this->schedule->start ) ) {
+ $this->schedule->start = wcs_get_datetime_utc_string( $datetime );
+ }
+
+ return $datetime;
+ }
+
+ /**
+ * Get date_modified.
+ *
+ * Used by parent::get_date()
+ *
+ * @throws WC_Data_Exception
+ * @return DateTime|NULL object if the date is set or null if there is no date.
+ */
+ public function get_date_modified( $context = 'view' ) {
+
+ if ( '0000-00-00 00:00:00' != $this->post->post_modified_gmt ) {
+ $datetime = new WC_DateTime( $this->post->post_modified_gmt, new DateTimeZone( 'UTC' ) );
+ $datetime->setTimezone( new DateTimeZone( wc_timezone_string() ) );
+ } else {
+ $datetime = new WC_DateTime( $this->post->post_modified, new DateTimeZone( wc_timezone_string() ) );
+ }
+
+ return $datetime;
+ }
+
+ /**
+ * Check if a given line item on the subscription had a sign-up fee, and if so, return the value of the sign-up fee.
+ *
+ * The single quantity sign-up fee will be returned instead of the total sign-up fee paid. For example, if 3 x a product
+ * with a 10 BTC sign-up fee was purchased, a total 30 BTC was paid as the sign-up fee but this function will return 10 BTC.
+ *
+ * @param array|int Either an order item (in the array format returned by self::get_items()) or the ID of an order item.
+ * @param string $tax_inclusive_or_exclusive Whether or not to adjust sign up fee if prices inc tax - ensures that the sign up fee paid amount includes the paid tax if inc
+ * @return bool
+ * @since 2.0
+ */
+ public function get_items_sign_up_fee( $line_item, $tax_inclusive_or_exclusive = 'exclusive_of_tax' ) {
+
+ if ( ! is_array( $line_item ) ) {
+ $line_item = wcs_get_order_item( $line_item, $this );
+ }
+
+ $parent_order = $this->get_parent();
+
+ // If there was no original order, nothing was paid up-front which means no sign-up fee
+ if ( false == $parent_order ) {
+
+ $sign_up_fee = 0;
+
+ } else {
+
+ $original_order_item = '';
+
+ // Find the matching item on the order
+ foreach ( $parent_order->get_items() as $order_item ) {
+ if ( wcs_get_canonical_product_id( $line_item ) == wcs_get_canonical_product_id( $order_item ) ) {
+ $original_order_item = $order_item;
+ break;
+ }
+ }
+
+ // No matching order item, so this item wasn't purchased in the original order
+ if ( empty( $original_order_item ) ) {
+
+ $sign_up_fee = 0;
+
+ } elseif ( isset( $line_item['item_meta']['_has_trial'] ) ) {
+
+ // Sign up is total amount paid for this item on original order when item has a free trial
+ $sign_up_fee = $original_order_item['line_total'] / $original_order_item['qty'];
+
+ } else {
+
+ // Sign-up fee is any amount on top of recurring amount
+ $sign_up_fee = max( $original_order_item['line_total'] / $original_order_item['qty'] - $line_item['line_total'] / $line_item['qty'], 0 );
+ }
+
+ // If prices inc tax, ensure that the sign up fee amount includes the tax
+ if ( 'inclusive_of_tax' === $tax_inclusive_or_exclusive && ! empty( $original_order_item ) && $this->get_prices_include_tax() ) {
+ $proportion = $sign_up_fee / ( $original_order_item['line_total'] / $original_order_item['qty'] );
+ $sign_up_fee += round( $original_order_item['line_tax'] * $proportion, 2 );
+ }
+ }
+
+ return apply_filters( 'woocommerce_subscription_items_sign_up_fee', $sign_up_fee, $line_item, $this, $tax_inclusive_or_exclusive );
+ }
+
+ /**
+ * Helper function to make sure when WC_Subscription calls get_prop() from
+ * it's new getters that the property is both retreived from the legacy class
+ * property and done so from post meta.
+ *
+ * For inherited dates props, like date_created, date_modified, date_paid,
+ * date_completed, we want to use our own get_date() function rather simply
+ * getting the stored value. Otherwise, we either get the prop set in memory
+ * or post meta if it's not set yet, because __get() in WC < 3.0 would fallback
+ * to post meta.
+ *
+ * @param string
+ * @param string
+ * @return mixed
+ */
+ protected function get_prop( $prop, $context = 'view' ) {
+
+ if ( 'switch_data' == $prop ) {
+ $prop = 'subscription_switch_data';
+ }
+
+ // The requires manual renewal prop uses boolean values but is stored as a string so needs special handling, it also needs to be handled before the checks on $this->$prop to avoid triggering __isset() & __get() magic methods for $this->requires_manual_renewal
+ if ( 'requires_manual_renewal' === $prop ) {
+ $value = get_post_meta( $this->get_id(), '_' . $prop, true );
+
+ if ( 'false' === $value || '' === $value ) {
+ $value = false;
+ } else {
+ $value = true;
+ }
+ } elseif ( ! isset( $this->$prop ) || empty( $this->$prop ) ) {
+ $value = get_post_meta( $this->get_id(), '_' . $prop, true );
+ } else {
+ $value = $this->$prop;
+ }
+
+ return $value;
+ }
+
+ /**
+ * Get the stored date for a specific schedule.
+ *
+ * @param string $date_type 'date_created', 'trial_end', 'next_payment', 'last_order_date_created' or 'end'
+ */
+ protected function get_date_prop( $date_type ) {
+
+ $datetime = parent::get_date_prop( $date_type );
+
+ // Cache the string equalivent of it in $this->schedule for backward compatibility
+ if ( ! isset( $this->schedule->{$date_type} ) ) {
+ if ( ! is_object( $datetime ) ) {
+ $this->schedule->{$date_type} = 0;
+ } else {
+ $this->schedule->{$date_type} = wcs_get_datetime_utc_string( $datetime );
+ }
+ }
+
+ return wcs_get_datetime_from( wcs_date_to_time( $datetime ) );
+ }
+
+ /*** Setters *****************************************************/
+
+ /**
+ * Set the unique ID for this object.
+ *
+ * @param int
+ */
+ public function set_id( $id ) {
+ $this->id = absint( $id );
+ }
+
+ /**
+ * Set parent order ID. We don't use WC_Abstract_Order::set_parent_id() because we want to allow false
+ * parent IDs, like 0.
+ *
+ * @since 2.2.0
+ * @param int $value
+ */
+ public function set_parent_id( $value ) {
+ // Update the parent in the database
+ wp_update_post( array(
+ 'ID' => $this->id,
+ 'post_parent' => $value,
+ ) );
+
+ // And update the parent in memory
+ $this->post->post_parent = $value;
+ $this->order = null;
+ }
+
+ /**
+ * Set subscription status.
+ *
+ * @param string $new_status Status to change the order to. No internal wc- prefix is required.
+ * @return array details of change
+ */
+ public function set_status( $new_status, $note = '', $manual_update = false ) {
+
+ $old_status = $this->get_status();
+ $new_status = 'wc-' === substr( $new_status, 0, 3 ) ? substr( $new_status, 3 ) : $new_status;
+
+ wp_update_post( array( 'ID' => $this->get_id(), 'post_status' => wcs_maybe_prefix_key( $new_status, 'wc-' ) ) );
+ $this->post_status = $this->post->post_status = wcs_maybe_prefix_key( $new_status, 'wc-' );
+
+ if ( $old_status !== $new_status ) {
+ $this->status_transition = array(
+ 'from' => ! empty( $this->status_transition['from'] ) ? $this->status_transition['from'] : $old_status,
+ 'to' => $new_status,
+ 'note' => $note,
+ 'manual' => (bool) $manual_update,
+ );
+ }
+
+ return array(
+ 'from' => $old_status,
+ 'to' => $new_status,
+ );
+ }
+
+ /**
+ * Helper function to make sure when WC_Subscription calls set_prop() that property is
+ * both set in the legacy class property and saved in post meta immediately.
+ *
+ * @param string $prop
+ * @param mixed $value
+ */
+ protected function set_prop( $prop, $value ) {
+
+ if ( 'switch_data' == $prop ) {
+ $prop = 'subscription_switch_data';
+ }
+
+ $this->$prop = $value;
+
+ // The requires manual renewal prop uses boolean values but it stored as a string
+ if ( 'requires_manual_renewal' === $prop ) {
+ if ( false === $value || '' === $value ) {
+ $value = 'false';
+ } else {
+ $value = 'true';
+ }
+ }
+
+ update_post_meta( $this->get_id(), '_' . $prop, $value );
+ }
+
+ /**
+ * Set the stored date for a specific schedule.
+ *
+ * @param string $date_type 'trial_end', 'next_payment', 'cancelled', 'payment_retry' or 'end'
+ * @param int $value UTC timestamp
+ */
+ protected function set_date_prop( $date_type, $value ) {
+ $datetime = wcs_get_datetime_from( $value );
+ $date = ! is_null( $datetime ) ? wcs_get_datetime_utc_string( $datetime ) : 0;
+
+ $this->set_prop( $this->get_date_prop_key( $date_type ), $date );
+ $this->schedule->{$date_type} = $date;
+ }
+
+ /**
+ * Set a certain date type for the last order on the subscription.
+ *
+ * @since 2.2.0
+ * @param string $date_type
+ * @param string|integer|object
+ * @return WC_DateTime|NULL object if the date is set or null if there is no date.
+ */
+ protected function set_last_order_date( $date_type, $date = null ) {
+
+ $last_order = $this->get_last_order( 'all' );
+
+ if ( $last_order ) {
+
+ $datetime = wcs_get_datetime_from( $date );
+
+ switch ( $date_type ) {
+ case 'date_paid' :
+ update_post_meta( $last_order->id, '_paid_date', ! is_null( $date ) ? $datetime->date( 'Y-m-d H:i:s' ) : '' );
+ // Preemptively set the UTC timestamp for WC 3.0+ also to avoid incorrect values when the site's timezone is changed between now and upgrading to WC 3.0
+ update_post_meta( $last_order->id, '_date_paid', ! is_null( $date ) ? $datetime->getTimestamp() : '' );
+ break;
+
+ case 'date_completed' :
+ update_post_meta( $last_order->id, '_completed_date', ! is_null( $date ) ? $datetime->date( 'Y-m-d H:i:s' ) : '' );
+ // Preemptively set the UTC timestamp for WC 3.0+ also to avoid incorrect values when the site's timezone is changed between now and upgrading to WC 3.0
+ update_post_meta( $last_order->id, '_date_completed', ! is_null( $date ) ? $datetime->getTimestamp() : '' );
+ break;
+
+ case 'date_modified' :
+ wp_update_post( array(
+ 'ID' => $last_order->id,
+ 'post_modified' => $datetime->date( 'Y-m-d H:i:s' ),
+ 'post_modified_gmt' => wcs_get_datetime_utc_string( $datetime ),
+ ) );
+ break;
+
+ case 'date_created' :
+ wp_update_post( array(
+ 'ID' => $last_order->id,
+ 'post_date' => $datetime->date( 'Y-m-d H:i:s' ),
+ 'post_date_gmt' => wcs_get_datetime_utc_string( $datetime ),
+ ) );
+ break;
+ }
+ }
+ }
+
+ /**
+ * Set date_created.
+ *
+ * Used by parent::update_dates()
+ *
+ * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date.
+ * @throws WC_Data_Exception
+ */
+ public function set_date_created( $date = null ) {
+ global $wpdb;
+
+ if ( ! is_null( $date ) ) {
+
+ $datetime_string = wcs_get_datetime_utc_string( wcs_get_datetime_from( $date ) );
+
+ // Don't use wp_update_post() to avoid infinite loops here
+ $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_date = %s, post_date_gmt = %s WHERE ID = %d", get_date_from_gmt( $datetime_string ), $datetime_string, $this->get_id() ) );
+
+ $this->post->post_date = get_date_from_gmt( $datetime_string );
+ $this->post->post_date_gmt = $datetime_string;
+ }
+ }
+
+ /**
+ * Set discount_total.
+ *
+ * @param string $value
+ * @throws WC_Data_Exception
+ */
+ public function set_discount_total( $value ) {
+ $this->set_total( $value, 'cart_discount' );
+ }
+
+ /**
+ * Set discount_tax.
+ *
+ * @param string $value
+ * @throws WC_Data_Exception
+ */
+ public function set_discount_tax( $value ) {
+ $this->set_total( $value, 'cart_discount_tax' );
+ }
+
+ /**
+ * Set shipping_total.
+ *
+ * @param string $value
+ * @throws WC_Data_Exception
+ */
+ public function set_shipping_total( $value ) {
+ $this->set_total( $value, 'shipping' );
+ }
+
+ /**
+ * Set shipping_tax.
+ *
+ * @param string $value
+ * @throws WC_Data_Exception
+ */
+ public function set_shipping_tax( $value ) {
+ $this->set_total( $value, 'shipping_tax' );
+ }
+
+ /**
+ * Set cart tax.
+ *
+ * @param string $value
+ * @throws WC_Data_Exception
+ */
+ public function set_cart_tax( $value ) {
+ $this->set_total( $value, 'tax' );
+ }
+
+ /**
+ * Save data to the database. Nothing to do here as it's all done separately when calling @see this->set_prop().
+ *
+ * @return int order ID
+ */
+ public function save() {
+ $this->status_transition();
+ return $this->get_id();
+ }
+
+ /**
+ * Update meta data by key or ID, if provided.
+ *
+ * @since 2.2.0
+ * @param string $key
+ * @param string $value
+ * @param int $meta_id
+ */
+ public function update_meta_data( $key, $value, $meta_id = '' ) {
+ if ( ! empty( $meta_id ) ) {
+ update_metadata_by_mid( 'post', $meta_id, $value, $key );
+ } else {
+ update_post_meta( $this->get_id(), $key, $value );
+ }
+ }
+}
diff --git a/includes/legacy/class-wcs-array-property-post-meta-black-magic.php b/includes/legacy/class-wcs-array-property-post-meta-black-magic.php
new file mode 100644
index 0000000..7eabcd8
--- /dev/null
+++ b/includes/legacy/class-wcs-array-property-post-meta-black-magic.php
@@ -0,0 +1,85 @@
+product_id = $product_id;
+ }
+
+ /**
+ * offsetGet
+ * @param string $key
+ * @return mixed
+ */
+ public function offsetGet( $key ) {
+ return get_post_meta( $this->product_id, $this->maybe_prefix_meta_key( $key ) );
+ }
+
+ /**
+ * offsetSet
+ * @param string $key
+ * @param mixed $value
+ */
+ public function offsetSet( $key, $value ) {
+ update_post_meta( $this->product_id, $this->maybe_prefix_meta_key( $key ), $value );
+ }
+
+ /**
+ * offsetExists
+ * @param string $key
+ * @return bool
+ */
+ public function offsetExists( $key ) {
+ return metadata_exists( 'post', $this->product_id, $this->maybe_prefix_meta_key( $key ) );
+ }
+
+ /**
+ * Nothing to do here as we access post meta directly.
+ */
+ public function offsetUnset( $key ) {
+ }
+
+ /**
+ * We only work with post meta data that has meta keys prefixed with an underscore, so
+ * add a prefix if it is not already set.
+ */
+ protected function maybe_prefix_meta_key( $key ) {
+ if ( '_' != substr( $key, 0, 1 ) ) {
+ $key = '_' . $key;
+ }
+ return $key;
+ }
+}
diff --git a/includes/legacy/class-wcs-product-legacy.php b/includes/legacy/class-wcs-product-legacy.php
new file mode 100644
index 0000000..80ff38f
--- /dev/null
+++ b/includes/legacy/class-wcs-product-legacy.php
@@ -0,0 +1,42 @@
+format( DATE_ATOM );
+ }
+
+ /**
+ * Missing in PHP 5.2.
+ *
+ * @since 3.0.0
+ * @return int
+ */
+ public function getTimestamp() {
+ return method_exists( 'DateTime', 'getTimestamp' ) ? parent::getTimestamp() : $this->format( 'U' );
+ }
+
+ /**
+ * Get the timestamp with the WordPress timezone offset added or subtracted.
+ *
+ * @since 3.0.0
+ * @return int
+ */
+ public function getOffsetTimestamp() {
+ return $this->getTimestamp() + $this->getOffset();
+ }
+
+ /**
+ * Format a date based on the offset timestamp.
+ *
+ * @since 3.0.0
+ * @param string $format
+ * @return string
+ */
+ public function date( $format ) {
+ return gmdate( $format, $this->getOffsetTimestamp() );
+ }
+
+ /**
+ * Return a localised date based on offset timestamp. Wrapper for date_i18n function.
+ *
+ * @since 3.0.0
+ * @param string $format
+ * @return string
+ */
+ public function date_i18n( $format = 'Y-m-d' ) {
+ return date_i18n( $format, $this->getOffsetTimestamp() );
+ }
+}
diff --git a/includes/payment-retry/class-wcs-retry-email.php b/includes/payment-retry/class-wcs-retry-email.php
index 2565669..fece963 100644
--- a/includes/payment-retry/class-wcs-retry-email.php
+++ b/includes/payment-retry/class-wcs-retry-email.php
@@ -68,7 +68,7 @@ class WCS_Retry_Email {
$email_class = $retry_rule->get_email_template( $recipient );
if ( class_exists( $email_class ) ) {
$email = new $email_class();
- $email->trigger( $last_order );
+ $email->trigger( wcs_get_objects_property( $last_order, 'id' ), $last_order );
}
}
}
@@ -89,8 +89,8 @@ class WCS_Retry_Email {
remove_action( 'woocommerce_order_status_failed', 'WC_Subscriptions_Email::send_renewal_order_email', 10 );
// Remove email sent to admin, which is sent by WooCommerce
- remove_action( 'woocommerce_order_status_pending_to_failed', array( 'WC_Emails', 'send_transactional_email' ), 10, 10 );
- remove_action( 'woocommerce_order_status_on-hold_to_failed', array( 'WC_Emails', 'send_transactional_email' ), 10, 10 );
+ WC_Subscriptions_Email::detach_woocommerce_transactional_email( 'woocommerce_order_status_pending_to_failed' );
+ WC_Subscriptions_Email::detach_woocommerce_transactional_email( 'woocommerce_order_status_on-hold_to_failed' );
self::$removed_emails_for_order_id = $order_id;
}
@@ -109,8 +109,8 @@ class WCS_Retry_Email {
add_action( 'woocommerce_order_status_failed', 'WC_Subscriptions_Email::send_renewal_order_email' );
// Reattach email sent to admin, which is sent by WooCommerce
- add_action( 'woocommerce_order_status_pending_to_failed', array( 'WC_Emails', 'send_transactional_email' ), 10, 10 );
- add_action( 'woocommerce_order_status_on-hold_to_failed', array( 'WC_Emails', 'send_transactional_email' ), 10, 10 );
+ WC_Subscriptions_Email::attach_woocommerce_transactional_email( 'woocommerce_order_status_pending_to_failed' );
+ WC_Subscriptions_Email::attach_woocommerce_transactional_email( 'woocommerce_order_status_on-hold_to_failed' );
self::$removed_emails_for_order_id = null;
}
diff --git a/includes/upgrades/class-wc-subscriptions-upgrader.php b/includes/upgrades/class-wc-subscriptions-upgrader.php
index c3a8c7b..9f6213a 100644
--- a/includes/upgrades/class-wc-subscriptions-upgrader.php
+++ b/includes/upgrades/class-wc-subscriptions-upgrader.php
@@ -209,7 +209,7 @@ class WC_Subscriptions_Upgrader {
* @since 2.1
*/
public static function maybe_redirect_after_upgrade_complete( $current_version, $previously_active_version ) {
- if ( version_compare( $previously_active_version, '2.1.0', '<' ) && version_compare( $current_version, '2.1.0', '>=' ) ) {
+ if ( version_compare( $previously_active_version, '2.1.0', '<' ) && version_compare( $current_version, '2.1.0', '>=' ) && version_compare( $current_version, '2.2.0', '<' ) ) {
wp_safe_redirect( self::$about_page_url );
exit();
}
diff --git a/includes/upgrades/class-wcs-repair-2-0-2.php b/includes/upgrades/class-wcs-repair-2-0-2.php
index de34cfc..3100963 100644
--- a/includes/upgrades/class-wcs-repair-2-0-2.php
+++ b/includes/upgrades/class-wcs-repair-2-0-2.php
@@ -58,11 +58,11 @@ class WCS_Repair_2_0_2 {
$subscription = wcs_get_subscription( $subscription_id );
if ( false !== $subscription && self::maybe_repair_subscription( $subscription ) ) {
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repair completed', $subscription->id ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repair completed', $subscription->get_id() ) );
$repaired_count++;
update_post_meta( $subscription_id, '_wcs_repaired_2_0_2', 'true' );
} else {
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: no repair needed', $subscription->id ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: no repair needed', $subscription->get_id() ) );
$unrepaired_count++;
update_post_meta( $subscription_id, '_wcs_repaired_2_0_2', 'false' );
}
@@ -87,10 +87,11 @@ class WCS_Repair_2_0_2 {
protected static function maybe_repair_subscription( $subscription ) {
$repaired_subscription = false;
+ $parent_order = $subscription->get_parent();
// if the subscription doesn't have an order, it must have been created in 2.0, so we can ignore it
- if ( false === $subscription->order ) {
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: no need to repair: it has no order.', $subscription->id ) );
+ if ( false === $parent_order ) {
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: no need to repair: it has no order.', $subscription->get_id() ) );
return $repaired_subscription;
}
@@ -98,7 +99,7 @@ class WCS_Repair_2_0_2 {
// if the subscription has more than one line item, it must have been created in 2.0, so we can ignore it
if ( count( $subscription_line_items ) > 1 ) {
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: no need to repair: it has more than one line item.', $subscription->id ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: no need to repair: it has more than one line item.', $subscription->get_id() ) );
return $repaired_subscription;
}
@@ -106,7 +107,7 @@ class WCS_Repair_2_0_2 {
$subscription_line_item = array_shift( $subscription_line_items );
// Get old order item's meta
- foreach ( $subscription->order->get_items() as $line_item_id => $line_item ) {
+ foreach ( $parent_order->get_items() as $line_item_id => $line_item ) {
if ( wcs_get_canonical_product_id( $line_item ) == wcs_get_canonical_product_id( $subscription_line_item ) ) {
$matching_line_item_id = $line_item_id;
$matching_line_item = $line_item;
@@ -116,7 +117,7 @@ class WCS_Repair_2_0_2 {
// we couldn't find a matching line item so we can't repair it
if ( ! isset( $matching_line_item ) ) {
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: can not repair: it has no matching line item.', $subscription->id ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: can not repair: it has no matching line item.', $subscription->get_id() ) );
return $repaired_subscription;
}
@@ -124,20 +125,20 @@ class WCS_Repair_2_0_2 {
// if the order item doesn't have migrated subscription data, the subscription wasn't migrated from 1.5
if ( ! isset( $matching_line_item_meta['_wcs_migrated_subscription_status'] ) && ! isset( $matching_line_item_meta['_wcs_migrated_subscription_start_date'] ) ) {
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: no need to repair: matching line item has no migrated meta data.', $subscription->id ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: no need to repair: matching line item has no migrated meta data.', $subscription->get_id() ) );
return $repaired_subscription;
}
if ( false !== self::maybe_repair_line_tax_data( $subscription_line_item_id, $matching_line_item_id, $matching_line_item ) ) {
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repaired missing line tax data.', $subscription->id ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repaired missing line tax data.', $subscription->get_id() ) );
$repaired_subscription = true;
} else {
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: line tax data not added.', $subscription->id ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: line tax data not added.', $subscription->get_id() ) );
}
// if the subscription has been cancelled, we don't need to repair any other data
if ( $subscription->has_status( array( 'pending-cancel', 'cancelled' ) ) ) {
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: no need to repair: it has cancelled status.', $subscription->id ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: no need to repair: it has cancelled status.', $subscription->get_id() ) );
return $repaired_subscription;
}
@@ -157,38 +158,38 @@ class WCS_Repair_2_0_2 {
if ( ! empty( $dates_to_update ) ) {
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repairing dates = %s', $subscription->id, str_replace( array( '{', '}', '"' ), '', wcs_json_encode( $dates_to_update ) ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repairing dates = %s', $subscription->get_id(), str_replace( array( '{', '}', '"' ), '', wcs_json_encode( $dates_to_update ) ) ) );
try {
$subscription->update_dates( $dates_to_update );
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repaired dates = %s', $subscription->id, str_replace( array( '{', '}', '"' ), '', wcs_json_encode( $dates_to_update ) ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repaired dates = %s', $subscription->get_id(), str_replace( array( '{', '}', '"' ), '', wcs_json_encode( $dates_to_update ) ) ) );
} catch ( Exception $e ) {
- WCS_Upgrade_Logger::add( sprintf( '!! For subscription %d: unable to repair dates (%s), exception "%s"', $subscription->id, str_replace( array( '{', '}', '"' ), '', wcs_json_encode( $dates_to_update ) ), $e->getMessage() ) );
+ WCS_Upgrade_Logger::add( sprintf( '!! For subscription %d: unable to repair dates (%s), exception "%s"', $subscription->get_id(), str_replace( array( '{', '}', '"' ), '', wcs_json_encode( $dates_to_update ) ), $e->getMessage() ) );
}
try {
self::maybe_repair_status( $subscription, $matching_line_item_meta, $dates_to_update );
} catch ( Exception $e ) {
- WCS_Upgrade_Logger::add( sprintf( '!! For subscription %d: unable to repair status. Exception: "%s"', $subscription->id, $e->getMessage() ) );
+ WCS_Upgrade_Logger::add( sprintf( '!! For subscription %d: unable to repair status. Exception: "%s"', $subscription->get_id(), $e->getMessage() ) );
}
$repaired_subscription = true;
}
- if ( ! empty( $subscription->order->customer_note ) && empty( $subscription->customer_note ) ) {
+ if ( '' !== wcs_get_objects_property( $parent_order, 'customer_note' ) && '' == $subscription->get_customer_note() ) {
$post_data = array(
- 'ID' => $subscription->id,
- 'post_excerpt' => $subscription->order->customer_note,
+ 'ID' => $subscription->get_id(),
+ 'post_excerpt' => wcs_get_objects_property( $parent_order, 'customer_note' ),
);
$updated_post_id = wp_update_post( $post_data, true );
if ( ! is_wp_error( $updated_post_id ) ) {
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repaired missing customer note.', $subscription->id ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repaired missing customer note.', $subscription->get_id() ) );
$repaired_subscription = true;
} else {
- WCS_Upgrade_Logger::add( sprintf( '!! For subscription %d: unable to repair missing customer note. Exception: "%s"', $subscription->id, $updated_post_id->get_error_message() ) );
+ WCS_Upgrade_Logger::add( sprintf( '!! For subscription %d: unable to repair missing customer note. Exception: "%s"', $subscription->get_id(), $updated_post_id->get_error_message() ) );
}
}
@@ -211,8 +212,8 @@ class WCS_Repair_2_0_2 {
$old_trial_end_date = isset( $former_order_item_meta['_wcs_migrated_subscription_trial_expiry_date'][0] ) ? $former_order_item_meta['_wcs_migrated_subscription_trial_expiry_date'][0] : 0;
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: new trial end date = %s.', $subscription->id, var_export( $subscription->get_date( 'trial_end' ), true ) ) );
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: old trial end date = %s.', $subscription->id, var_export( $old_trial_end_date, true ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: new trial end date = %s.', $subscription->get_id(), var_export( $subscription->get_date( 'trial_end' ), true ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: old trial end date = %s.', $subscription->get_id(), var_export( $old_trial_end_date, true ) ) );
// if the subscription has a trial end time whereas previously it didn't, we need it to be deleted
if ( 0 == $old_trial_end_date ) {
@@ -224,7 +225,7 @@ class WCS_Repair_2_0_2 {
$repair_date = false;
}
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repair trial end date = %s.', $subscription->id, var_export( $repair_date, true ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repair trial end date = %s.', $subscription->get_id(), var_export( $repair_date, true ) ) );
return $repair_date;
}
@@ -264,8 +265,8 @@ class WCS_Repair_2_0_2 {
wcs_json_encode( $old_hook_args )
) );
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: new next payment date = %s.', $subscription->id, var_export( $subscription->get_date( 'next_payment' ), true ) ) );
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: old next payment date = %s.', $subscription->id, var_export( $old_next_payment_date, true ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: new next payment date = %s.', $subscription->get_id(), var_export( $subscription->get_date( 'next_payment' ), true ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: old next payment date = %s.', $subscription->get_id(), var_export( $old_next_payment_date, true ) ) );
// if we have a date, make sure it's valid
if ( null !== $old_next_payment_date ) {
@@ -274,7 +275,7 @@ class WCS_Repair_2_0_2 {
if ( 0 == $repair_date ) {
$repair_date = false;
}
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: old next payment date is in the past, setting it to %s.', $subscription->id, var_export( $repair_date, true ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: old next payment date is in the past, setting it to %s.', $subscription->get_id(), var_export( $repair_date, true ) ) );
} else {
$repair_date = $old_next_payment_date;
}
@@ -289,13 +290,13 @@ class WCS_Repair_2_0_2 {
$repair_date = false;
}
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: no old next payment date, setting it to %s.', $subscription->id, var_export( $repair_date, true ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: no old next payment date, setting it to %s.', $subscription->get_id(), var_export( $repair_date, true ) ) );
}
} else {
$repair_date = false;
}
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repair next payment date = %s.', $subscription->id, var_export( $repair_date, true ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repair next payment date = %s.', $subscription->get_id(), var_export( $repair_date, true ) ) );
return $repair_date;
}
@@ -325,8 +326,8 @@ class WCS_Repair_2_0_2 {
$old_end_date = isset( $former_order_item_meta['_wcs_migrated_subscription_expiry_date'][0] ) ? $former_order_item_meta['_wcs_migrated_subscription_expiry_date'][0] : 0;
}
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: new end date = %s.', $subscription->id, var_export( $subscription->get_date( 'end' ), true ) ) );
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: old end date = %s.', $subscription->id, var_export( $old_end_date, true ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: new end date = %s.', $subscription->get_id(), var_export( $subscription->get_date( 'end' ), true ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: old end date = %s.', $subscription->get_id(), var_export( $old_end_date, true ) ) );
// if the subscription has an end time whereas previously it didn't, we need it to be deleted so set it 0
if ( 0 == $old_end_date ) {
@@ -338,7 +339,7 @@ class WCS_Repair_2_0_2 {
$repair_date = false;
}
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repair end date = %s.', $subscription->id, var_export( $repair_date, true ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repair end date = %s.', $subscription->get_id(), var_export( $repair_date, true ) ) );
return $repair_date;
}
@@ -359,27 +360,27 @@ class WCS_Repair_2_0_2 {
try {
// we need to bypass the update_status() method here because normally an expired subscription can't have it's status changed, we also don't want normal status change hooks to be fired
- wp_update_post( array( 'ID' => $subscription->id, 'post_status' => 'wc-on-hold' ) );
+ wp_update_post( array( 'ID' => $subscription->get_id(), 'post_status' => 'wc-on-hold' ) );
// if the payment method doesn't support date changes, we still want to reactivate the subscription but we also need to process a special failed payment at the next renewal to fix up the payment method so we'll set a special flag in post meta to handle that
if ( ! $subscription->payment_method_supports( 'subscription_date_changes' ) && $subscription->get_total() > 0 ) {
- update_post_meta( $subscription->id, '_wcs_repaired_2_0_2_needs_failed_payment', 'true' );
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: payment method does not support "subscription_date_changes" and total > 0, setting "_wcs_repaired_2_0_2_needs_failed_payment" post meta flag.', $subscription->id ) );
+ update_post_meta( $subscription->get_id(), '_wcs_repaired_2_0_2_needs_failed_payment', 'true' );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: payment method does not support "subscription_date_changes" and total > 0, setting "_wcs_repaired_2_0_2_needs_failed_payment" post meta flag.', $subscription->get_id() ) );
}
if ( 'active' == $former_order_item_meta['_wcs_migrated_subscription_status'][0] && $subscription->can_be_updated_to( 'active' ) ) {
$subscription->update_status( 'active' );
}
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repaired status. Status was "expired", it is now "%s".', $subscription->id, $subscription->get_status() ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: repaired status. Status was "expired", it is now "%s".', $subscription->get_id(), $subscription->get_status() ) );
$repair_status = true;
} catch ( Exception $e ) {
- WCS_Upgrade_Logger::add( sprintf( '!!! For subscription %d: unable to repair status, exception "%s"', $subscription->id, $e->getMessage() ) );
+ WCS_Upgrade_Logger::add( sprintf( '!!! For subscription %d: unable to repair status, exception "%s"', $subscription->get_id(), $e->getMessage() ) );
$repair_status = false;
}
} else {
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: no need to repair status, current status: %s; former status: %s.', $subscription->id, $subscription->get_status(), $former_order_item_meta['_wcs_migrated_subscription_status'][0] ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: no need to repair status, current status: %s; former status: %s.', $subscription->get_id(), $subscription->get_status(), $former_order_item_meta['_wcs_migrated_subscription_status'][0] ) );
$repair_status = false;
}
return $repair_status;
diff --git a/includes/upgrades/class-wcs-repair-2-0.php b/includes/upgrades/class-wcs-repair-2-0.php
index 4d6b4f6..e236296 100644
--- a/includes/upgrades/class-wcs-repair-2-0.php
+++ b/includes/upgrades/class-wcs-repair-2-0.php
@@ -262,11 +262,11 @@ class WCS_Repair_2_0 {
// let's get the last 2 renewal orders
$last_renewal_order = array_shift( $renewal_orders );
- $last_renewal_date = $last_renewal_order->order_date;
+ $last_renewal_date = wcs_get_datetime_utc_string( wcs_get_objects_property( $last_renewal_order, 'date_created' ) );
$last_renewal_timestamp = wcs_date_to_time( $last_renewal_date );
$second_renewal_order = array_shift( $renewal_orders );
- $second_renewal_date = $second_renewal_order->order_date;
+ $second_renewal_date = wcs_get_datetime_utc_string( wcs_get_objects_property( $second_renewal_order, 'date_created' ) );
$second_renewal_timestamp = wcs_date_to_time( $second_renewal_date );
$interval = 1;
@@ -284,7 +284,7 @@ class WCS_Repair_2_0 {
WCS_Upgrade_Logger::add( sprintf( '-- For order %d: we have 3 renewal orders, trying to make sure we are right.', $subscription['order_id'] ) );
$third_renewal_order = array_shift( $renewal_orders );
- $third_renewal_date = $third_renewal_order->order_date;
+ $third_renewal_date = wcs_get_datetime_utc_string( wcs_get_objects_property( $third_renewal_order, 'date_created' ) );
$period2 = wcs_estimate_period_between( $second_renewal_date, $third_renewal_date, $interval );
@@ -335,11 +335,11 @@ class WCS_Repair_2_0 {
// let's get the last 2 renewal orders
$last_renewal_order = array_shift( $renewal_orders );
- $last_renewal_date = $last_renewal_order->order_date;
+ $last_renewal_date = wcs_get_datetime_utc_string( wcs_get_objects_property( $last_renewal_order, 'date_created' ) );
$last_renewal_timestamp = wcs_date_to_time( $last_renewal_date );
$second_renewal_order = array_shift( $renewal_orders );
- $second_renewal_date = $second_renewal_order->order_date;
+ $second_renewal_date = wcs_get_datetime_utc_string( wcs_get_objects_property( $second_renewal_order, 'date_created' ) );
$second_renewal_timestamp = wcs_date_to_time( $second_renewal_date );
$subscription['interval'] = wcs_estimate_periods_between( $second_renewal_timestamp, $last_renewal_timestamp, $subscription['period'] );
@@ -470,7 +470,7 @@ class WCS_Repair_2_0 {
} else {
- $subscription['end_date'] = wcs_add_time( 5, 'hours', wcs_date_to_time( $last_order->order_date ) );
+ $subscription['end_date'] = wcs_add_time( 5, 'hours', wcs_get_objects_property( $last_order, 'date_created' )->getTimestamp() );
}
} else {
diff --git a/includes/upgrades/class-wcs-upgrade-2-0.php b/includes/upgrades/class-wcs-upgrade-2-0.php
index 32bb2dc..b5c74b2 100644
--- a/includes/upgrades/class-wcs-upgrade-2-0.php
+++ b/includes/upgrades/class-wcs-upgrade-2-0.php
@@ -82,19 +82,19 @@ class WCS_Upgrade_2_0 {
'order_id' => $old_subscription['order_id'],
'customer_id' => $old_subscription['user_id'],
'start_date' => $old_subscription['start_date'],
- 'customer_note' => ( ! empty( $original_order->customer_note ) ) ? $original_order->customer_note : '',
+ 'customer_note' => ( '' !== wcs_get_objects_property( $original_order, 'customer_note' ) ) ? wcs_get_objects_property( $original_order, 'customer_note' ) : '',
'billing_period' => $old_subscription['period'],
'billing_interval' => $old_subscription['interval'],
- 'order_version' => ( ! empty( $original_order->order_version ) ) ? $original_order->order_version : '', // Subscriptions will default to WC_Version if $original_order->order_version is not set, but we want the version set at the time of the order
+ 'order_version' => ( '' !== wcs_get_objects_property( $original_order, 'version' ) ) ? wcs_get_objects_property( $original_order, 'version' ) : '', // Subscriptions will default to WC_Version if order's version is not set, but we want the version set at the time of the order
) );
if ( ! is_wp_error( $new_subscription ) ) {
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: post created', $new_subscription->id ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: post created', $new_subscription->get_id() ) );
// Set the order to be manual
if ( isset( $original_order->wcs_requires_manual_renewal ) && 'true' == $original_order->wcs_requires_manual_renewal ) {
- $new_subscription->update_manual( true );
+ $new_subscription->set_requires_manual_renewal( true );
}
// Add the line item from the order
@@ -107,29 +107,29 @@ class WCS_Upgrade_2_0 {
self::migrate_dates( $new_subscription, $old_subscription );
// Set some meta from order meta
- self::migrate_post_meta( $new_subscription->id, $original_order );
+ self::migrate_post_meta( $new_subscription->get_id(), $original_order );
// Copy over order notes which are now logged on the subscription
- self::migrate_order_notes( $new_subscription->id, $original_order->id );
+ self::migrate_order_notes( $new_subscription->get_id(), wcs_get_objects_property( $original_order, 'id' ) );
// Migrate recurring tax, shipping and coupon line items to be plain line items on the subscription
- self::migrate_order_items( $new_subscription->id, $original_order->id );
+ self::migrate_order_items( $new_subscription->get_id(), wcs_get_objects_property( $original_order, 'id' ) );
// Update renewal orders to link via post meta key instead of post_parent column
- self::migrate_renewal_orders( $new_subscription->id, $original_order->id );
+ self::migrate_renewal_orders( $new_subscription->get_id(), wcs_get_objects_property( $original_order, 'id' ) );
// Make sure the resubscribe meta data is migrated to use the new subscription ID + meta key
- self::migrate_resubscribe_orders( $new_subscription->id, $original_order->id );
+ self::migrate_resubscribe_orders( $new_subscription->get_id(), wcs_get_objects_property( $original_order, 'id' ) );
// If the order for this subscription contains a switch, make sure the switch meta data is migrated to use the new subscription ID + meta key
self::migrate_switch_meta( $new_subscription, $original_order, $subscription_item_id );
// If the subscription was in the trash, now that we've set on the meta on it, we need to trash it
if ( 'trash' == $old_subscription['status'] ) {
- wp_trash_post( $new_subscription->id );
+ wp_trash_post( $new_subscription->get_id() );
}
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: upgrade complete', $new_subscription->id ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: upgrade complete', $new_subscription->get_id() ) );
} else {
@@ -251,12 +251,12 @@ class WCS_Upgrade_2_0 {
private static function add_product( $new_subscription, $order_item_id, $order_item ) {
global $wpdb;
- $item_id = wc_add_order_item( $new_subscription->id, array(
+ $item_id = wc_add_order_item( $new_subscription->get_id(), array(
'order_item_name' => $order_item['name'],
'order_item_type' => 'line_item',
) );
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: new line item ID %d added', $new_subscription->id, $item_id ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: new line item ID %d added', $new_subscription->get_id(), $item_id ) );
$order_item = WCS_Repair_2_0::maybe_repair_order_item( $order_item );
@@ -312,12 +312,12 @@ class WCS_Upgrade_2_0 {
}
}
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: for item %d added %s', $new_subscription->id, $item_id, implode( ', ', $meta_keys_to_copy ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: for item %d added %s', $new_subscription->get_id(), $item_id, implode( ', ', $meta_keys_to_copy ) ) );
// Now that we've copied over the old data, prefix some the subscription meta keys with _wcs_migrated to deprecate it without deleting it (yet)
$rows_affected = self::deprecate_item_meta( $order_item_id );
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: %s rows of line item meta deprecated', $new_subscription->id, $rows_affected ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: %s rows of line item meta deprecated', $new_subscription->get_id(), $rows_affected ) );
return $item_id;
}
@@ -436,12 +436,12 @@ class WCS_Upgrade_2_0 {
$rows_affected = $wpdb->update(
$wpdb->prefix . 'woocommerce_downloadable_product_permissions',
array(
- 'order_id' => $subscription->id,
- 'order_key' => $subscription->order_key,
+ 'order_id' => $subscription->get_id(),
+ 'order_key' => $subscription->get_order_key(),
),
array(
- 'order_id' => $order->id,
- 'order_key' => $order->order_key,
+ 'order_id' => wcs_get_objects_property( $order, 'id' ),
+ 'order_key' => wcs_get_objects_property( $order, 'order_key' ),
'product_id' => $product_id,
'user_id' => absint( $subscription->get_user_id() ),
),
@@ -449,7 +449,7 @@ class WCS_Upgrade_2_0 {
array( '%d', '%s', '%d', '%d' )
);
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: migrated %d download permissions for product %d', $subscription->id, $rows_affected, $product_id ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: migrated %d download permissions for product %d', $subscription->get_id(), $rows_affected, $product_id ) );
}
/**
@@ -506,7 +506,7 @@ class WCS_Upgrade_2_0 {
if ( $next_scheduled > 0 ) {
if ( 'end_of_prepaid_term' == $new_key ) {
- wc_schedule_single_action( $next_scheduled, 'woocommerce_scheduled_subscription_end_of_prepaid_term', array( 'subscription_id' => $new_subscription->id ) );
+ wc_schedule_single_action( $next_scheduled, 'woocommerce_scheduled_subscription_end_of_prepaid_term', array( 'subscription_id' => $new_subscription->get_id() ) );
} else {
$dates_to_update[ $new_key ] = gmdate( 'Y-m-d H:i:s', $next_scheduled );
}
@@ -517,7 +517,7 @@ class WCS_Upgrade_2_0 {
// Trash all the hooks in one go to save write requests
$wpdb->update( $wpdb->posts, array( 'post_status' => 'trash' ), array( 'post_type' => ActionScheduler_wpPostStore::POST_TYPE, 'post_content' => wcs_json_encode( $old_hook_args ) ), array( '%s', '%s' ) );
- $dates_to_update['start'] = $new_subscription->post->post_date_gmt;
+ $dates_to_update['date_created'] = $new_subscription->post->post_date_gmt;
// v2.0 enforces new rules for dates when they are being set, so we need to massage the old data to conform to these new rules
foreach ( $dates_to_update as $date_type => $date ) {
@@ -536,7 +536,7 @@ class WCS_Upgrade_2_0 {
$dates_to_update[ $date_type ] = $date;
}
case 'trial_end' :
- if ( array_key_exists( 'start', $dates_to_update ) && $date <= $dates_to_update['start'] ) {
+ if ( array_key_exists( 'date_created', $dates_to_update ) && $date <= $dates_to_update['date_created'] ) {
$dates_to_update[ $date_type ] = $date;
}
}
@@ -548,10 +548,10 @@ class WCS_Upgrade_2_0 {
$new_subscription->update_dates( $dates_to_update );
}
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: updated dates = %s', $new_subscription->id, str_replace( array( '{', '}', '"' ), '', wcs_json_encode( $dates_to_update ) ) ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: updated dates = %s', $new_subscription->get_id(), str_replace( array( '{', '}', '"' ), '', wcs_json_encode( $dates_to_update ) ) ) );
} catch ( Exception $e ) {
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: unable to update dates, exception "%s"', $new_subscription->id, $e->getMessage() ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: unable to update dates, exception "%s"', $new_subscription->get_id(), $e->getMessage() ) );
}
}
@@ -585,11 +585,11 @@ class WCS_Upgrade_2_0 {
'_paypal_subscription_id' => 'PayPal Subscriber ID',
);
- $order_meta = get_post_meta( $order->id );
+ $order_meta = get_post_meta( wcs_get_objects_property( $order, 'id' ) );
foreach ( $post_meta_with_new_key as $subscription_meta_key => $order_meta_key ) {
- $order_meta_value = get_post_meta( $order->id, $order_meta_key, true );
+ $order_meta_value = get_post_meta( wcs_get_objects_property( $order, 'id' ), $order_meta_key, true );
if ( isset( $order_meta[ $order_meta_key ] ) && '' !== $order_meta[ $order_meta_key ] ) {
update_post_meta( $subscription_id, $subscription_meta_key, $order_meta_value );
@@ -647,7 +647,7 @@ class WCS_Upgrade_2_0 {
}
// Now that we've copied over the old data, deprecate it
- $rows_affected = self::deprecate_post_meta( $order->id );
+ $rows_affected = self::deprecate_post_meta( wcs_get_objects_property( $order, 'id' ) );
WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: %d rows of post meta deprecated', $subscription_id, $rows_affected ) );
}
@@ -777,7 +777,7 @@ class WCS_Upgrade_2_0 {
// Set the post meta
foreach ( $renewal_order_ids as $renewal_order_id ) {
- update_post_meta( $renewal_order_id, '_subscription_renewal', $subscription_id );
+ wcs_set_objects_property( wc_get_order( $renewal_order_id ), 'subscription_renewal', $subscription_id );
}
WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: migrated data for renewal orders %s', $subscription_id, implode( ', ', $renewal_order_ids ) ) );
@@ -817,8 +817,8 @@ class WCS_Upgrade_2_0 {
// Because self::get_subscriptions() orders by order ID, it's safe to use wcs_get_subscriptions_for_order() here because the subscription in the new format will have been created for the original order (because its ID will be < the resubscribe order's ID)
foreach ( wcs_get_subscriptions_for_order( $original_order_id ) as $old_subscription ) {
- update_post_meta( $resubscribe_order_id, '_subscription_resubscribe', $old_subscription->id, true );
- update_post_meta( $new_subscription_id, '_subscription_resubscribe', $old_subscription->id, true );
+ update_post_meta( $resubscribe_order_id, '_subscription_resubscribe', $old_subscription->get_id(), true );
+ update_post_meta( $new_subscription_id, '_subscription_resubscribe', $old_subscription->get_id(), true );
}
$wpdb->query( $wpdb->prepare(
@@ -851,14 +851,14 @@ class WCS_Upgrade_2_0 {
global $wpdb;
// If the order doesn't contain a switch, we don't need to do anything
- if ( '' == get_post_meta( $switch_order->id, '_switched_subscription_key', true ) ) {
+ if ( '' == get_post_meta( wcs_get_objects_property( $switch_order, 'id' ), '_switched_subscription_key', true ) ) {
return;
}
$wpdb->query( $wpdb->prepare(
"UPDATE {$wpdb->postmeta} SET `meta_key` = concat( '_wcs_migrated', `meta_key` )
WHERE `post_id` = %d AND `meta_key` IN ('_switched_subscription_first_payment_timestamp','_switched_subscription_key')",
- $switch_order->id
+ wcs_get_objects_property( $switch_order, 'id' )
) );
// Select the orders which had the items which were switched by this order
@@ -870,7 +870,7 @@ class WCS_Upgrade_2_0 {
'meta_query' => array(
array(
'key' => '_switched_subscription_new_order',
- 'value' => $switch_order->id,
+ 'value' => wcs_get_objects_property( $switch_order, 'id' ),
),
),
) );
@@ -891,7 +891,7 @@ class WCS_Upgrade_2_0 {
if ( wcs_is_subscription( $old_subscription ) ) {
// Link the old subscription's ID to the switch order using the new switch meta key
- update_post_meta( $switch_order->id, '_subscription_switch', $old_subscription->id );
+ wcs_set_objects_property( $switch_order, 'subscription_switch', $old_subscription->get_id() );
// Now store the new/old item IDs for record keeping
foreach ( $old_subscription->get_items() as $item_id => $item ) {
@@ -899,7 +899,7 @@ class WCS_Upgrade_2_0 {
wc_add_order_item_meta( $subscription_item_id, '_switched_subscription_item_id', $item_id, true );
}
- WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: migrated switch data for subscription %d purchased in order %d', $new_subscription->id, $old_subscription->id, $previous_order_id ) );
+ WCS_Upgrade_Logger::add( sprintf( 'For subscription %d: migrated switch data for subscription %d purchased in order %d', $new_subscription->get_id(), $old_subscription->get_id(), $previous_order_id ) );
}
}
}
diff --git a/includes/upgrades/class-wcs-upgrade-logger.php b/includes/upgrades/class-wcs-upgrade-logger.php
index 1ef1de5..bc75689 100644
--- a/includes/upgrades/class-wcs-upgrade-logger.php
+++ b/includes/upgrades/class-wcs-upgrade-logger.php
@@ -46,10 +46,21 @@ class WCS_Upgrade_Logger {
* Clear entries from the upgrade log.
*/
public static function clear() {
- if ( empty( self::$log ) ) {
- self::$log = new WC_Logger();
+
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+
+ if ( empty( self::$log ) ) {
+ self::$log = new WC_Logger();
+ }
+
+ self::$log->clear( self::$handle );
+
+ } else {
+
+ $handler = new WC_Log_Handler_File();
+
+ $handler->clear( self::$handle );
}
- self::$log->clear( self::$handle );
}
/**
diff --git a/includes/wcs-cart-functions.php b/includes/wcs-cart-functions.php
index 4e039c5..b52ea6f 100644
--- a/includes/wcs-cart-functions.php
+++ b/includes/wcs-cart-functions.php
@@ -213,7 +213,7 @@ function wcs_cart_totals_coupon_html( $coupon, $cart ) {
$value = array();
- if ( $amount = $cart->get_coupon_discount_amount( $coupon->code, $cart->display_cart_ex_tax ) ) {
+ if ( $amount = $cart->get_coupon_discount_amount( wcs_get_coupon_property( $coupon, 'code' ), $cart->display_cart_ex_tax ) ) {
$discount_html = '-' . wc_price( $amount );
} else {
$discount_html = '';
@@ -221,7 +221,7 @@ function wcs_cart_totals_coupon_html( $coupon, $cart ) {
$value[] = apply_filters( 'woocommerce_coupon_discount_amount_html', $discount_html, $coupon );
- if ( $coupon->enable_free_shipping() ) {
+ if ( wcs_get_coupon_property( $coupon, 'enable_free_shipping' ) ) {
$value[] = __( 'Free shipping coupon', 'woocommerce-subscriptions' );
}
@@ -303,10 +303,11 @@ function wcs_cart_pluck( $cart, $field, $default = 0 ) {
$value = $cart->$field;
} else {
foreach ( $cart->get_cart() as $cart_item ) {
+
if ( isset( $cart_item[ $field ] ) ) {
$value = $cart_item[ $field ];
- } elseif ( $cart_item['data']->$field ) {
- $value = $cart_item['data']->$field;
+ } else {
+ $value = WC_Subscriptions_Product::get_meta_data( $cart_item['data'], $field, $default );
}
}
}
diff --git a/includes/wcs-compatibility-functions.php b/includes/wcs-compatibility-functions.php
index fad0da1..5af34ab 100644
--- a/includes/wcs-compatibility-functions.php
+++ b/includes/wcs-compatibility-functions.php
@@ -43,3 +43,475 @@ function wcs_help_tip( $tip, $allow_html = false ) {
return $help_tip;
}
+
+/**
+ * Access an object's property in a way that is compatible with CRUD and non-CRUD APIs for different versions of WooCommerce.
+ *
+ * We don't want to force the use of a custom legacy class for orders, similar to WC_Subscription_Legacy, because 3rd party
+ * code may expect the object type to be WC_Order with strict type checks.
+ *
+ * A note on dates: in WC 3.0+, dates are returned a timestamps in the site's timezone :upside_down_face:. In WC < 3.0, they were
+ * returned as MySQL strings in the site's timezone. We return them from here as MySQL strings in UTC timezone because that's how
+ * dates are used in Subscriptions in almost all cases, for sanity's sake.
+ *
+ * @param WC_Order|WC_Product|WC_Subscription $object The object whose property we want to access.
+ * @param string $property The property name.
+ * @param string $single Whether to return just the first piece of meta data with the given property key, or all meta data.
+ * @param mixed $default (optional) The value to return if no value is found - defaults to single -> null, multiple -> array()
+ * @since 2.2.0
+ * @return mixed
+ */
+function wcs_get_objects_property( $object, $property, $single = 'single', $default = null ) {
+
+ $prefixed_key = wcs_maybe_prefix_key( $property );
+
+ $value = ! is_null( $default ) ? $default : ( ( 'single' == $single ) ? null : array() );
+
+ switch ( $property ) {
+
+ case 'name' : // the replacement for post_title added in 3.0
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ $value = $object->post->post_title;
+ } else { // WC 3.0+
+ $value = $object->get_name();
+ }
+ break;
+
+ case 'post' :
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ $value = $object->post;
+ } else { // WC 3.0+
+ // In order to keep backwards compatibility it's required to use the parent data for variations.
+ if ( method_exists( $object, 'is_type' ) && $object->is_type( 'variation' ) ) {
+ $value = get_post( $object->get_parent_id() );
+ } else {
+ $value = get_post( $object->get_id() );
+ }
+ }
+ break;
+
+ case 'post_status' :
+ $value = wcs_get_objects_property( $object, 'post' )->post_status;
+ break;
+
+ case 'parent_id' :
+ if ( method_exists( $object, 'get_parent_id' ) ) { // WC 3.0+ or an instance of WC_Product_Subscription_Variation_Legacy with WC < 3.0
+ $value = $object->get_parent_id();
+ } else { // WC 2.1-2.6
+ $value = $object->get_parent();
+ }
+ break;
+
+ case 'variation_data' :
+ if ( function_exists( 'wc_get_product_variation_attributes' ) ) { // WC 3.0+
+ $value = wc_get_product_variation_attributes( $object->get_id() );
+ } else {
+ $value = $object->$property;
+ }
+ break;
+
+ case 'downloads' :
+ if ( method_exists( $object, 'get_downloads' ) ) { // WC 3.0+
+ $value = $object->get_downloads();
+ } else {
+ $value = $object->get_files();
+ }
+ break;
+
+ case 'order_version' :
+ case 'version' :
+ if ( method_exists( $object, 'get_version' ) ) { // WC 3.0+
+ $value = $object->get_version();
+ } else { // WC 2.1-2.6
+ $value = $object->order_version;
+ }
+ break;
+
+ case 'order_currency' :
+ case 'currency' :
+ if ( method_exists( $object, 'get_currency' ) ) { // WC 3.0+
+ $value = $object->get_currency();
+ } else { // WC 2.1-2.6
+ $value = $object->get_order_currency();
+ }
+ break;
+
+ // Always return a PHP DateTime object in site timezone (or null), the same thing the WC_Order::get_date_created() method returns in WC 3.0+ to make it easier to migrate away from WC < 3.0
+ case 'date_created' :
+ case 'order_date' :
+ case 'date' :
+ if ( method_exists( $object, 'get_date_created' ) ) { // WC 3.0+
+ $value = $object->get_date_created();
+ } else {
+ // Base the value off tht GMT value when possible and then set the DateTime's timezone based on the current site's timezone to avoid incorrect values when the timezone has changed
+ if ( '0000-00-00 00:00:00' != $object->post->post_date_gmt ) {
+ $value = new WC_DateTime( $object->post->post_date_gmt, new DateTimeZone( 'UTC' ) );
+ $value->setTimezone( new DateTimeZone( wc_timezone_string() ) );
+ } else {
+ $value = new WC_DateTime( $object->post->post_date, new DateTimeZone( wc_timezone_string() ) );
+ }
+ }
+ break;
+
+ // Always return a PHP DateTime object in site timezone (or null), the same thing the getter returns in WC 3.0+ to make it easier to migrate away from WC < 3.0
+ case 'date_paid' :
+ if ( method_exists( $object, 'get_date_paid' ) ) { // WC 3.0+
+ $value = $object->get_date_paid();
+ } else {
+ if ( ! empty( $object->paid_date ) ) {
+ // Because the paid_date post meta value was set in the site timezone at the time it was set, this won't always be correct, but is the best we can do with WC < 3.0
+ $value = new WC_DateTime( $object->paid_date, new DateTimeZone( wc_timezone_string() ) );
+ } else {
+ $value = null;
+ }
+ }
+ break;
+
+ case 'cart_discount' :
+ if ( method_exists( $object, 'get_total_discount' ) ) { // WC 3.0+
+ $value = $object->get_total_discount();
+ } else { // WC 2.1-2.6
+ $value = $object->cart_discount;
+ }
+ break;
+
+ default :
+
+ $function_name = 'get_' . $property;
+
+ if ( is_callable( array( $object, $function_name ) ) ) {
+ $value = $object->$function_name();
+ } else {
+
+ // If we don't have a method for this specific property, but we are using WC 3.0, it may be set as meta data on the object so check if we can use that
+ if ( method_exists( $object, 'get_meta' ) ) {
+ if ( $object->meta_exists( $prefixed_key ) ) {
+ if ( 'single' === $single ) {
+ $value = $object->get_meta( $prefixed_key, true );
+ } else {
+ // WC_Data::get_meta() returns an array of stdClass objects with id, key & value properties when meta is available
+ $value = wp_list_pluck( $object->get_meta( $prefixed_key, false ), 'value' );
+ }
+ }
+ } elseif ( 'single' === $single && isset( $object->$property ) ) { // WC < 3.0
+ $value = $object->$property;
+ } elseif ( metadata_exists( 'post', wcs_get_objects_property( $object, 'id' ), $prefixed_key ) ) {
+ // If we couldn't find a property or function, fallback to using post meta as that's what many __get() methods in WC < 3.0 did
+ if ( 'single' === $single ) {
+ $value = get_post_meta( wcs_get_objects_property( $object, 'id' ), $prefixed_key, true );
+ } else {
+ // Get all the meta values
+ $value = get_post_meta( wcs_get_objects_property( $object, 'id' ), $prefixed_key, false );
+ }
+ }
+ }
+ break;
+ }
+
+ return $value;
+}
+
+/**
+ * Set an object's property in a way that is compatible with CRUD and non-CRUD APIs for different versions of WooCommerce.
+ *
+ * @param WC_Order|WC_Product|WC_Subscription $object The object whose property we want to access.
+ * @param string $key The meta key name without '_' prefix
+ * @param mixed $value The data to set as the value of the meta
+ * @param string $save Whether to write the data to the database or not. Use 'save' to write to the database, anything else to only update it in memory.
+ * @param int $meta_id The meta ID of exiting meta data if you wish to overwrite an existing piece of meta.
+ * @param bool|string $prefix An optional prefix to add to the $key. Default '_'. Set to boolean false to have no prefix added.
+ * @since 2.2.0
+ * @return mixed
+ */
+function wcs_set_objects_property( &$object, $key, $value, $save = 'save', $meta_id = '' ) {
+
+ $prefixed_key = wcs_maybe_prefix_key( $key );
+
+ // WC will automatically set/update these keys when a shipping/billing address attribute changes so we can ignore these keys
+ if ( in_array( $prefixed_key, array( '_shipping_address_index', '_billing_address_index' ) ) ) {
+ return;
+ }
+
+ // Special cases where properties with setters which don't map nicely to their function names
+ $meta_setters_map = array(
+ '_cart_discount' => 'set_discount_total',
+ '_cart_discount_tax' => 'set_discount_tax',
+ '_customer_user' => 'set_customer_id',
+ '_order_tax' => 'set_cart_tax',
+ '_order_shipping' => 'set_shipping_total',
+ '_sale_price_dates_from' => 'set_date_on_sale_from',
+ '_sale_price_dates_to' => 'set_date_on_sale_to',
+ );
+
+ // If we have a 3.0 object with a predefined setter function, use it
+ if ( isset( $meta_setters_map[ $prefixed_key ] ) && is_callable( array( $object, $meta_setters_map[ $prefixed_key ] ) ) ) {
+ $function = $meta_setters_map[ $prefixed_key ];
+ $object->$function( $value );
+
+ // If we have a 3.0 object, use the setter if available.
+ } elseif ( is_callable( array( $object, 'set' . $prefixed_key ) ) ) {
+
+ // Prices include tax is stored as a boolean in props but saved in the database as a string yes/no, so we need to normalise it here to make sure if we have a string (which can be passed to it by things like wcs_copy_order_meta()) that it's converted to a boolean before being set
+ if ( '_prices_include_tax' === $prefixed_key && ! is_bool( $value ) ) {
+ $value = 'yes' === $value ? true : false;
+ }
+
+ $object->{ "set$prefixed_key" }( $value );
+
+ // If there is a setter without the order prefix (eg set_order_total -> set_total)
+ } elseif ( is_callable( array( $object, 'set' . str_replace( '_order', '', $prefixed_key ) ) ) ) {
+ $function_name = 'set' . str_replace( '_order', '', $prefixed_key );
+ $object->$function_name( $value );
+
+ // If there is no setter, treat as meta within the 3.0.x object.
+ } elseif ( is_callable( array( $object, 'update_meta_data' ) ) ) {
+ $object->update_meta_data( $prefixed_key, $value, $meta_id );
+
+ // 2.6.x handling for name which is not meta.
+ } elseif ( 'name' === $key ) {
+ $object->post->post_title = $value;
+
+ // 2.6.x handling for everything else.
+ } else {
+ $object->$key = $value;
+ }
+
+ // Save the data
+ if ( 'save' === $save ) {
+ if ( is_callable( array( $object, 'save' ) ) ) { // WC 3.0+
+ $object->save();
+ } elseif ( 'date_created' == $key ) { // WC < 3.0+
+ wp_update_post( array( 'ID' => wcs_get_objects_property( $object, 'id' ), 'post_date' => get_date_from_gmt( $value ), 'post_date_gmt' => $value ) );
+ } elseif ( 'name' === $key ) { // the replacement for post_title added in 3.0, need to update post_title not post meta
+ wp_update_post( array( 'ID' => wcs_get_objects_property( $object, 'id' ), 'post_title' => $value ) );
+ } else {
+
+ if ( ! empty( $meta_id ) ) {
+ update_metadata_by_mid( 'post', $meta_id, $value, $prefixed_key );
+ } else {
+ update_post_meta( wcs_get_objects_property( $object, 'id' ), $prefixed_key, $value );
+ }
+ }
+ }
+}
+
+/**
+ * Delete an object's property in a way that is compatible with CRUD and non-CRUD APIs for different versions of WooCommerce.
+ *
+ * @param WC_Order|WC_Product|WC_Subscription $object The object whose property we want to access.
+ * @param string $key The meta key name without '_' prefix
+ * @param mixed $value The data to set as the value of the meta
+ * @param string $save Whether to save the data or not, 'save' to save the data, otherwise it won't be saved.
+ * @since 2.2.0
+ * @return mixed
+ */
+function wcs_delete_objects_property( &$object, $key, $save = 'save', $meta_id = '' ) {
+
+ $prefixed_key = wcs_maybe_prefix_key( $key );
+
+ if ( ! empty( $meta_id ) && method_exists( $object, 'delete_meta_data_by_mid' ) ) {
+ $object->delete_meta_data_by_mid( $meta_id );
+ } elseif ( method_exists( $object, 'delete_meta_data' ) ) {
+ $object->delete_meta_data( $prefixed_key );
+ } elseif ( isset( $object->$key ) ) {
+ unset( $object->$key );
+ }
+
+ // Save the data
+ if ( 'save' === $save ) {
+ if ( method_exists( $object, 'save' ) ) { // WC 3.0+
+ $object->save();
+ } elseif ( ! empty( $meta_id ) ) {
+ delete_metadata_by_mid( 'post', $meta_id );
+ } else {
+ delete_post_meta( wcs_get_objects_property( $object, 'id' ), $prefixed_key );
+ }
+ }
+}
+
+/**
+ * Check whether an order is a standard order (i.e. not a refund or subscription) in version compatible way.
+ *
+ * WC 3.0 has the $order->get_type() API which returns 'shop_order', while WC < 3.0 provided the $order->order_type
+ * property which returned 'simple', so we need to check for both.
+ *
+ * @param WC_Order $order
+ * @since 2.2.0
+ * @return bool
+ */
+function wcs_is_order( $order ) {
+
+ if ( method_exists( $order, 'get_type' ) ) {
+ $is_order = ( 'shop_order' === $order->get_type() );
+ } else {
+ $is_order = ( 'simple' === $order->order_type );
+ }
+
+ return $is_order;
+}
+
+/**
+ * Find and return the value for a deprecated property property.
+ *
+ * Product properties should not be accessed directly with WooCommerce 3.0+, because of that, a lot of properties
+ * have been deprecated/removed in the subscription product type classes. This function centralises the handling
+ * of deriving deprecated properties. This saves duplicating the __get() method in WC_Product_Subscription,
+ * WC_Product_Variable_Subscription and WC_Product_Subscription_Variation.
+ *
+ * @param string $property
+ * @param WC_Product $product
+ * @since 2.2.0
+ * @return mixed
+ */
+function wcs_product_deprecated_property_handler( $property, $product ) {
+
+ $message_prefix = 'Product properties should not be accessed directly with WooCommerce 3.0+.';
+ $function_name = 'get_' . str_replace( 'subscription_', '', str_replace( 'subscription_period_', '', $property ) );
+ $class_name = get_class( $product );
+ $value = null;
+
+ if ( in_array( $property, array( 'product_type', 'parent_product_type', 'limit_subscriptions', 'subscription_limit', 'subscription_payment_sync_date', 'subscription_one_time_shipping' ) ) || ( is_callable( array( 'WC_Subscriptions_Product', $function_name ) ) && false !== strpos( $property, 'subscription' ) ) ) {
+
+ switch ( $property ) {
+ case 'product_type':
+ $value = $product->get_type();
+ $alternative = $class_name . '::get_type()';
+ break;
+
+ case 'parent_product_type':
+ if ( $product->is_type( 'subscription_variation' ) ) {
+ $value = 'variation';
+ $alternative = 'WC_Product_Variation::get_type()';
+ } else {
+ $value = 'variable';
+ $alternative = 'WC_Product_Variable::get_type()';
+ }
+ break;
+
+ case 'limit_subscriptions':
+ case 'subscription_limit':
+ $value = wcs_get_product_limitation( $product );
+ $alternative = 'wcs_get_product_limitation( $product )';
+ break;
+
+ case 'subscription_one_time_shipping':
+ $value = WC_Subscriptions_Product::needs_one_time_shipping( $product );
+ $alternative = 'WC_Subscriptions_Product::needs_one_time_shipping( $product )';
+ break;
+
+ case 'subscription_payment_sync_date':
+ $value = WC_Subscriptions_Synchroniser::get_products_payment_day( $product );
+ $alternative = 'WC_Subscriptions_Synchroniser::get_products_payment_day( $product )';
+ break;
+
+ case 'max_variation_period':
+ case 'max_variation_period_interval':
+ $meta_key = '_' . $property;
+ if ( '' === $product->get_meta( $meta_key ) ) {
+ WC_Product_Variable::sync( $product->get_id() );
+ }
+ $value = $product->get_meta( $meta_key );
+ $alternative = $class_name . '::get_meta( ' . $meta_key . ' ) or wcs_get_min_max_variation_data( $product )';
+ break;
+
+ default:
+ $value = call_user_func( array( 'WC_Subscriptions_Product', $function_name ), $product );
+ $alternative = sprintf( 'WC_Subscriptions_Product::%s( $product )', $function_name );
+ break;
+ }
+
+ wcs_deprecated_argument( $class_name . '::$' . $property, '2.2.0', sprintf( '%s Use %s', $message_prefix, $alternative ) );
+ }
+
+ return $value;
+}
+
+/**
+ * Access a coupon's property in a way that is compatible with CRUD and non-CRUD APIs for different versions of WooCommerce.
+ *
+ * Similar to @see wcs_get_objects_property
+ *
+ * @param WC_Coupon $coupon The coupon whose property we want to access.
+ * @param string $property The property name.
+ * @since 2.2
+ * @return mixed
+ */
+function wcs_get_coupon_property( $coupon, $property ) {
+
+ $value = '';
+
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ $value = $coupon->$property;
+ } else {
+ // Some coupon properties don't map nicely to their corresponding getter function. This array contains those exceptions.
+ $property_to_getter_map = array(
+ 'type' => 'get_discount_type',
+ 'exclude_product_ids' => 'get_excluded_product_ids',
+ 'expiry_date' => 'get_date_expires',
+ 'exclude_product_categories' => 'get_excluded_product_categories',
+ 'customer_email' => 'get_email_restrictions',
+ 'enable_free_shipping' => 'get_free_shipping',
+ );
+
+ switch ( true ) {
+ case 'exists' == $property:
+ $value = ( $coupon->get_id() > 0 ) ? true : false;
+ break;
+ case isset( $property_to_getter_map[ $property ] ) && is_callable( array( $coupon, $property_to_getter_map[ $property ] ) ):
+ $function = $property_to_getter_map[ $property ];
+ $value = $coupon->$function();
+ break;
+ case is_callable( array( $coupon, 'get_' . $property ) ):
+ $value = $coupon->{ "get_$property" }();
+ break;
+ }
+ }
+
+ return $value;
+}
+
+/**
+ * Set a coupon's property in a way that is compatible with CRUD and non-CRUD APIs for different versions of WooCommerce.
+ *
+ * Similar to @see wcs_set_objects_property
+ *
+ * @param WC_Coupon $coupon The coupon whose property we want to set.
+ * @param string $property The property name.
+ * @param mixed $value The data to set as the value
+ * @since 2.2
+ */
+function wcs_set_coupon_property( &$coupon, $property, $value ) {
+
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ $coupon->$property = $value;
+ } else {
+ // Some coupon properties don't map nicely to their corresponding setter function. This array contains those exceptions.
+ $property_to_setter_map = array(
+ 'type' => 'set_discount_type',
+ 'exclude_product_ids' => 'set_excluded_product_ids',
+ 'expiry_date' => 'set_date_expires',
+ 'exclude_product_categories' => 'set_excluded_product_categories',
+ 'customer_email' => 'set_email_restrictions',
+ 'enable_free_shipping' => 'set_free_shipping',
+ );
+
+ switch ( true ) {
+ case 'individual_use' == $property:
+ // set_individual_use expects a boolean, the individual_use property use to be either 'yes' or 'no' so we need to accept both types
+ if ( ! is_bool( $value ) ) {
+ $value = ( 'yes' === $value ) ? true : false;
+ }
+
+ $coupon->set_individual_use( $value );
+ break;
+ case isset( $property_to_setter_map[ $property ] ) && is_callable( array( $coupon, $property_to_setter_map[ $property ] ) ):
+ $function = $property_to_setter_map[ $property ];
+ $coupon->$function( $value );
+
+ break;
+ case is_callable( array( $coupon, 'set_' . $property ) ):
+ $coupon->{ "set_$property" }( $value );
+ break;
+ }
+ }
+}
diff --git a/includes/wcs-deprecated-functions.php b/includes/wcs-deprecated-functions.php
index 221c242..efbc9cf 100644
--- a/includes/wcs-deprecated-functions.php
+++ b/includes/wcs-deprecated-functions.php
@@ -16,6 +16,73 @@ if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
+/**
+ * Wrapper for wc_doing_it_wrong.
+ *
+ * @since 2.2.0
+ * @param string $function
+ * @param string $version
+ * @param string $replacement
+ */
+function wcs_doing_it_wrong( $function, $message, $version ) {
+
+ if ( function_exists( 'wc_doing_it_wrong' ) ) {
+ wc_doing_it_wrong( $function, $message, $version );
+ } else {
+ // Reimplment wc_doing_it_wrong() when WC 3.0 is not active
+ if ( is_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 2.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 {
+ // Reimplment wcs_deprecated_function() when WC 3.0 is not active
+ if ( is_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 2.2.0
+ * @param string $argument
+ * @param string $version
+ * @param string $message
+ */
+function wcs_deprecated_argument( $function, $version, $message = null ) {
+ if ( is_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.
*
@@ -37,7 +104,7 @@ if ( ! defined( 'ABSPATH' ) ) {
function wcs_get_old_subscription_key( WC_Subscription $subscription ) {
// Get an ID to use as the order ID
- $order_id = isset( $subscription->order->id ) ? $subscription->order->id : $subscription->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();
@@ -128,8 +195,15 @@ function wcs_get_subscription_in_deprecated_structure( WC_Subscription $subscrip
$completed_payments = array();
if ( $subscription->get_completed_payment_count() ) {
- if ( ! empty( $subscription->order ) && $subscription->order->has_status( $subscription->get_paid_order_statuses() ) ) {
- $completed_payments[] = $subscription->order->post->post_date_gmt;
+
+ $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 );
+ }
}
$paid_renewal_order_ids = get_posts( array(
@@ -143,14 +217,17 @@ function wcs_get_subscription_in_deprecated_structure( WC_Subscription $subscrip
array(
'key' => '_subscription_renewal',
'compare' => '=',
- 'value' => $subscription->id,
+ 'value' => $subscription->get_id(),
'type' => 'numeric',
),
),
) );
foreach ( $paid_renewal_order_ids as $paid_renewal_order_id ) {
- $completed_payments[] = get_post_field( 'post_date_gmt', $paid_renewal_order_id );
+ $date_created = wcs_get_objects_property( wc_get_order( $paid_renewal_order_id ), 'date_created' );
+ if ( ! is_null( $date_created ) ) {
+ $completed_payments[] = wcs_get_datetime_utc_string( $date_created );
+ }
}
}
@@ -160,27 +237,27 @@ function wcs_get_subscription_in_deprecated_structure( WC_Subscription $subscrip
if ( ! empty( $item ) ) {
$deprecated_subscription_object = array(
- 'order_id' => $subscription->order->id,
+ '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->billing_period,
- 'interval' => $subscription->billing_interval,
- 'length' => wcs_estimate_periods_between( ( 0 == $subscription->get_time( 'trial_end' ) ) ? $subscription->get_time( 'start' ) : $subscription->get_time( 'trial_end' ), $subscription->get_time( 'end' ) + 120, $subscription->billing_period, 'floor' ) / $subscription->billing_interval, // Since subscriptions no longer have a length, we need to calculate the length given the start and end dates and the period.
+ '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' ),
+ 'start_date' => $subscription->get_date( 'date_created' ),
'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->failed_payment_count,
+ 'failed_payments' => $subscription->get_failed_payment_count(),
'completed_payments' => $completed_payments,
- 'suspension_count' => $subscription->suspension_count,
- 'last_payment_date' => $subscription->get_date( 'last_payment' ),
+ 'suspension_count' => $subscription->get_suspension_count(),
+ 'last_payment_date' => $subscription->get_date( 'last_order_date_created' ),
);
} else {
diff --git a/includes/wcs-helper-functions.php b/includes/wcs-helper-functions.php
index 2331b27..967296e 100644
--- a/includes/wcs-helper-functions.php
+++ b/includes/wcs-helper-functions.php
@@ -158,3 +158,31 @@ function wcs_get_rounding_precision() {
return $precision;
}
+
+/**
+ * Add a prefix to a string if it doesn't already have it
+ *
+ * @param string
+ * @param string
+ * @since 2.2.0
+ * @return string
+ */
+function wcs_maybe_prefix_key( $key, $prefix = '_' ) {
+ return ( substr( $key, 0, strlen( $prefix ) ) != $prefix ) ? $prefix . $key : $key;
+}
+
+/**
+ * Find the name of the function which called the function which called this function.
+ *
+ * @since 2.2.0
+ * @return string
+ */
+function wcs_get_calling_function_name() {
+
+ $backtrace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 3 );
+ $calling_function = isset( $backtrace[2]['class'] ) ? $backtrace[2]['class'] : '';
+ $calling_function .= isset( $backtrace[2]['type'] ) ? $backtrace[2]['type'] : '';
+ $calling_function .= isset( $backtrace[2]['function'] ) ? $backtrace[2]['function'] : '';
+
+ return $calling_function;
+}
diff --git a/includes/wcs-limit-functions.php b/includes/wcs-limit-functions.php
index 5e3956b..04a7c4f 100644
--- a/includes/wcs-limit-functions.php
+++ b/includes/wcs-limit-functions.php
@@ -19,17 +19,12 @@ if ( ! defined( 'ABSPATH' ) ) {
* @return string containing the limit type
*/
function wcs_get_product_limitation( $product ) {
- if ( ! is_object( $product ) ) {
+
+ if ( ! is_object( $product ) || ! is_a( $product, 'WC_Product' ) ) {
$product = wc_get_product( $product );
}
- if ( ! isset( $product->product_custom_fields['_subscription_limit'][0] ) ) {
- return 'no';
- } elseif ( 'yes' == $product->product_custom_fields['_subscription_limit'][0] ) { // backward compatibility
- return 'any';
- } else {
- return $product->product_custom_fields['_subscription_limit'][0];
- }
+ return apply_filters( 'woocommerce_subscriptions_product_limitation', WC_Subscriptions_Product::get_meta_data( $product, 'subscription_limit', 0 ), $product );
}
/**
@@ -43,5 +38,5 @@ function wcs_is_product_limited_for_user( $product, $user_id = 0 ) {
$product = wc_get_product( $product );
}
- return ( ( 'active' == wcs_get_product_limitation( $product ) && wcs_user_has_subscription( $user_id, $product->id, 'on-hold' ) ) || ( 'no' !== wcs_get_product_limitation( $product ) && wcs_user_has_subscription( $user_id, $product->id, wcs_get_product_limitation( $product ) ) ) ) ? true : false;
+ return ( ( 'active' == wcs_get_product_limitation( $product ) && wcs_user_has_subscription( $user_id, $product->get_id(), 'on-hold' ) ) || ( 'no' !== wcs_get_product_limitation( $product ) && wcs_user_has_subscription( $user_id, $product->get_id(), wcs_get_product_limitation( $product ) ) ) ) ? true : false;
}
diff --git a/includes/wcs-order-functions.php b/includes/wcs-order-functions.php
index 7028d67..f9809d2 100644
--- a/includes/wcs-order-functions.php
+++ b/includes/wcs-order-functions.php
@@ -32,7 +32,7 @@ if ( ! defined( 'ABSPATH' ) ) {
function wcs_get_subscriptions_for_order( $order_id, $args = array() ) {
if ( is_object( $order_id ) ) {
- $order_id = $order_id->id;
+ $order_id = wcs_get_objects_property( $order_id, 'id' );
}
$args = wp_parse_args( $args, array(
@@ -83,31 +83,31 @@ function wcs_copy_order_address( $from_order, $to_order, $address_type = 'all' )
if ( in_array( $address_type, array( 'shipping', 'all' ) ) ) {
$to_order->set_address( array(
- 'first_name' => $from_order->shipping_first_name,
- 'last_name' => $from_order->shipping_last_name,
- 'company' => $from_order->shipping_company,
- 'address_1' => $from_order->shipping_address_1,
- 'address_2' => $from_order->shipping_address_2,
- 'city' => $from_order->shipping_city,
- 'state' => $from_order->shipping_state,
- 'postcode' => $from_order->shipping_postcode,
- 'country' => $from_order->shipping_country,
+ 'first_name' => wcs_get_objects_property( $from_order, 'shipping_first_name' ),
+ 'last_name' => wcs_get_objects_property( $from_order, 'shipping_last_name' ),
+ 'company' => wcs_get_objects_property( $from_order, 'shipping_company' ),
+ 'address_1' => wcs_get_objects_property( $from_order, 'shipping_address_1' ),
+ 'address_2' => wcs_get_objects_property( $from_order, 'shipping_address_2' ),
+ 'city' => wcs_get_objects_property( $from_order, 'shipping_city' ),
+ 'state' => wcs_get_objects_property( $from_order, 'shipping_state' ),
+ 'postcode' => wcs_get_objects_property( $from_order, 'shipping_postcode' ),
+ 'country' => wcs_get_objects_property( $from_order, 'shipping_country' ),
), 'shipping' );
}
if ( in_array( $address_type, array( 'billing', 'all' ) ) ) {
$to_order->set_address( array(
- 'first_name' => $from_order->billing_first_name,
- 'last_name' => $from_order->billing_last_name,
- 'company' => $from_order->billing_company,
- 'address_1' => $from_order->billing_address_1,
- 'address_2' => $from_order->billing_address_2,
- 'city' => $from_order->billing_city,
- 'state' => $from_order->billing_state,
- 'postcode' => $from_order->billing_postcode,
- 'country' => $from_order->billing_country,
- 'email' => $from_order->billing_email,
- 'phone' => $from_order->billing_phone,
+ 'first_name' => wcs_get_objects_property( $from_order, 'billing_first_name' ),
+ 'last_name' => wcs_get_objects_property( $from_order, 'billing_last_name' ),
+ 'company' => wcs_get_objects_property( $from_order, 'billing_company' ),
+ 'address_1' => wcs_get_objects_property( $from_order, 'billing_address_1' ),
+ 'address_2' => wcs_get_objects_property( $from_order, 'billing_address_2' ),
+ 'city' => wcs_get_objects_property( $from_order, 'billing_city' ),
+ 'state' => wcs_get_objects_property( $from_order, 'billing_state' ),
+ 'postcode' => wcs_get_objects_property( $from_order, 'billing_postcode' ),
+ 'country' => wcs_get_objects_property( $from_order, 'billing_country' ),
+ 'email' => wcs_get_objects_property( $from_order, 'billing_email' ),
+ 'phone' => wcs_get_objects_property( $from_order, 'billing_phone' ),
), 'billing' );
}
@@ -150,7 +150,9 @@ function wcs_copy_order_meta( $from_order, $to_order, $type = 'subscription' ) {
AND `meta_key` NOT LIKE '_schedule_%%'
AND `meta_key` NOT IN (
'_paid_date',
+ '_date_paid',
'_completed_date',
+ '_date_completed',
'_order_key',
'_edit_lock',
'_wc_points_earned',
@@ -163,7 +165,7 @@ function wcs_copy_order_meta( $from_order, $to_order, $type = 'subscription' ) {
'_payment_method',
'_payment_method_title'
)",
- $from_order->id
+ wcs_get_objects_property( $from_order, 'id' )
);
if ( 'renewal_order' == $type ) {
@@ -176,7 +178,7 @@ function wcs_copy_order_meta( $from_order, $to_order, $type = 'subscription' ) {
$meta = apply_filters( 'wcs_' . $type . '_meta', $meta, $to_order, $from_order );
foreach ( $meta as $meta_item ) {
- update_post_meta( $to_order->id, $meta_item['meta_key'], maybe_unserialize( $meta_item['meta_value'] ) );
+ wcs_set_objects_property( $to_order, $meta_item['meta_key'], maybe_unserialize( $meta_item['meta_value'] ) );
}
}
@@ -208,11 +210,9 @@ function wcs_create_order_from_subscription( $subscription, $type ) {
$new_order = wc_create_order( array(
'customer_id' => $subscription->get_user_id(),
- 'customer_note' => $subscription->customer_note,
+ 'customer_note' => $subscription->get_customer_note(),
) );
- $new_order->post->post_title = wcs_get_new_order_title( $type );
-
wcs_copy_order_meta( $subscription, $new_order, $type );
// Copy over line items and allow extensions to add/remove items or item meta
@@ -225,16 +225,23 @@ function wcs_create_order_from_subscription( $subscription, $type ) {
$item_name = apply_filters( 'wcs_' . $type . '_item_name', $item_name, $item, $subscription );
// Create order line item on the renewal order
- $recurring_item_id = wc_add_order_item( $new_order->id, array(
+ $order_item_id = wc_add_order_item( wcs_get_objects_property( $new_order, 'id' ), array(
'order_item_name' => $item_name,
'order_item_type' => $item['type'],
) );
// Remove recurring line items and set item totals based on recurring line totals
- foreach ( $item['item_meta'] as $meta_key => $meta_values ) {
- foreach ( $meta_values as $meta_value ) {
- wc_add_order_item_meta( $recurring_item_id, $meta_key, maybe_unserialize( $meta_value ) );
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ foreach ( $item['item_meta'] as $meta_key => $meta_values ) {
+ foreach ( $meta_values as $meta_value ) {
+ wc_add_order_item_meta( $order_item_id, $meta_key, maybe_unserialize( $meta_value ) );
+ }
}
+ } else {
+ $order_item = $new_order->get_item( $order_item_id );
+
+ wcs_copy_order_item( $item, $order_item );
+ $order_item->save();
}
// If the line item we're adding is a product line item and that product still exists, trigger the 'woocommerce_order_add_product' hook
@@ -256,8 +263,8 @@ function wcs_create_order_from_subscription( $subscription, $type ) {
);
// If we have a variation, get the attribute meta data from teh item to pass to callbacks
- if ( ! empty( $item['variation_id'] ) && ! empty( $product->variation_data ) ) {
- foreach ( $product->variation_data as $attribute => $variation ) {
+ if ( ! empty( $item['variation_id'] ) && null !== ( $variation_data = wcs_get_objects_property( $product, 'variation_data' ) ) ) {
+ foreach ( $variation_data as $attribute => $variation ) {
if ( isset( $item[ str_replace( 'attribute_', '', $attribute ) ] ) ) {
$args['variation'][ $attribute ] = $item[ str_replace( 'attribute_', '', $attribute ) ];
}
@@ -265,11 +272,17 @@ function wcs_create_order_from_subscription( $subscription, $type ) {
}
// Backorders
- if ( $product->backorders_require_notification() && $product->is_on_backorder( $item['qty'] ) ) {
- wc_add_order_item_meta( $recurring_item_id, apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce-subscriptions' ) ), $item['qty'] - max( 0, $product->get_total_stock() ) );
+ if ( isset( $order_item ) && is_callable( array( $order_item, 'set_backorder_meta' ) ) ) { // WC 3.0
+ $order_item->set_backorder_meta();
+ $order_item->save();
+ } elseif ( $product->backorders_require_notification() && $product->is_on_backorder( $item['qty'] ) ) { // WC 2.6
+ wc_add_order_item_meta( $order_item_id, apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce-subscriptions' ) ), $item['qty'] - max( 0, $product->get_total_stock() ) );
}
- do_action( 'woocommerce_order_add_product', $new_order->id, $recurring_item_id, $product, $item['qty'], $args );
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ // WC 3.0+ will also trigger the 'woocommerce_order_add_product when 'woocommerce_new_order_item', which is triggered in wc_add_order_item_meta()
+ do_action( 'woocommerce_order_add_product', wcs_get_objects_property( $new_order, 'id' ), $order_item_id, $product, $item['qty'], $args );
+ }
}
}
}
@@ -294,6 +307,8 @@ function wcs_create_order_from_subscription( $subscription, $type ) {
* @return string new title for a post
*/
function wcs_get_new_order_title( $type ) {
+ wcs_deprecated_function( __FUNCTION__, '2.2.0' );
+
$type = wcs_validate_new_order_type( $type );
$order_date = strftime( _x( '%b %d, %Y @ %I:%M %p', 'Used in subscription post title. "Subscription renewal order - "', 'woocommerce-subscriptions' ) );
@@ -346,29 +361,29 @@ function wcs_get_order_address( $order, $address_type = 'shipping' ) {
if ( 'billing' == $address_type ) {
$address = array(
- 'first_name' => $order->billing_first_name,
- 'last_name' => $order->billing_last_name,
- 'company' => $order->billing_company,
- 'address_1' => $order->billing_address_1,
- 'address_2' => $order->billing_address_2,
- 'city' => $order->billing_city,
- 'state' => $order->billing_state,
- 'postcode' => $order->billing_postcode,
- 'country' => $order->billing_country,
- 'email' => $order->billing_email,
- 'phone' => $order->billing_phone,
+ 'first_name' => wcs_get_objects_property( $order, 'billing_first_name' ),
+ 'last_name' => wcs_get_objects_property( $order, 'billing_last_name' ),
+ 'company' => wcs_get_objects_property( $order, 'billing_company' ),
+ 'address_1' => wcs_get_objects_property( $order, 'billing_address_1' ),
+ 'address_2' => wcs_get_objects_property( $order, 'billing_address_2' ),
+ 'city' => wcs_get_objects_property( $order, 'billing_city' ),
+ 'state' => wcs_get_objects_property( $order, 'billing_state' ),
+ 'postcode' => wcs_get_objects_property( $order, 'billing_postcode' ),
+ 'country' => wcs_get_objects_property( $order, 'billing_country' ),
+ 'email' => wcs_get_objects_property( $order, 'billing_email' ),
+ 'phone' => wcs_get_objects_property( $order, 'billing_phone' ),
);
} else {
$address = array(
- 'first_name' => $order->shipping_first_name,
- 'last_name' => $order->shipping_last_name,
- 'company' => $order->shipping_company,
- 'address_1' => $order->shipping_address_1,
- 'address_2' => $order->shipping_address_2,
- 'city' => $order->shipping_city,
- 'state' => $order->shipping_state,
- 'postcode' => $order->shipping_postcode,
- 'country' => $order->shipping_country,
+ 'first_name' => wcs_get_objects_property( $order, 'shipping_first_name' ),
+ 'last_name' => wcs_get_objects_property( $order, 'shipping_last_name' ),
+ 'company' => wcs_get_objects_property( $order, 'shipping_company' ),
+ 'address_1' => wcs_get_objects_property( $order, 'shipping_address_1' ),
+ 'address_2' => wcs_get_objects_property( $order, 'shipping_address_2' ),
+ 'city' => wcs_get_objects_property( $order, 'shipping_city' ),
+ 'state' => wcs_get_objects_property( $order, 'shipping_state' ),
+ 'postcode' => wcs_get_objects_property( $order, 'shipping_postcode' ),
+ 'country' => wcs_get_objects_property( $order, 'shipping_country' ),
);
}
@@ -397,7 +412,7 @@ function wcs_order_contains_subscription( $order, $order_type = array( 'parent',
$contains_subscription = false;
$get_all = ( in_array( 'any', $order_type ) ) ? true : false;
- if ( ( in_array( 'parent', $order_type ) || $get_all ) && count( wcs_get_subscriptions_for_order( $order->id, array( 'order_type' => 'parent' ) ) ) > 0 ) {
+ if ( ( in_array( 'parent', $order_type ) || $get_all ) && count( wcs_get_subscriptions_for_order( wcs_get_objects_property( $order, 'id' ), array( 'order_type' => 'parent' ) ) ) > 0 ) {
$contains_subscription = true;
} elseif ( ( in_array( 'renewal', $order_type ) || $get_all ) && wcs_order_contains_renewal( $order ) ) {
@@ -657,3 +672,99 @@ function wcs_get_line_item_name( $line_item ) {
return apply_filters( 'wcs_line_item_name', $line_item_name, $line_item );
}
+
+/**
+ * Display item meta data in a version compatible way.
+ *
+ * @since 2.2.0
+ * @param WC_Item $item
+ * @param WC_Order $order
+ * @return void
+ */
+function wcs_display_item_meta( $item, $order ) {
+ if ( function_exists( 'wc_display_item_meta' ) ) { // WC 3.0+
+ wc_display_item_meta( $item );
+ } else {
+ $order->display_item_meta( $item );
+ }
+}
+
+/**
+ * Display item download links in a version compatible way.
+ *
+ * @since 2.2.0
+ * @param WC_Item $item
+ * @param WC_Order $order
+ * @return void
+ */
+function wcs_display_item_downloads( $item, $order ) {
+ if ( function_exists( 'wc_display_item_downloads' ) ) { // WC 3.0+
+ wc_display_item_downloads( $item );
+ } else {
+ $order->display_item_downloads( $item );
+ }
+}
+
+/**
+ * Copy the order item data and meta data from one item to another.
+ *
+ * @since 2.2.0
+ * @param WC_Order_Item The order item to copy data from
+ * @param WC_Order_Item The order item to copy data to
+ * @return void
+ */
+function wcs_copy_order_item( $from_item, &$to_item ) {
+
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ wcs_doing_it_wrong( __FUNCTION__, 'This function uses data structures introduced in WC 3.0. To copy line item meta use $from_item[\'item_meta\'] and wc_add_order_item_meta().', '2.2' );
+ return;
+ }
+
+ foreach ( $from_item->get_meta_data() as $meta_data ) {
+ $to_item->update_meta_data( $meta_data->key, $meta_data->value );
+ }
+
+ switch ( $from_item->get_type() ) {
+ case 'line_item':
+ $to_item->set_props( array(
+ 'product_id' => $from_item->get_product_id(),
+ 'variation_id' => $from_item->get_variation_id(),
+ 'quantity' => $from_item->get_quantity(),
+ 'tax_class' => $from_item->get_tax_class(),
+ 'subtotal' => $from_item->get_subtotal(),
+ 'total' => $from_item->get_total(),
+ 'taxes' => $from_item->get_taxes(),
+ ) );
+ break;
+ case 'shipping':
+ $to_item->set_props( array(
+ 'method_id' => $from_item->get_method_id(),
+ 'total' => $from_item->get_total(),
+ 'taxes' => $from_item->get_taxes(),
+ ) );
+ break;
+ case 'tax':
+ $to_item->set_props( array(
+ 'rate_id' => $from_item->get_rate_id(),
+ 'label' => $from_item->get_label(),
+ 'compound' => $from_item->get_compound(),
+ 'tax_total' => $from_item->get_tax_total(),
+ 'shipping_tax_total' => $from_item->get_shipping_tax_total(),
+ ) );
+ break;
+ case 'fee':
+ $to_item->set_props( array(
+ 'tax_class' => $from_item->get_tax_class(),
+ 'tax_status' => $from_item->get_tax_status(),
+ 'total' => $from_item->get_total(),
+ 'taxes' => $from_item->get_taxes(),
+ ) );
+ break;
+ case 'coupon':
+ $to_item->set_props( array(
+ 'discount' => $from_item->discount(),
+ 'discount_tax' => $from_item->discount_tax(),
+ ) );
+ break;
+ }
+}
diff --git a/includes/wcs-product-functions.php b/includes/wcs-product-functions.php
new file mode 100644
index 0000000..6a2f957
--- /dev/null
+++ b/includes/wcs-product-functions.php
@@ -0,0 +1,414 @@
+ 1,
+ 'price' => $product->get_price(),
+ ) );
+
+ if ( function_exists( 'wc_get_price_including_tax' ) ) { // WC 3.0+
+ $price = wc_get_price_including_tax( $product, $args );
+ } else { // WC < 3.0
+ $price = $product->get_price_including_tax( $args['qty'], $args['price'] );
+ }
+
+ return $price;
+}
+
+/**
+ * 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 );
+ } else { // WC < 3.0
+ $price = $product->get_price_excluding_tax( $args['qty'], $args['price'] );
+ }
+
+ return $price;
+}
+
+/**
+ * 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 ) {
+
+ if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
+ $regular_price = $variation->regular_price;
+ $sale_price = $variation->sale_price;
+ } else {
+ $regular_price = $variation->get_regular_price( 'edit' );
+ $sale_price = $variation->get_sale_price( 'edit' );
+ }
+
+ $prices = 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 ),
+ );
+
+ return $prices;
+}
+
+/**
+ * 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 ( empty( $variation_data['price'] ) && empty( $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,
+ ),
+ );
+}
diff --git a/includes/wcs-renewal-functions.php b/includes/wcs-renewal-functions.php
index bd33ab4..9cf66bf 100644
--- a/includes/wcs-renewal-functions.php
+++ b/includes/wcs-renewal-functions.php
@@ -32,7 +32,7 @@ function wcs_create_renewal_order( $subscription ) {
return new WP_Error( 'renewal-order-error', $renewal_order->get_error_message() );
}
- update_post_meta( $renewal_order->id, '_subscription_renewal', $subscription->id );
+ wcs_set_objects_property( $renewal_order, 'subscription_renewal', $subscription->get_id(), 'save' );
return apply_filters( 'wcs_renewal_order_created', $renewal_order, $subscription );
}
@@ -49,7 +49,7 @@ function wcs_order_contains_renewal( $order ) {
$order = wc_get_order( $order );
}
- if ( 'simple' == $order->order_type && isset( $order->subscription_renewal ) && $order->subscription_renewal > 0 ) { // It's a parent order or original order
+ if ( wcs_is_order( $order ) && wcs_get_objects_property( $order, 'subscription_renewal' ) ) {
$is_renewal = true;
} else {
$is_renewal = false;
@@ -119,7 +119,7 @@ function wcs_get_subscriptions_for_renewal_order( $order ) {
// Only use the order if we actually found a valid order object
if ( is_object( $order ) ) {
- $subscription_ids = get_post_meta( $order->id, '_subscription_renewal', false );
+ $subscription_ids = wcs_get_objects_property( $order, 'subscription_renewal', 'multiple' );
foreach ( $subscription_ids as $subscription_id ) {
if ( wcs_is_subscription( $subscription_id ) ) {
diff --git a/includes/wcs-resubscribe-functions.php b/includes/wcs-resubscribe-functions.php
index d8d5ad4..2388957 100644
--- a/includes/wcs-resubscribe-functions.php
+++ b/includes/wcs-resubscribe-functions.php
@@ -26,7 +26,7 @@ function wcs_order_contains_resubscribe( $order ) {
$order = new WC_Order( $order );
}
- if ( '' !== get_post_meta( $order->id, '_subscription_resubscribe', true ) ) {
+ if ( wcs_get_objects_property( $order, 'subscription_resubscribe' ) ) {
$is_resubscribe_order = true;
} else {
$is_resubscribe_order = false;
@@ -55,7 +55,7 @@ function wcs_create_resubscribe_order( $subscription ) {
}
// Keep a record of the original subscription's ID on the new order
- update_post_meta( $resubscribe_order->id, '_subscription_resubscribe', $subscription->id, true );
+ wcs_set_objects_property( $resubscribe_order, 'subscription_resubscribe', $subscription->get_id(), true );
do_action( 'wcs_resubscribe_order_created', $resubscribe_order, $subscription );
@@ -71,7 +71,7 @@ function wcs_create_resubscribe_order( $subscription ) {
*/
function wcs_get_users_resubscribe_link( $subscription ) {
- $subscription_id = ( is_object( $subscription ) ) ? $subscription->id : $subscription;
+ $subscription_id = ( is_object( $subscription ) ) ? $subscription->get_id() : $subscription;
$resubscribe_link = add_query_arg( array( 'resubscribe' => $subscription_id ), get_permalink( wc_get_page_id( 'myaccount' ) ) );
$resubscribe_link = wp_nonce_url( $resubscribe_link, $subscription_id );
@@ -143,7 +143,7 @@ function wcs_get_subscriptions_for_resubscribe_order( $order ) {
}
$subscriptions = array();
- $subscription_ids = get_post_meta( $order->id, '_subscription_resubscribe', false );
+ $subscription_ids = wcs_get_objects_property( $order, 'subscription_resubscribe', 'multiple' );
foreach ( $subscription_ids as $subscription_id ) {
if ( wcs_is_subscription( $subscription_id ) ) {
@@ -187,7 +187,7 @@ function wcs_can_user_resubscribe_to( $subscription, $user_id = '' ) {
$can_user_resubscribe = false;
- } elseif ( ! user_can( $user_id, 'subscribe_again', $subscription->id ) ) {
+ } elseif ( ! user_can( $user_id, 'subscribe_again', $subscription->get_id() ) ) {
$can_user_resubscribe = false;
@@ -206,7 +206,7 @@ function wcs_can_user_resubscribe_to( $subscription, $user_id = '' ) {
array(
'key' => '_subscription_resubscribe',
'compare' => '=',
- 'value' => $subscription->id,
+ 'value' => $subscription->get_id(),
'type' => 'numeric',
),
),
@@ -229,7 +229,7 @@ function wcs_can_user_resubscribe_to( $subscription, $user_id = '' ) {
break;
}
- if ( 'active' == wcs_get_product_limitation( $product ) && ( wcs_user_has_subscription( $user_id, $product->id, 'on-hold' ) || wcs_user_has_subscription( $user_id, $product->id, 'active' ) ) ) {
+ if ( 'active' == wcs_get_product_limitation( $product ) && ( wcs_user_has_subscription( $user_id, $product->get_id(), 'on-hold' ) || wcs_user_has_subscription( $user_id, $product->get_id(), 'active' ) ) ) {
$has_active_limited_subscription = true;
break;
}
diff --git a/includes/wcs-switch-functions.php b/includes/wcs-switch-functions.php
index 793424a..b5a94b1 100644
--- a/includes/wcs-switch-functions.php
+++ b/includes/wcs-switch-functions.php
@@ -24,13 +24,13 @@ function wcs_order_contains_switch( $order ) {
$order = wc_get_order( $order );
}
- if ( 'simple' != $order->order_type || isset( $order->subscription_renewal ) ) { // It's a parent order or renewal order
+ if ( ! wcs_is_order( $order ) || wcs_order_contains_renewal( $order ) ) {
$is_switch_order = false;
} else {
- $subscription_ids = get_post_meta( $order->id, '_subscription_switch', false );
+ $subscription_ids = wcs_get_objects_property( $order, 'subscription_switch', 'multiple' );
if ( ! empty( $subscription_ids ) ) {
$is_switch_order = true;
@@ -49,14 +49,14 @@ function wcs_order_contains_switch( $order ) {
* @return array Subscription details in post_id => WC_Subscription form.
* @since 2.0
*/
-function wcs_get_subscriptions_for_switch_order( $order_id ) {
+function wcs_get_subscriptions_for_switch_order( $order ) {
- if ( is_object( $order_id ) ) {
- $order_id = $order_id->id;
+ if ( ! is_object( $order ) ) {
+ $order = wc_get_order( $order );
}
$subscriptions = array();
- $subscription_ids = get_post_meta( $order_id, '_subscription_switch', false );
+ $subscription_ids = wcs_get_objects_property( $order, 'subscription_switch', 'multiple' );
foreach ( $subscription_ids as $subscription_id ) {
$subscriptions[ $subscription_id ] = wcs_get_subscription( $subscription_id );
@@ -119,9 +119,11 @@ function wcs_is_product_switchable_type( $product ) {
} else {
// back compat for parent products
- if ( $product->is_type( 'subscription_variation' ) && ! empty( $product->parent ) ) {
+ $parent_id = wcs_get_objects_property( $product, 'parent_id' );
+
+ if ( $product->is_type( 'subscription_variation' ) && ! empty( $parent_id ) ) {
$variation = $product;
- $product = $product->parent;
+ $product = wc_get_product( $parent_id );;
}
$allow_switching = get_option( WC_Subscriptions_Admin::$option_prefix . '_allow_switching', 'no' );
@@ -131,10 +133,10 @@ function wcs_is_product_switchable_type( $product ) {
$is_product_switchable = ( $product->is_type( array( 'variable-subscription', 'subscription_variation' ) ) ) ? true : false;
break;
case 'grouped' :
- $is_product_switchable = ( 0 !== $product->post->post_parent ) ? true : false;
+ $is_product_switchable = ( ! empty( $parent_id ) ) ? true : false;
break;
case 'variable_grouped' :
- $is_product_switchable = ( $product->is_type( array( 'variable-subscription', 'subscription_variation' ) ) || 0 !== $product->post->post_parent ) ? true : false;
+ $is_product_switchable = ( $product->is_type( array( 'variable-subscription', 'subscription_variation' ) ) || ! empty( $parent_id ) ) ? true : false;
break;
case 'no' :
default:
diff --git a/includes/wcs-time-functions.php b/includes/wcs-time-functions.php
index f0abbf8..5042e91 100644
--- a/includes/wcs-time-functions.php
+++ b/includes/wcs-time-functions.php
@@ -777,3 +777,70 @@ function wcs_get_subscription_ranges_tlc() {
return wcs_get_non_cached_subscription_ranges();
}
+
+/**
+ * Take a date in the form of a timestamp, MySQL date/time string or DateTime object (or perhaps
+ * a WC_Datetime object when WC > 3.0 is active) and create a WC_DateTime object.
+ *
+ * @since 2.2.0
+ * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date.
+ * @return null|WC_DateTime in site's timezone
+ */
+function wcs_get_datetime_from( $variable_date_type ) {
+
+ try {
+ if ( empty( $variable_date_type ) ) {
+ $datetime = null;
+ } elseif ( is_a( $variable_date_type, 'WC_DateTime' ) ) {
+ $datetime = $variable_date_type;
+ } elseif ( is_numeric( $variable_date_type ) ) {
+ $datetime = new WC_DateTime( "@{$variable_date_type}", new DateTimeZone( 'UTC' ) );
+ $datetime->setTimezone( new DateTimeZone( wc_timezone_string() ) );
+ } else {
+ $datetime = new WC_DateTime( $variable_date_type, new DateTimeZone( wc_timezone_string() ) );
+ }
+ } catch ( Exception $e ) {
+ $datetime = null;
+ }
+
+ return $datetime;
+}
+
+/**
+ * Get a MySQL date/time string in UTC timezone from a WC_Datetime object.
+ *
+ * @since 2.2.0
+ * @param WC_DateTime
+ * @return string MySQL date/time string representation of the DateTime object in UTC timezone
+ */
+function wcs_get_datetime_utc_string( $datetime ) {
+ $date = clone $datetime; // Don't change the original date object's timezone
+ $date->setTimezone( new DateTimeZone( 'UTC' ) );
+ return $date->format( 'Y-m-d H:i:s' );
+}
+
+/**
+ * Format a date for output, a wrapper for wcs_format_datetime() introduced with WC 3.0.
+ *
+ * @since 2.2.0
+ * @param WC_DateTime $date
+ * @param string $format Defaults to the wc_date_format function if not set.
+ * @return string
+ */
+function wcs_format_datetime( $date, $format = '' ) {
+
+ if ( function_exists( 'wc_format_datetime' ) ) { // WC 3.0+
+ $formatted_datetime = wc_format_datetime( $date, $format );
+ } else { // WC < 3.0
+ if ( ! $format ) {
+ $format = wc_date_format();
+ }
+ if ( ! is_a( $date, 'WC_DateTime' ) ) {
+ return '';
+ }
+
+ $formatted_datetime = $date->date_i18n( $format );
+ }
+
+ return $formatted_datetime;
+}
diff --git a/includes/wcs-user-functions.php b/includes/wcs-user-functions.php
index 5576906..e2dfb49 100644
--- a/includes/wcs-user-functions.php
+++ b/includes/wcs-user-functions.php
@@ -235,7 +235,7 @@ function wcs_can_user_put_subscription_on_hold( $subscription, $user = '' ) {
if ( $user->ID == $subscription->get_user_id() ) {
// Make sure subscription suspension count hasn't been reached
- $suspension_count = intval( $subscription->suspension_count );
+ $suspension_count = intval( $subscription->get_suspension_count() );
$allowed_suspensions = get_option( WC_Subscriptions_Admin::$option_prefix . '_max_customer_suspensions', 0 );
if ( 'unlimited' === $allowed_suspensions || $allowed_suspensions > $suspension_count ) { // 0 not > anything so prevents a customer ever being able to suspend
@@ -256,19 +256,19 @@ function wcs_get_all_user_actions_for_subscription( $subscription, $user_id ) {
$actions = array();
- if ( user_can( $user_id, 'edit_shop_subscription_status', $subscription->id ) ) {
+ if ( user_can( $user_id, 'edit_shop_subscription_status', $subscription->get_id() ) ) {
$admin_with_suspension_disallowed = ( current_user_can( 'manage_woocommerce' ) && '0' === get_option( WC_Subscriptions_Admin::$option_prefix . '_max_customer_suspensions', '0' ) ) ? true : false;
$current_status = $subscription->get_status();
if ( $subscription->can_be_updated_to( 'on-hold' ) && wcs_can_user_put_subscription_on_hold( $subscription, $user_id ) && ! $admin_with_suspension_disallowed ) {
$actions['suspend'] = array(
- 'url' => wcs_get_users_change_status_link( $subscription->id, 'on-hold', $current_status ),
+ 'url' => wcs_get_users_change_status_link( $subscription->get_id(), 'on-hold', $current_status ),
'name' => __( 'Suspend', 'woocommerce-subscriptions' ),
);
} elseif ( $subscription->can_be_updated_to( 'active' ) && ! $subscription->needs_payment() ) {
$actions['reactivate'] = array(
- 'url' => wcs_get_users_change_status_link( $subscription->id, 'active', $current_status ),
+ 'url' => wcs_get_users_change_status_link( $subscription->get_id(), 'active', $current_status ),
'name' => __( 'Reactivate', 'woocommerce-subscriptions' ),
);
}
@@ -284,7 +284,7 @@ function wcs_get_all_user_actions_for_subscription( $subscription, $user_id ) {
$next_payment = $subscription->get_time( 'next_payment' );
if ( $subscription->can_be_updated_to( 'cancelled' ) && ! $subscription->is_one_payment() && ( $next_payment > 0 || ( $subscription->has_status( 'on-hold' ) && empty( $next_payment ) ) ) ) {
$actions['cancel'] = array(
- 'url' => wcs_get_users_change_status_link( $subscription->id, 'cancelled', $current_status ),
+ 'url' => wcs_get_users_change_status_link( $subscription->get_id(), 'cancelled', $current_status ),
'name' => _x( 'Cancel', 'an action on a subscription', 'woocommerce-subscriptions' ),
);
}
diff --git a/languages/woocommerce-subscriptions.pot b/languages/woocommerce-subscriptions.pot
index 17eabfa..760070c 100644
--- a/languages/woocommerce-subscriptions.pot
+++ b/languages/woocommerce-subscriptions.pot
@@ -2,87 +2,111 @@
# This file is distributed under the same license as the WooCommerce Subscriptions package.
msgid ""
msgstr ""
-"Project-Id-Version: WooCommerce Subscriptions 2.1.4\n"
+"Project-Id-Version: WooCommerce Subscriptions 2.2.3\n"
"Report-Msgid-Bugs-To: "
"https://github.com/Prospress/woocommerce-subscriptions/issues\n"
-"POT-Creation-Date: 2017-03-06 22:34:02+00:00\n"
+"POT-Creation-Date: 2017-04-07 23:50:11+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2017-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME \n"
-"Language-Team: Prospress Translations \n"
+"Last-Translator: Prospress Inc \n"
+"Language-Team: Prospress Inc \n"
"X-Generator: grunt-wp-i18n 0.5.4\n"
"Language: en_US\n"
-#: includes/admin/class-wc-subscriptions-admin.php:166
+#: includes/admin/class-wc-subscriptions-admin.php:174
msgid "Simple subscription"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:167
+#: includes/admin/class-wc-subscriptions-admin.php:175
msgid "Variable subscription"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:185
+#: includes/admin/class-wc-subscriptions-admin.php:193
msgid "Choose the subscription price, billing interval and period."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:198
-#: templates/admin/html-variation-price.php:44
+#. translators: placeholder is trial period validation message if passed an
+#. invalid value (e.g. "Trial period can not exceed 4 weeks")
+#: includes/admin/class-wc-subscriptions-admin.php:195
+msgctxt "Trial period field tooltip on Edit Product administration screen"
+msgid ""
+"An optional period of time to wait before charging the first recurring "
+"payment. Any sign up fee will still be charged at the outset of the "
+"subscription. %s"
+msgstr ""
+
#. translators: placeholder is a currency symbol / code
+#: includes/admin/class-wc-subscriptions-admin.php:206
+#: templates/admin/html-variation-price.php:42
msgid "Subscription price (%s)"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:201
+#: includes/admin/class-wc-subscriptions-admin.php:208
+msgctxt "example price"
+msgid "e.g. 5.90"
+msgstr ""
+
+#: includes/admin/class-wc-subscriptions-admin.php:209
msgid "Subscription interval"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:207
-#: includes/admin/class-wc-subscriptions-admin.php:340
+#: includes/admin/class-wc-subscriptions-admin.php:215
+#: includes/admin/class-wc-subscriptions-admin.php:350
msgid "Subscription period"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:221
-#: includes/admin/class-wc-subscriptions-admin.php:341
-#: templates/admin/html-variation-price.php:66
+#: includes/admin/class-wc-subscriptions-admin.php:229
+#: includes/admin/class-wc-subscriptions-admin.php:351
+#: templates/admin/html-variation-price.php:64
msgid "Subscription length"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:224
+#: includes/admin/class-wc-subscriptions-admin.php:232
msgid ""
-"Automatically expire the subscription after this length of time. This "
-"length is in addition to any free trial or amount of time provided before a "
+"Automatically expire the subscription after this length of time. This length "
+"is in addition to any free trial or amount of time provided before a "
"synchronised first renewal date."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:233
-#: templates/admin/html-variation-price.php:20
#. translators: %s is a currency symbol / code
+#: includes/admin/class-wc-subscriptions-admin.php:241
+#: templates/admin/html-variation-price.php:18
msgid "Sign-up fee (%s)"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:235
+#: includes/admin/class-wc-subscriptions-admin.php:242
+#: templates/admin/deprecated/html-variation-price.php:31
+#: templates/admin/deprecated/html-variation-price.php:86
+#: templates/admin/html-variation-price.php:19
+#: templates/admin/html-variation-price.php:45
+msgctxt "example price"
+msgid "e.g. 9.90"
+msgstr ""
+
+#: includes/admin/class-wc-subscriptions-admin.php:243
msgid ""
"Optionally include an amount to be charged at the outset of the "
"subscription. The sign-up fee will be charged immediately, even if the "
"product has a free trial or the payment dates are synced."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:246
-#: templates/admin/html-variation-price.php:25
+#: includes/admin/class-wc-subscriptions-admin.php:254
+#: templates/admin/html-variation-price.php:23
msgid "Free trial"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:249
+#: includes/admin/class-wc-subscriptions-admin.php:257
#: templates/admin/deprecated/html-variation-price.php:115
msgid "Subscription Trial Period"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:281
+#: includes/admin/class-wc-subscriptions-admin.php:289
msgid "One time shipping"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:282
+#: includes/admin/class-wc-subscriptions-admin.php:290
msgid ""
"Shipping for subscription products is normally charged on the initial order "
"and all renewal orders. Enable this to only charge shipping once on the "
@@ -90,53 +114,53 @@ msgid ""
"not have a free trial or a synced renewal date."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:337
+#: includes/admin/class-wc-subscriptions-admin.php:347
msgid "Subscription pricing"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:338
+#: includes/admin/class-wc-subscriptions-admin.php:348
msgid "Subscription sign-up fee"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:339
+#: includes/admin/class-wc-subscriptions-admin.php:349
msgid "Subscription billing interval"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:342
+#: includes/admin/class-wc-subscriptions-admin.php:352
msgid "Free trial length"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:343
+#: includes/admin/class-wc-subscriptions-admin.php:353
msgid "Free trial period"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:661
+#: includes/admin/class-wc-subscriptions-admin.php:674
msgid ""
"Unable to change subscription status to \"%s\". Please assign a customer to "
"the subscription to activate it."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:703
+#: includes/admin/class-wc-subscriptions-admin.php:716
msgid ""
"Trashing this order will also trash the subscriptions purchased with the "
"order."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:716
+#: includes/admin/class-wc-subscriptions-admin.php:729
msgid "Enter the new period, either day, week, month or year:"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:717
+#: includes/admin/class-wc-subscriptions-admin.php:730
msgid "Enter a new length (e.g. 5):"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:718
+#: includes/admin/class-wc-subscriptions-admin.php:731
msgid ""
"Enter a new interval as a single number (e.g. to charge every 2nd month, "
"enter 2):"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:723
+#: includes/admin/class-wc-subscriptions-admin.php:736
msgid ""
"You are about to trash one or more orders which contain a subscription.\n"
"\n"
@@ -144,7 +168,7 @@ msgid ""
"orders."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:736
+#: includes/admin/class-wc-subscriptions-admin.php:749
msgid ""
"WARNING: Bad things are about to happen!\n"
"\n"
@@ -156,74 +180,96 @@ msgid ""
"gateway."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:737
+#: includes/admin/class-wc-subscriptions-admin.php:750
msgid ""
"You are deleting a subscription item. You will also need to manually cancel "
"and trash the subscription on the Manage Subscriptions screen."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:744
+#: includes/admin/class-wc-subscriptions-admin.php:757
msgid ""
"Warning: Deleting a user will also delete the user's subscriptions. The "
"user's orders will remain but be reassigned to the 'Guest' user.\n"
"\n"
-"Do you want to continue to delete this user and any associated "
-"subscriptions?"
+"Do you want to continue to delete this user and any associated subscriptions?"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:807
+#. translators: placeholders are for HTML tags. They are 1$: "
", 2$:
+#. "
", 3$: "
", 4$: "", 5$: "", 6$: "", 7$: "", 8$:
+#. "
"
+#: includes/admin/class-wc-subscriptions-admin.php:775
+msgctxt ""
+"used in admin pointer script params in javascript as type pointer content"
+msgid ""
+"%1$sChoose Subscription%2$s%3$sThe WooCommerce Subscriptions extension adds "
+"two new subscription product types - %4$sSimple subscription%5$s and "
+"%6$sVariable subscription%7$s.%8$s"
+msgstr ""
+
+#. translators: placeholders are for HTML tags. They are 1$: "
", 2$:
+#. "
", 3$: "
", 4$: "
"
+#: includes/admin/class-wc-subscriptions-admin.php:777
+msgctxt ""
+"used in admin pointer script params in javascript as price pointer content"
+msgid ""
+"%1$sSet a Price%2$s%3$sSubscription prices are a little different to other "
+"product prices. For a subscription, you can set a billing period, length, "
+"sign-up fee and free trial.%4$s"
+msgstr ""
+
+#: includes/admin/class-wc-subscriptions-admin.php:820
msgid "Active subscriber?"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:850
+#: includes/admin/class-wc-subscriptions-admin.php:863
msgid "Manage Subscriptions"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:854
-#: woocommerce-subscriptions.php:214
+#: includes/admin/class-wc-subscriptions-admin.php:867
+#: woocommerce-subscriptions.php:233
msgid "Search Subscriptions"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:874
-#: includes/admin/class-wc-subscriptions-admin.php:970
+#: includes/admin/class-wc-subscriptions-admin.php:887
+#: includes/admin/class-wc-subscriptions-admin.php:983
#: includes/admin/class-wcs-admin-reports.php:55
#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:654
#: includes/class-wcs-query.php:95 includes/class-wcs-query.php:115
-#: includes/class-wcs-query.php:117 woocommerce-subscriptions.php:205
-#: woocommerce-subscriptions.php:218
+#: includes/class-wcs-query.php:117 templates/admin/status.php:9
+#: woocommerce-subscriptions.php:224 woocommerce-subscriptions.php:237
msgid "Subscriptions"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1010
+#: includes/admin/class-wc-subscriptions-admin.php:1023
msgid "Button Text"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1017
+#: includes/admin/class-wc-subscriptions-admin.php:1030
msgid "Add to Cart Button Text"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1018
+#: includes/admin/class-wc-subscriptions-admin.php:1031
msgid ""
"A product displays a button with the text \"Add to Cart\". By default, a "
"subscription changes this to \"Sign Up Now\". You can customise the button "
"text for subscriptions here."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1022
-#: includes/admin/class-wc-subscriptions-admin.php:1033
-#: includes/class-wc-product-subscription-variation.php:75
-#: includes/class-wc-product-subscription.php:122
-#: includes/class-wc-product-variable-subscription.php:108
-#: includes/class-wc-subscriptions-product.php:127
-#: woocommerce-subscriptions.php:461
+#: includes/admin/class-wc-subscriptions-admin.php:1035
+#: includes/admin/class-wc-subscriptions-admin.php:1046
+#: includes/class-wc-product-subscription-variation.php:98
+#: includes/class-wc-product-subscription.php:72
+#: includes/class-wc-product-variable-subscription.php:63
+#: includes/class-wc-subscriptions-product.php:96
+#: woocommerce-subscriptions.php:480
msgid "Sign Up Now"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1028
+#: includes/admin/class-wc-subscriptions-admin.php:1041
msgid "Place Order Button Text"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1029
+#: includes/admin/class-wc-subscriptions-admin.php:1042
msgid ""
"Use this field to customise the text displayed on the checkout button when "
"an order contains a subscription. Normally the checkout submission button "
@@ -231,12 +277,12 @@ msgid ""
"changed to \"Sign Up Now\"."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1041
+#: includes/admin/class-wc-subscriptions-admin.php:1054
msgid "Roles"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1044
#. translators: placeholders are tags
+#: includes/admin/class-wc-subscriptions-admin.php:1057
msgid ""
"Choose the default roles to assign to active and inactive subscribers. For "
"record keeping purposes, a user account must be created for subscribers. "
@@ -244,59 +290,74 @@ msgid ""
"allocated these roles to prevent locking out administrators."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1049
+#: includes/admin/class-wc-subscriptions-admin.php:1062
msgid "Subscriber Default Role"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1050
+#: includes/admin/class-wc-subscriptions-admin.php:1063
msgid ""
"When a subscription is activated, either manually or after a successful "
"purchase, new users will be assigned this role."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1061
+#: includes/admin/class-wc-subscriptions-admin.php:1074
msgid "Inactive Subscriber Role"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1062
+#: includes/admin/class-wc-subscriptions-admin.php:1075
msgid ""
-"If a subscriber's subscription is manually cancelled or expires, she will "
-"be assigned this role."
-msgstr ""
-
-#: includes/admin/class-wc-subscriptions-admin.php:1082
-msgid "Manual Renewal Payments"
-msgstr ""
-
-#: includes/admin/class-wc-subscriptions-admin.php:1083
-msgid "Accept Manual Renewals"
+"If a subscriber's subscription is manually cancelled or expires, she will be "
+"assigned this role."
msgstr ""
#: includes/admin/class-wc-subscriptions-admin.php:1088
+msgctxt "option section heading"
+msgid "Renewals"
+msgstr ""
+
+#: includes/admin/class-wc-subscriptions-admin.php:1095
+msgid "Manual Renewal Payments"
+msgstr ""
+
+#: includes/admin/class-wc-subscriptions-admin.php:1096
+msgid "Accept Manual Renewals"
+msgstr ""
+
#. translators: placeholders are opening and closing link tags
+#: includes/admin/class-wc-subscriptions-admin.php:1101
msgid ""
"With manual renewals, a customer's subscription is put on-hold until they "
"login and pay to renew it. %sLearn more%s."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1094
+#: includes/admin/class-wc-subscriptions-admin.php:1107
msgid "Turn off Automatic Payments"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1099
#. translators: placeholders are opening and closing link tags
+#: includes/admin/class-wc-subscriptions-admin.php:1112
msgid ""
-"If you don't want new subscription purchases to automatically charge "
-"renewal payments, you can turn off automatic payments. Existing automatic "
-"subscriptions will continue to charge customers automatically. %sLearn "
-"more%s."
+"If you don't want new subscription purchases to automatically charge renewal "
+"payments, you can turn off automatic payments. Existing automatic "
+"subscriptions will continue to charge customers automatically. %sLearn more"
+"%s."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1114
+#: includes/admin/class-wc-subscriptions-admin.php:1120
+msgctxt "options section heading"
+msgid "Miscellaneous"
+msgstr ""
+
+#: includes/admin/class-wc-subscriptions-admin.php:1127
msgid "Customer Suspensions"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1121
+#: includes/admin/class-wc-subscriptions-admin.php:1128
+msgctxt "there's a number immediately in front of this text"
+msgid "suspensions per billing period."
+msgstr ""
+
+#: includes/admin/class-wc-subscriptions-admin.php:1134
msgid ""
"Set a maximum number of times a customer can suspend their account for each "
"billing period. For example, for a value of 3 and a subscription billed "
@@ -306,124 +367,198 @@ msgid ""
"this to 0 to turn off the customer suspension feature completely."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1125
+#: includes/admin/class-wc-subscriptions-admin.php:1138
msgid "Mixed Checkout"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1126
+#: includes/admin/class-wc-subscriptions-admin.php:1139
msgid "Allow subscriptions and products to be purchased simultaneously."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1130
-msgid "Allow subscriptions and products to be purchased in a single transaction."
+#: includes/admin/class-wc-subscriptions-admin.php:1143
+msgid ""
+"Allow subscriptions and products to be purchased in a single transaction."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1134
+#: includes/admin/class-wc-subscriptions-admin.php:1147
#: includes/upgrades/templates/wcs-about-2-0.php:108
msgid "Drip Downloadable Content"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1135
+#: includes/admin/class-wc-subscriptions-admin.php:1148
msgid "Enable dripping for downloadable content on subscription products."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1139
+#: includes/admin/class-wc-subscriptions-admin.php:1152
msgid ""
"Enabling this grants access to new downloadable files added to a product "
"only after the next renewal is processed.%sBy default, access to new "
-"downloadable files added to a product is granted immediately to any "
-"customer that has an active subscription with that product."
+"downloadable files added to a product is granted immediately to any customer "
+"that has an active subscription with that product."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1175
#. translators: $1-$2: opening and closing tags, $3-$4: opening and
#. closing tags
+#: includes/admin/class-wc-subscriptions-admin.php:1188
msgid ""
"%1$sWooCommerce Subscriptions Installed%2$s – %3$sYou're ready to "
"start selling subscriptions!%4$s"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1180
+#: includes/admin/class-wc-subscriptions-admin.php:1193
msgid "Add a Subscription Product"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1181
+#: includes/admin/class-wc-subscriptions-admin.php:1194
#: includes/upgrades/templates/wcs-about-2-0.php:35
#: includes/upgrades/templates/wcs-about.php:34
-#: woocommerce-subscriptions.php:944
+#: tmp/old/wordpress/wp-admin/includes/ms.php:1087
+#: tmp/old/wordpress/wp-admin/menu.php:248
+#: tmp/old/wordpress/wp-admin/network/menu.php:53
+#: tmp/old/wordpress/wp-admin/options.php:21
+#: tmp/old/wordpress/wp-content/plugins/akismet/class.akismet-admin.php:88
+#: tmp/old/wordpress/wp-content/plugins/akismet/class.akismet-admin.php:218
+#: tmp/old/wordpress/wp-content/plugins/akismet/class.akismet-admin.php:631
+#: tmp/old/wordpress/wp-content/plugins/akismet/views/config.php:60
+#: tmp/old/wordpress/wp-includes/admin-bar.php:479
+#: tmp/wordpress/wp-admin/includes/ms.php:1087
+#: tmp/wordpress/wp-admin/menu.php:248
+#: tmp/wordpress/wp-admin/network/menu.php:53
+#: tmp/wordpress/wp-admin/options.php:21
+#: tmp/wordpress/wp-content/plugins/akismet/class.akismet-admin.php:88
+#: tmp/wordpress/wp-content/plugins/akismet/class.akismet-admin.php:218
+#: tmp/wordpress/wp-content/plugins/akismet/class.akismet-admin.php:631
+#: tmp/wordpress/wp-content/plugins/akismet/views/config.php:60
+#: tmp/wordpress/wp-includes/admin-bar.php:479
+#: woocommerce-subscriptions.php:991
msgid "Settings"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1267
#. translators: placeholder is a number
+#: includes/admin/class-wc-subscriptions-admin.php:1280
msgid "We can't find a subscription with ID #%d. Perhaps it was deleted?"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1300
-#: includes/admin/class-wc-subscriptions-admin.php:1305
#. translators: placeholders are opening link tag, ID of sub, and closing link
#. tag
+#: includes/admin/class-wc-subscriptions-admin.php:1313
+#: includes/admin/class-wc-subscriptions-admin.php:1318
msgid "Showing orders for %sSubscription %s%s"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1329
#. translators: number of 1$: days, 2$: weeks, 3$: months, 4$: years
+#: includes/admin/class-wc-subscriptions-admin.php:1342
msgid "The trial period can not exceed: %1s, %2s, %3s or %4s."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1334
#. translators: placeholder is a time period (e.g. "4 weeks")
+#: includes/admin/class-wc-subscriptions-admin.php:1347
msgid "The trial period can not exceed %s."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1390
-#: includes/admin/class-wc-subscriptions-admin.php:1443
+#: includes/admin/class-wc-subscriptions-admin.php:1373
+msgctxt "in [subscriptions] shortcode"
+msgid "No subscriptions found."
+msgstr ""
+
+#. translators: order number
+#: includes/admin/class-wc-subscriptions-admin.php:1382
+msgctxt "in [subscriptions] shortcode"
+msgid "Subscription %s"
+msgstr ""
+
+#: includes/admin/class-wc-subscriptions-admin.php:1399
+#: includes/admin/class-wc-subscriptions-admin.php:1427
+msgctxt "label that indicates whether debugging is turned on for the plugin"
+msgid "WCS_DEBUG"
+msgstr ""
+
+#: includes/admin/class-wc-subscriptions-admin.php:1400
+#: includes/admin/class-wc-subscriptions-admin.php:1428
+#: includes/admin/class-wc-subscriptions-admin.php:1481
+#: tmp/old/wordpress/wp-admin/includes/class-wp-links-list-table.php:258
+#: tmp/old/wordpress/wp-signup.php:178
+#: tmp/wordpress/wp-admin/includes/class-wp-links-list-table.php:258
+#: tmp/wordpress/wp-signup.php:178
msgid "Yes"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1390
+#: includes/admin/class-wc-subscriptions-admin.php:1400
+#: includes/admin/class-wc-subscriptions-admin.php:1428
+#: tmp/old/wordpress/wp-admin/includes/class-wp-links-list-table.php:260
+#: tmp/old/wordpress/wp-signup.php:182
+#: tmp/wordpress/wp-admin/includes/class-wp-links-list-table.php:260
+#: tmp/wordpress/wp-signup.php:182
msgid "No"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1426
+#: includes/admin/class-wc-subscriptions-admin.php:1405
+#: includes/admin/class-wc-subscriptions-admin.php:1433
+msgctxt "Live or Staging, Label on WooCommerce -> System Status page"
+msgid "Subscriptions Mode"
+msgstr ""
+
+#: includes/admin/class-wc-subscriptions-admin.php:1406
+#: includes/admin/class-wc-subscriptions-admin.php:1434
+msgctxt "refers to staging site"
+msgid "Staging"
+msgstr ""
+
+#: includes/admin/class-wc-subscriptions-admin.php:1406
+#: includes/admin/class-wc-subscriptions-admin.php:1434
+msgctxt "refers to live site"
+msgid "Live"
+msgstr ""
+
+#: includes/admin/class-wc-subscriptions-admin.php:1464
msgid "Automatic Recurring Payments"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1443
+#: includes/admin/class-wc-subscriptions-admin.php:1481
msgid ""
"Supports automatic renewal payments with the WooCommerce Subscriptions "
"extension."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1495
#. translators: $1-2: opening and closing tags of a link that takes to Woo
#. marketplace / Stripe product page
+#: includes/admin/class-wc-subscriptions-admin.php:1533
msgid ""
"No payment gateways capable of processing automatic subscription payments "
"are enabled. If you would like to process automatic payments, we recommend "
"the %1$sfree Stripe extension%2$s."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1500
+#: includes/admin/class-wc-subscriptions-admin.php:1538
msgid "Recurring Payments"
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1508
#. translators: placeholders are opening and closing link tags
+#: includes/admin/class-wc-subscriptions-admin.php:1546
msgid ""
"Payment gateways which don't support automatic recurring payments can be "
"used to process %smanual subscription renewal payments%s."
msgstr ""
-#: includes/admin/class-wc-subscriptions-admin.php:1515
#. translators: $1-$2: opening and closing tags. Link to documents->payment
#. gateways, 3$-4$: opening and closing tags. Link to WooCommerce extensions
#. shop page
+#: includes/admin/class-wc-subscriptions-admin.php:1553
msgid ""
"Find new gateways that %1$ssupport automatic subscription payments%2$s in "
"the official %3$sWooCommerce Marketplace%4$s."
msgstr ""
+#: includes/admin/class-wcs-admin-meta-boxes.php:56
+msgctxt "meta box title"
+msgid "Subscription Data"
+msgstr ""
+
+#: includes/admin/class-wcs-admin-meta-boxes.php:58
+msgctxt "meta box title"
+msgid "Billing Schedule"
+msgstr ""
+
#: includes/admin/class-wcs-admin-meta-boxes.php:62
#: includes/admin/class-wcs-admin-meta-boxes.php:66
#: templates/myaccount/related-orders.php:15
@@ -491,38 +626,73 @@ msgstr ""
msgid "Create pending renewal order requested by admin action."
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:193
+#: includes/admin/class-wcs-admin-post-types.php:200
msgid "Search for a product…"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:366
+#: includes/admin/class-wcs-admin-post-types.php:244
+msgctxt "an action on a subscription"
+msgid "Activate"
+msgstr ""
+
+#: includes/admin/class-wcs-admin-post-types.php:245
+msgctxt "an action on a subscription"
+msgid "Put on-hold"
+msgstr ""
+
+#: includes/admin/class-wcs-admin-post-types.php:246
+#: includes/admin/class-wcs-admin-post-types.php:459
+#: includes/class-wc-subscriptions-manager.php:1771
+#: includes/wcs-user-functions.php:288
+#: templates/myaccount/related-orders.php:67
+msgctxt "an action on a subscription"
+msgid "Cancel"
+msgstr ""
+
+#: includes/admin/class-wcs-admin-post-types.php:321
+msgctxt "Used in order note. Reason why status changed."
+msgid "Subscription status changed by bulk edit:"
+msgstr ""
+
#. translators: placeholder is the number of subscriptions updated
+#: includes/admin/class-wcs-admin-post-types.php:377
msgid "%s subscription status changed."
msgid_plural "%s subscription statuses changed."
msgstr[0] ""
msgstr[1] ""
-#: includes/admin/class-wcs-admin-post-types.php:373
#. translators: 1$: is the number of subscriptions not updated, 2$: is the
#. error message
+#: includes/admin/class-wcs-admin-post-types.php:384
msgid "%1$s subscription could not be updated: %2$s"
msgid_plural "%1$s subscriptions could not be updated: %2$s"
msgstr[0] ""
msgstr[1] ""
-#: includes/admin/class-wcs-admin-post-types.php:397
+#: includes/admin/class-wcs-admin-post-types.php:408
#: includes/admin/meta-boxes/views/html-related-orders-table.php:20
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:118
#: templates/myaccount/my-subscriptions.php:26
#: templates/myaccount/my-subscriptions.php:40
#: templates/myaccount/related-orders.php:24
-#: templates/myaccount/related-orders.php:44
+#: templates/myaccount/related-orders.php:45
#: templates/myaccount/related-subscriptions.php:21
#: templates/myaccount/related-subscriptions.php:35
#: templates/myaccount/view-subscription.php:32
+#: tmp/old/wordpress/wp-admin/edit-form-comment.php:76
+#: tmp/old/wordpress/wp-admin/includes/ajax-actions.php:1773
+#: tmp/old/wordpress/wp-admin/includes/class-wp-posts-list-table.php:1626
+#: tmp/old/wordpress/wp-content/plugins/akismet/class.akismet-admin.php:234
+#: tmp/old/wordpress/wp-content/plugins/akismet/views/config.php:194
+#: tmp/wordpress/wp-admin/edit-form-comment.php:76
+#: tmp/wordpress/wp-admin/includes/ajax-actions.php:1773
+#: tmp/wordpress/wp-admin/includes/class-wp-posts-list-table.php:1626
+#: tmp/wordpress/wp-content/plugins/akismet/class.akismet-admin.php:234
+#: tmp/wordpress/wp-content/plugins/akismet/views/config.php:194
msgid "Status"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:398
+#: includes/admin/class-wcs-admin-post-types.php:409
#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:61
#: templates/emails/cancelled-subscription.php:26
#: templates/emails/expired-subscription.php:26
@@ -530,153 +700,284 @@ msgstr ""
#: templates/emails/subscription-info.php:18
#: templates/myaccount/my-subscriptions.php:25
#: templates/myaccount/related-subscriptions.php:20
-#: woocommerce-subscriptions.php:206
+#: woocommerce-subscriptions.php:225
msgid "Subscription"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:399
+#: includes/admin/class-wcs-admin-post-types.php:410
msgid "Items"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:400
+#: includes/admin/class-wcs-admin-post-types.php:411
msgid "Total"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:401
+#: includes/admin/class-wcs-admin-post-types.php:412
msgid "Start Date"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:402
+#: includes/admin/class-wcs-admin-post-types.php:413
msgid "Trial End"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:403
+#: includes/admin/class-wcs-admin-post-types.php:414
msgid "Next Payment"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:404
-msgid "Last Payment"
+#: includes/admin/class-wcs-admin-post-types.php:415
+msgid "Last Order Date"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:405
+#: includes/admin/class-wcs-admin-post-types.php:416
msgid "End Date"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:446
+#: includes/admin/class-wcs-admin-post-types.php:417
+msgctxt "number of orders linked to a subscription"
+msgid "Orders"
+msgstr ""
+
+#: includes/admin/class-wcs-admin-post-types.php:457
#: includes/wcs-user-functions.php:272
msgid "Reactivate"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:447
+#: includes/admin/class-wcs-admin-post-types.php:458
#: includes/wcs-user-functions.php:267
msgid "Suspend"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:449
-#: includes/admin/class-wcs-admin-post-types.php:464
+#: includes/admin/class-wcs-admin-post-types.php:460
+#: includes/admin/class-wcs-admin-post-types.php:475
msgid "Trash"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:450
-#: includes/admin/class-wcs-admin-post-types.php:468
+#: includes/admin/class-wcs-admin-post-types.php:461
+#: includes/admin/class-wcs-admin-post-types.php:479
+#: tmp/old/wordpress/wp-admin/edit-form-comment.php:162
+#: tmp/old/wordpress/wp-admin/includes/class-wp-comments-list-table.php:306
+#: tmp/old/wordpress/wp-admin/includes/class-wp-comments-list-table.php:578
+#: tmp/old/wordpress/wp-admin/includes/class-wp-media-list-table.php:145
+#: tmp/old/wordpress/wp-admin/includes/class-wp-media-list-table.php:150
+#: tmp/old/wordpress/wp-admin/includes/class-wp-media-list-table.php:676
+#: tmp/old/wordpress/wp-admin/includes/class-wp-media-list-table.php:734
+#: tmp/old/wordpress/wp-admin/includes/class-wp-posts-list-table.php:405
+#: tmp/old/wordpress/wp-admin/includes/class-wp-posts-list-table.php:1264
+#: tmp/old/wordpress/wp-admin/includes/dashboard.php:639
+#: tmp/old/wordpress/wp-admin/includes/media.php:1499
+#: tmp/old/wordpress/wp-admin/includes/meta-boxes.php:248
+#: tmp/old/wordpress/wp-admin/includes/meta-boxes.php:338
+#: tmp/old/wordpress/wp-includes/media-template.php:438
+#: tmp/old/wordpress/wp-includes/media-template.php:541
+#: tmp/old/wordpress/wp-includes/media.php:3443
+#: tmp/wordpress/wp-admin/edit-form-comment.php:162
+#: tmp/wordpress/wp-admin/includes/class-wp-comments-list-table.php:306
+#: tmp/wordpress/wp-admin/includes/class-wp-comments-list-table.php:578
+#: tmp/wordpress/wp-admin/includes/class-wp-media-list-table.php:145
+#: tmp/wordpress/wp-admin/includes/class-wp-media-list-table.php:150
+#: tmp/wordpress/wp-admin/includes/class-wp-media-list-table.php:676
+#: tmp/wordpress/wp-admin/includes/class-wp-media-list-table.php:734
+#: tmp/wordpress/wp-admin/includes/class-wp-posts-list-table.php:405
+#: tmp/wordpress/wp-admin/includes/class-wp-posts-list-table.php:1264
+#: tmp/wordpress/wp-admin/includes/dashboard.php:639
+#: tmp/wordpress/wp-admin/includes/media.php:1499
+#: tmp/wordpress/wp-admin/includes/meta-boxes.php:248
+#: tmp/wordpress/wp-admin/includes/meta-boxes.php:338
+#: tmp/wordpress/wp-includes/media-template.php:438
+#: tmp/wordpress/wp-includes/media-template.php:541
+#: tmp/wordpress/wp-includes/media.php:3443
msgid "Delete Permanently"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:462
-#: includes/class-wc-subscriptions-product.php:797
+#: includes/admin/class-wcs-admin-post-types.php:473
+#: includes/class-wc-subscriptions-product.php:717
msgid "Restore this item from the Trash"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:462
-#: includes/class-wc-subscriptions-product.php:798
+#: includes/admin/class-wcs-admin-post-types.php:473
+#: includes/class-wc-subscriptions-product.php:718
+#: tmp/old/wordpress/wp-admin/includes/class-wp-comments-list-table.php:300
+#: tmp/old/wordpress/wp-admin/includes/class-wp-comments-list-table.php:574
+#: tmp/old/wordpress/wp-admin/includes/class-wp-media-list-table.php:144
+#: tmp/old/wordpress/wp-admin/includes/class-wp-media-list-table.php:715
+#: tmp/old/wordpress/wp-admin/includes/class-wp-posts-list-table.php:397
+#: tmp/old/wordpress/wp-admin/includes/class-wp-posts-list-table.php:1247
+#: tmp/wordpress/wp-admin/includes/class-wp-comments-list-table.php:300
+#: tmp/wordpress/wp-admin/includes/class-wp-comments-list-table.php:574
+#: tmp/wordpress/wp-admin/includes/class-wp-media-list-table.php:144
+#: tmp/wordpress/wp-admin/includes/class-wp-media-list-table.php:715
+#: tmp/wordpress/wp-admin/includes/class-wp-posts-list-table.php:397
+#: tmp/wordpress/wp-admin/includes/class-wp-posts-list-table.php:1247
msgid "Restore"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:464
+#: includes/admin/class-wcs-admin-post-types.php:475
msgid "Move this item to the Trash"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:468
+#: includes/admin/class-wcs-admin-post-types.php:479
msgid "Delete this item permanently"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:474
+#: includes/admin/class-wcs-admin-post-types.php:485
msgid "Cancel Now"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:507
+#: includes/admin/class-wcs-admin-post-types.php:513
+msgctxt "meaning billing address"
+msgid "Billing:"
+msgstr ""
+
#. translators: placeholder is customer's billing email
+#. translators: 1: Comment author URL
+#: includes/admin/class-wcs-admin-post-types.php:518
+#: tmp/old/wordpress/wp-includes/pluggable.php:1458
+#: tmp/old/wordpress/wp-includes/pluggable.php:1619
+#: tmp/old/wordpress/wp-includes/pluggable.php:1760
+#: tmp/wordpress/wp-includes/pluggable.php:1458
+#: tmp/wordpress/wp-includes/pluggable.php:1619
+#: tmp/wordpress/wp-includes/pluggable.php:1760
msgid "Email: %s"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:512
#. translators: placeholder is customer's billing phone number
+#: includes/admin/class-wcs-admin-post-types.php:523
msgid "Tel: %s"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:544
+#. translators: $1: is opening link, $2: is subscription order number, $3: is
+#. closing link tag, $4: is user's name
+#: includes/admin/class-wcs-admin-post-types.php:551
+msgctxt "Subscription title on admin table. (e.g.: #211 for John Doe)"
+msgid "%1$s#%2$s%3$s for %4$s"
+msgstr ""
+
+#: includes/admin/class-wcs-admin-post-types.php:555
+#: tmp/old/wordpress/wp-admin/includes/class-wp-comments-list-table.php:616
+#: tmp/old/wordpress/wp-admin/includes/class-wp-list-table.php:523
+#: tmp/old/wordpress/wp-admin/includes/class-wp-list-table.php:1324
+#: tmp/old/wordpress/wp-admin/includes/update.php:687
+#: tmp/wordpress/wp-admin/includes/class-wp-comments-list-table.php:616
+#: tmp/wordpress/wp-admin/includes/class-wp-list-table.php:523
+#: tmp/wordpress/wp-admin/includes/class-wp-list-table.php:1324
+#: tmp/wordpress/wp-admin/includes/update.php:687
msgid "Show more details"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:587
+#: includes/admin/class-wcs-admin-post-types.php:598
msgid "%d item"
msgid_plural "%d items"
msgstr[0] ""
msgstr[1] ""
-#: includes/admin/class-wcs-admin-post-types.php:631
-#: templates/myaccount/my-subscriptions.php:48
#. translators: placeholder is the display name of a payment gateway a
#. subscription was paid by
+#: includes/admin/class-wcs-admin-post-types.php:642
+#: templates/myaccount/my-subscriptions.php:48
msgid "Via %s"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:642
+#: includes/admin/class-wcs-admin-post-types.php:656
msgid "Y/m/d g:i:s A"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:645
+#: includes/admin/class-wcs-admin-post-types.php:659
msgid ""
"This date should be treated as an estimate only. The payment gateway for "
"this subscription controls when payments are processed."
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:919
-#: includes/admin/class-wcs-admin-post-types.php:922
-#: includes/admin/class-wcs-admin-post-types.php:925
+#: includes/admin/class-wcs-admin-post-types.php:932
+#: includes/admin/class-wcs-admin-post-types.php:935
+#: includes/admin/class-wcs-admin-post-types.php:938
msgid "Subscription updated."
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:920
+#: includes/admin/class-wcs-admin-post-types.php:933
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:453
+#: tmp/old/wordpress/wp-admin/edit-form-advanced.php:138
+#: tmp/old/wordpress/wp-admin/edit-form-advanced.php:152
+#: tmp/wordpress/wp-admin/edit-form-advanced.php:138
+#: tmp/wordpress/wp-admin/edit-form-advanced.php:152
msgid "Custom field updated."
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:921
+#: includes/admin/class-wcs-admin-post-types.php:934
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:454
+#: tmp/old/wordpress/wp-admin/edit-form-advanced.php:139
+#: tmp/old/wordpress/wp-admin/edit-form-advanced.php:153
+#: tmp/wordpress/wp-admin/edit-form-advanced.php:139
+#: tmp/wordpress/wp-admin/edit-form-advanced.php:153
msgid "Custom field deleted."
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:926
+#. translators: placeholder is previous post title
+#: includes/admin/class-wcs-admin-post-types.php:937
+msgctxt "used in post updated messages"
+msgid "Subscription restored to revision from %s"
+msgstr ""
+
+#: includes/admin/class-wcs-admin-post-types.php:939
msgid "Subscription saved."
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:927
+#: includes/admin/class-wcs-admin-post-types.php:940
msgid "Subscription submitted."
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:929
#. translators: php date string
+#: includes/admin/class-wcs-admin-post-types.php:942
msgid "Subscription scheduled for: %1$s."
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:930
+#: includes/admin/class-wcs-admin-post-types.php:942
+msgctxt "used in \"Subscription scheduled for \""
+msgid "M j, Y @ G:i"
+msgstr ""
+
+#: includes/admin/class-wcs-admin-post-types.php:943
msgid "Subscription draft updated."
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:968
+#: includes/admin/class-wcs-admin-post-types.php:979
msgid "Any Payment Method"
msgstr ""
-#: includes/admin/class-wcs-admin-post-types.php:969
+#: includes/admin/class-wcs-admin-post-types.php:980
+#: tmp/old/wordpress/wp-admin/edit-tag-form.php:161
+#: tmp/old/wordpress/wp-admin/edit-tags.php:408
+#: tmp/old/wordpress/wp-admin/includes/media.php:966
+#: tmp/old/wordpress/wp-admin/includes/media.php:1079
+#: tmp/old/wordpress/wp-admin/includes/media.php:2596
+#: tmp/old/wordpress/wp-admin/includes/media.php:2612
+#: tmp/old/wordpress/wp-includes/deprecated.php:688
+#: tmp/old/wordpress/wp-includes/media-template.php:626
+#: tmp/old/wordpress/wp-includes/media-template.php:653
+#: tmp/old/wordpress/wp-includes/media-template.php:731
+#: tmp/old/wordpress/wp-includes/media-template.php:857
+#: tmp/old/wordpress/wp-includes/media-template.php:872
+#: tmp/old/wordpress/wp-includes/media-template.php:923
+#: tmp/old/wordpress/wp-includes/media-template.php:985
+#: tmp/old/wordpress/wp-includes/media-template.php:1083
+#: tmp/old/wordpress/wp-includes/media-template.php:1172
+#: tmp/old/wordpress/wp-includes/script-loader.php:360
+#: tmp/wordpress/wp-admin/edit-tag-form.php:161
+#: tmp/wordpress/wp-admin/edit-tags.php:408
+#: tmp/wordpress/wp-admin/includes/media.php:966
+#: tmp/wordpress/wp-admin/includes/media.php:1079
+#: tmp/wordpress/wp-admin/includes/media.php:2596
+#: tmp/wordpress/wp-admin/includes/media.php:2612
+#: tmp/wordpress/wp-includes/deprecated.php:688
+#: tmp/wordpress/wp-includes/media-template.php:626
+#: tmp/wordpress/wp-includes/media-template.php:653
+#: tmp/wordpress/wp-includes/media-template.php:731
+#: tmp/wordpress/wp-includes/media-template.php:857
+#: tmp/wordpress/wp-includes/media-template.php:872
+#: tmp/wordpress/wp-includes/media-template.php:923
+#: tmp/wordpress/wp-includes/media-template.php:985
+#: tmp/wordpress/wp-includes/media-template.php:1083
+#: tmp/wordpress/wp-includes/media-template.php:1172
+#: tmp/wordpress/wp-includes/script-loader.php:360
msgid "None"
msgstr ""
@@ -705,10 +1006,36 @@ msgid "Failed Payment Retries"
msgstr ""
#: includes/admin/class-wcs-admin-reports.php:132
-#: includes/admin/reports/class-wcs-report-cache-manager.php:257
+#: includes/admin/reports/class-wcs-report-cache-manager.php:271
msgid "WooCommerce"
msgstr ""
+#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:82
+msgctxt "relation to order"
+msgid "Resubscribed Subscription"
+msgstr ""
+
+#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:90
+msgctxt "relation to order"
+msgid "Initial Subscription"
+msgstr ""
+
+#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:99
+msgctxt "relation to order"
+msgid "Parent Order"
+msgstr ""
+
+#: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:109
+msgctxt "relation to order"
+msgid "Renewal Order"
+msgstr ""
+
+#. translators: placeholder is the ID of the subscription
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:48
+msgctxt "edit subscription header"
+msgid "Subscription #%s details"
+msgstr ""
+
#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:54
msgid "Customer:"
msgstr ""
@@ -717,69 +1044,99 @@ msgstr ""
msgid "View other subscriptions"
msgstr ""
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:76
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:79
msgid "Search for a customer…"
msgstr ""
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:80
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:87
msgid "Subscription status:"
msgstr ""
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:98
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:105
msgid "Billing Details"
msgstr ""
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:104
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:106
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:172
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:174
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:111
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:113
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:179
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:181
msgid "Address"
msgstr ""
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:106
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:113
msgid "No billing address set."
msgstr ""
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:122
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:129
#: includes/class-wcs-change-payment-method-admin.php:38
#: includes/class-wcs-change-payment-method-admin.php:51
msgid "Payment Method"
msgstr ""
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:161
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:133
+#: includes/class-wcs-change-payment-method-admin.php:52
+msgctxt ""
+"The gateway ID displayed on the Edit Subscriptions screen when editing "
+"payment method."
+msgid "Gateway ID: [%s]"
+msgstr ""
+
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:168
msgid "Shipping Details"
msgstr ""
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:174
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:181
msgid "No shipping address set."
msgstr ""
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:192
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:219
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:199
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:226
msgid "Customer Note:"
msgstr ""
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:220
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:227
msgid "Customer's notes about the order"
msgstr ""
-#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:278
#. translators: placeholder is error message from the payment gateway or
#. subscriptions when updating the status
+#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:295
msgid "Error updating some information: %s"
msgstr ""
-#: includes/admin/meta-boxes/views/html-related-orders-row.php:29
+#: includes/admin/meta-boxes/views/html-related-orders-row.php:19
+#: includes/class-wc-subscriptions-renewal-order.php:145
+#: templates/myaccount/my-subscriptions.php:37
+#: templates/myaccount/related-orders.php:39
+#: templates/myaccount/related-subscriptions.php:32
+msgctxt "hash before order number"
+msgid "#%s"
+msgstr ""
+
+#. translators: php date format
+#: includes/admin/meta-boxes/views/html-related-orders-row.php:30
+#: includes/admin/meta-boxes/views/html-retries-table.php:44
+msgctxt "post date"
+msgid "Y/m/d g:i:s A"
+msgstr ""
+
+#: includes/admin/meta-boxes/views/html-related-orders-row.php:33
#: includes/admin/meta-boxes/views/html-retries-table.php:47
+#: tmp/old/wordpress/wp-admin/includes/class-wp-media-list-table.php:441
+#: tmp/old/wordpress/wp-admin/includes/class-wp-posts-list-table.php:978
+#: tmp/wordpress/wp-admin/includes/class-wp-media-list-table.php:441
+#: tmp/wordpress/wp-admin/includes/class-wp-posts-list-table.php:978
msgid "Unpublished"
msgstr ""
#: includes/admin/meta-boxes/views/html-related-orders-table.php:17
-#: templates/myaccount/related-orders.php:36
+#: templates/myaccount/related-orders.php:37
msgid "Order Number"
msgstr ""
#: includes/admin/meta-boxes/views/html-related-orders-table.php:18
+#: tmp/old/wordpress/wp-admin/includes/class-wp-links-list-table.php:131
+#: tmp/wordpress/wp-admin/includes/class-wp-links-list-table.php:131
msgid "Relationship"
msgstr ""
@@ -788,10 +1145,25 @@ msgstr ""
#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:173
#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:197
#: templates/myaccount/related-orders.php:23
-#: templates/myaccount/related-orders.php:41
+#: templates/myaccount/related-orders.php:42
+#: tmp/old/wordpress/wp-admin/includes/ajax-actions.php:1773
+#: tmp/old/wordpress/wp-admin/includes/class-wp-posts-list-table.php:577
+#: tmp/old/wordpress/wp-admin/includes/class-wp-posts-list-table.php:1414
+#: tmp/wordpress/wp-admin/includes/ajax-actions.php:1773
+#: tmp/wordpress/wp-admin/includes/class-wp-posts-list-table.php:577
+#: tmp/wordpress/wp-admin/includes/class-wp-posts-list-table.php:1414
msgid "Date"
msgstr ""
+#: includes/admin/meta-boxes/views/html-related-orders-table.php:21
+#: templates/myaccount/my-subscriptions.php:28
+#: templates/myaccount/related-orders.php:25
+#: templates/myaccount/related-subscriptions.php:23
+#: templates/myaccount/view-subscription.php:96
+msgctxt "table heading"
+msgid "Total"
+msgstr ""
+
#: includes/admin/meta-boxes/views/html-retries-table.php:17
msgid "Retry Date"
msgstr ""
@@ -823,12 +1195,32 @@ msgstr ""
#: includes/admin/meta-boxes/views/html-retries-table.php:28
msgid ""
-"The status applied to the subscription for the time between when the "
-"renewal payment failed or last retry occurred and when this retry was "
-"processed."
+"The status applied to the subscription for the time between when the renewal "
+"payment failed or last retry occurred and when this retry was processed."
msgstr ""
#: includes/admin/meta-boxes/views/html-retries-table.php:31
+#: tmp/old/wordpress/wp-admin/comment.php:158
+#: tmp/old/wordpress/wp-admin/includes/class-wp-ms-users-list-table.php:170
+#: tmp/old/wordpress/wp-admin/includes/class-wp-users-list-table.php:320
+#: tmp/old/wordpress/wp-admin/includes/template.php:416
+#: tmp/old/wordpress/wp-admin/network/site-users.php:322
+#: tmp/old/wordpress/wp-admin/network/user-new.php:113
+#: tmp/old/wordpress/wp-admin/user-edit.php:429
+#: tmp/old/wordpress/wp-admin/user-new.php:318
+#: tmp/old/wordpress/wp-admin/user-new.php:409
+#: tmp/old/wordpress/wp-includes/comment-template.php:2198
+#: tmp/old/wordpress/wp-login.php:726 tmp/wordpress/wp-admin/comment.php:158
+#: tmp/wordpress/wp-admin/includes/class-wp-ms-users-list-table.php:170
+#: tmp/wordpress/wp-admin/includes/class-wp-users-list-table.php:320
+#: tmp/wordpress/wp-admin/includes/template.php:416
+#: tmp/wordpress/wp-admin/network/site-users.php:322
+#: tmp/wordpress/wp-admin/network/user-new.php:113
+#: tmp/wordpress/wp-admin/user-edit.php:429
+#: tmp/wordpress/wp-admin/user-new.php:318
+#: tmp/wordpress/wp-admin/user-new.php:409
+#: tmp/wordpress/wp-includes/comment-template.php:2198
+#: tmp/wordpress/wp-login.php:726
msgid "Email"
msgstr ""
@@ -848,15 +1240,15 @@ msgstr ""
msgid "Billing Period"
msgstr ""
-#: includes/admin/meta-boxes/views/html-subscription-schedule.php:60
+#: includes/admin/meta-boxes/views/html-subscription-schedule.php:61
msgid "Timezone:"
msgstr ""
-#: includes/admin/meta-boxes/views/html-subscription-schedule.php:60
+#: includes/admin/meta-boxes/views/html-subscription-schedule.php:61
msgid "Error: unable to find timezone of your browser."
msgstr ""
-#: includes/admin/reports/class-wcs-report-cache-manager.php:260
+#: includes/admin/reports/class-wcs-report-cache-manager.php:274
msgid ""
"Please note: data for this report is cached. The data displayed may be out "
"of date by up to 24 hours. The cache is updated each morning at 4am in your "
@@ -875,6 +1267,21 @@ msgid_plural "%s renewals subscription renewals this month"
msgstr[0] ""
msgstr[1] ""
+#: includes/admin/reports/class-wcs-report-retention-rate.php:156
+msgctxt "X axis label on retention rate graph"
+msgid "Number of days after sign-up"
+msgstr ""
+
+#: includes/admin/reports/class-wcs-report-retention-rate.php:159
+msgctxt "X axis label on retention rate graph"
+msgid "Number of weeks after sign-up"
+msgstr ""
+
+#: includes/admin/reports/class-wcs-report-retention-rate.php:162
+msgctxt "X axis label on retention rate graph"
+msgid "Number of months after sign-up"
+msgstr ""
+
#: includes/admin/reports/class-wcs-report-retention-rate.php:226
msgid "Unended Subscription Count"
msgstr ""
@@ -1069,8 +1476,8 @@ msgstr ""
#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:414
msgid ""
-"The number of subscriptions upgraded, downgraded or cross-graded during "
-"this period."
+"The number of subscriptions upgraded, downgraded or cross-graded during this "
+"period."
msgstr ""
#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:420
@@ -1118,6 +1525,10 @@ msgstr ""
#: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:472
#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:137
+#: tmp/old/wordpress/wp-admin/includes/template.php:725
+#: tmp/old/wordpress/wp-includes/media.php:2182
+#: tmp/wordpress/wp-admin/includes/template.php:725
+#: tmp/wordpress/wp-includes/media.php:2182
msgid "Year"
msgstr ""
@@ -1199,8 +1610,7 @@ msgstr ""
#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:103
msgid ""
-"The number of renewal orders which had a failed payment use the retry "
-"system."
+"The number of renewal orders which had a failed payment use the retry system."
msgstr ""
#: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:108
@@ -1279,65 +1689,76 @@ msgstr ""
msgid "Renewals amount"
msgstr ""
-#: includes/api/class-wc-rest-subscriptions-controller.php:163
+#: includes/api/class-wc-rest-subscriptions-controller.php:109
+msgid "Customer ID is invalid."
+msgstr ""
+
+#: includes/api/class-wc-rest-subscriptions-controller.php:216
+#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:171
msgid "Invalid subscription id."
msgstr ""
-#: includes/api/class-wc-rest-subscriptions-controller.php:232
-msgid "Cannot create subscription: %s."
+#: includes/api/class-wc-rest-subscriptions-controller.php:287
+#: includes/api/legacy/class-wc-api-subscriptions.php:307
+#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:303
+msgid ""
+"Gateway does not support admin changing the payment method on a Subscription."
msgstr ""
-#: includes/api/class-wc-rest-subscriptions-controller.php:275
+#. translators: 1$: gateway id, 2$: error message
+#: includes/api/class-wc-rest-subscriptions-controller.php:318
+#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:333
+msgid ""
+"Subscription payment method could not be set to %1$s with error message: %2$s"
+msgstr ""
+
+#: includes/api/class-wc-rest-subscriptions-controller.php:383
+#: includes/api/class-wc-rest-subscriptions-controller.php:525
+#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:284
msgid "Updating subscription dates errored with message: %s"
msgstr ""
-#: includes/api/class-wc-rest-subscriptions-controller.php:294
-#: includes/api/legacy/class-wc-api-subscriptions.php:304
-msgid ""
-"Gateway does not support admin changing the payment method on a "
-"Subscription."
-msgstr ""
-
-#: includes/api/class-wc-rest-subscriptions-controller.php:327
-#. translators: 1$: gateway id, 2$: error message
-msgid ""
-"Subscription payment method could not be set to %1$s with error message: "
-"%2$s"
-msgstr ""
-
-#: includes/api/class-wc-rest-subscriptions-controller.php:341
+#: includes/api/class-wc-rest-subscriptions-controller.php:408
+#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:347
msgid "The number of billing periods between subscription renewals."
msgstr ""
-#: includes/api/class-wc-rest-subscriptions-controller.php:346
+#: includes/api/class-wc-rest-subscriptions-controller.php:413
+#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:352
msgid "Billing period for the subscription."
msgstr ""
-#: includes/api/class-wc-rest-subscriptions-controller.php:352
+#: includes/api/class-wc-rest-subscriptions-controller.php:419
+#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:358
msgid "Subscription payment details."
msgstr ""
-#: includes/api/class-wc-rest-subscriptions-controller.php:357
+#: includes/api/class-wc-rest-subscriptions-controller.php:424
+#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:363
msgid "Payment gateway ID."
msgstr ""
-#: includes/api/class-wc-rest-subscriptions-controller.php:364
+#: includes/api/class-wc-rest-subscriptions-controller.php:431
+#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:370
msgid "The subscription's start date."
msgstr ""
-#: includes/api/class-wc-rest-subscriptions-controller.php:369
+#: includes/api/class-wc-rest-subscriptions-controller.php:436
+#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:375
msgid "The subscription's trial date"
msgstr ""
-#: includes/api/class-wc-rest-subscriptions-controller.php:374
+#: includes/api/class-wc-rest-subscriptions-controller.php:441
+#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:380
msgid "The subscription's next payment date."
msgstr ""
-#: includes/api/class-wc-rest-subscriptions-controller.php:379
+#: includes/api/class-wc-rest-subscriptions-controller.php:446
+#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:385
msgid "The subscription's end date."
msgstr ""
-#: includes/api/legacy/class-wc-api-subscriptions.php:102 wcs-functions.php:170
+#: includes/api/legacy/class-wc-api-subscriptions.php:102 wcs-functions.php:172
msgid "Invalid subscription status given."
msgstr ""
@@ -1349,132 +1770,178 @@ msgstr ""
msgid "You do not have permission to create subscriptions"
msgstr ""
-#: includes/api/legacy/class-wc-api-subscriptions.php:239
+#: includes/api/legacy/class-wc-api-subscriptions.php:240
msgid "The requested subscription cannot be edited."
msgstr ""
-#: includes/api/legacy/class-wc-api-subscriptions.php:342
+#. translators: placeholder is error message
+#: includes/api/legacy/class-wc-api-subscriptions.php:268
+msgctxt "API error message when editing the order failed"
+msgid "Edit subscription failed with error: %s"
+msgstr ""
+
#. translators: 1$: gateway id, 2$: error message
+#: includes/api/legacy/class-wc-api-subscriptions.php:345
msgid ""
"Subscription payment method could not be set to %1$s and has been set to "
"manual with error message: %2$s"
msgstr ""
-#: includes/api/legacy/class-wc-api-subscriptions.php:377 wcs-functions.php:144
+#: includes/api/legacy/class-wc-api-subscriptions.php:380 wcs-functions.php:146
msgid ""
-"Invalid subscription billing interval given. Must be an integer greater "
-"than 0."
+"Invalid subscription billing interval given. Must be an integer greater than "
+"0."
msgstr ""
-#: includes/api/legacy/class-wc-api-subscriptions.php:389 wcs-functions.php:139
+#: includes/api/legacy/class-wc-api-subscriptions.php:391 wcs-functions.php:141
msgid "Invalid subscription billing period given."
msgstr ""
-#: includes/class-wc-subscription.php:305
-msgid "Unable to change subscription status to \"%s\"."
+#: includes/api/legacy/class-wc-api-subscriptions.php:608
+msgctxt "API response confirming order note deleted from a subscription"
+msgid "Permanently deleted subscription note"
msgstr ""
-#: includes/class-wc-subscription.php:401
-#. translators: $1 note why the status changes (if any), $2: old status, $3:
-#. new status
-msgid "%1$s Status changed from %2$s to %3$s."
+#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:240
+msgid "Cannot create subscription: %s."
msgstr ""
#: includes/class-wc-subscription.php:415
+msgid "Unable to change subscription status to \"%s\"."
+msgstr ""
+
+#: includes/class-wc-subscription.php:516
msgid "Unable to change subscription status to \"%s\". Exception: %s"
msgstr ""
-#: includes/class-wc-subscription.php:703
-#: includes/class-wc-subscriptions-manager.php:2212
-#: includes/wcs-formatting-functions.php:228
+#. translators: 1: old subscription status 2: new subscription status
+#: includes/class-wc-subscription.php:538
+msgid "Status changed from %1$s to %2$s."
+msgstr ""
+
+#. translators: %s: new order status
+#: includes/class-wc-subscription.php:550
+msgid "Status set to %s."
+msgstr ""
+
#. translators: placeholder is human time diff (e.g. "3 weeks")
+#: includes/class-wc-subscription.php:1144
+#: includes/class-wc-subscriptions-manager.php:2221
+#: includes/wcs-formatting-functions.php:228
msgid "In %s"
msgstr ""
-#: includes/class-wc-subscription.php:706
-#: includes/wcs-formatting-functions.php:231
#. translators: placeholder is human time diff (e.g. "3 weeks")
+#. translators: %s: Time since the last update
+#: includes/class-wc-subscription.php:1147
+#: includes/wcs-formatting-functions.php:231
+#: tmp/old/wordpress/wp-admin/includes/class-wp-media-list-table.php:449
+#: tmp/old/wordpress/wp-admin/includes/class-wp-plugin-install-list-table.php:559
+#: tmp/old/wordpress/wp-admin/includes/class-wp-posts-list-table.php:988
+#: tmp/old/wordpress/wp-admin/includes/plugin-install.php:575
+#: tmp/old/wordpress/wp-admin/includes/revision.php:209
+#: tmp/old/wordpress/wp-admin/includes/revision.php:251
+#: tmp/old/wordpress/wp-content/plugins/akismet/class.akismet-admin.php:619
+#: tmp/wordpress/wp-admin/includes/class-wp-media-list-table.php:449
+#: tmp/wordpress/wp-admin/includes/class-wp-plugin-install-list-table.php:559
+#: tmp/wordpress/wp-admin/includes/class-wp-posts-list-table.php:988
+#: tmp/wordpress/wp-admin/includes/plugin-install.php:575
+#: tmp/wordpress/wp-admin/includes/revision.php:209
+#: tmp/wordpress/wp-admin/includes/revision.php:251
+#: tmp/wordpress/wp-content/plugins/akismet/class.akismet-admin.php:619
msgid "%s ago"
msgstr ""
-#: includes/class-wc-subscription.php:713
+#: includes/class-wc-subscription.php:1154
msgid "Not yet ended"
msgstr ""
-#: includes/class-wc-subscription.php:716
+#: includes/class-wc-subscription.php:1157
msgid "Not cancelled"
msgstr ""
-#: includes/class-wc-subscription.php:812
+#: includes/class-wc-subscription.php:1162
+msgctxt "original denotes there is no date to display"
+msgid "-"
+msgstr ""
+
+#: includes/class-wc-subscription.php:1272
msgid "The start date of a subscription can not be deleted, only updated."
msgstr ""
-#: includes/class-wc-subscription.php:815
+#: includes/class-wc-subscription.php:1276
msgid ""
-"The last payment date of a subscription can not be deleted. You must delete "
-"the order."
+"The %s date of a subscription can not be deleted. You must delete the order."
msgstr ""
-#: includes/class-wc-subscription.php:1226
+#: includes/class-wc-subscription.php:1659
msgid "Sign-up complete."
msgstr ""
-#: includes/class-wc-subscription.php:1228
+#: includes/class-wc-subscription.php:1661
msgid "Payment received."
msgstr ""
-#: includes/class-wc-subscription.php:1259
+#: includes/class-wc-subscription.php:1692
msgid "Payment failed."
msgstr ""
-#: includes/class-wc-subscription.php:1263
+#: includes/class-wc-subscription.php:1696
msgid "Subscription Cancelled: maximum number of failed payments reached."
msgstr ""
-#: includes/class-wc-subscription.php:1458
-#: includes/class-wcs-change-payment-method-admin.php:155
+#: includes/class-wc-subscription.php:1897
+#: includes/class-wcs-change-payment-method-admin.php:156
msgid "Manual Renewal"
msgstr ""
-#: includes/class-wc-subscription.php:1523
+#: includes/class-wc-subscription.php:1974
msgid "Payment method meta must be an array."
msgstr ""
-#: includes/class-wc-subscription.php:1746
+#: includes/class-wc-subscription.php:2201
msgid "Invalid format. First parameter needs to be an array."
msgstr ""
-#: includes/class-wc-subscription.php:1750
+#: includes/class-wc-subscription.php:2205
msgid "Invalid data. First parameter was empty when passed to update_dates()."
msgstr ""
-#: includes/class-wc-subscription.php:1758
+#: includes/class-wc-subscription.php:2212
msgid ""
"Invalid data. First parameter has a date that is not in the registered date "
"types."
msgstr ""
-#: includes/class-wc-subscription.php:1810
+#. translators: placeholder is date type (e.g. "end", "next_payment"...)
+#: includes/class-wc-subscription.php:2239
+msgctxt "appears in an error message if date is wrong format"
+msgid "Invalid %s date. The date must be of the format: \"Y-m-d H:i:s\"."
+msgstr ""
+
+#: includes/class-wc-subscription.php:2276
msgid "The %s date must occur after the cancellation date."
msgstr ""
-#: includes/class-wc-subscription.php:1815
+#: includes/class-wc-subscription.php:2281
msgid "The %s date must occur after the last payment date."
msgstr ""
-#: includes/class-wc-subscription.php:1819
+#: includes/class-wc-subscription.php:2285
msgid "The %s date must occur after the next payment date."
msgstr ""
-#: includes/class-wc-subscription.php:1824
+#: includes/class-wc-subscription.php:2290
msgid "The %s date must occur after the trial end date."
msgstr ""
-#: includes/class-wc-subscription.php:1828
+#: includes/class-wc-subscription.php:2294
msgid "The %s date must occur after the start date."
msgstr ""
-#: includes/class-wc-subscription.php:1856 includes/wcs-order-functions.php:269
+#: includes/class-wc-subscription.php:2323
+#: includes/class-wc-subscriptions-checkout.php:315
+#: includes/wcs-order-functions.php:279
msgid "Backordered"
msgstr ""
@@ -1488,243 +1955,320 @@ msgid ""
"shipping address for future purchases will be updated."
msgstr ""
-#: includes/class-wc-subscriptions-addresses.php:83
#. translators: $1: address type (Shipping Address / Billing Address), $2:
#. opening tag, $3: closing tag
+#: includes/class-wc-subscriptions-addresses.php:83
msgid "Update the %1$s used for %2$sall%3$s of my active subscriptions"
msgstr ""
-#: includes/class-wc-subscriptions-cart.php:832
+#: includes/class-wc-subscriptions-cart.php:864
msgid "Please enter a valid postcode/ZIP."
msgstr ""
-#: includes/class-wc-subscriptions-cart.php:1003
+#: includes/class-wc-subscriptions-cart.php:1035
msgid ""
"That subscription product can not be added to your cart as it already "
"contains a subscription renewal."
msgstr ""
-#: includes/class-wc-subscriptions-cart.php:1091
+#: includes/class-wc-subscriptions-cart.php:1123
msgid "Invalid recurring shipping method."
msgstr ""
-#: includes/class-wc-subscriptions-cart.php:1869
+#: includes/class-wc-subscriptions-cart.php:1889
msgid "now"
msgstr ""
-#: includes/class-wc-subscriptions-change-payment-gateway.php:126
-#: templates/emails/plain/email-order-details.php:19
#. translators: placeholder is the subscription order number wrapped in
#. tags
+#: includes/class-wc-subscriptions-change-payment-gateway.php:148
+#: templates/emails/plain/email-order-details.php:19
msgid "Subscription Number: %s"
msgstr ""
-#: includes/class-wc-subscriptions-change-payment-gateway.php:132
#. translators: placeholder is the subscription's next payment date (either
#. human readable or normal date) wrapped in tags
+#: includes/class-wc-subscriptions-change-payment-gateway.php:154
msgid "Next Payment Date: %s"
msgstr ""
-#: includes/class-wc-subscriptions-change-payment-gateway.php:138
#. translators: placeholder is the formatted total to be paid for the
#. subscription wrapped in tags
+#: includes/class-wc-subscriptions-change-payment-gateway.php:160
msgid "Total: %s"
msgstr ""
-#: includes/class-wc-subscriptions-change-payment-gateway.php:145
#. translators: placeholder is the display name of the payment method
+#: includes/class-wc-subscriptions-change-payment-gateway.php:167
msgid "Payment Method: %s"
msgstr ""
-#: includes/class-wc-subscriptions-change-payment-gateway.php:157
+#: includes/class-wc-subscriptions-change-payment-gateway.php:179
msgid ""
-"Sorry, this subscription change payment method request is invalid and "
-"cannot be processed."
+"Sorry, this subscription change payment method request is invalid and cannot "
+"be processed."
msgstr ""
-#: includes/class-wc-subscriptions-change-payment-gateway.php:189
+#: includes/class-wc-subscriptions-change-payment-gateway.php:211
msgid "There was an error with your request. Please try again."
msgstr ""
-#: includes/class-wc-subscriptions-change-payment-gateway.php:193
+#: includes/class-wc-subscriptions-change-payment-gateway.php:215
#: templates/myaccount/view-subscription.php:20
msgid "Invalid Subscription."
msgstr ""
-#: includes/class-wc-subscriptions-change-payment-gateway.php:197
+#: includes/class-wc-subscriptions-change-payment-gateway.php:219
#: includes/class-wcs-cart-resubscribe.php:78
#: includes/class-wcs-cart-resubscribe.php:129
#: includes/class-wcs-user-change-status-handler.php:103
msgid "That doesn't appear to be one of your subscriptions."
msgstr ""
-#: includes/class-wc-subscriptions-change-payment-gateway.php:201
+#: includes/class-wc-subscriptions-change-payment-gateway.php:223
msgid "The payment method can not be changed for that subscription."
msgstr ""
-#: includes/class-wc-subscriptions-change-payment-gateway.php:207
#. translators: placeholder is next payment's date
+#: includes/class-wc-subscriptions-change-payment-gateway.php:229
msgid " Next payment is due %s."
msgstr ""
-#: includes/class-wc-subscriptions-change-payment-gateway.php:213
#. translators: placeholder is either empty or "Next payment is due..."
+#: includes/class-wc-subscriptions-change-payment-gateway.php:235
msgid "Choose a new payment method.%s"
msgstr ""
-#: includes/class-wc-subscriptions-change-payment-gateway.php:235
+#: includes/class-wc-subscriptions-change-payment-gateway.php:264
msgid "Invalid order."
msgstr ""
-#: includes/class-wc-subscriptions-change-payment-gateway.php:328
+#: includes/class-wc-subscriptions-change-payment-gateway.php:288
+msgctxt "label on button, imperative"
+msgid "Change Payment"
+msgstr ""
+
+#: includes/class-wc-subscriptions-change-payment-gateway.php:366
msgid "Payment method updated."
msgstr ""
-#: includes/class-wc-subscriptions-checkout.php:167
-#: includes/class-wc-subscriptions-checkout.php:279
+#: includes/class-wc-subscriptions-change-payment-gateway.php:414
+msgctxt "%1$s: old payment title, %2$s: new payment title"
+msgid ""
+"Payment method changed from \"%1$s\" to \"%2$s\" by the subscriber from "
+"their account page."
+msgstr ""
+
+#: includes/class-wc-subscriptions-change-payment-gateway.php:539
+msgctxt "the page title of the change payment method form"
+msgid "Change Payment Method"
+msgstr ""
+
#. translators: placeholder is an internal error number
+#: includes/class-wc-subscriptions-checkout.php:175
+#: includes/class-wc-subscriptions-checkout.php:346
msgid "Error %d: Unable to create subscription. Please try again."
msgstr ""
-#: includes/class-wc-subscriptions-checkout.php:180
#. translators: placeholder is an internal error number
+#: includes/class-wc-subscriptions-checkout.php:192
msgid "Error %d: Unable to add tax to subscription. Please try again."
msgstr ""
-#: includes/class-wc-subscriptions-checkout.php:188
#. translators: placeholder is an internal error number
+#: includes/class-wc-subscriptions-checkout.php:204
msgid "Error %d: Unable to create order. Please try again."
msgstr ""
-#: includes/class-wc-subscriptions-checkout.php:244
-#: includes/class-wc-subscriptions-manager.php:467
-msgid "Error: Unable to create subscription. Please try again."
-msgstr ""
-
-#: includes/class-wc-subscriptions-coupon.php:58
+#: includes/class-wc-subscriptions-coupon.php:63
msgid "Sign Up Fee Discount"
msgstr ""
-#: includes/class-wc-subscriptions-coupon.php:59
+#: includes/class-wc-subscriptions-coupon.php:64
msgid "Sign Up Fee % Discount"
msgstr ""
-#: includes/class-wc-subscriptions-coupon.php:60
+#: includes/class-wc-subscriptions-coupon.php:65
msgid "Recurring Product Discount"
msgstr ""
-#: includes/class-wc-subscriptions-coupon.php:61
+#: includes/class-wc-subscriptions-coupon.php:66
msgid "Recurring Product % Discount"
msgstr ""
-#: includes/class-wc-subscriptions-coupon.php:249
+#: includes/class-wc-subscriptions-coupon.php:256
msgid ""
"Sorry, this coupon is only valid for an initial payment and the cart does "
"not require an initial payment."
msgstr ""
-#: includes/class-wc-subscriptions-coupon.php:255
+#: includes/class-wc-subscriptions-coupon.php:262
msgid "Sorry, this coupon is only valid for new subscriptions."
msgstr ""
-#: includes/class-wc-subscriptions-coupon.php:260
+#: includes/class-wc-subscriptions-coupon.php:267
msgid "Sorry, this coupon is only valid for subscription products."
msgstr ""
-#: includes/class-wc-subscriptions-coupon.php:266
#. translators: 1$: coupon code that is being removed
+#: includes/class-wc-subscriptions-coupon.php:273
msgid "Sorry, the \"%1$s\" coupon is only valid for renewals."
msgstr ""
-#: includes/class-wc-subscriptions-coupon.php:271
+#: includes/class-wc-subscriptions-coupon.php:278
msgid ""
"Sorry, this coupon is only valid for subscription products with a sign-up "
"fee."
msgstr ""
+#: includes/class-wc-subscriptions-coupon.php:503
+msgid "Renewal % discount"
+msgstr ""
+
+#: includes/class-wc-subscriptions-coupon.php:504
+msgid "Renewal product discount"
+msgstr ""
+
+#: includes/class-wc-subscriptions-coupon.php:505
+msgid "Renewal cart discount"
+msgstr ""
+
+#: includes/class-wc-subscriptions-manager.php:94
+#: includes/class-wc-subscriptions-manager.php:1835
+#: includes/class-wc-subscriptions-manager.php:1853
+msgctxt "used in order note as reason for why subscription status changed"
+msgid "Subscription renewal payment due:"
+msgstr ""
+
#: includes/class-wc-subscriptions-manager.php:104
msgid ""
"Error: Unable to create renewal order from scheduled payment. Please try "
"again."
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:141
-#: includes/gateways/class-wc-subscriptions-payment-gateways.php:201
+#: includes/class-wc-subscriptions-manager.php:145
+#: includes/gateways/class-wc-subscriptions-payment-gateways.php:204
msgid "Subscription doesn't exist in scheduled action: %d"
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:278
#. translators: $1: order number, $2: error message
+#: includes/class-wc-subscriptions-manager.php:282
msgid "Failed to activate subscription status for order #%1$s: %2$s"
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:306
#. translators: $1: order number, $2: error message
-msgid "Failed to update subscription status after order #%1$s was put on-hold: %2$s"
+#: includes/class-wc-subscriptions-manager.php:310
+msgid ""
+"Failed to update subscription status after order #%1$s was put on-hold: %2$s"
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:334
#. translators: $1: order number, $2: error message
+#: includes/class-wc-subscriptions-manager.php:338
msgid "Failed to cancel subscription after order #%1$s was cancelled: %2$s"
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:362
#. translators: $1: order number, $2: error message
+#: includes/class-wc-subscriptions-manager.php:366
msgid "Failed to set subscription as expired for order #%1$s: %2$s"
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:388
+#: includes/class-wc-subscriptions-manager.php:392
msgid "Subscription sign up failed."
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:398
#. translators: $1: order number, $2: error message
+#: includes/class-wc-subscriptions-manager.php:402
msgid "Failed to process failed payment on subscription for order #%1$s: %2$s"
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:486
+#: includes/class-wc-subscriptions-manager.php:471
+msgid "Error: Unable to create subscription. Please try again."
+msgstr ""
+
+#: includes/class-wc-subscriptions-manager.php:490
msgid "Error: Unable to add product to created subscription. Please try again."
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:526
+#: includes/class-wc-subscriptions-manager.php:535
msgid "Pending subscription created."
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:1752
+#: includes/class-wc-subscriptions-manager.php:982 wcs-functions.php:209
+msgctxt "Subscription status"
+msgid "Active"
+msgstr ""
+
+#: includes/class-wc-subscriptions-manager.php:985 wcs-functions.php:211
+msgctxt "Subscription status"
+msgid "Cancelled"
+msgstr ""
+
+#: includes/class-wc-subscriptions-manager.php:988 wcs-functions.php:213
+msgctxt "Subscription status"
+msgid "Expired"
+msgstr ""
+
+#: includes/class-wc-subscriptions-manager.php:991 wcs-functions.php:208
+msgctxt "Subscription status"
+msgid "Pending"
+msgstr ""
+
+#: includes/class-wc-subscriptions-manager.php:994
+msgctxt "Subscription status"
+msgid "Failed"
+msgstr ""
+
+#: includes/class-wc-subscriptions-manager.php:998
+msgctxt "Subscription status"
+msgid "On-hold"
+msgstr ""
+
+#. translators: 1$: month number (e.g. "01"), 2$: month abbreviation (e.g.
+#. "Jan")
+#: includes/class-wc-subscriptions-manager.php:1748
+msgctxt "used in a select box"
+msgid "%1$s-%2$s"
+msgstr ""
+
#. translators: all fields are full html nodes: 1$: month input, 2$: day input,
#. 3$: year input, 4$: hour input, 5$: minute input. Change the order if you'd
#. like
+#: includes/class-wc-subscriptions-manager.php:1761
msgid "%1$s%2$s, %3$s @ %4$s : %5$s"
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:1756
#. translators: all fields are full html nodes: 1$: month input, 2$: day input,
#. 3$: year input. Change the order if you'd like
+#: includes/class-wc-subscriptions-manager.php:1765
msgid "%1$s%2$s, %3$s"
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:1761
+#: includes/class-wc-subscriptions-manager.php:1770
+#: tmp/old/wordpress/wp-admin/includes/class-wp-users-list-table.php:270
+#: tmp/old/wordpress/wp-content/plugins/akismet/views/config.php:224
+#: tmp/wordpress/wp-admin/includes/class-wp-users-list-table.php:270
+#: tmp/wordpress/wp-content/plugins/akismet/views/config.php:224
msgid "Change"
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:2094
#. translators: placeholder is subscription ID
+#: includes/class-wc-subscriptions-manager.php:2103
msgid "Failed sign-up for subscription %s."
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:2185
+#: includes/class-wc-subscriptions-manager.php:2194
msgid "Invalid security token, please reload the page and try again."
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:2189
+#: includes/class-wc-subscriptions-manager.php:2198
msgid "Only store managers can edit payment dates."
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:2193
+#: includes/class-wc-subscriptions-manager.php:2202
msgid "Please enter all date fields."
msgstr ""
-#: includes/class-wc-subscriptions-manager.php:2218
+#: includes/class-wc-subscriptions-manager.php:2227
msgid "Date Changed"
msgstr ""
@@ -1734,8 +2278,8 @@ msgid_plural "Your subscriptions will be activated when payment clears."
msgstr[0] ""
msgstr[1] ""
-#: includes/class-wc-subscriptions-order.php:378
#. translators: placeholders are opening and closing link tags
+#: includes/class-wc-subscriptions-order.php:378
msgid "View the status of your subscription in %syour account%s."
msgid_plural "View the status of your subscriptions in %syour account%s."
msgstr[0] ""
@@ -1757,130 +2301,160 @@ msgstr ""
msgid "Parent Order"
msgstr ""
-#: includes/class-wc-subscriptions-order.php:689
+#: includes/class-wc-subscriptions-order.php:673
msgid "All orders types"
msgstr ""
-#: includes/class-wc-subscriptions-order.php:956
+#: includes/class-wc-subscriptions-order.php:676
+msgctxt "An order type"
+msgid "Original"
+msgstr ""
+
+#: includes/class-wc-subscriptions-order.php:677
+msgctxt "An order type"
+msgid "Subscription Parent"
+msgstr ""
+
+#: includes/class-wc-subscriptions-order.php:678
+msgctxt "An order type"
+msgid "Subscription Renewal"
+msgstr ""
+
+#: includes/class-wc-subscriptions-order.php:679
+msgctxt "An order type"
+msgid "Subscription Resubscribe"
+msgstr ""
+
+#: includes/class-wc-subscriptions-order.php:680
+msgctxt "An order type"
+msgid "Subscription Switch"
+msgstr ""
+
+#: includes/class-wc-subscriptions-order.php:681
+msgctxt "An order type"
+msgid "Non-subscription"
+msgstr ""
+
#. translators: $1: opening link tag, $2: order number, $3: closing link tag
+#: includes/class-wc-subscriptions-order.php:940
msgid "Subscription cancelled for refunded order %1$s#%2$s%3$s."
msgstr ""
-#: includes/class-wc-subscriptions-product.php:348
-#: includes/wcs-formatting-functions.php:102
-#: includes/wcs-formatting-functions.php:186
#. translators: 1$: recurring amount string, 2$: day of the week (e.g. "$10
#. every Wednesday")
+#: includes/class-wc-subscriptions-product.php:311
+#: includes/wcs-formatting-functions.php:102
+#: includes/wcs-formatting-functions.php:186
msgid "%1$s every %2$s"
msgstr ""
-#: includes/class-wc-subscriptions-product.php:351
-#: includes/wcs-formatting-functions.php:111
#. translators: 1$: recurring amount string, 2$: period, 3$: day of the week
#. (e.g. "$10 every 2nd week on Wednesday")
+#: includes/class-wc-subscriptions-product.php:314
+#: includes/wcs-formatting-functions.php:111
msgid "%1$s every %2$s on %3$s"
msgstr ""
-#: includes/class-wc-subscriptions-product.php:358
-#: includes/wcs-formatting-functions.php:129
#. translators: placeholder is recurring amount
+#: includes/class-wc-subscriptions-product.php:321
+#: includes/wcs-formatting-functions.php:129
msgid "%s on the last day of each month"
msgstr ""
-#: includes/class-wc-subscriptions-product.php:361
-#: includes/wcs-formatting-functions.php:132
#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g.
#. "$5 every 23rd of each month")
+#: includes/class-wc-subscriptions-product.php:324
+#: includes/wcs-formatting-functions.php:132
msgid "%1$s on the %2$s of each month"
msgstr ""
-#: includes/class-wc-subscriptions-product.php:366
-#: includes/wcs-formatting-functions.php:148
#. translators: 1$: recurring amount, 2$: interval (e.g. "3rd") (e.g. "$10 on
#. the last day of every 3rd month")
+#: includes/class-wc-subscriptions-product.php:329
+#: includes/wcs-formatting-functions.php:148
msgid "%1$s on the last day of every %2$s month"
msgstr ""
-#: includes/class-wc-subscriptions-product.php:369
-#: includes/wcs-formatting-functions.php:151
#. translators: 1$: on the, 2$: day of every, 3$:
#. month (e.g. "$10 on the 23rd day of every 2nd month")
#. translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g.
#. "$5 every 23rd of each month")
+#: includes/class-wc-subscriptions-product.php:332
+#: includes/wcs-formatting-functions.php:151
msgid "%1$s on the %2$s day of every %3$s month"
msgstr ""
-#: includes/class-wc-subscriptions-product.php:376
-#: includes/wcs-formatting-functions.php:164
#. translators: 1$: on, 2$: , 3$: each year (e.g. "$15 on
#. March 15th each year")
#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the
#. month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year")
+#: includes/class-wc-subscriptions-product.php:339
+#: includes/wcs-formatting-functions.php:164
msgid "%1$s on %2$s %3$s each year"
msgstr ""
-#: includes/class-wc-subscriptions-product.php:379
-#: includes/wcs-formatting-functions.php:173
#. translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the
#. month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year")
+#: includes/class-wc-subscriptions-product.php:342
+#: includes/wcs-formatting-functions.php:173
msgid "%1$s on %2$s %3$s every %4$s year"
msgstr ""
-#: includes/class-wc-subscriptions-product.php:385
-#: includes/wcs-formatting-functions.php:184
#. translators: 1$: recurring amount, 2$: subscription period (e.g. "month" or
#. "3 months") (e.g. "$15 / month" or "$15 every 2nd month")
+#: includes/class-wc-subscriptions-product.php:348
+#: includes/wcs-formatting-functions.php:184
msgid "%1$s / %2$s"
msgid_plural " %1$s every %2$s"
msgstr[0] ""
msgstr[1] ""
-#: includes/class-wc-subscriptions-product.php:391
#. translators: billing period (e.g. "every week")
+#: includes/class-wc-subscriptions-product.php:354
msgid "every %s"
msgstr ""
-#: includes/class-wc-subscriptions-product.php:397
-#: includes/wcs-formatting-functions.php:194
#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March
#. 23rd every 3rd year"), 2$: length (e.g. "4 years")
+#: includes/class-wc-subscriptions-product.php:360
+#: includes/wcs-formatting-functions.php:194
msgid "%1$s for %2$s"
msgstr ""
-#: includes/class-wc-subscriptions-product.php:403
#. translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years
#. for 6 years"), 2$: trial length (e.g.: "with 4 months free trial")
+#: includes/class-wc-subscriptions-product.php:366
msgid "%1$s with %2$s free trial"
msgstr ""
-#: includes/class-wc-subscriptions-product.php:408
#. translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years
#. for 6 years with 2 months free trial"), 2$: signup fee price (e.g. "and a
#. $30 sign-up fee")
+#: includes/class-wc-subscriptions-product.php:371
msgid "%1$s and a %2$s sign-up fee"
msgstr ""
-#: includes/class-wc-subscriptions-renewal-order.php:141
#. translators: placeholder is order ID
+#: includes/class-wc-subscriptions-renewal-order.php:148
msgid "Order %s created to record renewal."
msgstr ""
-#: includes/class-wc-subscriptions-renewal-order.php:161
+#: includes/class-wc-subscriptions-renewal-order.php:168
msgid "Subscription renewal orders cannot be cancelled."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:151
+#: includes/class-wc-subscriptions-switcher.php:170
msgid ""
"You have a subscription to this product. Choosing a new subscription will "
"replace your existing subscription."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:153
+#: includes/class-wc-subscriptions-switcher.php:172
msgid "Choose a new subscription."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:175
-#: includes/class-wc-subscriptions-switcher.php:893
+#: includes/class-wc-subscriptions-switcher.php:194
+#: includes/class-wc-subscriptions-switcher.php:1016
msgid ""
"Your cart contained an invalid subscription switch request. It has been "
"removed."
@@ -1890,201 +2464,330 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: includes/class-wc-subscriptions-switcher.php:217
+#: includes/class-wc-subscriptions-switcher.php:236
msgid ""
"You have already subscribed to this product and it is limited to one per "
"customer. You can not purchase the product again."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:226
#. translators: 1$: is the "You have already subscribed to this product"
#. notice, 2$-4$: opening/closing link tags, 3$: an order number
+#: includes/class-wc-subscriptions-switcher.php:245
msgid ""
"%1$s Complete payment on %2$sOrder %3$s%4$s to be able to change your "
"subscription."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:305
+#: includes/class-wc-subscriptions-switcher.php:324
msgid "Switching"
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:308
#. translators: placeholders are opening and closing link tags
+#: includes/class-wc-subscriptions-switcher.php:327
msgid ""
"Allow subscribers to switch (upgrade or downgrade) between different "
"subscriptions. %sLearn more%s."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:313
+#: includes/class-wc-subscriptions-switcher.php:332
msgid "Allow Switching"
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:314
+#: includes/class-wc-subscriptions-switcher.php:333
msgid ""
"Allow subscribers to switch between subscriptions combined in a grouped "
"product, different variations of a Variable subscription or don't allow "
"switching."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:330
+#: includes/class-wc-subscriptions-switcher.php:340
+#: includes/class-wc-subscriptions-switcher.php:357
+#: includes/class-wc-subscriptions-switcher.php:391
+#: includes/class-wc-subscriptions-synchroniser.php:174
+msgctxt "when to allow a setting"
+msgid "Never"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:341
+msgctxt "when to allow switching"
+msgid "Between Subscription Variations"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:342
+msgctxt "when to allow switching"
+msgid "Between Grouped Subscriptions"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:343
+msgctxt "when to allow switching"
+msgid "Between Both Variations & Grouped Subscriptions"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:349
msgid "Prorate Recurring Payment"
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:331
+#: includes/class-wc-subscriptions-switcher.php:350
msgid ""
"When switching to a subscription with a different recurring payment or "
"billing period, should the price paid for the existing billing period be "
"prorated when switching to the new subscription?"
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:348
+#: includes/class-wc-subscriptions-switcher.php:358
+msgctxt "when to prorate recurring fee when switching"
+msgid "For Upgrades of Virtual Subscription Products Only"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:359
+msgctxt "when to prorate recurring fee when switching"
+msgid "For Upgrades of All Subscription Products"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:360
+msgctxt "when to prorate recurring fee when switching"
+msgid "For Upgrades & Downgrades of Virtual Subscription Products Only"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:361
+msgctxt "when to prorate recurring fee when switching"
+msgid "For Upgrades & Downgrades of All Subscription Products"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:367
msgid "Prorate Sign up Fee"
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:349
+#: includes/class-wc-subscriptions-switcher.php:368
msgid ""
"When switching to a subscription with a sign up fee, you can require the "
"customer pay only the gap between the existing subscription's sign up fee "
"and the new subscription's sign up fee (if any)."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:364
+#: includes/class-wc-subscriptions-switcher.php:375
+msgctxt "when to prorate signup fee when switching"
+msgid "Never (do not charge a sign up fee)"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:376
+msgctxt "when to prorate signup fee when switching"
+msgid "Never (charge the full sign up fee)"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:377
+msgctxt "when to prorate signup fee when switching"
+msgid "Always"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:383
msgid "Prorate Subscription Length"
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:365
+#: includes/class-wc-subscriptions-switcher.php:384
msgid ""
"When switching to a subscription with a length, you can take into account "
"the payments already completed by the customer when determining how many "
"payments the subscriber needs to make for the new subscription."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:380
+#: includes/class-wc-subscriptions-switcher.php:392
+#: includes/class-wc-subscriptions-synchroniser.php:175
+msgctxt "when to prorate first payment / subscription length"
+msgid "For Virtual Subscription Products Only"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:393
+#: includes/class-wc-subscriptions-synchroniser.php:176
+msgctxt "when to prorate first payment / subscription length"
+msgid "For All Subscription Products"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:399
msgid "Switch Button Text"
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:381
+#: includes/class-wc-subscriptions-switcher.php:400
msgid ""
"Customise the text displayed on the button next to the subscription on the "
"subscriber's account page. The default is \"Switch Subscription\", but you "
"may wish to change this to \"Upgrade\" or \"Change Subscription\"."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:385
-#: includes/class-wc-subscriptions-switcher.php:411
-#: includes/class-wc-subscriptions-switcher.php:2159
+#: includes/class-wc-subscriptions-switcher.php:404
+#: includes/class-wc-subscriptions-switcher.php:430
+#: includes/class-wc-subscriptions-switcher.php:2302
msgid "Upgrade or Downgrade"
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:759
+#: includes/class-wc-subscriptions-switcher.php:880
msgid "Switch order cancelled due to a new switch order being created #%s."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:846
+#: includes/class-wc-subscriptions-switcher.php:967
msgid "Switch Order"
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:861
+#: includes/class-wc-subscriptions-switcher.php:983
msgid "Switched Subscription"
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:960
+#: includes/class-wc-subscriptions-switcher.php:1085
msgid "You can only switch to a subscription product."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:966
+#: includes/class-wc-subscriptions-switcher.php:1091
msgid "We can not find your old subscription item."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:988
+#: includes/class-wc-subscriptions-switcher.php:1113
msgid "You can not switch to the same subscription."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:1035
+#: includes/class-wc-subscriptions-switcher.php:1160
msgid ""
"You can not switch this subscription. It appears you do not own the "
"subscription."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:1070
+#: includes/class-wc-subscriptions-switcher.php:1195
msgid "There was an error locating the switch details."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:1764
-#: includes/class-wc-subscriptions-switcher.php:2065
+#: includes/class-wc-subscriptions-switcher.php:1779
+msgctxt "a switch order"
+msgid "Downgrade"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:1782
+msgctxt "a switch order"
+msgid "Upgrade"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:1785
+msgctxt "a switch order"
+msgid "Crossgrade"
+msgstr ""
+
+#. translators: %1: product subtotal, %2: HTML span tag, %3: direction
+#. (upgrade, downgrade, crossgrade), %4: closing HTML span tag
+#: includes/class-wc-subscriptions-switcher.php:1790
+msgctxt "product subtotal string"
+msgid "%1$s %2$s(%3$s)%4$s"
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:1893
+#: includes/class-wc-subscriptions-switcher.php:2208
msgid "The original subscription item being switched cannot be found."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:1766
+#: includes/class-wc-subscriptions-switcher.php:1895
msgid "The item on the switch order cannot be found."
msgstr ""
-#: includes/class-wc-subscriptions-switcher.php:2103
+#. translators: 1$: old item, 2$: new item when switching
+#: includes/class-wc-subscriptions-switcher.php:1906
+#: includes/class-wc-subscriptions-switcher.php:2219
+msgctxt "used in order notes"
+msgid "Customer switched from: %1$s to %2$s."
+msgstr ""
+
+#: includes/class-wc-subscriptions-switcher.php:2246
msgid "Failed to update the subscription shipping method."
msgstr ""
+#: includes/class-wc-subscriptions-switcher.php:2443 wcs-functions.php:212
+msgctxt "Subscription status"
+msgid "Switched"
+msgstr ""
+
#: includes/class-wc-subscriptions-synchroniser.php:47
msgid "Synchronise renewals"
msgstr ""
#: includes/class-wc-subscriptions-synchroniser.php:48
msgid ""
-"Align the payment date for all customers who purchase this subscription to "
-"a specific day of the week or month."
+"Align the payment date for all customers who purchase this subscription to a "
+"specific day of the week or month."
msgstr ""
-#: includes/class-wc-subscriptions-synchroniser.php:146
+#. translators: placeholder is a year (e.g. "2016")
+#: includes/class-wc-subscriptions-synchroniser.php:50
+msgctxt "used in subscription product edit screen"
+msgid ""
+"Align the payment date for this subscription to a specific day of the year. "
+"If the date has already taken place this year, the first payment will be "
+"processed in %s. Set the day to 0 to disable payment syncing for this "
+"product."
+msgstr ""
+
+#: includes/class-wc-subscriptions-synchroniser.php:151
msgid "Synchronisation"
msgstr ""
-#: includes/class-wc-subscriptions-synchroniser.php:155
+#. translators: placeholders are opening and closing link tags
+#: includes/class-wc-subscriptions-synchroniser.php:154
+msgctxt "used in the general subscription options page"
+msgid ""
+"Align subscription renewal to a specific day of the week, month or year. For "
+"example, the first day of the month. %sLearn more%s."
+msgstr ""
+
+#: includes/class-wc-subscriptions-synchroniser.php:160
msgid "Align Subscription Renewal Day"
msgstr ""
-#: includes/class-wc-subscriptions-synchroniser.php:162
+#: includes/class-wc-subscriptions-synchroniser.php:167
msgid "Prorate First Payment"
msgstr ""
-#: includes/class-wc-subscriptions-synchroniser.php:163
+#: includes/class-wc-subscriptions-synchroniser.php:168
msgid ""
"If a subscription is synchronised to a specific day of the week, month or "
"year, charge a prorated amount for the subscription at the time of sign up."
msgstr ""
-#: includes/class-wc-subscriptions-synchroniser.php:234
+#: includes/class-wc-subscriptions-synchroniser.php:237
+#: templates/admin/deprecated/html-variation-synchronisation.php:36
+#: templates/admin/html-variation-synchronisation.php:34
+msgctxt "input field placeholder for day field for annual subscriptions"
+msgid "Day"
+msgstr ""
+
+#: includes/class-wc-subscriptions-synchroniser.php:239
msgid "Month for Synchronisation"
msgstr ""
-#: includes/class-wc-subscriptions-synchroniser.php:600
+#: includes/class-wc-subscriptions-synchroniser.php:603
msgid "Do not synchronise"
msgstr ""
-#: includes/class-wc-subscriptions-synchroniser.php:608
#. translators: placeholder is a day of the week
+#: includes/class-wc-subscriptions-synchroniser.php:611
msgid "%s each week"
msgstr ""
-#: includes/class-wc-subscriptions-synchroniser.php:614
#. translators: placeholder is a number of day with language specific suffix
#. applied (e.g. "1st", "3rd", "5th", etc...)
+#: includes/class-wc-subscriptions-synchroniser.php:617
msgid "%s day of the month"
msgstr ""
-#: includes/class-wc-subscriptions-synchroniser.php:616
+#: includes/class-wc-subscriptions-synchroniser.php:619
msgid "Last day of the month"
msgstr ""
-#: includes/class-wc-subscriptions-synchroniser.php:664
+#: includes/class-wc-subscriptions-synchroniser.php:667
msgid "Today!"
msgstr ""
-#: includes/class-wc-subscriptions-synchroniser.php:671
#. translators: placeholder is a date
+#: includes/class-wc-subscriptions-synchroniser.php:674
msgid "First payment prorated. Next payment: %s"
msgstr ""
-#: includes/class-wc-subscriptions-synchroniser.php:674
#. translators: placeholder is a date
+#: includes/class-wc-subscriptions-synchroniser.php:677
msgid "First payment: %s"
msgstr ""
@@ -2101,27 +2804,27 @@ msgid "View and manage subscriptions"
msgstr ""
#: includes/class-wcs-cart-initial-payment.php:56
-#: includes/class-wcs-cart-renewal.php:129
+#: includes/class-wcs-cart-renewal.php:154
msgid "That doesn't appear to be your order."
msgstr ""
-#: includes/class-wcs-cart-renewal.php:157
+#: includes/class-wcs-cart-renewal.php:182
msgid "Complete checkout to renew your subscription."
msgstr ""
-#: includes/class-wcs-cart-renewal.php:196
#. translators: placeholder is an item name
+#: includes/class-wcs-cart-renewal.php:221
msgid ""
"The %s product has been deleted and can no longer be renewed. Please choose "
"a new product or contact us for assistance."
msgstr ""
-#: includes/class-wcs-cart-renewal.php:229
#. translators: %s is subscription's number
+#: includes/class-wcs-cart-renewal.php:254
msgid "Subscription #%s has not been added to the cart."
msgstr ""
-#: includes/class-wcs-cart-renewal.php:355
+#: includes/class-wcs-cart-renewal.php:382
msgid ""
"We couldn't find the original subscription for an item in your cart. The "
"item was removed."
@@ -2131,7 +2834,7 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: includes/class-wcs-cart-renewal.php:362
+#: includes/class-wcs-cart-renewal.php:389
msgid ""
"We couldn't find the original renewal order for an item in your cart. The "
"item was removed."
@@ -2141,10 +2844,17 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
-#: includes/class-wcs-cart-renewal.php:626
+#: includes/class-wcs-cart-renewal.php:663
msgid "All linked subscription items have been removed from the cart."
msgstr ""
+#: includes/class-wcs-cart-renewal.php:692
+msgctxt ""
+"Used in WooCommerce by removed item notification: \"_All linked subscription "
+"items were_ removed. Undo?\" Filter for item title."
+msgid "All linked subscription items were"
+msgstr ""
+
#: includes/class-wcs-cart-resubscribe.php:70
msgid "There was an error with your request to resubscribe. Please try again."
msgstr ""
@@ -2164,7 +2874,7 @@ msgstr ""
msgid "Complete checkout to resubscribe."
msgstr ""
-#: includes/class-wcs-cart-resubscribe.php:313
+#: includes/class-wcs-cart-resubscribe.php:314
msgid "Customer resubscribed in order #%s"
msgstr ""
@@ -2176,11 +2886,11 @@ msgstr ""
msgid "Limit subscription"
msgstr ""
-#: includes/class-wcs-limiter.php:48
#. translators: placeholders are opening and closing link tags
+#: includes/class-wcs-limiter.php:48
msgid ""
-"Only allow a customer to have one subscription to this product. %sLearn "
-"more%s."
+"Only allow a customer to have one subscription to this product. %sLearn more"
+"%s."
msgstr ""
#: includes/class-wcs-limiter.php:50
@@ -2195,33 +2905,86 @@ msgstr ""
msgid "Limit to one of any status"
msgstr ""
-#: includes/class-wcs-remove-item.php:106
+#: includes/class-wcs-query.php:92
+msgctxt "hash before order number"
+msgid "Subscription #%s"
+msgstr ""
+
+#: includes/class-wcs-remove-item.php:68
+msgctxt "hash before subscription ID"
+msgid "Subscription #%d does not exist."
+msgstr ""
+
+#. translators: 1$: product name, 2$: product id
+#: includes/class-wcs-remove-item.php:104
+msgctxt "used in order note"
+msgid "Customer added \"%1$s\" (Product ID: #%2$d) via the My Account page."
+msgstr ""
+
+#: includes/class-wcs-remove-item.php:107
msgid "Your request to undo your previous action was unsuccessful."
msgstr ""
-#: includes/class-wcs-remove-item.php:127
-#. translators: placeholders are 1$: item name, and, 2$: opening and, 3$:
-#. closing link tags
-msgid "You have successfully removed \"%1$s\" from your subscription. %2$sUndo?%3$s"
+#. translators: 1$: product name, 2$: product id
+#: includes/class-wcs-remove-item.php:125
+msgctxt "used in order note"
+msgid "Customer removed \"%1$s\" (Product ID: #%2$d) via the My Account page."
msgstr ""
-#: includes/class-wcs-remove-item.php:156
+#. translators: placeholders are 1$: item name, and, 2$: opening and, 3$:
+#. closing link tags
+#: includes/class-wcs-remove-item.php:128
+msgid ""
+"You have successfully removed \"%1$s\" from your subscription. %2$sUndo?%3$s"
+msgstr ""
+
+#: includes/class-wcs-remove-item.php:162
#: includes/class-wcs-user-change-status-handler.php:99
msgid "Security error. Please contact us if you need assistance."
msgstr ""
-#: includes/class-wcs-remove-item.php:160
+#: includes/class-wcs-remove-item.php:166
msgid "You cannot modify a subscription that does not belong to you."
msgstr ""
-#: includes/class-wcs-remove-item.php:164
+#: includes/class-wcs-remove-item.php:170
msgid "You cannot remove an item that does not exist. "
msgstr ""
-#: includes/class-wcs-remove-item.php:168
+#: includes/class-wcs-remove-item.php:174
msgid ""
-"The item was not removed because this Subscription's payment method does "
-"not support removing an item."
+"The item was not removed because this Subscription's payment method does not "
+"support removing an item."
+msgstr ""
+
+#: includes/class-wcs-retry-manager.php:120
+msgctxt "table heading"
+msgid "Renewal Payment Retry"
+msgstr ""
+
+#: includes/class-wcs-retry-manager.php:229
+msgctxt "used in order note as reason for why status changed"
+msgid "Retry rule applied:"
+msgstr ""
+
+#: includes/class-wcs-retry-manager.php:295
+msgctxt "used in order note as reason for why order status changed"
+msgid "Subscription renewal payment retry:"
+msgstr ""
+
+#: includes/class-wcs-retry-manager.php:299
+msgctxt "used in order note as reason for why subscription status changed"
+msgid "Subscription renewal payment retry:"
+msgstr ""
+
+#: includes/class-wcs-user-change-status-handler.php:56
+msgctxt "order note left on subscription after user action"
+msgid "Subscription reactivated by the subscriber from their account page."
+msgstr ""
+
+#: includes/class-wcs-user-change-status-handler.php:57
+msgctxt "Notice displayed to user confirming their action."
+msgid "Your subscription has been reactivated."
msgstr ""
#: includes/class-wcs-user-change-status-handler.php:60
@@ -2230,18 +2993,39 @@ msgid ""
"contact us if you need assistance."
msgstr ""
+#: includes/class-wcs-user-change-status-handler.php:66
+msgctxt "order note left on subscription after user action"
+msgid "Subscription put on hold by the subscriber from their account page."
+msgstr ""
+
+#: includes/class-wcs-user-change-status-handler.php:67
+msgctxt "Notice displayed to user confirming their action."
+msgid "Your subscription has been put on hold."
+msgstr ""
+
#: includes/class-wcs-user-change-status-handler.php:70
msgid ""
"You can not suspend that subscription - the suspension limit has been "
"reached. Please contact us if you need assistance."
msgstr ""
-#: includes/class-wcs-user-change-status-handler.php:95
-msgid "That subscription does not exist. Please contact us if you need assistance."
+#: includes/class-wcs-user-change-status-handler.php:75
+msgctxt "order note left on subscription after user action"
+msgid "Subscription cancelled by the subscriber from their account page."
+msgstr ""
+
+#: includes/class-wcs-user-change-status-handler.php:76
+msgctxt "Notice displayed to user confirming their action."
+msgid "Your subscription has been cancelled."
+msgstr ""
+
+#: includes/class-wcs-user-change-status-handler.php:95
+msgid ""
+"That subscription does not exist. Please contact us if you need assistance."
msgstr ""
-#: includes/class-wcs-user-change-status-handler.php:108
#. translators: placeholder is subscription's new status, translated
+#: includes/class-wcs-user-change-status-handler.php:108
msgid ""
"That subscription can not be changed to %s. Please contact us if you need "
"assistance."
@@ -2277,6 +3061,21 @@ msgstr ""
msgid "Subscription Cancelled"
msgstr ""
+#. translators: placeholder is {blogname}, a variable that will be substituted
+#. when email is sent out
+#: includes/emails/class-wcs-email-cancelled-subscription.php:32
+msgctxt "default email subject for cancelled emails sent to the admin"
+msgid "[%s] Subscription Cancelled"
+msgstr ""
+
+#: includes/emails/class-wcs-email-cancelled-subscription.php:126
+#: includes/emails/class-wcs-email-customer-renewal-invoice.php:181
+#: includes/emails/class-wcs-email-expired-subscription.php:124
+#: includes/emails/class-wcs-email-on-hold-subscription.php:124
+msgctxt "an email notification"
+msgid "Enable/Disable"
+msgstr ""
+
#: includes/emails/class-wcs-email-cancelled-subscription.php:128
#: includes/emails/class-wcs-email-customer-renewal-invoice.php:183
#: includes/emails/class-wcs-email-expired-subscription.php:126
@@ -2284,13 +3083,27 @@ msgstr ""
msgid "Enable this email notification"
msgstr ""
+#: includes/emails/class-wcs-email-cancelled-subscription.php:132
+#: includes/emails/class-wcs-email-expired-subscription.php:130
+#: includes/emails/class-wcs-email-on-hold-subscription.php:130
+msgctxt "of an email"
+msgid "Recipient(s)"
+msgstr ""
+
+#. translators: placeholder is admin email
#: includes/emails/class-wcs-email-cancelled-subscription.php:135
#: includes/emails/class-wcs-email-expired-subscription.php:133
#: includes/emails/class-wcs-email-on-hold-subscription.php:133
-#. translators: placeholder is admin email
msgid ""
-"Enter recipients (comma separated) for this email. Defaults to "
-"%s."
+"Enter recipients (comma separated) for this email. Defaults to %s"
+"code>."
+msgstr ""
+
+#: includes/emails/class-wcs-email-cancelled-subscription.php:140
+#: includes/emails/class-wcs-email-expired-subscription.php:138
+#: includes/emails/class-wcs-email-on-hold-subscription.php:138
+msgctxt "of an email"
+msgid "Subject"
msgstr ""
#: includes/emails/class-wcs-email-cancelled-subscription.php:142
@@ -2301,6 +3114,15 @@ msgid ""
"subject: %s."
msgstr ""
+#: includes/emails/class-wcs-email-cancelled-subscription.php:147
+#: includes/emails/class-wcs-email-expired-subscription.php:145
+#: includes/emails/class-wcs-email-on-hold-subscription.php:145
+msgctxt ""
+"Name the setting that controls the main heading contained within the email "
+"notification"
+msgid "Email Heading"
+msgstr ""
+
#: includes/emails/class-wcs-email-cancelled-subscription.php:149
#: includes/emails/class-wcs-email-expired-subscription.php:147
#: includes/emails/class-wcs-email-on-hold-subscription.php:147
@@ -2309,12 +3131,40 @@ msgid ""
"Leave blank to use the default heading: %s."
msgstr ""
+#: includes/emails/class-wcs-email-cancelled-subscription.php:154
+#: includes/emails/class-wcs-email-expired-subscription.php:152
+#: includes/emails/class-wcs-email-on-hold-subscription.php:152
+msgctxt "text, html or multipart"
+msgid "Email type"
+msgstr ""
+
#: includes/emails/class-wcs-email-cancelled-subscription.php:156
#: includes/emails/class-wcs-email-expired-subscription.php:154
#: includes/emails/class-wcs-email-on-hold-subscription.php:154
msgid "Choose which format of email to send."
msgstr ""
+#: includes/emails/class-wcs-email-cancelled-subscription.php:160
+#: includes/emails/class-wcs-email-expired-subscription.php:158
+#: includes/emails/class-wcs-email-on-hold-subscription.php:158
+msgctxt "email type"
+msgid "Plain text"
+msgstr ""
+
+#: includes/emails/class-wcs-email-cancelled-subscription.php:161
+#: includes/emails/class-wcs-email-expired-subscription.php:159
+#: includes/emails/class-wcs-email-on-hold-subscription.php:159
+msgctxt "email type"
+msgid "HTML"
+msgstr ""
+
+#: includes/emails/class-wcs-email-cancelled-subscription.php:162
+#: includes/emails/class-wcs-email-expired-subscription.php:160
+#: includes/emails/class-wcs-email-on-hold-subscription.php:160
+msgctxt "email type"
+msgid "Multipart"
+msgstr ""
+
#: includes/emails/class-wcs-email-customer-completed-renewal-order.php:25
msgid "Completed Renewal Order"
msgstr ""
@@ -2326,6 +3176,34 @@ msgid ""
"that renewal period has been shipped."
msgstr ""
+#: includes/emails/class-wcs-email-customer-completed-renewal-order.php:29
+msgctxt ""
+"Default email heading for email to customer on completed renewal order"
+msgid "Your renewal order is complete"
+msgstr ""
+
+#. translators: $1: {blogname}, $2: {order_date}, variables that will be
+#. substituted when email is sent out
+#: includes/emails/class-wcs-email-customer-completed-renewal-order.php:31
+msgctxt ""
+"Default email subject for email to customer on completed renewal order"
+msgid "Your %1$s renewal order from %2$s is complete"
+msgstr ""
+
+#: includes/emails/class-wcs-email-customer-completed-renewal-order.php:38
+msgctxt "Default email heading for email with downloadable files in it"
+msgid "Your subscription renewal order is complete - download your files"
+msgstr ""
+
+#. translators: $1: {blogname}, $2: {order_date}, variables will be substituted
+#. when email is sent out
+#: includes/emails/class-wcs-email-customer-completed-renewal-order.php:40
+msgctxt "Default email subject for email with downloadable files in it"
+msgid ""
+"Your %1$s subscription renewal order from %2$s is complete - download your "
+"files"
+msgstr ""
+
#: includes/emails/class-wcs-email-customer-completed-switch-order.php:26
msgid "Subscription Switch Complete"
msgstr ""
@@ -2350,8 +3228,8 @@ msgstr ""
#: includes/emails/class-wcs-email-customer-completed-switch-order.php:39
msgid ""
-"Your {blogname} subscription change from {order_date} is complete - "
-"download your files"
+"Your {blogname} subscription change from {order_date} is complete - download "
+"your files"
msgstr ""
#: includes/emails/class-wcs-email-customer-payment-retry.php:27
@@ -2402,9 +3280,9 @@ msgstr ""
msgid ""
"Sent to a customer when the subscription is due for renewal and the renewal "
"requires a manual payment, either because it uses manual renewals or the "
-"automatic recurring payment failed for the initial attempt and all "
-"automatic retries (if any). The email contains renewal order information "
-"and payment links."
+"automatic recurring payment failed for the initial attempt and all automatic "
+"retries (if any). The email contains renewal order information and payment "
+"links."
msgstr ""
#: includes/emails/class-wcs-email-customer-renewal-invoice.php:39
@@ -2420,13 +3298,21 @@ msgid "Expired Subscription"
msgstr ""
#: includes/emails/class-wcs-email-expired-subscription.php:28
-msgid "Expired Subscription emails are sent when a customer's subscription expires."
+msgid ""
+"Expired Subscription emails are sent when a customer's subscription expires."
msgstr ""
#: includes/emails/class-wcs-email-expired-subscription.php:30
msgid "Subscription Expired"
msgstr ""
+#. translators: placeholder is {blogname}, a variable that will be substituted
+#. when email is sent out
+#: includes/emails/class-wcs-email-expired-subscription.php:32
+msgctxt "default email subject for expired emails sent to the admin"
+msgid "[%s] Subscription Expired"
+msgstr ""
+
#: includes/emails/class-wcs-email-expired-subscription.php:59
#: includes/emails/class-wcs-email-on-hold-subscription.php:59
msgid "Subscription argument passed in is not an object."
@@ -2447,7 +3333,8 @@ msgid "New subscription renewal order"
msgstr ""
#: includes/emails/class-wcs-email-new-renewal-order.php:26
-msgid "[{blogname}] New subscription renewal order ({order_number}) - {order_date}"
+msgid ""
+"[{blogname}] New subscription renewal order ({order_number}) - {order_date}"
msgstr ""
#: includes/emails/class-wcs-email-new-switch-order.php:22
@@ -2479,6 +3366,13 @@ msgstr ""
msgid "Subscription Suspended"
msgstr ""
+#. translators: placeholder is {blogname}, a variable that will be substituted
+#. when email is sent out
+#: includes/emails/class-wcs-email-on-hold-subscription.php:32
+msgctxt "default email subject for suspended emails sent to the admin"
+msgid "[%s] Subscription Suspended"
+msgstr ""
+
#: includes/emails/class-wcs-email-payment-retry.php:26
msgid "Payment Retry"
msgstr ""
@@ -2512,22 +3406,38 @@ msgid "Unable to find order for PayPal billing agreement."
msgstr ""
#: includes/gateways/paypal/class-wcs-paypal.php:261
-msgid "An error occurred, please try again or try an alternate form of payment."
+msgid ""
+"An error occurred, please try again or try an alternate form of payment."
+msgstr ""
+
+#. translators: placeholder is for blog name
+#: includes/gateways/paypal/class-wcs-paypal.php:344
+#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:208
+#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:316
+#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:327
+#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:355
+#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:367
+#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:139
+#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:142
+msgctxt ""
+"hash before the order number. Used as a character to remove from the actual "
+"order number"
+msgid "#"
msgstr ""
-#: includes/gateways/paypal/class-wcs-paypal.php:368
#. translators: placeholders are PayPal API error code and PayPal API error
#. message
+#: includes/gateways/paypal/class-wcs-paypal.php:368
msgid "PayPal API error: (%d) %s"
msgstr ""
-#: includes/gateways/paypal/class-wcs-paypal.php:373
#. translators: placeholder is PayPal transaction status message
+#: includes/gateways/paypal/class-wcs-paypal.php:373
msgid "PayPal Transaction Held: %s"
msgstr ""
-#: includes/gateways/paypal/class-wcs-paypal.php:385
#. translators: placeholder is PayPal transaction status message
+#: includes/gateways/paypal/class-wcs-paypal.php:385
msgid "PayPal payment declined: %s"
msgstr ""
@@ -2542,6 +3452,13 @@ msgid ""
"This will suspend the subscription at PayPal."
msgstr ""
+#: includes/gateways/paypal/class-wcs-paypal.php:556
+msgctxt ""
+"used in User Agent data sent to PayPal to help identify where a payment came "
+"from"
+msgid "WooCommerce Subscriptions PayPal"
+msgstr ""
+
#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:56
msgid ""
"It is strongly recommended you do not change the Receiver Email "
@@ -2549,18 +3466,18 @@ msgid ""
"break existing subscriptions."
msgstr ""
-#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:109
#. translators: placeholders are opening and closing link tags. 1$-2$: to docs
#. on woocommerce, 3$-4$ to gateway settings on the site
+#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:109
msgid ""
"PayPal is inactive for subscription transactions. Please %1$sset up the "
"PayPal IPN%2$s and %3$senter your API credentials%4$s to enable PayPal for "
"Subscriptions."
msgstr ""
-#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:122
#. translators: placeholders are opening and closing strong and link tags.
#. 1$-2$: strong tags, 3$-8$ link to docs on woocommerce
+#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:122
msgid ""
"%1$sPayPal Reference Transactions are not enabled on your account%2$s, some "
"subscription management features are not enabled. Please contact PayPal and "
@@ -2568,24 +3485,24 @@ msgid ""
"%5$sCheck PayPal Account%6$s %7$sLearn more %8$s"
msgstr ""
-#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:140
#. translators: placeholders are opening and closing strong tags.
+#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:140
msgid ""
"%1$sPayPal Reference Transactions are enabled on your account%2$s. All "
"subscription management features are now enabled. Happy selling!"
msgstr ""
-#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:151
#. translators: placeholders are link opening and closing tags. 1$-2$: to
#. gateway settings, 3$-4$: support docs on woocommerce.com
+#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:151
msgid ""
"There is a problem with PayPal. Your API credentials may be incorrect. "
"Please update your %1$sAPI credentials%2$s. %3$sLearn more%4$s."
msgstr ""
-#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:164
#. translators: placeholders are opening and closing link tags. 1$-2$: docs on
#. woocommerce, 3$-4$: dismiss link
+#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:164
msgid ""
"There is a problem with PayPal. Your PayPal account is issuing out-of-date "
"subscription IDs. %1$sLearn more%2$s. %3$sDismiss%4$s."
@@ -2594,10 +3511,10 @@ msgstr ""
#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:178
msgid ""
"%sA fatal error has occurred when processing a recent subscription payment "
-"with PayPal. Please %sopen a new ticket at WooCommerce Support%s "
-"immediately to get this resolved.%sIn order to get the quickest possible "
-"response please attach a %sTemporary Admin Login%s and a copy of your PHP "
-"error logs to your support ticket.%sLast recorded error: %s"
+"with PayPal. Please %sopen a new ticket at WooCommerce Support%s immediately "
+"to get this resolved.%sIn order to get the quickest possible response please "
+"attach a %sTemporary Admin Login%s and a copy of your PHP error logs to your "
+"support ticket.%sLast recorded error: %s"
msgstr ""
#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:186
@@ -2612,28 +3529,65 @@ msgstr ""
msgid "PayPal Subscription ID:"
msgstr ""
+#. translators: placeholder is blogname
+#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:71
+msgctxt "data sent to paypal"
+msgid "Orders with %s"
+msgstr ""
+
#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:274
msgid "Total Discount"
msgstr ""
-#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:302
#. translators: placeholder is blogname
+#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:302
msgid "%s - Order"
msgstr ""
-#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:513
+#. translators: 1$: new status (e.g. "Cancel"), 2$: blog name
+#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:398
+msgctxt "data sent to paypal"
+msgid "%1$s subscription event triggered at %2$s"
+msgstr ""
+
+#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:518
msgid "SKU: %s"
msgstr ""
-#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response-payment.php:119
#. translators: placeholder is localised datetime
+#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response-payment.php:119
msgid "expected clearing date %s"
msgstr ""
+#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:136
+msgctxt "used in api error message if there is no severity code from PayPal"
+msgid "Error"
+msgstr ""
+
+#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:138
+msgctxt "used in api error message if there is no long message"
+msgid "Unknown error"
+msgstr ""
+
+#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:150
+#: templates/admin/deprecated/order-shipping-html.php:14
+#: templates/admin/deprecated/order-tax-html.php:9
+msgctxt "no information about something"
+msgid "N/A"
+msgstr ""
+
#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-ipn-handler.php:114
msgid "Billing agreement cancelled at PayPal."
msgstr ""
+#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:255
+msgctxt ""
+"when it is a payment change, and there is a subscr_signup message, this will "
+"be a confirmation message that PayPal accepted it being the new payment "
+"method"
+msgid "IPN subscription payment method changed to PayPal."
+msgstr ""
+
#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:259
msgid "IPN subscription sign up completed."
msgstr ""
@@ -2647,6 +3601,19 @@ msgstr ""
msgid "IPN subscription failing payment method changed."
msgstr ""
+#. translators: placeholder is payment status (e.g. "completed")
+#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:389
+#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:398
+msgctxt "used in order note"
+msgid "IPN subscription payment %s."
+msgstr ""
+
+#. translators: placeholder is payment status (e.g. "completed")
+#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:402
+msgctxt "used in order note"
+msgid "IPN subscription payment %s for reason: %s."
+msgstr ""
+
#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:428
msgid "IPN subscription suspended."
msgstr ""
@@ -2659,6 +3626,13 @@ msgstr ""
msgid "IPN subscription payment failure."
msgstr ""
+#. translators: 1$: subscription ID, 2$: order ID, 3$: names of items, comma
+#. separated
+#: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:74
+msgctxt "item name sent to paypal"
+msgid "Subscription %1$s (Order %2$s) - %3$s"
+msgstr ""
+
#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:42
msgid "Subscription cancelled with PayPal"
msgstr ""
@@ -2675,6 +3649,435 @@ msgstr ""
msgid "PayPal API error - credentials are incorrect."
msgstr ""
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:79
+#: tmp/old/wordpress/wp-admin/includes/ajax-actions.php:1782
+#: tmp/old/wordpress/wp-admin/includes/class-wp-posts-list-table.php:995
+#: tmp/old/wordpress/wp-admin/includes/class-wp-posts-list-table.php:1632
+#: tmp/old/wordpress/wp-admin/includes/meta-boxes.php:85
+#: tmp/old/wordpress/wp-admin/includes/meta-boxes.php:108
+#: tmp/old/wordpress/wp-includes/post.php:691
+#: tmp/old/wordpress/wp-includes/post.php:711
+#: tmp/old/wordpress/wp-includes/script-loader.php:573
+#: tmp/wordpress/wp-admin/includes/ajax-actions.php:1782
+#: tmp/wordpress/wp-admin/includes/class-wp-posts-list-table.php:995
+#: tmp/wordpress/wp-admin/includes/class-wp-posts-list-table.php:1632
+#: tmp/wordpress/wp-admin/includes/meta-boxes.php:85
+#: tmp/wordpress/wp-admin/includes/meta-boxes.php:108
+#: tmp/wordpress/wp-includes/post.php:691
+#: tmp/wordpress/wp-includes/post.php:711
+#: tmp/wordpress/wp-includes/script-loader.php:573
+msgid "Published"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:79
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:178
+msgid "Complete"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:117
+msgid "Hook"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:119
+msgid "Arguments"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:120
+msgid "Group"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:121
+msgid "Recurrence"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:122
+msgid "Scheduled Date"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:127
+msgid "Started"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:129
+msgid "Completed"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:133
+msgid "Claim ID"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:134
+msgid "Log"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:195
+msgid "Non-repeating"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:201
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:210
+msgid " (%s ago)"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:242
+msgid "Process the action now as if it were run as part of a queue"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:242
+msgid "Run"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:320
+msgid ""
+"Maximum simulatenous batches already in progress (%s queues). No actions "
+"will be processed until the current batches are complete."
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:329
+msgid "Successfully executed the action: %s"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:333
+msgid "Could not execute the action: %s"
+msgstr ""
+
+#. translators: Time difference between two dates, in years. 1: Number of years
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:355
+#: includes/wcs-time-functions.php:57
+#: tmp/old/wordpress/wp-includes/formatting.php:3257
+#: tmp/wordpress/wp-includes/formatting.php:3257
+msgid "%s year"
+msgid_plural "%s years"
+msgstr[0] ""
+msgstr[1] ""
+
+#. translators: Time difference between two dates, in months. 1: Number of
+#. months
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:356
+#: includes/wcs-time-functions.php:56
+#: tmp/old/wordpress/wp-includes/formatting.php:3251
+#: tmp/wordpress/wp-includes/formatting.php:3251
+msgid "%s month"
+msgid_plural "%s months"
+msgstr[0] ""
+msgstr[1] ""
+
+#. translators: Time difference between two dates, in weeks. 1: Number of weeks
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:357
+#: includes/wcs-time-functions.php:55
+#: tmp/old/wordpress/wp-includes/formatting.php:3245
+#: tmp/wordpress/wp-includes/formatting.php:3245
+msgid "%s week"
+msgid_plural "%s weeks"
+msgstr[0] ""
+msgstr[1] ""
+
+#. translators: Time difference between two dates, in days. 1: Number of days
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:358
+#: includes/wcs-time-functions.php:54
+#: tmp/old/wordpress/wp-includes/formatting.php:3239
+#: tmp/wordpress/wp-includes/formatting.php:3239
+msgid "%s day"
+msgid_plural "%s days"
+msgstr[0] ""
+msgstr[1] ""
+
+#. translators: Time difference between two dates, in hours. 1: Number of hours
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:359
+#: tmp/old/wordpress/wp-includes/formatting.php:3233
+#: tmp/wordpress/wp-includes/formatting.php:3233
+msgid "%s hour"
+msgid_plural "%s hours"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:360
+msgid "%s minute"
+msgid_plural "%s minutes"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:361
+msgid "%s second"
+msgid_plural "%s seconds"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:365
+msgid "Now!"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:452
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:455
+msgid "Action updated."
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:456
+msgid "Action restored to revision from %s"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:457
+msgid "Action scheduled."
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:458
+msgid "Action saved."
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:459
+msgid "Action submitted."
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:460
+msgid "Action scheduled for: %1$s"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:460
+msgid "M j, Y @ G:i"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_AdminView.php:461
+msgid "Action draft updated."
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_QueueRunner.php:136
+msgid "Every minute"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpCommentLogger.php:246
+msgid "action created"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpCommentLogger.php:250
+msgid "action canceled"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpCommentLogger.php:254
+msgid "action started"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpCommentLogger.php:258
+msgid "action complete"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpCommentLogger.php:262
+msgid "action failed: %s"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpCommentLogger.php:266
+msgid "action timed out after %s seconds"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpCommentLogger.php:271
+msgid "unexpected shutdown: PHP Fatal error %s in %s on line %s"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpCommentLogger.php:276
+msgid "action reset"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore.php:23
+msgid "Error saving action: %s"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore.php:42
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore.php:51
+msgid "Invalid schedule. Cannot save action."
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore.php:67
+msgid "Unable to save action."
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore.php:317
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore.php:326
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore.php:352
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore.php:487
+msgid "Unidentified action %s"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore.php:408
+msgid "Unable to claim actions. Database error."
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore.php:438
+msgid "Unable to unlock claim %s. Database error."
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore.php:454
+msgid "Unable to unlock claim on action %s. Database error."
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore.php:465
+msgid "Unable to mark failure on action %s. Database error."
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostStatusRegistrar.php:36
+msgctxt "post"
+msgid "Failed"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostStatusRegistrar.php:37
+msgid "Failed (%s)"
+msgid_plural "Failed (%s)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostStatusRegistrar.php:50
+msgctxt "post"
+msgid "In-Progress"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostStatusRegistrar.php:51
+msgid "In-Progress (%s)"
+msgid_plural "In-Progress (%s)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:19
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:30
+msgid "Scheduled Actions"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:20
+msgid "Scheduled actions are hooks triggered on a cetain date and time."
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:31
+msgid "Scheduled Action"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:32
+msgctxt "Admin menu name"
+msgid "Scheduled Actions"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:33
+#: includes/payment-retry/class-wcs-retry-post-store.php:36
+#: tmp/old/wordpress/wp-admin/includes/class-wp-press-this.php:905
+#: tmp/old/wordpress/wp-admin/includes/class-wp-press-this.php:954
+#: tmp/old/wordpress/wp-admin/includes/meta-boxes.php:443
+#: tmp/old/wordpress/wp-admin/includes/meta-boxes.php:979
+#: tmp/old/wordpress/wp-includes/class-wp-customize-control.php:598
+#: tmp/old/wordpress/wp-includes/class-wp-customize-nav-menus.php:1032
+#: tmp/wordpress/wp-admin/includes/class-wp-press-this.php:905
+#: tmp/wordpress/wp-admin/includes/class-wp-press-this.php:954
+#: tmp/wordpress/wp-admin/includes/meta-boxes.php:443
+#: tmp/wordpress/wp-admin/includes/meta-boxes.php:979
+#: tmp/wordpress/wp-includes/class-wp-customize-control.php:598
+#: tmp/wordpress/wp-includes/class-wp-customize-nav-menus.php:1032
+msgid "Add"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:34
+msgid "Add New Scheduled Action"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:35
+#: includes/payment-retry/class-wcs-retry-post-store.php:38
+#: tmp/old/wordpress/wp-admin/comment.php:216
+#: tmp/old/wordpress/wp-admin/edit-form-comment.php:102
+#: tmp/old/wordpress/wp-admin/includes/class-walker-nav-menu-edit.php:148
+#: tmp/old/wordpress/wp-admin/includes/class-wp-comments-list-table.php:584
+#: tmp/old/wordpress/wp-admin/includes/class-wp-links-list-table.php:329
+#: tmp/old/wordpress/wp-admin/includes/class-wp-media-list-table.php:656
+#: tmp/old/wordpress/wp-admin/includes/class-wp-media-list-table.php:705
+#: tmp/old/wordpress/wp-admin/includes/class-wp-ms-sites-list-table.php:519
+#: tmp/old/wordpress/wp-admin/includes/class-wp-ms-themes-list-table.php:462
+#: tmp/old/wordpress/wp-admin/includes/class-wp-ms-users-list-table.php:335
+#: tmp/old/wordpress/wp-admin/includes/class-wp-ms-users-list-table.php:442
+#: tmp/old/wordpress/wp-admin/includes/class-wp-plugins-list-table.php:642
+#: tmp/old/wordpress/wp-admin/includes/class-wp-posts-list-table.php:399
+#: tmp/old/wordpress/wp-admin/includes/class-wp-posts-list-table.php:1230
+#: tmp/old/wordpress/wp-admin/includes/class-wp-terms-list-table.php:443
+#: tmp/old/wordpress/wp-admin/includes/class-wp-users-list-table.php:406
+#: tmp/old/wordpress/wp-admin/includes/dashboard.php:634
+#: tmp/old/wordpress/wp-admin/includes/meta-boxes.php:101
+#: tmp/old/wordpress/wp-admin/includes/meta-boxes.php:148
+#: tmp/old/wordpress/wp-admin/includes/meta-boxes.php:212
+#: tmp/old/wordpress/wp-admin/includes/post.php:1351
+#: tmp/old/wordpress/wp-content/themes/twentyfifteen/content-link.php:56
+#: tmp/old/wordpress/wp-content/themes/twentyfifteen/content-page.php:35
+#: tmp/old/wordpress/wp-content/themes/twentyfifteen/content-search.php:28
+#: tmp/old/wordpress/wp-content/themes/twentyfifteen/content-search.php:33
+#: tmp/old/wordpress/wp-content/themes/twentyfifteen/content.php:57
+#: tmp/old/wordpress/wp-content/themes/twentyfifteen/image.php:71
+#: tmp/old/wordpress/wp-content/themes/twentyfourteen/content-aside.php:40
+#: tmp/old/wordpress/wp-content/themes/twentyfourteen/content-audio.php:40
+#: tmp/old/wordpress/wp-content/themes/twentyfourteen/content-gallery.php:40
+#: tmp/old/wordpress/wp-content/themes/twentyfourteen/content-image.php:40
+#: tmp/old/wordpress/wp-content/themes/twentyfourteen/content-link.php:40
+#: tmp/old/wordpress/wp-content/themes/twentyfourteen/content-page.php:28
+#: tmp/old/wordpress/wp-content/themes/twentyfourteen/content-quote.php:40
+#: tmp/old/wordpress/wp-content/themes/twentyfourteen/content-video.php:40
+#: tmp/old/wordpress/wp-content/themes/twentyfourteen/content.php:42
+#: tmp/old/wordpress/wp-content/themes/twentyfourteen/image.php:34
+#: tmp/old/wordpress/wp-content/themes/twentyfourteen/page-templates/contributors.php:35
+#: tmp/old/wordpress/wp-includes/class-walker-comment.php:244
+#: tmp/old/wordpress/wp-includes/class-walker-comment.php:350
+#: tmp/old/wordpress/wp-includes/class-wp-editor.php:1055
+#: tmp/wordpress/wp-admin/comment.php:216
+#: tmp/wordpress/wp-admin/edit-form-comment.php:102
+#: tmp/wordpress/wp-admin/includes/class-walker-nav-menu-edit.php:148
+#: tmp/wordpress/wp-admin/includes/class-wp-comments-list-table.php:584
+#: tmp/wordpress/wp-admin/includes/class-wp-links-list-table.php:329
+#: tmp/wordpress/wp-admin/includes/class-wp-media-list-table.php:656
+#: tmp/wordpress/wp-admin/includes/class-wp-media-list-table.php:705
+#: tmp/wordpress/wp-admin/includes/class-wp-ms-sites-list-table.php:519
+#: tmp/wordpress/wp-admin/includes/class-wp-ms-themes-list-table.php:462
+#: tmp/wordpress/wp-admin/includes/class-wp-ms-users-list-table.php:335
+#: tmp/wordpress/wp-admin/includes/class-wp-ms-users-list-table.php:442
+#: tmp/wordpress/wp-admin/includes/class-wp-plugins-list-table.php:642
+#: tmp/wordpress/wp-admin/includes/class-wp-posts-list-table.php:399
+#: tmp/wordpress/wp-admin/includes/class-wp-posts-list-table.php:1230
+#: tmp/wordpress/wp-admin/includes/class-wp-terms-list-table.php:443
+#: tmp/wordpress/wp-admin/includes/class-wp-users-list-table.php:406
+#: tmp/wordpress/wp-admin/includes/dashboard.php:634
+#: tmp/wordpress/wp-admin/includes/meta-boxes.php:101
+#: tmp/wordpress/wp-admin/includes/meta-boxes.php:148
+#: tmp/wordpress/wp-admin/includes/meta-boxes.php:212
+#: tmp/wordpress/wp-admin/includes/post.php:1351
+#: tmp/wordpress/wp-content/themes/twentyfifteen/content-link.php:56
+#: tmp/wordpress/wp-content/themes/twentyfifteen/content-page.php:35
+#: tmp/wordpress/wp-content/themes/twentyfifteen/content-search.php:28
+#: tmp/wordpress/wp-content/themes/twentyfifteen/content-search.php:33
+#: tmp/wordpress/wp-content/themes/twentyfifteen/content.php:57
+#: tmp/wordpress/wp-content/themes/twentyfifteen/image.php:71
+#: tmp/wordpress/wp-includes/class-walker-comment.php:244
+#: tmp/wordpress/wp-includes/class-walker-comment.php:350
+#: tmp/wordpress/wp-includes/class-wp-editor.php:1055
+msgid "Edit"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:36
+msgid "Edit Scheduled Action"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:37
+msgid "New Scheduled Action"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:38
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:39
+msgid "View Action"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:40
+msgid "Search Scheduled Actions"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:41
+msgid "No actions found"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:42
+msgid "No actions found in trash"
+msgstr ""
+
+#: includes/libraries/action-scheduler/classes/ActionScheduler_wpPostStore_TaxonomyRegistrar.php:14
+msgid "Action Group"
+msgstr ""
+
#: includes/payment-retry/class-wcs-retry-admin.php:46
msgid "Automatic Failed Payment Retries"
msgstr ""
@@ -2729,22 +4132,24 @@ msgid ""
"renewal payments."
msgstr ""
+#: includes/payment-retry/class-wcs-retry-post-store.php:33
+msgctxt "Post type name"
+msgid "Renewal Payment Retries"
+msgstr ""
+
#: includes/payment-retry/class-wcs-retry-post-store.php:34
msgid "Renewal Payment Retry"
msgstr ""
-#: includes/payment-retry/class-wcs-retry-post-store.php:36
-msgid "Add"
+#: includes/payment-retry/class-wcs-retry-post-store.php:35
+msgctxt "Admin menu name"
+msgid "Renewal Payment Retries"
msgstr ""
#: includes/payment-retry/class-wcs-retry-post-store.php:37
msgid "Add New Retry"
msgstr ""
-#: includes/payment-retry/class-wcs-retry-post-store.php:38
-msgid "Edit"
-msgstr ""
-
#: includes/payment-retry/class-wcs-retry-post-store.php:39
msgid "Edit Retry"
msgstr ""
@@ -2770,31 +4175,87 @@ msgstr ""
msgid "No retries found in trash"
msgstr ""
-#: includes/upgrades/class-wc-subscriptions-upgrader.php:276
#. translators: placeholder is a list of version numbers (e.g. "1.3 & 1.4 &
#. 1.5")
+#: includes/upgrades/class-wc-subscriptions-upgrader.php:276
msgid "Database updated to version %s"
msgstr ""
-#: includes/upgrades/class-wc-subscriptions-upgrader.php:299
+#. translators: placeholder is number of upgraded subscriptions
+#: includes/upgrades/class-wc-subscriptions-upgrader.php:287
+msgctxt "used in the subscriptions upgrader"
+msgid "Marked %s subscription products as \"sold individually\"."
+msgstr ""
+
#. translators: 1$: number of action scheduler hooks upgraded, 2$:
#. "{execution_time}", will be replaced on front end with actual time
+#: includes/upgrades/class-wc-subscriptions-upgrader.php:299
msgid ""
"Migrated %1$s subscription related hooks to the new scheduler (in %2$s "
"seconds)."
msgstr ""
-#: includes/upgrades/class-wc-subscriptions-upgrader.php:315
#. translators: 1$: number of subscriptions upgraded, 2$: "{execution_time}",
#. will be replaced on front end with actual time it took
+#: includes/upgrades/class-wc-subscriptions-upgrader.php:315
msgid "Migrated %1$s subscriptions to the new structure (in %2$s seconds)."
msgstr ""
-#: includes/upgrades/class-wc-subscriptions-upgrader.php:328
+#. translators: placeholder is "{time_left}", will be replaced on front end
+#. with actual time
+#: includes/upgrades/class-wc-subscriptions-upgrader.php:318
+#: includes/upgrades/class-wc-subscriptions-upgrader.php:368
+msgctxt "Message that gets sent to front end."
+msgid "Estimated time left (minutes:seconds): %s"
+msgstr ""
+
#. translators: 1$: error message, 2$: opening link tag, 3$: closing link tag
+#: includes/upgrades/class-wc-subscriptions-upgrader.php:328
msgid ""
-"Unable to upgrade subscriptions. Error: %1$s Please refresh the "
-"page and try again. If problem persists, %2$scontact support%3$s."
+"Unable to upgrade subscriptions. Error: %1$s Please refresh the page "
+"and try again. If problem persists, %2$scontact support%3$s."
+msgstr ""
+
+#. translators: placeholder is the number of subscriptions repaired
+#: includes/upgrades/class-wc-subscriptions-upgrader.php:347
+msgctxt "Repair message that gets sent to front end."
+msgid ""
+"Repaired %d subscriptions with incorrect dates, line tax data or missing "
+"customer notes."
+msgstr ""
+
+#. translators: placeholder is number of subscriptions that were checked and
+#. did not need repairs. There's a space at the beginning!
+#: includes/upgrades/class-wc-subscriptions-upgrader.php:353
+msgctxt "Repair message that gets sent to front end."
+msgid " %d other subscription was checked and did not need any repairs."
+msgid_plural ""
+"%d other subscriptions were checked and did not need any repairs."
+msgstr[0] ""
+msgstr[1] ""
+
+#. translators: placeholder is "{execution_time}", which will be replaced on
+#. front end with actual time
+#: includes/upgrades/class-wc-subscriptions-upgrader.php:357
+msgctxt "Repair message that gets sent to front end."
+msgid "(in %s seconds)"
+msgstr ""
+
+#. translators: $1: "Repaired x subs with incorrect dates...", $2: "X others
+#. were checked and no repair needed", $3: "(in X seconds)". Ordering for RTL
+#. languages.
+#: includes/upgrades/class-wc-subscriptions-upgrader.php:360
+msgctxt "The assembled repair message that gets sent to front end."
+msgid "%1$s%2$s %3$s"
+msgstr ""
+
+#. translators: 1$: error message, 2$: opening link tag, 3$: closing link tag
+#: includes/upgrades/class-wc-subscriptions-upgrader.php:379
+msgctxt ""
+"Error message that gets sent to front end when upgrading Subscriptions"
+msgid ""
+"Unable to repair subscriptions. Error: %1$s Please refresh the page "
+"and try again. If problem persists, %2$scontact support%3$s."
msgstr ""
#: includes/upgrades/class-wc-subscriptions-upgrader.php:583
@@ -2811,7 +4272,8 @@ msgstr ""
#: includes/upgrades/templates/wcs-about-2-0.php:23
#: includes/upgrades/templates/wcs-about.php:22
-msgid "Thank you for updating to the latest version of WooCommerce Subscriptions."
+msgid ""
+"Thank you for updating to the latest version of WooCommerce Subscriptions."
msgstr ""
#: includes/upgrades/templates/wcs-about-2-0.php:24
@@ -2825,12 +4287,36 @@ msgstr ""
msgid "We hope you enjoy it!"
msgstr ""
+#. translators: placeholder is version number
+#. translators: %s: Plugin version
#: includes/upgrades/templates/wcs-about-2-0.php:31
#: includes/upgrades/templates/wcs-about.php:30
-#. translators: placeholder is version number
+#: tmp/old/wordpress/wp-admin/about.php:38
+#: tmp/old/wordpress/wp-admin/credits.php:25
+#: tmp/old/wordpress/wp-admin/freedoms.php:24
+#: tmp/old/wordpress/wp-admin/includes/ajax-actions.php:3683
+#: tmp/old/wordpress/wp-admin/includes/ajax-actions.php:3726
+#: tmp/old/wordpress/wp-admin/includes/class-wp-ms-themes-list-table.php:562
+#: tmp/old/wordpress/wp-admin/includes/class-wp-plugins-list-table.php:773
+#: tmp/old/wordpress/wp-admin/includes/update.php:193
+#: tmp/old/wordpress/wp-admin/includes/update.php:218
+#: tmp/wordpress/wp-admin/about.php:38 tmp/wordpress/wp-admin/credits.php:25
+#: tmp/wordpress/wp-admin/freedoms.php:24
+#: tmp/wordpress/wp-admin/includes/ajax-actions.php:3683
+#: tmp/wordpress/wp-admin/includes/ajax-actions.php:3726
+#: tmp/wordpress/wp-admin/includes/class-wp-ms-themes-list-table.php:562
+#: tmp/wordpress/wp-admin/includes/class-wp-plugins-list-table.php:773
+#: tmp/wordpress/wp-admin/includes/update.php:193
+#: tmp/wordpress/wp-admin/includes/update.php:218
msgid "Version %s"
msgstr ""
+#: includes/upgrades/templates/wcs-about-2-0.php:36
+#: woocommerce-subscriptions.php:992
+msgctxt "short for documents"
+msgid "Docs"
+msgstr ""
+
#: includes/upgrades/templates/wcs-about-2-0.php:42
#: includes/upgrades/templates/wcs-about.php:41
msgid "Check Out What's New"
@@ -2851,8 +4337,8 @@ msgid ""
"of sign-up fees and/or free trials."
msgstr ""
-#: includes/upgrades/templates/wcs-about-2-0.php:56
#. translators: placeholders are opening and closing link tags
+#: includes/upgrades/templates/wcs-about-2-0.php:56
msgid "Learn more about the new %smultiple subscriptions%s feature."
msgstr ""
@@ -2869,28 +4355,26 @@ msgid ""
"adding a product line item."
msgstr ""
-#: includes/upgrades/templates/wcs-about-2-0.php:72
#. translators: placeholders are opening and closing tags
+#: includes/upgrades/templates/wcs-about-2-0.php:72
msgid ""
"The new interface is also built on the existing %sEdit Order%s screen. If "
-"you've ever modified an order, you already know how to modify a "
-"subscription."
+"you've ever modified an order, you already know how to modify a subscription."
msgstr ""
-#: includes/upgrades/templates/wcs-about-2-0.php:76
#. translators: placeholers are link tags: 1$-2$ new subscription page, 3$-4$:
#. docs on woocommerce.com
+#: includes/upgrades/templates/wcs-about-2-0.php:76
msgid ""
-"%1$sAdd a subscription%2$s now or %3$slearn more%4$s about the new "
-"interface."
+"%1$sAdd a subscription%2$s now or %3$slearn more%4$s about the new interface."
msgstr ""
#: includes/upgrades/templates/wcs-about-2-0.php:87
msgid "New View Subscription Page"
msgstr ""
-#: includes/upgrades/templates/wcs-about-2-0.php:91
#. translators: placeholders are opening and closing tags
+#: includes/upgrades/templates/wcs-about-2-0.php:91
msgid ""
"Your customers can now view the full details of a subscription, including "
"line items, billing and shipping address, billing schedule and renewal "
@@ -2900,17 +4384,17 @@ msgstr ""
#: includes/upgrades/templates/wcs-about-2-0.php:93
msgid ""
"This new page is also where the customer can suspend or cancel their "
-"subscription, change payment method, change shipping address or "
-"upgrade/downgrade an item."
+"subscription, change payment method, change shipping address or upgrade/"
+"downgrade an item."
msgstr ""
-#: includes/upgrades/templates/wcs-about-2-0.php:97
#. translators: placeholders are opening and closing link tags
+#: includes/upgrades/templates/wcs-about-2-0.php:97
msgid "Learn more about the new %sView Subscription page%s."
msgstr ""
-#: includes/upgrades/templates/wcs-about-2-0.php:111
#. translators: placeholders are for opening and closing link () tags
+#: includes/upgrades/templates/wcs-about-2-0.php:111
msgid ""
"By default, adding new files to an existing subscription product will "
"automatically provide active subscribers with access to the new files. "
@@ -2918,6 +4402,12 @@ msgid ""
"subscribers with access to new files only after the next renewal payment."
msgstr ""
+#. translators: placeholders are for opening and closing link () tags
+#. translators: placeholders are for opening and closing link () tags
+#. translators: placeholders are opening and closing anchor tags linking to
+#. documentation
+#. translators: placeholders are opening and closing anchor tags linking to
+#. documentation
#: includes/upgrades/templates/wcs-about-2-0.php:115
#: includes/upgrades/templates/wcs-about-2-0.php:128
#: includes/upgrades/templates/wcs-about-2-0.php:141
@@ -2926,17 +4416,16 @@ msgstr ""
#: includes/upgrades/templates/wcs-about.php:142
#: includes/upgrades/templates/wcs-about.php:170
#: includes/upgrades/templates/wcs-about.php:191
-#. translators: placeholders are for opening and closing link () tags
-#. translators: placeholders are for opening and closing link () tags
-#. translators: placeholders are opening and closing anchor tags linking to
-#. documentation
-#. translators: placeholders are opening and closing anchor tags linking to
-#. documentation
msgid "%sLearn more »%s"
msgstr ""
-#: includes/upgrades/templates/wcs-about-2-0.php:124
+#: includes/upgrades/templates/wcs-about-2-0.php:121
+msgctxt "h3 on the About Subscriptions page for this new feature"
+msgid "Change Payment Method"
+msgstr ""
+
#. translators: placeholders are opening and closing tags
+#: includes/upgrades/templates/wcs-about-2-0.php:124
msgid ""
"For a store manager to change a subscription from automatic to manual "
"renewal payments (or manual to automatic) with Subscriptions v1.5, the "
@@ -2949,13 +4438,13 @@ msgstr ""
msgid "Change Trial and End Dates"
msgstr ""
-#: includes/upgrades/templates/wcs-about-2-0.php:137
#. translators: placeholders are opening and closing tags
+#: includes/upgrades/templates/wcs-about-2-0.php:137
msgid ""
"It was already possible to change a subscription's next payment date, but "
-"some store managers wanted to provide a customer with an extended free "
-"trial or add an extra month to the expiration date. Now you can change all "
-"of these dates from the %sEdit Subscription%s screen."
+"some store managers wanted to provide a customer with an extended free trial "
+"or add an extra month to the expiration date. Now you can change all of "
+"these dates from the %sEdit Subscription%s screen."
msgstr ""
#: includes/upgrades/templates/wcs-about-2-0.php:150
@@ -2973,8 +4462,8 @@ msgid ""
"Custom Order Types API."
msgstr ""
-#: includes/upgrades/templates/wcs-about-2-0.php:164
#. translators: placeholders are opening and closing code tags
+#: includes/upgrades/templates/wcs-about-2-0.php:164
msgid "New %sshop_subscription%s Post Type"
msgstr ""
@@ -2985,32 +4474,32 @@ msgid ""
"database schema that is as scalable as WordPress posts and pages."
msgstr ""
-#: includes/upgrades/templates/wcs-about-2-0.php:169
#. translators: placeholders are opening and closing tags
+#: includes/upgrades/templates/wcs-about-2-0.php:169
msgid ""
"Developers can also now use all the familiar WordPress functions, like "
"%sget_posts()%s, to query or modify subscription data."
msgstr ""
-#: includes/upgrades/templates/wcs-about-2-0.php:175
#. translators: placeholders are opening and closing tags
+#: includes/upgrades/templates/wcs-about-2-0.php:175
msgid "New %sWC_Subscription%s Object"
msgstr ""
#: includes/upgrades/templates/wcs-about-2-0.php:177
msgid ""
-"Subscriptions 2.0 introduces a new object for working with a subscription "
-"at the application level. The cumbersome APIs for retrieving or modifying a "
+"Subscriptions 2.0 introduces a new object for working with a subscription at "
+"the application level. The cumbersome APIs for retrieving or modifying a "
"subscription's data are gone!"
msgstr ""
-#: includes/upgrades/templates/wcs-about-2-0.php:180
#. translators: all placeholders are opening and closing tags, no need
#. to order them
+#: includes/upgrades/templates/wcs-about-2-0.php:180
msgid ""
"Because the %sWC_Subscription%s class extends %sWC_Order%s, you can use its "
-"familiar methods, like %s$subscription->update_status()%s or "
-"%s$subscription->get_total()%s."
+"familiar methods, like %s$subscription->update_status()%s or %s$subscription-"
+">get_total()%s."
msgstr ""
#: includes/upgrades/templates/wcs-about-2-0.php:184
@@ -3024,13 +4513,13 @@ msgid ""
"subscriptions via RESTful API endpoints."
msgstr ""
-#: includes/upgrades/templates/wcs-about-2-0.php:188
#. translators: all placeholders are opening and closing tags, no need
#. to order them
+#: includes/upgrades/templates/wcs-about-2-0.php:188
msgid ""
-"Want to list all the subscriptions on a site? Get "
-"%sexample.com/wc-api/v2/subscriptions/%s. Want the details of a specific "
-"subscription? Get %s/wc-api/v2/subscriptions//%s."
+"Want to list all the subscriptions on a site? Get %sexample.com/wc-api/v2/"
+"subscriptions/%s. Want the details of a specific subscription? Get %s/wc-api/"
+"v2/subscriptions//%s."
msgstr ""
#: includes/upgrades/templates/wcs-about-2-0.php:194
@@ -3047,6 +4536,11 @@ msgid ""
"just like you (and possibly even by %syou%s)."
msgstr ""
+#: includes/upgrades/templates/wcs-about.php:35
+msgctxt "short for documents"
+msgid "Documentation"
+msgstr ""
+
#: includes/upgrades/templates/wcs-about.php:49
msgid "Subscription Reports"
msgstr ""
@@ -3072,6 +4566,11 @@ msgstr ""
msgid "View Reports"
msgstr ""
+#: includes/upgrades/templates/wcs-about.php:55
+msgctxt "learn more link to subscription reports documentation"
+msgid "Learn More"
+msgstr ""
+
#: includes/upgrades/templates/wcs-about.php:67
msgid "Automatic Failed Payment Retry"
msgstr ""
@@ -3115,12 +4614,18 @@ msgstr ""
msgid "Enable Automatic Retry"
msgstr ""
+#: includes/upgrades/templates/wcs-about.php:79
+msgctxt "learn more link to failed payment retry documentation"
+msgid "Learn More"
+msgstr ""
+
#: includes/upgrades/templates/wcs-about.php:90
msgid "New Subscription Emails"
msgstr ""
#: includes/upgrades/templates/wcs-about.php:91
-msgid "Subscriptions 2.1 also introduces a number of new emails to notify you when:"
+msgid ""
+"Subscriptions 2.1 also introduces a number of new emails to notify you when:"
msgstr ""
#: includes/upgrades/templates/wcs-about.php:93
@@ -3137,14 +4642,19 @@ msgstr ""
#: includes/upgrades/templates/wcs-about.php:97
msgid ""
-"These emails can be enabled, disabled and customised under the "
-"%sWooCommerce > Settings > Emails%s administration screen."
+"These emails can be enabled, disabled and customised under the %sWooCommerce "
+"> Settings > Emails%s administration screen."
msgstr ""
#: includes/upgrades/templates/wcs-about.php:99
msgid "View Email Settings"
msgstr ""
+#: includes/upgrades/templates/wcs-about.php:100
+msgctxt "learn more link to subscription emails documentation"
+msgid "Learn More"
+msgstr ""
+
#: includes/upgrades/templates/wcs-about.php:108
msgid "But wait, there's more!"
msgstr ""
@@ -3174,11 +4684,16 @@ msgid ""
"the subscription over its lifecycle."
msgstr ""
+#: includes/upgrades/templates/wcs-about.php:126
+msgctxt "h3 on the About Subscriptions page for this new feature"
+msgid "Import/Export Subscriptions"
+msgstr ""
+
#: includes/upgrades/templates/wcs-about.php:127
msgid ""
"Import subscriptions to WooCommerce via CSV, or export your subscriptions "
-"from WooCommerce to a CSV with the WooCommerce Subscriptions "
-"Importer/Exporter extension."
+"from WooCommerce to a CSV with the WooCommerce Subscriptions Importer/"
+"Exporter extension."
msgstr ""
#: includes/upgrades/templates/wcs-about.php:128
@@ -3193,19 +4708,20 @@ msgid "Subscribe All the Things"
msgstr ""
#: includes/upgrades/templates/wcs-about.php:138
-msgid "Want your customers to be able to subscribe to non-subscription products?"
+msgid ""
+"Want your customers to be able to subscribe to non-subscription products?"
msgstr ""
#: includes/upgrades/templates/wcs-about.php:139
msgid ""
"With WooCommerce Subscribe All the Things, they can! This experimental "
-"extension is exploring how to convert any product, including Product "
-"Bundles and Composite Products, into a subscription product. It also offers "
+"extension is exploring how to convert any product, including Product Bundles "
+"and Composite Products, into a subscription product. It also offers "
"customers a way to subscribe to a cart of non-subscription products."
msgstr ""
-#: includes/upgrades/templates/wcs-about.php:157
#. translators: placeholders are opening and closing tags
+#: includes/upgrades/templates/wcs-about.php:157
msgid "Customise Retry Rules"
msgstr ""
@@ -3215,20 +4731,20 @@ msgid ""
"are completely customisable."
msgstr ""
-#: includes/upgrades/templates/wcs-about.php:162
#. translators: all placeholders are opening and closing tags, no need
#. to order them
+#: includes/upgrades/templates/wcs-about.php:162
msgid ""
"With the %s'wcs_default_retry_rules'%s filter, you can define a set of "
"default rules to apply to all failed payments in your store."
msgstr ""
-#: includes/upgrades/templates/wcs-about.php:166
#. translators: all placeholders are opening and closing tags, no need
#. to order them
+#: includes/upgrades/templates/wcs-about.php:166
msgid ""
-"To apply a specific rule based on certain conditions, like high value "
-"orders or an infrequent renewal schedule, you can use the retry specific "
+"To apply a specific rule based on certain conditions, like high value orders "
+"or an infrequent renewal schedule, you can use the retry specific "
"%s'wcs_get_retry_rule'%s filter. This provides the ID of the renewal order "
"for the failed payment, which can be used to find information about the "
"products, subscription and totals to which the failed payment relates."
@@ -3238,16 +4754,17 @@ msgstr ""
msgid "WP REST API Endpoints"
msgstr ""
-#: includes/upgrades/templates/wcs-about.php:177
#. translators: $1: opening tag linking to WC API docs, $2: closing
#. tag, $3: opening tag linking to WP API docs, $4: closing tag
+#: includes/upgrades/templates/wcs-about.php:177
msgid ""
"WooCommerce 2.6 added support for %1$sREST API%2$s endpoints built on "
"WordPress core's %3$sREST API%4$s infrastructure."
msgstr ""
#: includes/upgrades/templates/wcs-about.php:179
-msgid "Subscriptions 2.1 adds support for subscription data to this infrastructure."
+msgid ""
+"Subscriptions 2.1 adds support for subscription data to this infrastructure."
msgstr ""
#: includes/upgrades/templates/wcs-about.php:180
@@ -3257,24 +4774,24 @@ msgid ""
"WooCommerce's REST API endpoints."
msgstr ""
+#. translators: all placeholders are opening and closing tags, no need
+#. to order them
#: includes/upgrades/templates/wcs-about.php:183
-#. translators: all placeholders are opening and closing tags, no need
-#. to order them
msgid ""
-"Want to list all the subscriptions on a site? Get "
-"%s/wp-json/wc/v1/subscriptions%s."
+"Want to list all the subscriptions on a site? Get %s/wp-json/wc/v1/"
+"subscriptions%s."
msgstr ""
+#. translators: all placeholders are opening and closing tags, no need
+#. to order them
#: includes/upgrades/templates/wcs-about.php:187
-#. translators: all placeholders are opening and closing tags, no need
-#. to order them
msgid ""
-"Want the details of a specific subscription? Get "
-"%s/wp-json/wc/v1/subscriptions//%s."
+"Want the details of a specific subscription? Get %s/wp-json/wc/v1/"
+"subscriptions//%s."
msgstr ""
-#: includes/upgrades/templates/wcs-about.php:197
#. translators: placeholders are opening and closing code tags
+#: includes/upgrades/templates/wcs-about.php:197
msgid "Honour Renewal Order Data"
msgstr ""
@@ -3286,20 +4803,20 @@ msgid ""
"a renewal."
msgstr ""
-#: includes/upgrades/templates/wcs-about.php:202
#. translators: placeholders are opening and closing tags
+#: includes/upgrades/templates/wcs-about.php:202
msgid ""
"Subscriptions 2.1 now passes the renewal order's total, making it possible "
-"to add a fee or discount to the renewal order with simple one-liners like "
-"%s$order->add_fee()%s or %s$order->add_coupon()%s."
+"to add a fee or discount to the renewal order with simple one-liners like %s"
+"$order->add_fee()%s or %s$order->add_coupon()%s."
msgstr ""
-#: includes/upgrades/templates/wcs-about.php:206
#. translators: placeholders are opening and closing tags
+#: includes/upgrades/templates/wcs-about.php:206
msgid ""
-"Subscriptions also now uses the renewal order to setup the cart for "
-"%smanual renewals%s, making it easier to add products or discounts to a "
-"single renewal paid manually."
+"Subscriptions also now uses the renewal order to setup the cart for %smanual "
+"renewals%s, making it easier to add products or discounts to a single "
+"renewal paid manually."
msgstr ""
#: includes/upgrades/templates/wcs-about.php:212
@@ -3324,8 +4841,8 @@ msgid ""
"upgrade routine."
msgstr ""
-#: includes/upgrades/templates/wcs-upgrade-in-progress.php:34
#. translators: placeholder is number of seconds
+#: includes/upgrades/templates/wcs-upgrade-in-progress.php:34
msgid ""
"If you received a server error and reloaded the page to find this notice, "
"please refresh the page in %s seconds and the upgrade routine will "
@@ -3344,6 +4861,10 @@ msgid "WooCommerce Subscriptions Update"
msgstr ""
#: includes/upgrades/templates/wcs-upgrade.php:29
+#: tmp/old/wordpress/wp-admin/network/upgrade.php:125
+#: tmp/old/wordpress/wp-admin/upgrade.php:96
+#: tmp/wordpress/wp-admin/network/upgrade.php:125
+#: tmp/wordpress/wp-admin/upgrade.php:96
msgid "Database Update Required"
msgstr ""
@@ -3351,17 +4872,17 @@ msgstr ""
msgid "The WooCommerce Subscriptions plugin has been updated!"
msgstr ""
-#: includes/upgrades/templates/wcs-upgrade.php:33
#. translators: placeholders are opening and closing tags
+#: includes/upgrades/templates/wcs-upgrade.php:33
msgid ""
"Before we send you on your way, we need to update your database to the "
"newest version. If you do not have a recent backup of your site, %snow is "
"the time to create one%s."
msgstr ""
-#: includes/upgrades/templates/wcs-upgrade.php:38
#. translators: 1$: number of subscriptions on site, 2$, lower estimate
#. (minutes), 3$: upper estimate
+#: includes/upgrades/templates/wcs-upgrade.php:38
msgid ""
"The full update process for the %1$d subscriptions on your site will take "
"between %2$d and %3$d minutes."
@@ -3377,6 +4898,11 @@ msgid ""
"your store without interuption while the update is in progress."
msgstr ""
+#: includes/upgrades/templates/wcs-upgrade.php:45
+msgctxt "text on submit button"
+msgid "Update Database"
+msgstr ""
+
#: includes/upgrades/templates/wcs-upgrade.php:49
msgid "Update in Progress"
msgstr ""
@@ -3401,6 +4927,8 @@ msgid ""
msgstr ""
#: includes/upgrades/templates/wcs-upgrade.php:61
+#: tmp/old/wordpress/wp-admin/upgrade.php:109
+#: tmp/wordpress/wp-admin/upgrade.php:109
msgid "Update Complete"
msgstr ""
@@ -3409,11 +4937,16 @@ msgid "Your database has been updated successfully!"
msgstr ""
#: includes/upgrades/templates/wcs-upgrade.php:63
+#: tmp/old/wordpress/wp-admin/includes/media.php:1505
+#: tmp/old/wordpress/wp-admin/upgrade.php:77
+#: tmp/old/wordpress/wp-admin/upgrade.php:111
+#: tmp/wordpress/wp-admin/includes/media.php:1505
+#: tmp/wordpress/wp-admin/upgrade.php:77 tmp/wordpress/wp-admin/upgrade.php:111
msgid "Continue"
msgstr ""
-#: includes/upgrades/templates/wcs-upgrade.php:66
#. translators: $1: placeholder is number of weeks, 2$: path to the file
+#: includes/upgrades/templates/wcs-upgrade.php:66
msgid ""
"To record the progress of the update a new log file was created. This file "
"will be automatically deleted in %1$d weeks. If you would like to delete it "
@@ -3425,7 +4958,8 @@ msgid "Update Error"
msgstr ""
#: includes/upgrades/templates/wcs-upgrade.php:72
-msgid "There was an error with the update. Please refresh the page and try again."
+msgid ""
+"There was an error with the update. Please refresh the page and try again."
msgstr ""
#: includes/wcs-cart-functions.php:76 includes/wcs-cart-functions.php:77
@@ -3438,1539 +4972,138 @@ msgid_plural "Shipping %d"
msgstr[0] ""
msgstr[1] ""
-#: includes/wcs-cart-functions.php:225
-msgid "Free shipping coupon"
-msgstr ""
-
-#: includes/wcs-cart-functions.php:328
-#. translators: placeholder is a date
-msgid "First renewal: %s"
-msgstr ""
-
-#: includes/wcs-deprecated-functions.php:113
-#. translators: placeholder is either subscription key or a subscription id,
-#. or, failing that, empty (e.g. "145_21" or "145")
-msgid ""
-"Could not get subscription. Most likely the subscription key does not refer "
-"to a subscription. The key was: \"%s\"."
-msgstr ""
-
-#: includes/wcs-formatting-functions.php:85
-#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"),
-#. 3$: recurring amount string (e.g. "£10 / month" )
-msgid "%1$s %2$s then %3$s"
-msgstr ""
-
-#: includes/wcs-formatting-functions.php:99
-#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"),
-#. 3$: recurring amount string, 4$: payment day of the week (e.g. "$15 up
-#. front, then $10 every Wednesday")
-msgid "%1$s %2$s then %3$s every %4$s"
-msgstr ""
-
-#: includes/wcs-formatting-functions.php:108
-#. translators: 1$: initial amount, 2$: initial description (e.g. "up front" ),
-#. 3$: recurring amount, 4$: interval (e.g. "2nd week"), 5$: day of the week
-#. (e.g. "Thursday"); (e.g. "$10 up front, then $20 every 2nd week on
-#. Wednesday")
-msgid "%1$s %2$s then %3$s every %4%s on %5$s"
-msgstr ""
-
-#: includes/wcs-formatting-functions.php:121
-#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"),
-#. 3$: recurring amount; (e.g. "$10 up front then $30 on the last day of each
-#. month")
-msgid "%1$s %2$s then %3$s on the last day of each month"
-msgstr ""
-
-#: includes/wcs-formatting-functions.php:124
-#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"),
-#. 3$: recurring amount, 4$: day of the month (e.g. "23rd"); (e.g. "$10 up
-#. front then $40 on the 23rd of each month")
-msgid "%1$s %2$s then %3$s on the %4$s of each month"
-msgstr ""
-
-#: includes/wcs-formatting-functions.php:140
-#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"),
-#. 3$: recurring amount, 4$: interval (e.g. "3rd")
-msgid "%1$s %2$s then %3$s on the last day of every %4$s month"
-msgstr ""
-
-#: includes/wcs-formatting-functions.php:143
-#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"),
-#. 3$: recurring amount, 4$: day of the month (e.g. "23rd"), 5$: interval (e.g.
-#. "3rd")
-msgid "%1$s %2$s then %3$s on the %4$s day of every %5$s month"
-msgstr ""
-
-#: includes/wcs-formatting-functions.php:161
-#. translators: 1$: initial amount, 2$: intial description (e.g. "up front"),
-#. 3$: recurring amount, 4$: month of year (e.g. "March"), 5$: day of the month
-#. (e.g. "23rd")
-msgid "%1$s %2$s then %3$s on %4$s %5$s each year"
-msgstr ""
-
-#: includes/wcs-formatting-functions.php:170
-#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"),
-#. 3$: recurring amount, 4$: month (e.g. "March"), 5$: day of the month (e.g.
-#. "23rd"), 6$: interval (e.g. "3rd")
-msgid "%1$s %2$s then %3$s on %4$s %5$s every %6$s year"
-msgstr ""
-
-#: includes/wcs-formatting-functions.php:180
-#. translators: 1$: initial amount, 2$: initial description (e.g. "up front"),
-#. 3$: recurring amount, 4$: subscription period (e.g. "month" or "3 months")
-msgid "%1$s %2$s then %3$s / %4$s"
-msgid_plural "%1$s %2$s then %3$s every %4$s"
-msgstr[0] ""
-msgstr[1] ""
-
-#: includes/wcs-formatting-functions.php:201
-#. translators: 1$: subscription string (e.g. "$10 up front then $5 on March
-#. 23rd every 3rd year"), 2$: trial length (e.g. "3 weeks")
-msgid "%1$s after %2$s free trial"
-msgstr ""
-
-#: includes/wcs-formatting-functions.php:204
-#. translators: 1$: trial length (e.g. "3 weeks"), 2$: subscription string
-#. (e.g. "$10 up front then $5 on March 23rd every 3rd year")
-msgid "%1$s free trial then %2$s"
-msgstr ""
-
-#: includes/wcs-helper-functions.php:38
-#. translators: date placeholder for input, javascript format
-msgid "YYYY-MM-DD"
-msgstr ""
-
-#: includes/wcs-helper-functions.php:43
-#. translators: hour placeholder for time input, javascript format
-msgid "HH"
-msgstr ""
-
-#: includes/wcs-helper-functions.php:46
-#. translators: minute placeholder for time input, javascript format
-msgid "MM"
-msgstr ""
-
-#: includes/wcs-order-functions.php:303
-msgid "Subscription Renewal Order – %s"
-msgstr ""
-
-#: includes/wcs-order-functions.php:306
-msgid "Resubscribe Order – %s"
-msgstr ""
-
-#: includes/wcs-order-functions.php:325
-msgid "$type passed to the function was not a string."
-msgstr ""
-
-#: includes/wcs-order-functions.php:330
-msgid "\"%s\" is not a valid new order type."
-msgstr ""
-
-#: includes/wcs-order-functions.php:517
-msgid "Invalid data. No valid subscription / order was passed in."
-msgstr ""
-
-#: includes/wcs-order-functions.php:521
-msgid "Invalid data. No valid item id was passed in."
-msgstr ""
-
-#: includes/wcs-time-functions.php:54
-msgid "%s day"
-msgid_plural "a %s-day"
-msgstr[0] ""
-msgstr[1] ""
-
-#: includes/wcs-time-functions.php:55
-msgid "%s week"
-msgid_plural "a %s-week"
-msgstr[0] ""
-msgstr[1] ""
-
-#: includes/wcs-time-functions.php:56
-msgid "%s month"
-msgid_plural "a %s-month"
-msgstr[0] ""
-msgstr[1] ""
-
-#: includes/wcs-time-functions.php:57
-msgid "%s year"
-msgid_plural "a %s-year"
-msgstr[0] ""
-msgstr[1] ""
-
-#: includes/wcs-user-functions.php:279
-#: templates/single-product/add-to-cart/subscription.php:41
-#: templates/single-product/add-to-cart/variable-subscription.php:29
-msgid "Resubscribe"
-msgstr ""
-
-#: templates/admin/deprecated/html-variation-price.php:20
-#: templates/admin/deprecated/html-variation-price.php:30
-#. translators: placeholder is a currency symbol / code
-msgid "Subscription Price (%s)"
-msgstr ""
-
-#: templates/admin/deprecated/html-variation-price.php:46
-msgid "Subscription Periods"
-msgstr ""
-
-#: templates/admin/deprecated/html-variation-price.php:69
-msgid "Subscription Length"
-msgstr ""
-
-#: templates/admin/deprecated/html-variation-price.php:85
-msgid "Sign-up Fee (%s)"
-msgstr ""
-
-#: templates/admin/deprecated/html-variation-price.php:97
-#: templates/admin/deprecated/html-variation-price.php:104
-msgid "Free Trial"
-msgstr ""
-
-#: templates/admin/deprecated/html-variation-synchronisation.php:30
-msgid "Synchronise Renewals"
-msgstr ""
-
-#: templates/admin/deprecated/order-shipping-html.php:8
-msgid "Label"
-msgstr ""
-
-#: templates/admin/deprecated/order-shipping-html.php:13
-msgid "Shipping Method"
-msgstr ""
-
-#: templates/admin/deprecated/order-shipping-html.php:34
-#: templates/admin/deprecated/order-shipping-html.php:36
-msgid "Other"
-msgstr ""
-
-#: templates/admin/deprecated/order-tax-html.php:17
-msgid "Recurring Sales Tax:"
-msgstr ""
-
-#: templates/admin/deprecated/order-tax-html.php:21
-msgid "Shipping Tax:"
-msgstr ""
-
-#: templates/admin/html-variation-price.php:31
-msgid "Subscription trial period:"
-msgstr ""
-
-#: templates/admin/html-variation-price.php:49
-msgid "Billing interval:"
-msgstr ""
-
-#: templates/admin/html-variation-price.php:56
-msgid "Billing Period:"
-msgstr ""
-
-#: templates/cart/cart-recurring-shipping.php:19
-msgid "Recurring shipping options can be selected on checkout."
-msgstr ""
-
-#: templates/cart/cart-recurring-shipping.php:33
-msgid "Shipping costs will be calculated once you have provided your address."
-msgstr ""
-
-#: templates/cart/cart-recurring-shipping.php:35
-msgid ""
-"There are no shipping methods available. Please double check your address, "
-"or contact us if you need any help."
-msgstr ""
-
-#: templates/checkout/form-change-payment-method.php:82
-msgid ""
-"Sorry, it seems no payment gateways support changing the recurring payment "
-"method. Please contact us if you require assistance or to make alternate "
-"arrangements."
-msgstr ""
-
-#: templates/checkout/recurring-totals.php:19
-msgid "Recurring Totals"
-msgstr ""
-
-#: templates/checkout/recurring-totals.php:28
-#: templates/checkout/recurring-totals.php:29
-msgid "Subtotal"
-msgstr ""
-
-#: templates/checkout/recurring-totals.php:111
-#: templates/checkout/recurring-totals.php:112
-msgid "Recurring Total"
-msgstr ""
-
-#: templates/emails/admin-new-switch-order.php:24
-msgid "Switch Order Details"
-msgstr ""
-
-#: templates/emails/admin-new-switch-order.php:30
-#: templates/emails/customer-completed-switch-order.php:28
-msgid "New Subscription Details"
-msgstr ""
-
-#: templates/emails/admin-payment-retry.php:28
-#: templates/emails/plain/admin-payment-retry.php:21
-msgid "The renewal order is as follows:"
-msgstr ""
-
-#: templates/emails/cancelled-subscription.php:19
-#: templates/emails/plain/cancelled-subscription.php:16
-#. translators: $1: customer's billing first name and last name
-msgid ""
-"A subscription belonging to %1$s has been cancelled. Their subscription's "
-"details are as follows:"
-msgstr ""
-
-#: templates/emails/cancelled-subscription.php:46
-#: templates/emails/expired-subscription.php:46
-#: templates/emails/on-hold-subscription.php:46
-msgid "-"
-msgstr ""
-
-#: templates/emails/customer-completed-renewal-order.php:20
-#: templates/emails/plain/customer-completed-renewal-order.php:16
-#. translators: placeholder is the name of the site
-msgid ""
-"Hi there. Your subscription renewal order with %s has been completed. Your "
-"order details are shown below for your reference:"
-msgstr ""
-
-#: templates/emails/customer-completed-switch-order.php:20
-#: templates/emails/plain/customer-completed-switch-order.php:16
-#. translators: placeholder is the name of the site
-msgid ""
-"Hi there. You have successfully changed your subscription items on %s. Your "
-"new order and subscription details are shown below for your reference:"
-msgstr ""
-
-#: templates/emails/customer-processing-renewal-order.php:17
-#: templates/emails/plain/customer-processing-renewal-order.php:15
-msgid ""
-"Your subscription renewal order has been received and is now being "
-"processed. Your order details are shown below for your reference:"
-msgstr ""
-
-#: templates/emails/customer-renewal-invoice.php:20
-#: templates/emails/customer-renewal-invoice.php:27
-msgid "Pay Now »"
-msgstr ""
-
-#: templates/emails/expired-subscription.php:19
-#: templates/emails/plain/expired-subscription.php:16
-#. translators: $1: customer's billing first name and last name
-msgid ""
-"A subscription belonging to %1$s has expired. Their subscription's details "
-"are as follows:"
-msgstr ""
-
-#: templates/emails/on-hold-subscription.php:19
-#: templates/emails/plain/on-hold-subscription.php:16
-#. translators: $1: customer's billing first name and last name
-msgid ""
-"A subscription belonging to %1$s has been suspended by the user. Their "
-"subscription's details are as follows:"
-msgstr ""
-
-#: templates/emails/plain/cancelled-subscription.php:32
-#: templates/emails/plain/expired-subscription.php:32
-#: templates/emails/plain/on-hold-subscription.php:32
-#. translators: placeholder is last time subscription was paid
-msgid "Last Payment: %s"
-msgstr ""
-
-#: templates/emails/plain/cancelled-subscription.php:39
-#. translators: placeholder is localised date string
-msgid "End of Prepaid Term: %s"
-msgstr ""
-
-#: templates/emails/plain/customer-completed-switch-order.php:23
-#. translators: placeholder is order's view url
-msgid "View your order: %s"
-msgstr ""
-
-#: templates/emails/plain/customer-completed-switch-order.php:34
-#. translators: placeholder is subscription's view url
-msgid "View your subscription: %s"
-msgstr ""
-
-#: templates/emails/plain/email-order-details.php:16
-msgid "Order number: %s"
-msgstr ""
-
-#: templates/emails/plain/email-order-details.php:17
-msgid "Order date: %s"
-msgstr ""
-
-#: templates/emails/plain/expired-subscription.php:39
-#. translators: placeholder is localised date string
-msgid "End Date: %s"
-msgstr ""
-
-#: templates/emails/plain/on-hold-subscription.php:36
-#. translators: placeholder is localised date string
-msgid "Date Suspended: %s"
-msgstr ""
-
-#: templates/emails/plain/subscription-info.php:16
-#: templates/emails/subscription-info.php:14
-msgid "Subscription Information:"
-msgstr ""
-
-#: templates/myaccount/my-subscriptions.php:17
-msgid "My Subscriptions"
-msgstr ""
-
-#: templates/myaccount/my-subscriptions.php:36
-#: templates/myaccount/related-subscriptions.php:30
-msgid "ID"
-msgstr ""
-
-#: templates/myaccount/my-subscriptions.php:71
-#. translators: placeholders are opening and closing link tags to take to the
-#. shop page
-msgid ""
-"You have no active subscriptions. Find your first subscription in the "
-"%sstore%s."
-msgstr ""
-
-#: templates/myaccount/related-orders.php:22
-msgid "Order"
-msgstr ""
-
-#: templates/myaccount/related-orders.php:50
-#. translators: $1: formatted order total for the order, $2: number of items
-#. bought
-msgid "%1$s for %2$d item"
-msgid_plural "%1$s for %2$d items"
-msgstr[0] ""
-msgstr[1] ""
-
-#: templates/myaccount/related-subscriptions.php:15
-msgid "Related Subscriptions"
-msgstr ""
-
-#: templates/myaccount/view-subscription.php:20
-msgid "My Account"
-msgstr ""
-
-#: templates/myaccount/view-subscription.php:57
-msgid "Actions"
-msgstr ""
-
-#: templates/myaccount/view-subscription.php:69
-msgid "Subscription Updates"
-msgstr ""
-
-#: templates/myaccount/view-subscription.php:88
-msgid "Subscription Totals"
-msgstr ""
-
-#: templates/myaccount/view-subscription.php:109
-msgid "Are you sure you want remove this item from your subscription?"
-msgstr ""
-
-#: templates/single-product/add-to-cart/subscription.php:43
-#: templates/single-product/add-to-cart/variable-subscription.php:31
-msgid "You have an active subscription to this product already."
-msgstr ""
-
-#: templates/single-product/add-to-cart/variable-subscription.php:24
-msgid "This product is currently out of stock and unavailable."
-msgstr ""
-
-#: templates/single-product/add-to-cart/variable-subscription.php:43
-msgid "Clear selection"
-msgstr ""
-
-#: wcs-functions.php:228
-msgid "Can not get status name. Status is not a string."
-msgstr ""
-
-#: wcs-functions.php:251
-msgid "Can not get address type display name. Address type is not a string."
-msgstr ""
-
-#: wcs-functions.php:255
-msgid "Shipping Address"
-msgstr ""
-
-#: wcs-functions.php:256
-msgid "Billing Address"
-msgstr ""
-
-#: wcs-functions.php:314
-msgid "Date type is not a string."
-msgstr ""
-
-#: wcs-functions.php:316
-msgid "Date type can not be an empty string."
-msgstr ""
-
-#: woocommerce-subscriptions.php:220
-msgid "This is where subscriptions are stored."
-msgstr ""
-
-#: woocommerce-subscriptions.php:264
-msgid "No Subscriptions found"
-msgstr ""
-
-#: woocommerce-subscriptions.php:266
-msgid ""
-"Subscriptions will appear here for you to view and manage once purchased by "
-"a customer."
-msgstr ""
-
-#: woocommerce-subscriptions.php:268
-#. translators: placeholders are opening and closing link tags
-msgid "%sLearn more about managing subscriptions »%s"
-msgstr ""
-
-#: woocommerce-subscriptions.php:270
-#. translators: placeholders are opening and closing link tags
-msgid "%sAdd a subscription product »%s"
-msgstr ""
-
-#: woocommerce-subscriptions.php:384
-msgid ""
-"A subscription renewal has been removed from your cart. Multiple "
-"subscriptions can not be purchased at the same time."
-msgstr ""
-
-#: woocommerce-subscriptions.php:390
-msgid ""
-"A subscription has been removed from your cart. Due to payment gateway "
-"restrictions, different subscription products can not be purchased at the "
-"same time."
-msgstr ""
-
-#: woocommerce-subscriptions.php:396
-msgid ""
-"A subscription has been removed from your cart. Products and subscriptions "
-"can not be purchased at the same time."
-msgstr ""
-
-#: woocommerce-subscriptions.php:530 woocommerce-subscriptions.php:547
-#. translators: placeholder is a number, this is for the teens
-#. translators: placeholder is a number, numbers ending in 4-9, 0
-msgid "%sth"
-msgstr ""
-
-#: woocommerce-subscriptions.php:535
-#. translators: placeholder is a number, numbers ending in 1
-msgid "%sst"
-msgstr ""
-
-#: woocommerce-subscriptions.php:539
-#. translators: placeholder is a number, numbers ending in 2
-msgid "%snd"
-msgstr ""
-
-#: woocommerce-subscriptions.php:543
-#. translators: placeholder is a number, numbers ending in 3
-msgid "%srd"
-msgstr ""
-
-#: woocommerce-subscriptions.php:573
-#. translators: 1$-2$: opening and closing tags, 3$-4$: link tags,
-#. takes to woocommerce plugin on wp.org, 5$-6$: opening and closing link tags,
-#. leads to plugins.php in admin
-msgid ""
-"%1$sWooCommerce Subscriptions is inactive.%2$s The %3$sWooCommerce "
-"plugin%4$s must be active for WooCommerce Subscriptions to work. Please "
-"%5$sinstall & activate WooCommerce »%6$s"
-msgstr ""
-
-#: woocommerce-subscriptions.php:580
-#. translators: 1$-2$: opening and closing tags, 3$-4$: opening and
-#. closing link tags, leads to plugin admin
-msgid ""
-"%1$sWooCommerce Subscriptions is inactive.%2$s This version of "
-"Subscriptions requires WooCommerce 2.4 or newer. Please %3$supdate "
-"WooCommerce to version 2.4 or newer »%4$s"
-msgstr ""
-
-#: woocommerce-subscriptions.php:606
-msgid "Variable Subscription"
-msgstr ""
-
-#: woocommerce-subscriptions.php:765
-#. translators: 1$-2$: opening and closing tags, 3$-4$: opening and
-#. closing link tags. Leads to duplicate site article on docs
-msgid ""
-"It looks like this site has moved or is a duplicate site. %1$sWooCommerce "
-"Subscriptions%2$s has disabled automatic payments and subscription related "
-"emails on this site to prevent duplicate payments from a staging or test "
-"environment. %3$sLearn more »%4$s."
-msgstr ""
-
-#: woocommerce-subscriptions.php:767
-msgid "Quit nagging me (but don't enable automatic payments)"
-msgstr ""
-
-#: woocommerce-subscriptions.php:768
-msgid "Enable automatic payments"
-msgstr ""
-
-#: woocommerce-subscriptions.php:946
-msgid "Support"
-msgstr ""
-
-#: woocommerce-subscriptions.php:1051
-#. translators: placeholders are opening and closing tags. Leads to docs on
-#. version 2
-msgid ""
-"Warning! Version 2.0 is a major update to the WooCommerce Subscriptions "
-"extension. Before updating, please create a backup, update all WooCommerce "
-"extensions and test all plugins, custom code and payment gateways with "
-"version 2.0 on a staging site. %sLearn more about the changes in version "
-"2.0 »%s"
-msgstr ""
-
-#: woocommerce-subscriptions.php:1066
-msgid ""
-"Warning! You are running version %s of WooCommerce Subscriptions plugin "
-"code but your database has been upgraded to Subscriptions version 2.0. This "
-"will cause major problems on your store."
-msgstr ""
-
-#: woocommerce-subscriptions.php:1067
-msgid ""
-"Please upgrade the WooCommerce Subscriptions plugin to version 2.0 or newer "
-"immediately. If you need assistance, after upgrading to Subscriptions v2.0, "
-"please %sopen a support ticket%s."
-msgstr ""
-
-#. Plugin Name of the plugin/theme
-msgid "WooCommerce Subscriptions"
-msgstr ""
-
-#. Plugin URI of the plugin/theme
-msgid "http://www.woocommerce.com/products/woocommerce-subscriptions/"
-msgstr ""
-
-#. Description of the plugin/theme
-msgid ""
-"Sell products and services with recurring payments in your WooCommerce "
-"Store."
-msgstr ""
-
-#. Author of the plugin/theme
-msgid "Prospress Inc."
-msgstr ""
-
-#. Author URI of the plugin/theme
-msgid "http://prospress.com/"
-msgstr ""
-
-#: includes/admin/class-wc-subscriptions-admin.php:187
-#. translators: placeholder is trial period validation message if passed an
-#. invalid value (e.g. "Trial period can not exceed 4 weeks")
-msgctxt "Trial period field tooltip on Edit Product administration screen"
-msgid ""
-"An optional period of time to wait before charging the first recurring "
-"payment. Any sign up fee will still be charged at the outset of the "
-"subscription. %s"
-msgstr ""
-
-#: includes/admin/class-wc-subscriptions-admin.php:200
-msgctxt "example price"
-msgid "e.g. 5.90"
-msgstr ""
-
-#: includes/admin/class-wc-subscriptions-admin.php:234
-#: templates/admin/deprecated/html-variation-price.php:31
-#: templates/admin/deprecated/html-variation-price.php:86
-#: templates/admin/html-variation-price.php:21
-#: templates/admin/html-variation-price.php:47
-msgctxt "example price"
-msgid "e.g. 9.90"
-msgstr ""
-
-#: includes/admin/class-wc-subscriptions-admin.php:762
-#. translators: placeholders are for HTML tags. They are 1$: "