diff --git a/changelog.txt b/changelog.txt
index 3452d34..f559510 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,5 +1,12 @@
*** Woo Subscriptions Changelog ***
+2024-01-11 - version 5.9.0
+* Fix: Resolved an issue that caused ordering the Admin Subscriptions List Table to not work when HPOS is enabled.
+* Fix: When switching all subscription items in the same cart, ensure the previous subscription is reused where possible instead of creating all new subscriptions.
+* Update: Changed the edit subscription product "Expire after" (Subscription length) so it more clearly describes when a subscription will automatically stop renewing.
+* Update: Log all exceptions caught by WooCommerce while processing a subscription scheduled action.
+* Dev: Update subscriptions-core to 6.7.0.
+
2023-12-21 - version 5.8.0
* Fix: Incorrect switch calculation when upgrading a synchronised product before the first renewal is due where the initial payment was prorated.
* Fix: When updating a subscription via the REST API, don't update the start date to the current time if the start date is not set in the request.
diff --git a/includes/switching/class-wc-subscriptions-switcher.php b/includes/switching/class-wc-subscriptions-switcher.php
index be60c74..e412ba7 100644
--- a/includes/switching/class-wc-subscriptions-switcher.php
+++ b/includes/switching/class-wc-subscriptions-switcher.php
@@ -1025,113 +1025,115 @@ class WC_Subscriptions_Switcher {
$subscription->set_shipping_total( $subscription_shipping_total );
$switch_order_data[ $subscription->get_id() ]['shipping_line_items'] = $new_shipping_line_items;
+ }
- // Loop through cart items to add them to the switched subscription.
- foreach ( $recurring_cart->get_cart() as $cart_item_key => $cart_item ) {
+ // Loop through cart items to add them to the switched subscription.
+ foreach ( $recurring_cart->get_cart() as $cart_item_key => $cart_item ) {
+ // 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'] = wcs_date_to_time( $recurring_cart->next_payment_date );
+ }
- // 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'] = wcs_date_to_time( $recurring_cart->next_payment_date );
- }
+ $is_different_billing_schedule = self::has_different_billing_schedule( $cart_item, $subscription );
+ $is_different_payment_date = self::has_different_payment_date( $cart_item, $subscription );
+ $is_different_length = self::has_different_length( $recurring_cart, $subscription );
+ $is_single_item_subscription = self::is_single_item_subscription( $subscription );
- $is_different_billing_schedule = self::has_different_billing_schedule( $cart_item, $subscription );
- $is_different_payment_date = self::has_different_payment_date( $cart_item, $subscription );
- $is_different_length = self::has_different_length( $recurring_cart, $subscription );
- $is_single_item_subscription = self::is_single_item_subscription( $subscription );
+ $switched_item_data = array();
- $switched_item_data = array();
+ if ( ! empty( $cart_item['subscription_switch']['item_id'] ) ) {
+ $existing_item = wcs_get_order_item( $cart_item['subscription_switch']['item_id'], $subscription );
+ $switch_item = new WCS_Switch_Cart_Item( $cart_item, $subscription, $existing_item );
+ $is_switch_with_matching_trials = $switch_item->is_switch_during_trial() && $switch_item->trial_periods_match();
+ $switched_item_data['remove_line_item'] = $cart_item['subscription_switch' ]['item_id'];
+ $switched_item_data['switch_direction'] = $switch_item->get_switch_type();
+ }
- if ( ! empty( $cart_item['subscription_switch']['item_id'] ) ) {
- $existing_item = wcs_get_order_item( $cart_item['subscription_switch']['item_id'], $subscription );
- $switch_item = new WCS_Switch_Cart_Item( $cart_item, $subscription, $existing_item );
- $is_switch_with_matching_trials = $switch_item->is_switch_during_trial() && $switch_item->trial_periods_match();
- $switched_item_data['remove_line_item'] = $cart_item['subscription_switch' ]['item_id'];
- $switched_item_data['switch_direction'] = $switch_item->get_switch_type();
- }
+ // An existing subscription can be updated if it's a single item subscription or switches already calculated have left it with just one item.
+ $can_update_existing_subscription = $is_single_item_subscription || ! empty( $existing_item ) && self::is_last_remaining_item_after_previous_switches( $subscription, $existing_item, $switch_order_data );
- // If the item is on the same schedule, we can just add it to the new subscription and remove the old item.
- if ( $is_single_item_subscription || ( false === $is_different_billing_schedule && false === $is_different_payment_date && false === $is_different_length ) ) {
- // Add the new item
- $item = new WC_Order_Item_Pending_Switch;
- $item->legacy_values = $cart_item; // @deprecated For legacy actions.
- $item->legacy_cart_item_key = $cart_item_key; // @deprecated For legacy actions.
+ // If the item is on the same schedule, we can just add it to the new subscription and remove the old item.
+ if ( $can_update_existing_subscription || ( false === $is_different_billing_schedule && false === $is_different_payment_date && false === $is_different_length ) ) {
+ // Add the new item
+ $item = new WC_Order_Item_Pending_Switch;
+ $item->legacy_values = $cart_item; // @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(
- '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'],
+ '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 ( ! 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' because we added an item
- $subscription->save();
- $item_id = $item->get_id();
-
- $switched_item_data['add_line_item'] = $item_id;
-
- // Remove the item from the cart so that WC_Subscriptions_Checkout doesn't add it to a subscription
- if ( 1 == count( WC()->cart->recurring_carts[ $recurring_cart_key ]->get_cart() ) ) {
- // If this is the only item in the cart, clear out recurring carts so WC_Subscriptions_Checkout doesn't try to create an empty subscription
- unset( WC()->cart->recurring_carts[ $recurring_cart_key ] );
- } else {
- unset( WC()->cart->recurring_carts[ $recurring_cart_key ]->cart_contents[ $cart_item_key ] );
- }
}
- $switch_order_data[ $subscription->get_id() ]['switches'][ $cart_item['subscription_switch']['order_line_item_id'] ] = $switched_item_data;
+ if ( WC_Subscriptions_Product::get_trial_length( wcs_get_canonical_product_id( $cart_item ) ) > 0 ) {
+ $item->add_meta_data( '_has_trial', 'true' );
+ }
- // If the old subscription has just one item, we can safely update its billing schedule
- if ( $is_single_item_subscription ) {
+ do_action( 'woocommerce_checkout_create_order_line_item', $item, $cart_item_key, $cart_item, $subscription );
- if ( $is_different_billing_schedule ) {
- $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'] ) );
- }
+ $subscription->add_item( $item );
- $updated_dates = array();
+ // The subscription is not saved automatically, we need to call 'save' because we added an item
+ $subscription->save();
+ $item_id = $item->get_id();
- 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 ) {
- $updated_dates['next_payment'] = gmdate( 'Y-m-d H:i:s', $cart_item['subscription_switch']['first_payment_timestamp'] );
- }
+ $switched_item_data['add_line_item'] = $item_id;
- if ( $is_different_length ) {
- $updated_dates['end'] = $recurring_cart->end_date;
- }
+ // Remove the item from the cart so that WC_Subscriptions_Checkout doesn't add it to a subscription
+ if ( 1 == count( WC()->cart->recurring_carts[ $recurring_cart_key ]->get_cart() ) ) {
+ // If this is the only item in the cart, clear out recurring carts so WC_Subscriptions_Checkout doesn't try to create an empty subscription
+ unset( WC()->cart->recurring_carts[ $recurring_cart_key ] );
+ } else {
+ unset( WC()->cart->recurring_carts[ $recurring_cart_key ]->cart_contents[ $cart_item_key ] );
+ }
+ }
- // If the switch should maintain the current trial or delete it.
- if ( isset( $is_switch_with_matching_trials ) && $is_switch_with_matching_trials ) {
- $updated_dates['trial_end'] = $subscription->get_date( 'trial_end' );
- } else {
- $updated_dates['trial_end'] = 0;
- }
+ $switch_order_data[ $subscription->get_id() ]['switches'][ $cart_item['subscription_switch']['order_line_item_id'] ] = $switched_item_data;
- if ( ! empty( $updated_dates ) ) {
- $subscription->validate_date_updates( $updated_dates );
- $switch_order_data[ $subscription->get_id() ]['dates']['update'] = $updated_dates;
- }
+ // If the old subscription has just one item, we can safely update its billing schedule
+ if ( $can_update_existing_subscription ) {
+
+ if ( $is_different_billing_schedule ) {
+ $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' == 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 ) {
+ $updated_dates['next_payment'] = gmdate( 'Y-m-d H:i:s', $cart_item['subscription_switch']['first_payment_timestamp'] );
+ }
+
+ if ( $is_different_length ) {
+ $updated_dates['end'] = $recurring_cart->end_date;
+ }
+
+ // If the switch should maintain the current trial or delete it.
+ if ( isset( $is_switch_with_matching_trials ) && $is_switch_with_matching_trials ) {
+ $updated_dates['trial_end'] = $subscription->get_date( 'trial_end' );
+ } else {
+ $updated_dates['trial_end'] = 0;
+ }
+
+ if ( ! empty( $updated_dates ) ) {
+ $subscription->validate_date_updates( $updated_dates );
+ $switch_order_data[ $subscription->get_id() ]['dates']['update'] = $updated_dates;
}
}
}
@@ -2340,6 +2342,41 @@ class WC_Subscriptions_Switcher {
}
}
+ /**
+ * Determines if a subscription item being switched is the last remaining item on the subscription after previous switches.
+ *
+ * If the item being switched is the last remaining item on the subscription after previous switches, then the subscription
+ * can be updated even if the billing schedule is being changed.
+ *
+ * @param WC_Subscription $subscription The subscription being switched.
+ * @param WC_Order_Item_Product $switched_item The subscription line item being switched.
+ * @param array $switch_data Data about the switches that will occur on the subscription.
+ *
+ * @return bool True if the item being switched is the last remaining item on the subscription after previous switches.
+ */
+ private static function is_last_remaining_item_after_previous_switches( $subscription, $switched_item, $switch_data ) {
+ $remaining_items = $subscription->get_items();
+
+ // If there is no switch data for this subscription return false.
+ if ( ! isset( $switch_data[ $subscription->get_id() ]['switches'] ) ) {
+ return false;
+ }
+
+ foreach( $switch_data[ $subscription->get_id() ]['switches'] as $switch ) {
+ // If items are actively being added to this subscription, then it is not the last remaining item.
+ if ( isset( $switch['add_line_item'] ) ) {
+ return false;
+ }
+
+ if ( isset( $switch['remove_line_item'] ) ) {
+ unset( $remaining_items[ $switch['remove_line_item'] ] );
+ }
+ }
+
+ // If there's only 1 item left and it's the item we're switching, then it's the last remaining item.
+ return 1 === count( $remaining_items ) && isset( $remaining_items[ $switched_item->get_id() ] );
+ }
+
/**
* Adds switch orders or switched subscriptions to the related order meta box.
*
diff --git a/languages/woocommerce-subscriptions.pot b/languages/woocommerce-subscriptions.pot
index 9ea0b45..bed6a1b 100644
--- a/languages/woocommerce-subscriptions.pot
+++ b/languages/woocommerce-subscriptions.pot
@@ -1,17 +1,17 @@
-# Copyright (C) 2023 WooCommerce
+# Copyright (C) 2024 WooCommerce
# This file is distributed under the same license as the Woo Subscriptions plugin.
msgid ""
msgstr ""
-"Project-Id-Version: Woo Subscriptions 5.8.0\n"
+"Project-Id-Version: Woo Subscriptions 5.9.0\n"
"Report-Msgid-Bugs-To: https://woocommerce.com/contact-us\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"POT-Creation-Date: 2023-12-21T00:30:53+00:00\n"
+"POT-Creation-Date: 2024-01-11T06:31:17+00:00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"X-Generator: WP-CLI 2.8.1\n"
+"X-Generator: WP-CLI 2.9.0\n"
"X-Domain: woocommerce-subscriptions\n"
#. Plugin Name of the plugin
@@ -1090,7 +1090,7 @@ msgid "Set a maximum number of times a customer can suspend their account for ea
msgstr ""
#: includes/class-wcs-customer-suspension-manager.php:111
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1334
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1364
msgid "Suspend"
msgstr ""
@@ -1224,7 +1224,7 @@ msgid "Welcome to Woo Subscriptions %s!"
msgstr ""
#: includes/class-wcs-upgrade-notice-manager.php:112
-#: vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php:163
+#: vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php:221
msgid "Learn more"
msgstr ""
@@ -1644,7 +1644,7 @@ msgid "Choose a new subscription."
msgstr ""
#: includes/switching/class-wc-subscriptions-switcher.php:237
-#: includes/switching/class-wc-subscriptions-switcher.php:1238
+#: includes/switching/class-wc-subscriptions-switcher.php:1240
msgid "Your cart contained an invalid subscription switch request. It has been removed."
msgid_plural "Your cart contained invalid subscription switch requests. They have been removed."
msgstr[0] ""
@@ -1755,7 +1755,7 @@ msgstr ""
#: includes/switching/class-wc-subscriptions-switcher.php:448
#: includes/switching/class-wc-subscriptions-switcher.php:550
-#: includes/switching/class-wc-subscriptions-switcher.php:2642
+#: includes/switching/class-wc-subscriptions-switcher.php:2679
msgid "Upgrade or Downgrade"
msgstr ""
@@ -1774,87 +1774,87 @@ msgid "Between Grouped Subscriptions"
msgstr ""
#. translators: %s: order number.
-#: includes/switching/class-wc-subscriptions-switcher.php:1147
+#: includes/switching/class-wc-subscriptions-switcher.php:1149
msgid "Switch order cancelled due to a new switch order being created #%s."
msgstr ""
-#: includes/switching/class-wc-subscriptions-switcher.php:1366
+#: includes/switching/class-wc-subscriptions-switcher.php:1368
msgid "You can only switch to a subscription product."
msgstr ""
-#: includes/switching/class-wc-subscriptions-switcher.php:1372
+#: includes/switching/class-wc-subscriptions-switcher.php:1374
msgid "We can not find your old subscription item."
msgstr ""
-#: includes/switching/class-wc-subscriptions-switcher.php:1394
+#: includes/switching/class-wc-subscriptions-switcher.php:1396
msgid "You can not switch to the same subscription."
msgstr ""
-#: includes/switching/class-wc-subscriptions-switcher.php:1441
+#: includes/switching/class-wc-subscriptions-switcher.php:1443
msgid "You can not switch this subscription. It appears you do not own the subscription."
msgstr ""
-#: includes/switching/class-wc-subscriptions-switcher.php:1482
+#: includes/switching/class-wc-subscriptions-switcher.php:1484
msgid "There was an error locating the switch details."
msgstr ""
-#: includes/switching/class-wc-subscriptions-switcher.php:1863
+#: includes/switching/class-wc-subscriptions-switcher.php:1865
msgctxt "a switch type"
msgid "Downgrade"
msgstr ""
-#: includes/switching/class-wc-subscriptions-switcher.php:1866
+#: includes/switching/class-wc-subscriptions-switcher.php:1868
msgctxt "a switch type"
msgid "Upgrade"
msgstr ""
-#: includes/switching/class-wc-subscriptions-switcher.php:1869
+#: includes/switching/class-wc-subscriptions-switcher.php:1871
msgctxt "a switch type"
msgid "Crossgrade"
msgstr ""
#. translators: %1: product subtotal, %2: HTML span tag, %3: direction (upgrade, downgrade, crossgrade), %4: closing HTML span tag
-#: includes/switching/class-wc-subscriptions-switcher.php:1874
+#: includes/switching/class-wc-subscriptions-switcher.php:1876
msgctxt "product subtotal string"
msgid "%1$s %2$s(%3$s)%4$s"
msgstr ""
-#: includes/switching/class-wc-subscriptions-switcher.php:1990
+#: includes/switching/class-wc-subscriptions-switcher.php:1992
msgid "The original subscription item being switched cannot be found."
msgstr ""
-#: includes/switching/class-wc-subscriptions-switcher.php:1992
+#: includes/switching/class-wc-subscriptions-switcher.php:1994
msgid "The item on the switch order cannot be found."
msgstr ""
#. translators: 1$: old item, 2$: new item when switching
-#: includes/switching/class-wc-subscriptions-switcher.php:2003
+#: includes/switching/class-wc-subscriptions-switcher.php:2005
msgctxt "used in order notes"
msgid "Customer switched from: %1$s to %2$s."
msgstr ""
#. translators: %s: new item name.
-#: includes/switching/class-wc-subscriptions-switcher.php:2006
+#: includes/switching/class-wc-subscriptions-switcher.php:2008
msgctxt "used in order notes"
msgid "Customer added %s."
msgstr ""
-#: includes/switching/class-wc-subscriptions-switcher.php:2366
-#: includes/switching/class-wc-subscriptions-switcher.php:2919
+#: includes/switching/class-wc-subscriptions-switcher.php:2403
+#: includes/switching/class-wc-subscriptions-switcher.php:2956
msgid "Switch Order"
msgstr ""
-#: includes/switching/class-wc-subscriptions-switcher.php:2381
-#: includes/switching/class-wc-subscriptions-switcher.php:2934
+#: includes/switching/class-wc-subscriptions-switcher.php:2418
+#: includes/switching/class-wc-subscriptions-switcher.php:2971
msgid "Switched Subscription"
msgstr ""
-#: includes/switching/class-wc-subscriptions-switcher.php:2599
+#: includes/switching/class-wc-subscriptions-switcher.php:2636
msgctxt "add to cart button text while switching a subscription"
msgid "Switch subscription"
msgstr ""
-#: includes/switching/class-wc-subscriptions-switcher.php:2783
+#: includes/switching/class-wc-subscriptions-switcher.php:2820
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:224
msgctxt "Subscription status"
msgid "Switched"
@@ -1941,11 +1941,11 @@ msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:341
#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:482
#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:66
-msgid "Expire after"
+msgid "Stop renewing after"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:344
-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 synchronised first renewal date."
+msgid "Automatically stop renewing 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 ""
#. translators: %s is a currency symbol / code
@@ -2332,41 +2332,41 @@ msgstr ""
msgid "Lock manual price increases"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:235
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:234
msgid "Search for a product…"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:298
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:329
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:297
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:328
msgctxt "an action on a subscription"
msgid "Move to Trash"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:307
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:306
msgctxt "an action on a subscription"
msgid "Restore"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:308
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:307
msgctxt "an action on a subscription"
msgid "Delete Permanently"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:326
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1722
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:325
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1752
msgctxt "an action on a subscription"
msgid "Activate"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:327
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1723
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:326
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1753
msgctxt "an action on a subscription"
msgid "Put on-hold"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:328
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1335
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1724
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:327
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1365
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1754
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1937
#: vendor/woocommerce/subscriptions-core/includes/wcs-user-functions.php:327
#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:78
@@ -2375,20 +2375,20 @@ msgid "Cancel"
msgstr ""
#. translators: placeholder is the number of subscriptions updated
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:416
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:415
msgid "%s subscription status changed."
msgid_plural "%s subscription statuses changed."
msgstr[0] ""
msgstr[1] ""
#. translators: 1$: is the number of subscriptions not updated, 2$: is the error message
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:435
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:434
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] ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:463
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:462
#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-related-orders-table.php:21
#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:22
#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:37
@@ -2400,7 +2400,7 @@ msgstr[1] ""
msgid "Status"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:464
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:463
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:337
#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:21
#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:21
@@ -2410,79 +2410,79 @@ msgstr ""
msgid "Subscription"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:465
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:464
msgid "Items"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:466
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:465
#: vendor/woocommerce/subscriptions-core/build/index.js:11
#: vendor/woocommerce/subscriptions-core/build/index.js:17
msgid "Total"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:467
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:466
msgid "Start Date"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:468
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:467
msgid "Trial End"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:469
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:468
msgid "Next Payment"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:470
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:469
msgid "Last Order Date"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:471
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:470
msgid "End Date"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:472
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:471
msgctxt "number of orders linked to a subscription"
msgid "Orders"
msgstr ""
#. translators: placeholder is a subscription ID.
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:507
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:506
msgctxt "hash before subscription number"
msgid "#%s"
msgstr ""
#. translators: Placeholder is a
HTML tag.
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:519
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:518
msgid "This subscription couldn't be loaded from the database. %s Click to learn more."
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:557
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:556
msgctxt "meaning billing address"
msgid "Billing:"
msgstr ""
#. translators: placeholder is customer's billing email
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:562
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:561
msgid "Email: %s"
msgstr ""
#. translators: placeholder is customer's billing phone number
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:567
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:566
msgid "Tel: %s"
msgstr ""
#. translators: $1: is opening link, $2: is subscription order number, $3: is closing link tag, $4: is user's name
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:597
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:596
msgctxt "Subscription title on admin table. (e.g.: #211 for John Doe)"
msgid "%1$s#%2$s%3$s for %4$s"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:606
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:605
msgid "Show more details"
msgstr ""
#. translators: %d: item count.
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:627
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:626
msgid "%d item"
msgid_plural "%d items"
msgstr[0] ""
@@ -2490,131 +2490,131 @@ msgstr[1] ""
#. translators: placeholder is the display name of a payment gateway a subscription was paid by
#. translators: %s: payment method.
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:646
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:645
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2126
msgid "Via %s"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:689
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:688
msgid "Y/m/d g:i:s A"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:706
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:705
msgid "Subscription payment overdue."
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:711
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:710
msgid "This date should be treated as an estimate only. The payment gateway for this subscription controls when payments are processed."
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1069
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1072
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1075
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1099
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1102
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1105
msgid "Subscription updated."
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1070
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1100
msgid "Custom field updated."
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1071
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1101
msgid "Custom field deleted."
msgstr ""
#. translators: placeholder is previous post title
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1074
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1104
msgctxt "used in post updated messages"
msgid "Subscription restored to revision from %s"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1076
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1106
msgid "Subscription saved."
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1077
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1107
msgid "Subscription submitted."
msgstr ""
#. translators: php date string
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1079
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1109
msgid "Subscription scheduled for: %1$s."
msgstr ""
#. translators: php date string
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1079
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1109
msgctxt "used in \"Subscription scheduled for \""
msgid "M j, Y @ G:i"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1080
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1110
msgid "Subscription draft updated."
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1122
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1152
msgid "Any Payment Method"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1123
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1153
msgid "None"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1129
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1159
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2108
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:170
msgid "Manual Renewal"
msgstr ""
#. translators: 1: user display name 2: user ID 3: user email
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1288
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1318
msgid "%1$s (#%2$s – %3$s)"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1295
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1325
#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:96
msgid "Search for a customer…"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1333
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1363
#: vendor/woocommerce/subscriptions-core/includes/wcs-user-functions.php:311
msgid "Reactivate"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1336
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1366
msgid "Trash"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1337
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1367
msgid "Delete Permanently"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1356
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1386
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:768
msgid "Restore this item from the Trash"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1358
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1388
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:769
msgid "Restore"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1363
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1393
msgid "Move this item to the Trash"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1377
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1407
msgid "Delete this item permanently"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1388
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1418
msgid "Cancel Now"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1454
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1484
msgctxt "Used in order note. Reason why status changed."
msgid "Subscription status changed by bulk edit:"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1572
+#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1602
msgid "All"
msgstr ""
@@ -3665,9 +3665,9 @@ msgctxt "used in order note as reason for why subscription status changed"
msgid "Subscription renewal payment due:"
msgstr ""
-#. translators: placeholder is an order note.
+#. translators: placeholder %1 is an order note. %2 is the error message that was thrown.
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:149
-msgid "Error: Unable to create renewal order with note \"%s\""
+msgid "Error: Unable to create renewal order with note \"%1$s\". Message: %2$s"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:159
@@ -4189,7 +4189,7 @@ msgstr ""
msgid "Admin turned on automatic renewals by changing payment method to \"%s\" via the Edit Subscription screen."
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php:158
+#: vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php:216
msgid "Ignore this error"
msgstr ""
@@ -4489,7 +4489,9 @@ msgid "Subscription – %s"
msgstr ""
#. translators: %s: Order date
+#. translators: placeholders are strftime() strings.
#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php:265
+#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:261
msgctxt "Order date parsed by DateTime::format"
msgid "M d, Y @ h:i A"
msgstr ""
@@ -5989,36 +5991,35 @@ msgctxt "Refers to the type of the copy being performed: \"copy_order\", \"subsc
msgid "Invalid data. Type of copy is not a string."
msgstr ""
-#. translators: placeholders are strftime() strings.
-#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:253
-msgctxt "Used in subscription post title. \"Subscription renewal order - \""
-msgid "%b %d, %Y @ %I:%M %p"
+#. translators: placeholder %1 is the order type. %2 is the subscription ID we attempted to create the order for.
+#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:229
+msgid "There was an error fetching the new order (%1$s) for subscription %2$d."
msgstr ""
#. translators: placeholder is a date.
-#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:258
+#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:266
msgid "Subscription Renewal Order – %s"
msgstr ""
#. translators: placeholder is a date.
-#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:262
+#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:270
msgid "Resubscribe Order – %s"
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:281
+#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:289
msgid "$type passed to the function was not a string."
msgstr ""
#. translators: placeholder is an order type.
-#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:286
+#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:294
msgid "\"%s\" is not a valid new order type."
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:537
+#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:545
msgid "Invalid data. No valid subscription / order was passed in."
msgstr ""
-#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:541
+#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:549
msgid "Invalid data. No valid item id was passed in."
msgstr ""
@@ -6056,7 +6057,7 @@ msgstr[1] ""
#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:88
msgctxt "Subscription length"
-msgid "Never expire"
+msgid "Do not stop until cancelled"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:93
@@ -6233,7 +6234,7 @@ msgstr ""
#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:67
msgctxt "Subscription Length dropdown's description in pricing fields"
-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 synchronised first renewal date."
+msgid "Automatically stop renewing 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 ""
#: vendor/woocommerce/subscriptions-core/templates/cart/cart-recurring-shipping.php:32
diff --git a/vendor/autoload.php b/vendor/autoload.php
index 5ea7985..d7f5a78 100644
--- a/vendor/autoload.php
+++ b/vendor/autoload.php
@@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) {
require_once __DIR__ . '/composer/autoload_real.php';
-return ComposerAutoloaderInita652888dbfcef5cfe9fff35250423322::getLoader();
+return ComposerAutoloaderInit9ece70b6f360bc43bc3bc8c8cedd9233::getLoader();
diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php
index aad5c34..f2ee97d 100644
--- a/vendor/composer/autoload_real.php
+++ b/vendor/composer/autoload_real.php
@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
-class ComposerAutoloaderInita652888dbfcef5cfe9fff35250423322
+class ComposerAutoloaderInit9ece70b6f360bc43bc3bc8c8cedd9233
{
private static $loader;
@@ -24,12 +24,12 @@ class ComposerAutoloaderInita652888dbfcef5cfe9fff35250423322
require __DIR__ . '/platform_check.php';
- spl_autoload_register(array('ComposerAutoloaderInita652888dbfcef5cfe9fff35250423322', 'loadClassLoader'), true, true);
+ spl_autoload_register(array('ComposerAutoloaderInit9ece70b6f360bc43bc3bc8c8cedd9233', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
- spl_autoload_unregister(array('ComposerAutoloaderInita652888dbfcef5cfe9fff35250423322', 'loadClassLoader'));
+ spl_autoload_unregister(array('ComposerAutoloaderInit9ece70b6f360bc43bc3bc8c8cedd9233', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
- call_user_func(\Composer\Autoload\ComposerStaticInita652888dbfcef5cfe9fff35250423322::getInitializer($loader));
+ call_user_func(\Composer\Autoload\ComposerStaticInit9ece70b6f360bc43bc3bc8c8cedd9233::getInitializer($loader));
$loader->register(true);
diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php
index 2658c19..315a720 100644
--- a/vendor/composer/autoload_static.php
+++ b/vendor/composer/autoload_static.php
@@ -4,7 +4,7 @@
namespace Composer\Autoload;
-class ComposerStaticInita652888dbfcef5cfe9fff35250423322
+class ComposerStaticInit9ece70b6f360bc43bc3bc8c8cedd9233
{
public static $prefixLengthsPsr4 = array (
'C' =>
@@ -129,9 +129,9 @@ class ComposerStaticInita652888dbfcef5cfe9fff35250423322
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
- $loader->prefixLengthsPsr4 = ComposerStaticInita652888dbfcef5cfe9fff35250423322::$prefixLengthsPsr4;
- $loader->prefixDirsPsr4 = ComposerStaticInita652888dbfcef5cfe9fff35250423322::$prefixDirsPsr4;
- $loader->classMap = ComposerStaticInita652888dbfcef5cfe9fff35250423322::$classMap;
+ $loader->prefixLengthsPsr4 = ComposerStaticInit9ece70b6f360bc43bc3bc8c8cedd9233::$prefixLengthsPsr4;
+ $loader->prefixDirsPsr4 = ComposerStaticInit9ece70b6f360bc43bc3bc8c8cedd9233::$prefixDirsPsr4;
+ $loader->classMap = ComposerStaticInit9ece70b6f360bc43bc3bc8c8cedd9233::$classMap;
}, null, ClassLoader::class);
}
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index b9107bb..8dbd05c 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -156,17 +156,17 @@
},
{
"name": "woocommerce/subscriptions-core",
- "version": "6.6.0",
- "version_normalized": "6.6.0.0",
+ "version": "6.7.0",
+ "version_normalized": "6.7.0.0",
"source": {
"type": "git",
"url": "https://github.com/Automattic/woocommerce-subscriptions-core.git",
- "reference": "5abcf9aac4e53ad9bdcf3752a34a04ae42261bac"
+ "reference": "2531db11c67a060cbb06c6246c162688a2c9eccb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/5abcf9aac4e53ad9bdcf3752a34a04ae42261bac",
- "reference": "5abcf9aac4e53ad9bdcf3752a34a04ae42261bac",
+ "url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/2531db11c67a060cbb06c6246c162688a2c9eccb",
+ "reference": "2531db11c67a060cbb06c6246c162688a2c9eccb",
"shasum": ""
},
"require": {
@@ -179,7 +179,7 @@
"woocommerce/woocommerce-sniffs": "0.1.0",
"yoast/phpunit-polyfills": "1.1.0"
},
- "time": "2023-12-20T07:19:09+00:00",
+ "time": "2024-01-11T04:55:48+00:00",
"type": "wordpress-plugin",
"extra": {
"phpcodesniffer-search-depth": 2
@@ -209,7 +209,7 @@
"description": "Sell products and services with recurring payments in your WooCommerce Store.",
"homepage": "https://github.com/Automattic/woocommerce-subscriptions-core",
"support": {
- "source": "https://github.com/Automattic/woocommerce-subscriptions-core/tree/6.6.0",
+ "source": "https://github.com/Automattic/woocommerce-subscriptions-core/tree/6.7.0",
"issues": "https://github.com/Automattic/woocommerce-subscriptions-core/issues"
},
"install-path": "../woocommerce/subscriptions-core"
diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php
index ba3b91c..eff33b2 100644
--- a/vendor/composer/installed.php
+++ b/vendor/composer/installed.php
@@ -1,9 +1,9 @@
array(
'name' => 'woocommerce/woocommerce-subscriptions',
- 'pretty_version' => 'dev-release/5.8.0',
- 'version' => 'dev-release/5.8.0',
- 'reference' => '49bca69e2b17a445dc250b21c753175bdd9ed2c6',
+ 'pretty_version' => 'dev-release/5.9.0',
+ 'version' => 'dev-release/5.9.0',
+ 'reference' => '559969625c750b519df548291b5ba9280cdf8690',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -32,18 +32,18 @@
),
),
'woocommerce/subscriptions-core' => array(
- 'pretty_version' => '6.6.0',
- 'version' => '6.6.0.0',
- 'reference' => '5abcf9aac4e53ad9bdcf3752a34a04ae42261bac',
+ 'pretty_version' => '6.7.0',
+ 'version' => '6.7.0.0',
+ 'reference' => '2531db11c67a060cbb06c6246c162688a2c9eccb',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../woocommerce/subscriptions-core',
'aliases' => array(),
'dev_requirement' => false,
),
'woocommerce/woocommerce-subscriptions' => array(
- 'pretty_version' => 'dev-release/5.8.0',
- 'version' => 'dev-release/5.8.0',
- 'reference' => '49bca69e2b17a445dc250b21c753175bdd9ed2c6',
+ 'pretty_version' => 'dev-release/5.9.0',
+ 'version' => 'dev-release/5.9.0',
+ 'reference' => '559969625c750b519df548291b5ba9280cdf8690',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
diff --git a/vendor/woocommerce/subscriptions-core/changelog.txt b/vendor/woocommerce/subscriptions-core/changelog.txt
index 6817b6e..dbb431f 100644
--- a/vendor/woocommerce/subscriptions-core/changelog.txt
+++ b/vendor/woocommerce/subscriptions-core/changelog.txt
@@ -1,5 +1,10 @@
*** WooCommerce Subscriptions Core Changelog ***
+= 6.7.0 - 2024-01-11 =
+* Update - Changed the edit subscription product "Expire after" (Subscription length) so it more clearly describes when a subscription will automatically stop renewing.
+* Update - Log all exceptions caught by WooCommerce while processing a subscription scheduled action.
+* Fix - Resolved an issue that caused ordering the Admin Subscriptions List Table to not work when HPOS is enabled.
+
= 6.6.0 - 2023-12-20 =
* Fix - When using the checkout block to pay for renewal orders, ensure the order's cart hash is updated to make sure the existing order can be used.
* Fix - Prevents a PHP fatal error that occurs when the cart contains a renewal order item that no longer exists.
diff --git a/vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php b/vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php
index a0a8579..878a6c6 100644
--- a/vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php
+++ b/vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php
@@ -338,10 +338,10 @@ class WC_Subscriptions_Admin {
array(
'id' => '_subscription_length',
'class' => 'wc_input_subscription_length select short wc-enhanced-select',
- 'label' => __( 'Expire after', 'woocommerce-subscriptions' ),
+ 'label' => __( 'Stop renewing after', 'woocommerce-subscriptions' ),
'options' => wcs_get_subscription_ranges( $chosen_period ),
'desc_tip' => true,
- 'description' => __( '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.', 'woocommerce-subscriptions' ),
+ 'description' => __( 'Automatically stop renewing 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.', 'woocommerce-subscriptions' ),
)
);
@@ -479,7 +479,7 @@ class WC_Subscriptions_Admin {
-
+
diff --git a/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php
index 7ee883b..463adf6 100644
--- a/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php
+++ b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php
@@ -204,7 +204,6 @@ class WCS_Admin_Post_Types {
return $pieces;
}
-
/**
* Displays the dropdown for the product filter
*
@@ -880,6 +879,7 @@ class WCS_Admin_Post_Types {
$request_query = $this->set_filter_by_customer_query( $request_query );
$request_query = $this->set_filter_by_product_query( $request_query );
$request_query = $this->set_filter_by_payment_method_query( $request_query );
+ $request_query = $this->set_order_by_query_args( $request_query );
return $request_query;
}
@@ -1021,6 +1021,36 @@ class WCS_Admin_Post_Types {
return $request_query;
}
+ /**
+ * Sets the order by query args for the subscriptions list table request on HPOS enabled sites.
+ *
+ * This function is similar to the posts table equivalent function (self::request_query()) except it only sets the order by.
+ *
+ * @param array $request_query The query args sent to wc_get_orders() to populate the list table.
+ * @return array $request_query
+ */
+ private function set_order_by_query_args( $request_query ) {
+
+ if ( ! isset( $request_query['orderby'] ) ) {
+ return $request_query;
+ }
+
+ switch ( $request_query['orderby'] ) {
+ case 'last_payment_date':
+ add_filter( 'woocommerce_orders_table_query_clauses', [ $this, 'orders_table_query_clauses' ], 10, 3 );
+ break;
+ case 'start_date':
+ case 'trial_end_date':
+ case 'next_payment_date':
+ case 'end_date':
+ $request_query['meta_key'] = sprintf( '_schedule_%s', str_replace( '_date', '', $request_query['orderby'] ) ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
+ $request_query['orderby'] = 'meta_value';
+ break;
+ }
+
+ return $request_query;
+ }
+
/**
* Set the 'post__in' query var with a given set of post ids.
*
@@ -1752,4 +1782,109 @@ class WCS_Admin_Post_Types {
is_db_user_privileged() ) {
+ $pieces = self::orders_table_clauses_high_performance( $pieces );
+ } else {
+ $pieces = self::orders_table_clauses_low_performance( $pieces );
+ }
+
+ $query_order = strtoupper( $args['order'] );
+
+ // fields and order are identical in both cases
+ $pieces['fields'] .= ', COALESCE(lp.last_payment, orders.date_created_gmt, 0) as lp';
+ $pieces['orderby'] = "CAST(lp AS DATETIME) {$query_order}";
+
+ return $pieces;
+ }
+
+ /**
+ * Adds order table query clauses to sort the subscriptions list table by last payment date.
+ *
+ * This function provides a lower performance method using a subquery to sort by last payment date.
+ * It is a HPOS version of @see self::posts_clauses_low_performance().
+ *
+ * @param string[] $pieces Associative array of the clauses for the query.
+ * @return string[] $pieces Updated associative array of clauses for the query.
+ */
+ private function orders_table_clauses_low_performance( $pieces ) {
+ $order_datastore = wc_get_container()->get( \Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore::class );
+ $order_table = $order_datastore::get_orders_table_name();
+ $meta_table = $order_datastore::get_meta_table_name();
+
+ $pieces['join'] .= "LEFT JOIN
+ (SELECT
+ MAX( orders.date_created_gmt ) as last_payment,
+ order_meta.meta_value
+ FROM {$meta_table} as order_meta
+ LEFT JOIN {$order_table} orders ON orders.id = order_meta.order_id
+ WHERE order_meta.meta_key = '_subscription_renewal'
+ GROUP BY order_meta.meta_value) lp
+ ON {$order_table}.id = lp.meta_value
+ LEFT JOIN {$order_table} orders on {$order_table}.parent_order_id = orders.ID";
+
+ return $pieces;
+ }
+
+ /**
+ * Adds order table query clauses to sort the subscriptions list table by last payment date.
+ *
+ * This function provides a higher performance method using a temporary table to sort by last payment date.
+ * It is a HPOS version of @see self::posts_clauses_high_performance().
+ *
+ * @param string[] $pieces Associative array of the clauses for the query.
+ * @return string[] $pieces Updated associative array of clauses for the query.
+ */
+ private function orders_table_clauses_high_performance( $pieces ) {
+ global $wpdb;
+
+ $order_datastore = wc_get_container()->get( \Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore::class );
+ $order_table = $order_datastore::get_orders_table_name();
+ $meta_table = $order_datastore::get_meta_table_name();
+ $session = wp_get_session_token();
+
+ $table_name = substr( "{$wpdb->prefix}tmp_{$session}_lastpayment", 0, 64 );
+
+ // Create a temporary table, drop the previous one.
+ $wpdb->query( $wpdb->prepare( 'DROP TEMPORARY TABLE IF EXISTS %s', $table_name ) );
+
+ $wpdb->query(
+ $wpdb->prepare(
+ "CREATE TEMPORARY TABLE %s (id INT PRIMARY KEY, last_payment DATETIME) AS
+ SELECT order_meta.meta_value as id, MAX( orders.date_created_gmt ) as last_payment FROM %s order_meta
+ LEFT JOIN %s as orders ON orders.id = order_meta.order_id
+ WHERE order_meta.meta_key = '_subscription_renewal'
+ GROUP BY order_meta.meta_value",
+ $table_name,
+ $meta_table,
+ $order_table
+ )
+ );
+
+ $pieces['join'] .= "LEFT JOIN {$table_name} lp
+ ON {$order_table}.id = lp.id
+ LEFT JOIN {$order_table} orders on {$order_table}.parent_order_id = orders.id";
+
+ return $pieces;
+ }
}
diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php
index b81b159..1c8623b 100644
--- a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php
+++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php
@@ -16,7 +16,7 @@ class WC_Subscriptions_Core_Plugin {
* The version of subscriptions-core library.
* @var string
*/
- protected $library_version = '6.6.0'; // WRCS: DEFINED_VERSION.
+ protected $library_version = '6.7.0'; // WRCS: DEFINED_VERSION.
/**
* The subscription scheduler instance.
diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php
index d24a010..85a3f3d 100644
--- a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php
+++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php
@@ -145,8 +145,8 @@ class WC_Subscriptions_Manager {
$renewal_order = wcs_create_renewal_order( $subscription );
if ( is_wp_error( $renewal_order ) ) {
- // translators: placeholder is an order note.
- throw new Exception( sprintf( __( 'Error: Unable to create renewal order with note "%s"', 'woocommerce-subscriptions' ), $order_note ) );
+ // translators: placeholder %1 is an order note. %2 is the error message that was thrown.
+ throw new Exception( sprintf( __( 'Error: Unable to create renewal order with note "%1$s". Message: %2$s', 'woocommerce-subscriptions' ), $order_note, $renewal_order->get_error_message() ) );
}
}
diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php
index 6945e26..56d78c2 100644
--- a/vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php
+++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php
@@ -34,6 +34,13 @@ class WCS_Failed_Scheduled_Action_Manager {
*/
protected $logger;
+ /**
+ * Exceptions caught by WC while this class is listening to the `woocommerce_caught_exception` action.
+ *
+ * @var Exception[]
+ */
+ protected $exceptions = [];
+
/**
* Constructor.
*
@@ -55,6 +62,7 @@ class WCS_Failed_Scheduled_Action_Manager {
add_action( 'action_scheduler_failed_execution', array( $this, 'log_action_scheduler_failure' ), 10, 2 );
add_action( 'action_scheduler_unexpected_shutdown', array( $this, 'log_action_scheduler_failure' ), 10, 2 );
add_action( 'admin_notices', array( $this, 'maybe_show_admin_notice' ) );
+ add_action( 'action_scheduler_begin_execute', array( $this, 'maybe_attach_exception_listener' ) );
}
/**
@@ -106,6 +114,56 @@ class WCS_Failed_Scheduled_Action_Manager {
);
update_option( WC_Subscriptions_Admin::$option_prefix . '_failed_scheduled_actions', $failed_scheduled_actions );
+
+ // If there is an exception listener and it's caught exceptions, log them for additional debugging.
+ if ( ! empty( $this->exceptions ) ) {
+ foreach ( $this->exceptions as $exception ) {
+ $message = 'Exception: ' . $exception->getMessage() . ' in ' . $exception->getFile() . ':' . $exception->getLine();
+ $this->log( $message . PHP_EOL . $exception->getTraceAsString() );
+ ActionScheduler_Logger::instance()->log( $action_id, $message );
+ }
+
+ // Now that we've logged the exceptions, we can detach the exception listener.
+ $this->clear_exceptions_and_detach_listener();
+ }
+ }
+
+ /**
+ * Creates a new exception listener when processing subscription-related scheduled actions.
+ *
+ * @param int $action_id The ID of the scheduled action being ran.
+ */
+ public function maybe_attach_exception_listener( $action_id ) {
+ $action = $this->get_action( $action_id );
+
+ if ( ! $action || ! isset( $this->tracked_scheduled_actions[ $action->get_hook() ] ) ) {
+ return;
+ }
+
+ // Add an action to detach the exception listener and clear the caught exceptions after the scheduled action has been executed.
+ add_action( 'action_scheduler_after_execute', [ $this, 'clear_exceptions_and_detach_listener' ] );
+
+ // Attach the exception listener.
+ add_action( 'woocommerce_caught_exception', [ $this, 'handle_exception' ] );
+ }
+
+ /**
+ * Adds an exception to the list of exceptions caught by WC.
+ *
+ * @param Exception $exception The exception that was caught.
+ */
+ public function handle_exception( $exception ) {
+ $this->exceptions[] = $exception;
+ }
+
+ /**
+ * Clears the list of exceptions caught by WC and detaches the listener.
+ *
+ * This function is called directly and attached to an action that runs after a scheduled action has finished being executed.
+ */
+ public function clear_exceptions_and_detach_listener() {
+ $this->exceptions = [];
+ remove_action( 'woocommerce_caught_exception', [ $this, 'handle_exception' ] );
}
/**
diff --git a/vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php
index 15f5d28..0cdd197 100644
--- a/vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php
+++ b/vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php
@@ -218,17 +218,25 @@ function wcs_create_order_from_subscription( $subscription, $type ) {
// Delete the transient that caches whether the order needs processing. Because we've added line items, the order may now need processing.
delete_transient( 'wc_order_' . $new_order->get_id() . '_needs_processing' );
+ /*
+ * Fetch a fresh instance of the order because the current order instance has an empty line item cache generated before we had copied the line items.
+ * Fetching a new instance will ensure the line items are available via $new_order->get_items().
+ */
+ $order = wc_get_order( $new_order->get_id() );
+
+ if ( ! $order ) {
+ // translators: placeholder %1 is the order type. %2 is the subscription ID we attempted to create the order for.
+ throw new Exception( sprintf( __( 'There was an error fetching the new order (%1$s) for subscription %2$d.', 'woocommerce-subscriptions' ), $type, $subscription->get_id() ) );
+ }
+
/**
* Filters the new order created from the subscription.
*
- * Fetches a fresh instance of the order because the current order instance has an empty line item cache generated before we had copied the line items.
- * Fetching a new instance will ensure the line items are available via $new_order->get_items().
- *
* @param WC_Order $new_order The new order created from the subscription.
* @param WC_Subscription $subscription The subscription the order was created from.
* @param string $type The type of order being created. Either 'renewal_order' or 'resubscribe_order'.
*/
- return apply_filters( 'wcs_new_order_created', wc_get_order( $new_order->get_id() ), $subscription, $type );
+ return apply_filters( 'wcs_new_order_created', $order, $subscription, $type );
} catch ( Exception $e ) {
// There was an error adding the subscription
@@ -250,7 +258,7 @@ function wcs_get_new_order_title( $type ) {
$type = wcs_validate_new_order_type( $type );
// translators: placeholders are strftime() strings.
- $order_date = strftime( _x( '%b %d, %Y @ %I:%M %p', 'Used in subscription post title. "Subscription renewal order - "', 'woocommerce-subscriptions' ) ); // phpcs:ignore WordPress.WP.I18n.UnorderedPlaceholdersText
+ $order_date = ( new DateTime( 'now' ) )->format( _x( 'M d, Y @ h:i A', 'Order date parsed by DateTime::format', 'woocommerce-subscriptions' ) );
switch ( $type ) {
case 'renewal_order':
diff --git a/vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php
index f69febe..cd918e4 100644
--- a/vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php
+++ b/vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php
@@ -85,7 +85,7 @@ function wcs_get_non_cached_subscription_ranges() {
foreach ( array( 'day', 'week', 'month', 'year' ) as $period ) {
$subscription_lengths = array(
- _x( 'Never expire', 'Subscription length', 'woocommerce-subscriptions' ),
+ _x( 'Do not stop until cancelled', 'Subscription length', 'woocommerce-subscriptions' ),
);
switch ( $period ) {
diff --git a/vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php b/vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php
index 290cbe5..5f51921 100644
--- a/vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php
+++ b/vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php
@@ -63,8 +63,8 @@ if ( ! defined( 'ABSPATH' ) ) {