Updates to 5.7.0

This commit is contained in:
WooCommerce
2023-11-09 10:12:17 +00:00
parent 5eedf6aedb
commit a87183cf97
31 changed files with 925 additions and 442 deletions

View File

@@ -1,5 +1,18 @@
*** Woo Subscriptions Changelog ***
2023-11-09 - version 5.7.0
* Add: Introduce a new REST API endpoint to create subscription(s) from a given order. This endpoint is available at POST `/wc/v3/orders/{order_id}/subscriptions` and accepts a single order ID.
* Add: When a customer toggles automatic renewals on or off via their My Account page, add a note to the subscription to record that event.
* Fix: Set and update a subscription's trial end date via the REST API.
* Fix: Ensure the `woocommerce_subscription_renewal_payment_complete` hook is always triggered when processing early renewals via the checkout page (introduced in 5.6.0).
* Fix: When a subscription is flagged as requiring manual payments, allow admin users to turn on automatic payments for a subscription via the Edit Subscription page by selecting a new payment method.
* Fix: When processing an early renewal order, make sure the suspension count is reset back to 0 on payment complete.
* Fix: Ensure proper backfilling of subscription metadata (i.e. dates and cache) to the postmeta table when HPOS is enabled and compatibility mode (data syncing) is turned on.
* Fix: Fetch and update the `_cancelled_email_sent` meta in a HPOS compatibile way.
* Dev: Introduce a new wcs_get_subscription_grouping_key() function to generate a unique key for a subscription based on its billing schedule. This function uses the existing recurring cart key concept.
* Dev: Deprecate the WC_Subscriptions_Synchroniser::add_to_recurring_cart_key(). Use WC_Subscriptions_Synchroniser::add_to_recurring_product_grouping_key() instead.
* Dev: Update subscriptions-core to 6.5.0.
2023-10-18 - version 5.6.0
* Add: Introduce the "Subscription Relationship" column under the Orders list admin page when HPOS is enabled.
* Add: Use admin theme color and the correct WooCommerce colors.

View File

@@ -60,6 +60,16 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller {
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
register_rest_route( $this->namespace, "/orders/(?P<id>[\d]+)/{$this->rest_base}", array(
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_subscriptions_from_order' ),
'permission_callback' => array( $this, 'create_item_permissions_check' ),
'args' => $this->get_collection_params(),
),
'schema' => array( $this, 'get_public_item_schema' ),
) );
}
/**
@@ -261,7 +271,7 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller {
$this->update_address( $subscription, $value, $key );
break;
case 'start_date':
case 'trial_end':
case 'trial_end_date':
case 'next_payment_date':
case 'cancelled_date':
case 'end_date':
@@ -413,8 +423,8 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller {
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
),
'trial_date' => array(
'description' => __( "The subscription's trial date, as GMT.", 'woocommerce-subscriptions' ),
'trial_end_date' => array(
'description' => __( "The subscription's trial end date, as GMT.", 'woocommerce-subscriptions' ),
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
),
@@ -512,4 +522,196 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller {
throw new WC_REST_Exception( 'woocommerce_rest_invalid_payment_data', sprintf( __( 'Subscription payment method could not be set to %1$s with error message: %2$s', 'woocommerce-subscriptions' ), $payment_method, $e->getMessage() ), 400 );
}
}
/**
* Creates subscriptions from an order.
*
* @param WP_REST_Request $request
* @return array Subscriptions created from the order.
*/
public function create_subscriptions_from_order( $request ) {
$order_id = absint( $request->get_param( 'id' ) );
if ( empty( $order_id ) ) {
return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order ID.', 'woocommerce-subscriptions' ), array( 'status' => 404 ) );
}
$order = wc_get_order( $order_id );
if ( ! $order || ! wcs_is_order( $order ) ) {
return new WP_Error( 'woocommerce_rest_order_invalid_id', sprintf( __( 'Failed to load order object with the ID %d.', 'woocommerce-subscriptions' ), $order_id ), array( 'status' => 404 ) );
}
if ( ! $order->get_customer_id() ) {
return new WP_Error( 'woocommerce_rest_invalid_order', __( 'Order does not have a customer associated with it. Subscriptions require a customer.', 'woocommerce-subscriptions' ), array( 'status' => 404 ) );
}
if ( wcs_order_contains_subscription( $order, 'any' ) ) {
return new WP_Error( 'woocommerce_rest_invalid_order', __( 'Order already has subscriptions associated with it.', 'woocommerce-subscriptions' ), array( 'status' => 404 ) );
}
$subscription_groups = [];
$subscriptions = [];
// Group the order items into subscription groups.
foreach ( $order->get_items() as $item ) {
$product = $item->get_product();
if ( ! WC_Subscriptions_Product::is_subscription( $product ) ) {
continue;
}
$subscription_groups[ wcs_get_subscription_item_grouping_key( $item ) ][] = $item;
}
// Return a 204 if there are no subscriptions to be created.
if ( empty( $subscription_groups ) ) {
$response = rest_ensure_response( $subscriptions );
$response->set_status( 204 );
return $response;
}
/**
* Start creating any subscriptions start transaction if available.
*
* To ensure data integrity, if any subscription fails to be created, the transaction will be rolled back. This will enable
* the client to resubmit the request without having to worry about duplicate subscriptions being created.
*/
$transaction = new WCS_SQL_Transaction();
$transaction->start();
try {
// Create subscriptions.
foreach ( $subscription_groups as $items ) {
// Get the first item in the group to use as the base for the subscription.
$product = $items[0]->get_product();
$start_date = wcs_get_datetime_utc_string( $order->get_date_created( 'edit' ) );
$subscription = wcs_create_subscription( [
'order_id' => $order_id,
'created_via' => 'rest-api',
'start_date' => $start_date,
'status' => $order->is_paid() ? 'active' : 'pending',
'billing_period' => WC_Subscriptions_Product::get_period( $product ),
'billing_interval' => WC_Subscriptions_Product::get_interval( $product ),
'customer_note' => $order->get_customer_note(),
] );
if ( is_wp_error( $subscription ) ) {
throw new Exception( $subscription->get_error_message() );
}
wcs_copy_order_address( $order, $subscription );
$subscription->update_dates(
array(
'trial_end' => WC_Subscriptions_Product::get_trial_expiration_date( $product, $start_date ),
'next_payment' => WC_Subscriptions_Product::get_first_renewal_payment_date( $product, $start_date ),
'end' => WC_Subscriptions_Product::get_expiration_date( $product, $start_date ),
)
);
$subscription->set_payment_method( $order->get_payment_method() );
wcs_copy_order_meta( $order, $subscription, 'subscription' );
// Add items.
$subscription_needs_shipping = false;
foreach ( $items as $item ) {
// Create order line item.
$item_id = wc_add_order_item(
$subscription->get_id(),
[
'order_item_name' => $item->get_name(),
'order_item_type' => $item->get_type(),
]
);
$subscription_item = $subscription->get_item( $item_id );
wcs_copy_order_item( $item, $subscription_item );
$subscription_item->save();
// Check if this subscription will need shipping.
if ( ! $subscription_needs_shipping ) {
$product = $item->get_product();
if ( $product ) {
$subscription_needs_shipping = $product->needs_shipping() && ! WC_Subscriptions_Product::needs_one_time_shipping( $product );
}
}
}
// Add coupons.
foreach ( $order->get_coupons() as $coupon_item ) {
$coupon = new WC_Coupon( $coupon_item->get_code() );
try {
// validate_subscription_coupon_for_order will throw an exception if the coupon cannot be applied to the subscription.
WC_Subscriptions_Coupon::validate_subscription_coupon_for_order( true, $coupon, $subscription );
$subscription->apply_coupon( $coupon->get_code() );
} catch ( Exception $e ) {
// Do nothing. The coupon will not be applied to the subscription.
}
}
// Add shipping.
if ( $subscription_needs_shipping ) {
foreach ( $order->get_shipping_methods() as $shipping_item ) {
$rate = new WC_Shipping_Rate( $shipping_item->get_method_id(), $shipping_item->get_method_title(), $shipping_item->get_total(), $shipping_item->get_taxes(), $shipping_item->get_instance_id() );
$item = new WC_Order_Item_Shipping();
$item->set_order_id( $subscription->get_id() );
$item->set_shipping_rate( $rate );
$subscription->add_item( $item );
}
}
// Add fees.
foreach ( $order->get_fees() as $fee_item ) {
if ( ! apply_filters( 'wcs_should_copy_fee_item_to_subscription', true, $fee_item, $subscription, $order ) ) {
continue;
}
$item = new WC_Order_Item_Fee();
$item->set_props(
array(
'name' => $fee_item->get_name(),
'tax_class' => $fee_item->get_tax_class(),
'amount' => $fee_item->get_amount(),
'total' => $fee_item->get_total(),
'total_tax' => $fee_item->get_total_tax(),
'taxes' => $fee_item->get_taxes(),
)
);
$subscription->add_item( $item );
}
$subscription->calculate_totals();
$subscription->save();
/**
* Fires after a single subscription is created or updated via the REST API.
*
* @param WC_Subscription $object Inserted subscription.
* @param WP_REST_Request $request Request object.
* @param boolean $creating True when creating object, false when updating.
*/
do_action( "woocommerce_rest_insert_{$this->post_type}_object", $subscription, $request, true );
$response = $this->prepare_object_for_response( wcs_get_subscription( $subscription->get_id() ), $request );
$subscriptions[] = $this->prepare_response_for_collection( $response );
}
} catch ( Exception $e ) {
$transaction->rollback();
return new WP_Error( 'woocommerce_rest_invalid_subscription_data', $e->getMessage(), array( 'status' => 404 ) );
}
// If we got here, the subscription was created without problems
$transaction->commit();
return rest_ensure_response( $subscriptions );
}
}

View File

@@ -479,6 +479,9 @@ class WCS_Cart_Early_Renewal extends WCS_Cart_Renewal {
// Payment success - if payment was successful and dates haven't been updated for this order, update the subscription dates and store meta to prevent dates being updated multiple times for the same order.
if ( $subscription && $order->is_paid() && ! $order->meta_exists( self::SUBSCRIPTION_DATES_UPDATED_META_KEY ) ) {
// Call the subscription payment complete function to trigger the payment complete hook and reset suspension counts and update user roles.
$subscription->payment_complete();
wcs_update_dates_after_early_renewal( $subscription, $order );
$order->update_meta_data( self::SUBSCRIPTION_DATES_UPDATED_META_KEY, wc_bool_to_string( true ) );

View File

@@ -2,14 +2,14 @@
# This file is distributed under the same license as the Woo Subscriptions plugin.
msgid ""
msgstr ""
"Project-Id-Version: Woo Subscriptions 5.6.0\n"
"Project-Id-Version: Woo Subscriptions 5.7.0\n"
"Report-Msgid-Bugs-To: https://woocommerce.com/contact-us\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2023-10-18T04:37:04+00:00\n"
"POT-Creation-Date: 2023-11-09T05:16:09+00:00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"X-Generator: WP-CLI 2.8.1\n"
"X-Domain: woocommerce-subscriptions\n"
@@ -669,55 +669,55 @@ msgstr ""
msgid "Payment Gateway Feature Support."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:155
#: includes/api/class-wc-rest-subscriptions-controller.php:165
msgid "Invalid subscription ID."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:161
#: includes/api/class-wc-rest-subscriptions-controller.php:171
msgid "Failed to load subscription object with the ID %d."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:323
#: includes/api/class-wc-rest-subscriptions-controller.php:333
msgid "Subscription dates could not be set. Error message: %s"
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:359
#: includes/api/class-wc-rest-subscriptions-controller.php:369
msgid "Subscription status."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:362
#: includes/api/class-wc-rest-subscriptions-controller.php:372
msgid "Where the subscription was created."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:363
#: includes/api/class-wc-rest-subscriptions-controller.php:373
msgid "Currency the subscription was created with, in ISO format."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:364
#: includes/api/class-wc-rest-subscriptions-controller.php:374
msgid "The date the subscription was created, in the site's timezone."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:365
#: includes/api/class-wc-rest-subscriptions-controller.php:375
msgid "The date the subscription was created, as GMT."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:366
#: includes/api/class-wc-rest-subscriptions-controller.php:376
msgid "The date the subscription was last modified, in the site's timezone."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:367
#: includes/api/class-wc-rest-subscriptions-controller.php:377
msgid "The date the subscription was last modified, as GMT."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:368
#: includes/api/class-wc-rest-subscriptions-controller.php:378
msgid "User ID who owns the subscription."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:378
#: includes/api/class-wc-rest-subscriptions-controller.php:388
msgid "The status to transition a subscription to."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:384
#: includes/api/class-wc-rest-subscriptions-controller.php:394
#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:350
#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:506
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:179
@@ -725,7 +725,7 @@ msgstr ""
msgid "The number of billing periods between subscription renewals."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:389
#: includes/api/class-wc-rest-subscriptions-controller.php:399
#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:355
#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:511
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:172
@@ -733,56 +733,72 @@ msgstr ""
msgid "Billing period for the subscription."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:395
#: includes/api/class-wc-rest-subscriptions-controller.php:405
#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:361
#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:517
msgid "Subscription payment details."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:400
#: includes/api/class-wc-rest-subscriptions-controller.php:410
msgid "Payment method meta and token in a post_meta_key: token format."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:405
#: includes/api/class-wc-rest-subscriptions-controller.php:415
msgid "Payment method meta and token in a user_meta_key : token format."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:412
#: includes/api/class-wc-rest-subscriptions-controller.php:422
msgid "The subscription's start date, as GMT."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:417
msgid "The subscription's trial date, as GMT."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:422
msgid "The subscription's next payment date, as GMT."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:427
msgid "The subscription's cancelled date, as GMT."
msgid "The subscription's trial end date, as GMT."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:432
msgid "The subscription's next payment date, as GMT."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:437
msgid "The subscription's cancelled date, as GMT."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:442
msgid "The subscription's end date, as GMT."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:451
#: includes/api/class-wc-rest-subscriptions-controller.php:461
msgid "Limit result set to subscriptions which have specific statuses."
msgstr ""
#. translators: placeholder is the payment method ID.
#: includes/api/class-wc-rest-subscriptions-controller.php:495
#: includes/api/class-wc-rest-subscriptions-controller.php:505
msgid "The %s payment gateway does not support admin changing the payment method."
msgstr ""
#. translators: 1$: gateway id, 2$: error message
#: includes/api/class-wc-rest-subscriptions-controller.php:512
#: includes/api/class-wc-rest-subscriptions-controller.php:522
#: includes/api/legacy/class-wc-rest-subscriptions-controller.php:336
#: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:405
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:536
msgid "Invalid order ID."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:542
msgid "Failed to load order object with the ID %d."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:546
msgid "Order does not have a customer associated with it. Subscriptions require a customer."
msgstr ""
#: includes/api/class-wc-rest-subscriptions-controller.php:550
msgid "Order already has subscriptions associated with it."
msgstr ""
#: includes/api/legacy/class-wc-api-subscriptions.php:102
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:136
msgid "Invalid subscription status given."
@@ -1287,11 +1303,11 @@ msgid "Order %s created to record early renewal."
msgstr ""
#: includes/early-renewal/class-wcs-cart-early-renewal.php:294
#: includes/early-renewal/class-wcs-cart-early-renewal.php:624
#: includes/early-renewal/class-wcs-cart-early-renewal.php:627
msgid "Cancel"
msgstr ""
#: includes/early-renewal/class-wcs-cart-early-renewal.php:592
#: includes/early-renewal/class-wcs-cart-early-renewal.php:595
msgctxt "used in order note as reason for why subscription status changed"
msgid "Customer requested to renew early:"
msgstr ""
@@ -1718,13 +1734,13 @@ msgid "When switching to a subscription with a length, you can take into account
msgstr ""
#: includes/switching/class-wc-subscriptions-switcher.php:437
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:225
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:226
msgctxt "when to prorate first payment / subscription length"
msgid "For Virtual Subscription Products Only"
msgstr ""
#: includes/switching/class-wc-subscriptions-switcher.php:438
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:226
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:227
msgctxt "when to prorate first payment / subscription length"
msgid "For All Subscription Products"
msgstr ""
@@ -1870,6 +1886,46 @@ msgstr ""
msgid "Want to renew early via the checkout? Click %shere.%s"
msgstr ""
#: tests/unit/scheduler/scheduler.php:65
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:291
msgctxt "table heading"
msgid "Start Date"
msgstr ""
#: tests/unit/scheduler/scheduler.php:66
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:292
msgctxt "table heading"
msgid "Trial End"
msgstr ""
#: tests/unit/scheduler/scheduler.php:67
#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:40
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:293
msgctxt "table heading"
msgid "Next Payment"
msgstr ""
#: tests/unit/scheduler/scheduler.php:68
#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:23
#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:23
#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:23
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:294
msgctxt "table heading"
msgid "Last Order Date"
msgstr ""
#: tests/unit/scheduler/scheduler.php:69
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:295
msgctxt "table heading"
msgid "Cancelled Date"
msgstr ""
#: tests/unit/scheduler/scheduler.php:70
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:296
msgctxt "table heading"
msgid "End Date"
msgstr ""
#. translators: 1: relation type, 2: list of valid relation types.
#: vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-related-order-store.php:148
msgid "Invalid relation type: %1$s. Order relationship type must be one of: %2$s."
@@ -1952,7 +2008,7 @@ msgid "Optionally include an amount to be charged at the outset of the subscript
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:371
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2469
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2422
#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:25
msgid "Free trial"
msgstr ""
@@ -2463,7 +2519,7 @@ 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/class-wc-subscription.php:2047
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2052
msgid "Via %s"
msgstr ""
@@ -2531,7 +2587,7 @@ msgid "None"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1129
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2029
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2034
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:170
msgid "Manual Renewal"
msgstr ""
@@ -2783,14 +2839,14 @@ msgid "No billing address set."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:188
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:39
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:52
msgid "Payment Method"
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:36
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:47
msgid "Payment method"
msgstr ""
#. translators: %s: gateway ID.
#: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:193
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:54
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:49
msgctxt "The gateway ID displayed on the Edit Subscriptions screen when editing payment method."
msgid "Gateway ID: [%s]"
msgstr ""
@@ -2950,7 +3006,7 @@ msgstr ""
#. translators: %d: subscription ID.
#. translators: %d: order ID.
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1365
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2470
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2475
msgid "Subscription #%d: "
msgstr ""
@@ -2958,67 +3014,67 @@ msgstr ""
msgid "Payment status marked complete."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1807
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1812
msgid "Payment failed."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1812
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1817
msgid "Subscription Cancelled: maximum number of failed payments reached."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1922
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1927
msgid "The \"all\" value for $order_type parameter is deprecated. It was a misnomer, as it did not return resubscribe orders. It was also inconsistent with order type values accepted by wcs_get_subscription_orders(). Use array( \"parent\", \"renewal\", \"switch\" ) to maintain previous behaviour, or \"any\" to receive all order types, including switch and resubscribe."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2126
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2131
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:835
msgid "Payment method meta must be an array."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2362
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2367
msgid "Invalid format. First parameter needs to be an array."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2366
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2371
msgid "Invalid data. First parameter was empty when passed to update_dates()."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2373
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2378
msgid "Invalid data. First parameter has a date that is not in the registered date types."
msgstr ""
#. translators: placeholder is date type (e.g. "end", "next_payment"...)
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2400
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2405
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 ""
#. translators: %s: date type (e.g. "end").
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2438
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2443
msgid "The %s date must occur after the cancellation date."
msgstr ""
#. translators: %s: date type (e.g. "end").
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2444
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2449
msgid "The %s date must occur after the last payment date."
msgstr ""
#. translators: %s: date type (e.g. "end").
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2449
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2454
msgid "The %s date must occur after the next payment date."
msgstr ""
#. translators: %s: date type (e.g. "end").
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2455
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2460
msgid "The %s date must occur after the trial end date."
msgstr ""
#. translators: %s: date type (e.g. "next_payment").
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2460
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2465
msgid "The %s date must occur after the start date."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2490
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2495
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-checkout.php:348
msgid "Backordered"
msgstr ""
@@ -3069,7 +3125,7 @@ msgid "Your cart has been emptied of subscription products. Only one subscriptio
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart-validator.php:128
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:1529
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:1482
msgid "That subscription product can not be added to your cart as it already contains a subscription renewal."
msgstr ""
@@ -3081,16 +3137,16 @@ msgstr ""
msgid "Please enter a valid postcode/ZIP."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:1167
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:1120
msgid "Invalid recurring shipping method."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2205
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2158
msgid "now"
msgstr ""
#. translators: placeholder is a number of days.
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2364
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2317
#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:58
msgid "%s day"
msgid_plural "%s days"
@@ -3098,7 +3154,7 @@ msgstr[0] ""
msgstr[1] ""
#. translators: placeholder is a number of weeks.
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2368
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2321
#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:60
msgid "%s week"
msgid_plural "%s weeks"
@@ -3106,7 +3162,7 @@ msgstr[0] ""
msgstr[1] ""
#. translators: placeholder is a number of months.
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2372
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2325
#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:62
msgid "%s month"
msgid_plural "%s months"
@@ -3114,7 +3170,7 @@ msgstr[0] ""
msgstr[1] ""
#. translators: placeholder is a number of years.
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2376
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2329
#: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:64
msgid "%s year"
msgid_plural "%s years"
@@ -3122,49 +3178,49 @@ msgstr[0] ""
msgstr[1] ""
#. translators: 1$: day of the week (e.g. "every Wednesday").
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2398
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2351
msgid "every %1$s"
msgstr ""
#. translators: 1$: period, 2$: day of the week (e.g. "every 2nd week on Wednesday").
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2402
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2355
msgid "every %1$s on %2$s"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2411
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2364
msgid "on the last day of each month"
msgstr ""
#. translators: 1$: day of the month (e.g. "23rd") (e.g. "every 23rd of each month").
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2415
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2368
msgid "on the %1$s of each month"
msgstr ""
#. translators: 1$: interval (e.g. "3rd") (e.g. "on the last day of every 3rd month").
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2423
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2376
msgid "on the last day of every %1$s month"
msgstr ""
#. translators: on the, 1$: <date> day of every, 2$: <interval> month (e.g. "on the 23rd day of every 2nd month").
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2429
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2382
msgid "on the %1$s day of every %2$s month"
msgstr ""
#. translators: on, 1$: <date>, 2$: <month> each year (e.g. "on March 15th each year").
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2440
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2393
msgid "on %1$s %2$s each year"
msgstr ""
#. translators: 1$: month (e.g. "March"), 2$: day of the month (e.g. "23rd), 3$: interval year (r.g March 23rd every 2nd year").
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2447
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2400
msgid "on %1$s %2$s every %3$s year"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2479
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2432
msgid "Sign up fee"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2489
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2442
msgid "Renews"
msgstr ""
@@ -3965,92 +4021,92 @@ 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 ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:199
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:200
msgid "Synchronisation"
msgstr ""
#. translators: placeholders are opening and closing link tags
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:202
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:203
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. %1$sLearn more%2$s."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:208
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:209
msgid "Align Subscription Renewal Day"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:215
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:216
msgid "Prorate First Renewal"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:216
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:217
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 ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:223
msgctxt "when to prorate first payment / subscription length"
msgid "Never (do not charge any recurring amount)"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:224
msgctxt "when to prorate first payment / subscription length"
msgid "Never (do not charge any recurring amount)"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:225
msgctxt "when to prorate first payment / subscription length"
msgid "Never (charge the full recurring amount at sign-up)"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:232
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:233
msgid "Sign-up grace period"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:233
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:234
msgctxt "there's a number immediately in front of this text"
msgid "days prior to Renewal Day"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:237
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:238
msgid "Subscriptions created within this many days prior to the Renewal Day will not be charged at sign-up. Set to zero for all new Subscriptions to be charged the full recurring amount. Must be a positive number."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:306
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:307
msgid "Month for Synchronisation"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:314
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:315
#: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-synchronisation.php:36
#: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-synchronisation.php:42
msgctxt "input field placeholder for day field for annual subscriptions"
msgid "Day"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:745
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:762
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:746
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:763
msgid "Do not synchronise"
msgstr ""
#. translators: placeholder is a day of the week
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:770
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:771
msgid "%s each week"
msgstr ""
#. translators: placeholder is a number of day with language specific suffix applied (e.g. "1st", "3rd", "5th", etc...)
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:776
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:777
msgid "%s day of the month"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:778
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:779
msgid "Last day of the month"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:826
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:827
msgid "Today!"
msgstr ""
#. translators: placeholder is a date
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:833
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:834
msgid "First payment prorated. Next payment: %s"
msgstr ""
#. translators: placeholder is a date
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:836
#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:837
msgid "First payment: %s"
msgstr ""
@@ -4152,10 +4208,15 @@ msgctxt "The place order button text while resubscribing to a subscription"
msgid "Resubscribe"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:123
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:116
msgid "Please choose a valid payment gateway to change to."
msgstr ""
#. Translators: Placeholder is the payment gateway title.
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:149
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
msgid "Ignore this error"
msgstr ""
@@ -4181,15 +4242,23 @@ msgstr ""
msgid "Limit to one of any status"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:153
msgid "Auto Renewal Toggle"
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:101
msgid "Customer turned off automatic renewals via their My Account page."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:154
msgid "Display the auto renewal toggle"
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:126
msgid "Customer turned on automatic renewals via their My Account page."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:155
msgid "Auto Renewal Toggle"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:156
msgid "Display the auto renewal toggle"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:157
msgid "Allow customers to turn on and off automatic renewals from their View Subscription page."
msgstr ""
@@ -4443,12 +4512,12 @@ msgid "This will clear the persistent cache of all renewal, switch, resubscribe
msgstr ""
#. translators: %s: Order date
#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php:248
#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php:265
msgid "Subscription &ndash; %s"
msgstr ""
#. translators: %s: Order date
#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php:248
#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php:265
msgctxt "Order date parsed by DateTime::format"
msgid "M d, Y @ h:i A"
msgstr ""
@@ -4481,7 +4550,7 @@ msgctxt "default email subject for cancelled emails sent to the admin"
msgid "[%s] Subscription Cancelled"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:143
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:145
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-renewal-invoice.php:210
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:141
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:141
@@ -4489,14 +4558,14 @@ msgctxt "an email notification"
msgid "Enable/Disable"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:145
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:147
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-renewal-invoice.php:212
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:143
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:143
msgid "Enable this email notification"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:149
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:151
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:147
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:147
msgctxt "of an email"
@@ -4504,13 +4573,13 @@ msgid "Recipient(s)"
msgstr ""
#. translators: placeholder is admin email
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:152
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:154
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:150
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:150
msgid "Enter recipients (comma separated) for this email. Defaults to %s."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:157
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:159
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:155
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:155
msgctxt "of an email"
@@ -4518,13 +4587,13 @@ msgid "Subject"
msgstr ""
#. translators: %s: default e-mail subject.
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:160
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:162
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:158
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:158
msgid "This controls the email subject line. Leave blank to use the default subject: %s."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:165
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:167
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:163
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:163
msgctxt "Name the setting that controls the main heading contained within the email notification"
@@ -4532,38 +4601,38 @@ msgid "Email Heading"
msgstr ""
#. translators: %s: default e-mail heading.
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:168
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:170
msgid "This controls the main heading contained within the email notification. Leave blank to use the default heading: %s."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:173
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:175
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:171
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:171
msgctxt "text, html or multipart"
msgid "Email type"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:175
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:177
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:173
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:173
msgid "Choose which format of email to send."
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:179
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:181
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:177
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:177
msgctxt "email type"
msgid "Plain text"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:180
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:182
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:178
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:178
msgctxt "email type"
msgid "HTML"
msgstr ""
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:181
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:183
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:179
#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:179
msgctxt "email type"
@@ -6325,14 +6394,6 @@ msgctxt "table headings in notification email"
msgid "Price"
msgstr ""
#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:23
#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:23
#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:23
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:294
msgctxt "table heading"
msgid "Last Order Date"
msgstr ""
#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:24
msgctxt "table headings in notification email"
msgid "End of Prepaid Term"
@@ -6615,12 +6676,6 @@ msgstr ""
msgid "ID"
msgstr ""
#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:40
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:293
msgctxt "table heading"
msgid "Next Payment"
msgstr ""
#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:46
#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:53
#: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:42
@@ -6800,26 +6855,6 @@ msgstr ""
msgid "Can not get address type display name. Address type is not a string."
msgstr ""
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:291
msgctxt "table heading"
msgid "Start Date"
msgstr ""
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:292
msgctxt "table heading"
msgid "Trial End"
msgstr ""
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:295
msgctxt "table heading"
msgid "Cancelled Date"
msgstr ""
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:296
msgctxt "table heading"
msgid "End Date"
msgstr ""
#: vendor/woocommerce/subscriptions-core/wcs-functions.php:331
msgid "Date type is not a string."
msgstr ""

20
vendor/autoload.php vendored
View File

@@ -2,24 +2,6 @@
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit59c7b20d3f201de5581a0bc09b6c2289::getLoader();
return ComposerAutoloaderInitfe47e554dced83cd1f1961109287683e::getLoader();

View File

@@ -42,79 +42,30 @@ namespace Composer\Autoload;
*/
class ClassLoader
{
/** @var \Closure(string):void */
private static $includeFile;
/** @var ?string */
private $vendorDir;
// PSR-4
/**
* @var array[]
* @psalm-var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, array<int, string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* @var array[]
* @psalm-var array<string, array<string, string[]>>
*/
private $prefixesPsr0 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var string[]
* @psalm-var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var bool[]
* @psalm-var array<string, bool>
*/
private $missingClasses = array();
/** @var ?string */
private $apcuPrefix;
/**
* @var self[]
*/
private static $registeredLoaders = array();
/**
* @param ?string $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
* @return string[]
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
@@ -124,47 +75,28 @@ class ClassLoader
return array();
}
/**
* @return array[]
* @psalm-return array<string, array<int, string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return string[] Array of classname => path
* @psalm-return array<string, string>
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
*
* @return void
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
@@ -180,10 +112,8 @@ class ClassLoader
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 root directories
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
@@ -227,12 +157,10 @@ class ClassLoader
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
@@ -277,9 +205,7 @@ class ClassLoader
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 base directories
*
* @return void
* @param array|string $paths The PSR-0 base directories
*/
public function set($prefix, $paths)
{
@@ -295,11 +221,9 @@ class ClassLoader
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
@@ -319,8 +243,6 @@ class ClassLoader
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
@@ -343,8 +265,6 @@ class ClassLoader
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
@@ -365,8 +285,6 @@ class ClassLoader
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
@@ -387,8 +305,6 @@ class ClassLoader
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
@@ -408,8 +324,6 @@ class ClassLoader
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
@@ -429,8 +343,7 @@ class ClassLoader
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
$includeFile = self::$includeFile;
$includeFile($file);
includeFile($file);
return true;
}
@@ -490,11 +403,6 @@ class ClassLoader
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
@@ -560,26 +468,14 @@ class ClassLoader
return false;
}
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = \Closure::bind(static function($file) {
function includeFile($file)
{
include $file;
}, null, null);
}
}

View File

@@ -20,27 +20,12 @@ use Composer\Semver\VersionParser;
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
* To require it's presence, you can require `composer-runtime-api ^2.0`
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
/**
@@ -98,7 +83,7 @@ class InstalledVersions
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
}
}
@@ -119,7 +104,7 @@ class InstalledVersions
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints((string) $constraint);
$constraint = $parser->parseConstraints($constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
@@ -243,7 +228,7 @@ class InstalledVersions
/**
* @return array
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}
*/
public static function getRootPackage()
{
@@ -257,7 +242,7 @@ class InstalledVersions
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}
*/
public static function getRawData()
{
@@ -280,7 +265,7 @@ class InstalledVersions
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
*/
public static function getAllRawData()
{
@@ -303,7 +288,7 @@ class InstalledVersions
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>} $data
*/
public static function reload($data)
{
@@ -313,7 +298,7 @@ class InstalledVersions
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
*/
private static function getInstalled()
{
@@ -328,9 +313,7 @@ class InstalledVersions
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
$installed[] = self::$installedByVendor[$vendorDir] = $required;
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
@@ -342,17 +325,12 @@ class InstalledVersions
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
self::$installed = require __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
if (self::$installed !== array()) {
$installed[] = self::$installed;
}
return $installed;
}

View File

@@ -2,7 +2,7 @@
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(__DIR__);
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(__DIR__);
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(__DIR__);
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit59c7b20d3f201de5581a0bc09b6c2289
class ComposerAutoloaderInitfe47e554dced83cd1f1961109287683e
{
private static $loader;
@@ -24,12 +24,31 @@ class ComposerAutoloaderInit59c7b20d3f201de5581a0bc09b6c2289
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit59c7b20d3f201de5581a0bc09b6c2289', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit59c7b20d3f201de5581a0bc09b6c2289', 'loadClassLoader'));
spl_autoload_register(array('ComposerAutoloaderInitfe47e554dced83cd1f1961109287683e', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInitfe47e554dced83cd1f1961109287683e', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit59c7b20d3f201de5581a0bc09b6c2289::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInitfe47e554dced83cd1f1961109287683e::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);

View File

@@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInit59c7b20d3f201de5581a0bc09b6c2289
class ComposerStaticInitfe47e554dced83cd1f1961109287683e
{
public static $prefixLengthsPsr4 = array (
'C' =>
@@ -129,9 +129,9 @@ class ComposerStaticInit59c7b20d3f201de5581a0bc09b6c2289
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit59c7b20d3f201de5581a0bc09b6c2289::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit59c7b20d3f201de5581a0bc09b6c2289::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit59c7b20d3f201de5581a0bc09b6c2289::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInitfe47e554dced83cd1f1961109287683e::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitfe47e554dced83cd1f1961109287683e::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitfe47e554dced83cd1f1961109287683e::$classMap;
}, null, ClassLoader::class);
}

View File

@@ -156,17 +156,17 @@
},
{
"name": "woocommerce/subscriptions-core",
"version": "6.4.0",
"version_normalized": "6.4.0.0",
"version": "6.5.0",
"version_normalized": "6.5.0.0",
"source": {
"type": "git",
"url": "https://github.com/Automattic/woocommerce-subscriptions-core.git",
"reference": "a94c9aab6d47f32461974ed09a4d3cad590f25b0"
"reference": "19ca9b7cf2b48cba4abd6ecf811475382b9d6673"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/a94c9aab6d47f32461974ed09a4d3cad590f25b0",
"reference": "a94c9aab6d47f32461974ed09a4d3cad590f25b0",
"url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/19ca9b7cf2b48cba4abd6ecf811475382b9d6673",
"reference": "19ca9b7cf2b48cba4abd6ecf811475382b9d6673",
"shasum": ""
},
"require": {
@@ -177,9 +177,9 @@
"dave-liddament/sarb": "^1.1",
"phpunit/phpunit": "9.5.14",
"woocommerce/woocommerce-sniffs": "0.1.0",
"yoast/phpunit-polyfills": "1.0.3"
"yoast/phpunit-polyfills": "1.1.0"
},
"time": "2023-10-18T03:32:50+00:00",
"time": "2023-11-09T04:27:49+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.4.0",
"source": "https://github.com/Automattic/woocommerce-subscriptions-core/tree/6.5.0",
"issues": "https://github.com/Automattic/woocommerce-subscriptions-core/issues"
},
"install-path": "../woocommerce/subscriptions-core"

View File

@@ -1,22 +1,22 @@
<?php return array(
'root' => array(
'name' => 'woocommerce/woocommerce-subscriptions',
'pretty_version' => 'dev-release/5.6.0',
'version' => 'dev-release/5.6.0',
'reference' => '434da4e19c4fde75e431338fa82595320bd5b6c1',
'pretty_version' => 'dev-release/5.7.0',
'version' => 'dev-release/5.7.0',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '05388f52bd8a4479997a2672e130fb44de3548f4',
'name' => 'woocommerce/woocommerce-subscriptions',
'dev' => false,
),
'versions' => array(
'composer/installers' => array(
'pretty_version' => 'v1.12.0',
'version' => '1.12.0.0',
'reference' => 'd20a64ed3c94748397ff5973488761b22f6d3f19',
'type' => 'composer-plugin',
'install_path' => __DIR__ . '/./installers',
'aliases' => array(),
'reference' => 'd20a64ed3c94748397ff5973488761b22f6d3f19',
'dev_requirement' => false,
),
'roundcube/plugin-installer' => array(
@@ -32,21 +32,21 @@
),
),
'woocommerce/subscriptions-core' => array(
'pretty_version' => '6.4.0',
'version' => '6.4.0.0',
'reference' => 'a94c9aab6d47f32461974ed09a4d3cad590f25b0',
'pretty_version' => '6.5.0',
'version' => '6.5.0.0',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../woocommerce/subscriptions-core',
'aliases' => array(),
'reference' => '19ca9b7cf2b48cba4abd6ecf811475382b9d6673',
'dev_requirement' => false,
),
'woocommerce/woocommerce-subscriptions' => array(
'pretty_version' => 'dev-release/5.6.0',
'version' => 'dev-release/5.6.0',
'reference' => '434da4e19c4fde75e431338fa82595320bd5b6c1',
'pretty_version' => 'dev-release/5.7.0',
'version' => 'dev-release/5.7.0',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '05388f52bd8a4479997a2672e130fb44de3548f4',
'dev_requirement' => false,
),
),

View File

@@ -351,4 +351,17 @@ jQuery( function ( $ ) {
);
}
} );
/**
* When the auto-renewal is toggled on or off, show or hide the chosen payment methods meta fields.
*/
$( '#wc-subscription-auto-renew' ).on( 'change', function() {
var $payment_method_meta_elements = $( '#wcs_' + $( '#_payment_method' ).val() + '_fields' );
if ( $( this ).is( ':checked' ) ) {
$payment_method_meta_elements.fadeIn();
} else {
$payment_method_meta_elements.fadeOut();
}
} );
} );

View File

@@ -1,5 +1,14 @@
*** WooCommerce Subscriptions Core Changelog ***
= 6.5.0 - 2023-11-09 =
* Add - When a customer toggles automatic renewals on or off via their My Account page, add a note to the subscription to record that event.
* Fix - When a subscription is flagged as requiring manual payments, allow admin users to turn on automatic payments for a subscription via the Edit Subscription page by selecting a new payment method.
* Fix - When processing an early renewal order, make sure the suspension count is reset back to 0 on payment complete.
* Fix - Ensure proper backfilling of subscription metadata (i.e. dates and cache) to the postmeta table when HPOS is enabled and compatibility mode (data syncing) is turned on.
* Fix - Fetch and update the `_cancelled_email_sent` meta in a HPOS compatibile way.
* Dev - Introduce a new wcs_get_subscription_grouping_key() function to generate a unique key for a subscription based on its billing schedule. This function uses the existing recurring cart key concept.
* Dev - Deprecate the WC_Subscriptions_Synchroniser::add_to_recurring_cart_key(). Use WC_Subscriptions_Synchroniser::add_to_recurring_product_grouping_key() instead.
= 6.4.0 - 2023-10-18 =
* Add - Use admin theme color and the correct WooCommerce colors.
* Fix - Resolve an issue that would cause 3rd party plugin edit product fields with the show_if_variable-subscription class to be incorrectly hidden.

View File

@@ -185,7 +185,7 @@ class WCS_Meta_Box_Subscription_Data extends WC_Meta_Box_Order_Data {
echo '<p><strong>' . esc_html( $field['label'] ) . ':</strong> ' . wp_kses_post( make_clickable( esc_html( $field_value ) ) ) . '</p>';
}
echo '<p' . ( ( '' != $subscription->get_payment_method() ) ? ' class="' . esc_attr( $subscription->get_payment_method() ) . '"' : '' ) . '><strong>' . esc_html__( 'Payment Method', 'woocommerce-subscriptions' ) . ':</strong>' . wp_kses_post( nl2br( $subscription->get_payment_method_to_display() ) ); // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
echo '<p' . ( ( '' != $subscription->get_payment_method() ) ? ' class="' . esc_attr( $subscription->get_payment_method() ) . '"' : '' ) . '><strong>' . esc_html__( 'Payment method', 'woocommerce-subscriptions' ) . ':</strong>' . wp_kses_post( nl2br( $subscription->get_payment_method_to_display() ) ); // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
// Display help tip
if ( '' != $subscription->get_payment_method() && ! $subscription->is_manual() ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison

View File

@@ -1778,7 +1778,12 @@ class WC_Subscription extends WC_Order {
// Add order note depending on initial payment
$this->add_order_note( __( 'Payment status marked complete.', 'woocommerce-subscriptions' ) );
$this->update_status( 'active' ); // also saves the subscription
// $this->update_status() only calls save if the status has changed.
if ( 'active' !== $this->get_status( 'edit' ) ) {
$this->update_status( 'active' );
} else {
$this->save();
}
do_action( 'woocommerce_subscription_payment_complete', $this );

View File

@@ -1022,59 +1022,12 @@ class WC_Subscriptions_Cart {
* Subscriptions groups products by billing schedule when calculating cart totals, so that shipping and other "per order" amounts
* can be calculated for each group of items for each renewal. This method constructs a cart key based on the billing schedule
* to allow products on the same billing schedule to be grouped together - free trials and synchronisation is accounted for by
* using the first renewal date (if any) for the susbcription.
* using the first renewal date (if any) for the subscription.
*
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
*/
public static function get_recurring_cart_key( $cart_item, $renewal_time = '' ) {
$cart_key = '';
$product = $cart_item['data'];
$renewal_time = ! empty( $renewal_time ) ? $renewal_time : WC_Subscriptions_Product::get_first_renewal_payment_time( $product );
$interval = WC_Subscriptions_Product::get_interval( $product );
$period = WC_Subscriptions_Product::get_period( $product );
$length = WC_Subscriptions_Product::get_length( $product );
$trial_period = WC_Subscriptions_Product::get_trial_period( $product );
$trial_length = WC_Subscriptions_Product::get_trial_length( $product );
if ( $renewal_time > 0 ) {
$cart_key .= gmdate( 'Y_m_d_', $renewal_time );
}
// First start with the billing interval and period
switch ( $interval ) {
case 1:
if ( 'day' == $period ) {
$cart_key .= 'daily'; // always gotta be one exception
} else {
$cart_key .= sprintf( '%sly', $period );
}
break;
case 2:
$cart_key .= sprintf( 'every_2nd_%s', $period );
break;
case 3:
$cart_key .= sprintf( 'every_3rd_%s', $period ); // or sometimes two exceptions it would seem
break;
default:
$cart_key .= sprintf( 'every_%dth_%s', $interval, $period );
break;
}
if ( $length > 0 ) {
$cart_key .= '_for_';
$cart_key .= sprintf( '%d_%s', $length, $period );
if ( $length > 1 ) {
$cart_key .= 's';
}
}
if ( $trial_length > 0 ) {
$cart_key .= sprintf( '_after_a_%d_%s_trial', $trial_length, $trial_period );
}
return apply_filters( 'woocommerce_subscriptions_recurring_cart_key', $cart_key, $cart_item );
return apply_filters( 'woocommerce_subscriptions_recurring_cart_key', wcs_get_subscription_grouping_key( $cart_item['data'], $renewal_time ), $cart_item );
}
/**

View File

@@ -16,7 +16,7 @@ class WC_Subscriptions_Core_Plugin {
* The version of subscriptions-core library.
* @var string
*/
protected $library_version = '6.4.0'; // WRCS: DEFINED_VERSION.
protected $library_version = '6.5.0'; // WRCS: DEFINED_VERSION.
/**
* The subscription scheduler instance.

View File

@@ -110,7 +110,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->get_id(), '_cancelled_email_sent', true ) ) {
if ( $subscription->has_status( array( 'pending-cancel', 'cancelled' ) ) && 'true' !== $subscription->get_cancelled_email_sent() ) {
do_action( 'cancelled_subscription_notification', $subscription );
}
}

View File

@@ -112,7 +112,8 @@ class WC_Subscriptions_Synchroniser {
// If it's an initial sync order and the total is zero, and nothing needs to be shipped, do not reduce stock
add_filter( 'woocommerce_order_item_quantity', __CLASS__ . '::maybe_do_not_reduce_stock', 10, 3 );
add_filter( 'woocommerce_subscriptions_recurring_cart_key', __CLASS__ . '::add_to_recurring_cart_key', 10, 2 );
add_filter( 'woocommerce_subscriptions_recurring_cart_key', __CLASS__ . '::add_to_recurring_product_grouping_key', 10, 2 );
add_filter( 'woocommerce_subscriptions_item_grouping_key', __CLASS__ . '::add_to_recurring_product_grouping_key', 10, 2 );
// Add defaults for our options.
add_filter( 'default_option_' . self::$setting_id_days_no_fee, array( __CLASS__, 'option_default' ), 10, 3 );
@@ -1207,18 +1208,27 @@ class WC_Subscriptions_Synchroniser {
}
/**
* If the cart item is synced, add a '_synced' string to the recurring cart key.
* Alters the subscription grouping key to ensure synced products are grouped separately.
*
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
* @param string $key The subscription product's grouping key.
* @param array|WC_Order_Item_Product $item The cart item or order item that the key is being generated for.
*
* @return string The subscription product grouping key with a synced product flag if the product is synced.
*/
public static function add_to_recurring_cart_key( $cart_key, $cart_item ) {
$product = $cart_item['data'];
public static function add_to_recurring_product_grouping_key( $key, $item ) {
$product = false;
if ( false === strpos( $cart_key, '_synced' ) && self::is_product_synced( $product ) ) {
$cart_key .= '_synced';
if ( is_a( $item, 'WC_Order_Item_Product' ) ) {
$product = $item->get_product();
} elseif ( is_array( $item ) && isset( $item['data'] ) ) {
$product = $item['data'];
}
return $cart_key;
if ( $product && false === strpos( $key, '_synced' ) && self::is_product_synced( $product ) ) {
$key .= '_synced';
}
return $key;
}
/**
@@ -1591,4 +1601,19 @@ class WC_Subscriptions_Synchroniser {
return $end_date;
}
/**
* Alters the recurring cart item key to ensure synced products are grouped separately.
*
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
* @deprecated 6.5.0
*
* @param string $cart_key The recurring cart item key.
* @param array $cart_item The cart item's data.
*
* @return string The cart item recurring cart key with a synced product flag if the product is synced.
*/
public static function add_to_recurring_cart_key( $cart_key, $cart_item ) {
wcs_deprecated_function( __METHOD__, '6.5.0', __CLASS__ . '::add_to_recurring_product_grouping_key' );
return self::add_to_recurring_product_grouping_key( $cart_key, $cart_item );
}
}

View File

@@ -18,7 +18,6 @@ class WCS_Change_Payment_Method_Admin {
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
*/
public static function display_fields( $subscription ) {
$payment_method = $subscription->get_payment_method();
$valid_payment_methods = self::get_valid_payment_methods( $subscription );
@@ -34,22 +33,18 @@ class WCS_Change_Payment_Method_Admin {
echo '<p class="form-field form-field-wide">';
if ( count( $valid_payment_methods ) > 1 ) {
$found_method = false;
echo '<label>' . esc_html__( 'Payment Method', 'woocommerce-subscriptions' ) . ':</label>';
echo '<label>' . esc_html__( 'Payment method', 'woocommerce-subscriptions' ) . '</label>';
echo '<select class="wcs_payment_method_selector" name="_payment_method" id="_payment_method" class="first">';
foreach ( $valid_payment_methods as $gateway_id => $gateway_title ) {
$selected_payment_method = $subscription->get_requires_manual_renewal() ? 'manual' : $subscription->get_payment_method();
echo '<option value="' . esc_attr( $gateway_id ) . '" ' . selected( $payment_method, $gateway_id, false ) . '>' . esc_html( $gateway_title ) . '</option>';
if ( $payment_method == $gateway_id ) {
$found_method = true;
}
foreach ( $valid_payment_methods as $gateway_id => $gateway_title ) {
echo '<option value="' . esc_attr( $gateway_id ) . '" ' . selected( $selected_payment_method, $gateway_id, false ) . '>' . esc_html( $gateway_title ) . '</option>';
}
echo '</select>';
} elseif ( count( $valid_payment_methods ) == 1 ) {
echo '<strong>' . esc_html__( 'Payment Method', 'woocommerce-subscriptions' ) . ':</strong><br/>' . esc_html( current( $valid_payment_methods ) );
echo '<strong>' . esc_html__( 'Payment method', 'woocommerce-subscriptions' ) . '</strong><br/>' . esc_html( current( $valid_payment_methods ) );
// translators: %s: gateway ID.
echo wcs_help_tip( sprintf( _x( 'Gateway ID: [%s]', 'The gateway ID displayed on the Edit Subscriptions screen when editing payment method.', 'woocommerce-subscriptions' ), key( $valid_payment_methods ) ) );
echo '<input type="hidden" value="' . esc_attr( key( $valid_payment_methods ) ) . '" id="_payment_method" name="_payment_method">';
@@ -91,12 +86,10 @@ class WCS_Change_Payment_Method_Admin {
}
echo '</div>';
}
}
wp_nonce_field( 'wcs_change_payment_method_admin', '_wcsnonce' );
}
/**
@@ -149,6 +142,13 @@ class WCS_Change_Payment_Method_Admin {
// Update the payment method for manual only if it has changed.
if ( ! $subscription->is_manual() || 'manual' !== $payment_method ) {
// If the subscription is being changed away from manual and it is flagged as requiring manual payments turn on automatic renewals.
if ( 'manual' !== $payment_method && $subscription->get_requires_manual_renewal() && ! wcs_is_manual_renewal_required() && $payment_gateway->supports( 'subscriptions' ) ) {
$subscription->set_requires_manual_renewal( false );
// Translators: Placeholder is the payment gateway title.
$subscription->add_order_note( sprintf( __( 'Admin turned on automatic renewals by changing payment method to "%s" via the Edit Subscription screen.', 'woocommerce-subscriptions' ), $payment_gateway->get_title() ), false, true );
}
$subscription->set_payment_method( $payment_gateway, $payment_method_meta );
$subscription->save();
}

View File

@@ -98,6 +98,7 @@ class WCS_My_Account_Auto_Renew_Toggle {
if ( $subscription && self::can_user_toggle_auto_renewal( $subscription ) ) {
$subscription->set_requires_manual_renewal( true );
$subscription->add_order_note( __( 'Customer turned off automatic renewals via their My Account page.', 'woocommerce-subscriptions' ) );
$subscription->save();
self::send_ajax_response( $subscription );
@@ -122,6 +123,7 @@ class WCS_My_Account_Auto_Renew_Toggle {
if ( wc_get_payment_gateway_by_order( $subscription ) && self::can_user_toggle_auto_renewal( $subscription ) ) {
$subscription->set_requires_manual_renewal( false );
$subscription->add_order_note( __( 'Customer turned on automatic renewals via their My Account page.', 'woocommerce-subscriptions' ) );
$subscription->save();
self::send_ajax_response( $subscription );

View File

@@ -882,4 +882,112 @@ class WCS_Orders_Table_Subscription_Data_Store extends \Automattic\WooCommerce\I
return $results ? array_combine( array_column( $results, 'status' ), array_map( 'absint', array_column( $results, 'cnt' ) ) ) : array();
}
/**
* Fetches the subscription's start date.
* This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB.
*
* @param \WC_Subscription $subscription Subscription object.
*
* @return string
*/
public function get_schedule_start( $subscription ) {
return $subscription->get_date( 'start' );
}
/**
* Fetches the subscription's trial end date.
* This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB.
*
* @param \WC_Subscription $subscription Subscription object.
*
* @return string
*/
public function get_schedule_trial_end( $subscription ) {
return $subscription->get_date( 'trial_end' );
}
/**
* Fetches the subscription's next payment date.
* This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB.
*
* @param \WC_Subscription $subscription Subscription object.
*
* @return string
*/
public function get_schedule_next_payment( $subscription ) {
return $subscription->get_date( 'next_payment' );
}
/**
* Fetches the subscription's cancelled date.
* This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB.
*
* @param \WC_Subscription $subscription Subscription object.
*
* @return string
*/
public function get_schedule_cancelled( $subscription ) {
return $subscription->get_date( 'cancelled' );
}
/**
* Fetches the subscription's end date.
* This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB.
*
* @param \WC_Subscription $subscription Subscription object.
*
* @return string
*/
public function get_schedule_end( $subscription ) {
return $subscription->get_date( 'end' );
}
/**
* Fetches the subscription's payment retry date.
* This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB.
*
* @param \WC_Subscription $subscription Subscription object.
*
* @return string
*/
public function get_schedule_payment_retry( $subscription ) {
return $subscription->get_date( 'payment_retry' );
}
/**
* Returns a list of subscriptions's renewal order IDs stored in cache meta.
* This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB.
*
* @param \WC_Subscription $subscription Subscription object.
*
* @return array
*/
public function get_renewal_order_ids_cache( $subscription ) {
return $subscription->get_meta( '_subscription_renewal_order_ids_cache' );
}
/**
* Returns a list of subscriptions's resubscribe order IDs stored in cache meta.
* This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB.
*
* @param \WC_Subscription $subscription Subscription object.
*
* @return array
*/
public function get_resubscribe_order_ids_cache( $subscription ) {
return $subscription->get_meta( '_subscription_resubscribe_order_ids_cache' );
}
/**
* Returns a list of subscriptions's switch order IDs stored in cache meta.
* This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB.
*
* @param \WC_Subscription $subscription Subscription object.
*
* @return array
*/
public function get_switch_order_ids_cache( $subscription ) {
return $subscription->get_meta( '_subscription_switch_order_ids_cache' );
}
}

View File

@@ -60,6 +60,23 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements
'_subscription_switch_data' => 'switch_data',
);
/**
* Custom setters for subscription internal props in the form meta_key => set_|get_{value}.
*
* @var string[]
*/
protected $internal_data_store_key_getters = array(
'_schedule_start' => 'schedule_start',
'_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_renewal_order_ids_cache' => 'renewal_order_ids_cache',
'_subscription_resubscribe_order_ids_cache' => 'resubscribe_order_ids_cache',
'_subscription_switch_order_ids_cache' => 'switch_order_ids_cache',
);
/**
* Constructor.
*/
@@ -604,4 +621,146 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements
public function get_subscriptions_count_by_status() {
return (array) wp_count_posts( 'shop_subscription' );
}
/**
* Sets the subscription's start date.
*
* This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record()
* when backfilling subscription data to the WP_Post database.
*
* @param WC_Subscription $subscription
* @param string $date
*/
public function set_schedule_start( $subscription, $date ) {
update_post_meta( $subscription->get_id(), '_schedule_start', $date );
}
/**
* Sets the subscription's trial end date.
*
* This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record()
* when backfilling subscription data to the WP_Post database.
*
* @param WC_Subscription $subscription
* @param string $date
*/
public function set_schedule_trial_end( $subscription, $date ) {
update_post_meta( $subscription->get_id(), '_schedule_trial_end', $date );
}
/**
* Sets the subscription's next payment date.
*
* This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record()
* when backfilling subscription data to the WP_Post database.
*
* @param WC_Subscription $subscription
* @param string $date
*/
public function set_schedule_next_payment( $subscription, $date ) {
update_post_meta( $subscription->get_id(), '_schedule_next_payment', $date );
}
/**
* Sets the subscription's cancelled date.
*
* This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record()
* when backfilling subscription data to the WP_Post database.
*
* @param WC_Subscription $subscription
* @param string $date
*/
public function set_schedule_cancelled( $subscription, $date ) {
update_post_meta( $subscription->get_id(), '_schedule_cancelled', $date );
}
/**
* Sets the subscription's end date.
*
* This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record()
* when backfilling subscription data to the WP_Post database.
*
* @param WC_Subscription $subscription
* @param string $date
*/
public function set_schedule_end( $subscription, $date ) {
update_post_meta( $subscription->get_id(), '_schedule_end', $date );
}
/**
* Sets the subscription's payment retry date.
*
* This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record()
* when backfilling subscription data to the WP_Post database.
*
* @param WC_Subscription $subscription
* @param string $date
*/
public function set_schedule_payment_retry( $subscription, $date ) {
update_post_meta( $subscription->get_id(), '_schedule_payment_retry', $date );
}
/**
* Manually sets the list of subscription's renewal order IDs stored in cache.
*
* This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record()
* when backfilling subscription data to the WP_Post database.
*
* @param WC_Subscription $subscription
* @param array $renewal_order_ids
*/
public function set_renewal_order_ids_cache( $subscription, $renewal_order_ids ) {
$this->cleanup_backfill_related_order_cache_duplicates( $subscription, 'renewal' );
update_post_meta( $subscription->get_id(), '_subscription_renewal_order_ids_cache', $renewal_order_ids );
}
/**
* Manually sets the list of subscription's resubscribe order IDs stored in cache.
*
* This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record()
* when backfilling subscription data to the WP_Post database.
*
* @param WC_Subscription $subscription
* @param array $resubscribe_order_ids
*/
public function set_resubscribe_order_ids_cache( $subscription, $resubscribe_order_ids ) {
$this->cleanup_backfill_related_order_cache_duplicates( $subscription, 'resubscribe' );
update_post_meta( $subscription->get_id(), '_subscription_resubscribe_order_ids_cache', $resubscribe_order_ids );
}
/**
* Manually sets the list of subscription's switch order IDs stored in cache.
*
* This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record()
* when backfilling subscription data to the WP_Post database.
*
* @param WC_Subscription $subscription
* @param array $switch_order_ids
*/
public function set_switch_order_ids_cache( $subscription, $switch_order_ids ) {
$this->cleanup_backfill_related_order_cache_duplicates( $subscription, 'switch' );
update_post_meta( $subscription->get_id(), '_subscription_switch_order_ids_cache', $switch_order_ids );
}
/**
* Deletes a subscription's related order cache - including any duplicates.
*
* WC core between v8.1 and v8.4 would duplicate related order cache meta when backfilling the post record. This method deletes all
* instances of a order type cache (duplicates included). It is intended to be called before setting the cache manually.
*
* Note: this function assumes that the fix to WC (listed below) will be included in 8.4. If it's pushed back, this function will need to be updated,
* if it's brought forward to 8.3, it can be updated but is not strictly required.
*
* @see https://github.com/woocommerce/woocommerce/pull/41281
* @see https://github.com/Automattic/woocommerce-subscriptions-core/pull/538
*
* @param WC_Subscription $subscription The Subscription.
* @param string $relationship_type The type of subscription related order relationship to delete. One of: 'renewal', 'resubscribe', 'switch'.
*/
private function cleanup_backfill_related_order_cache_duplicates( $subscription, $relationship_type ) {
// Delete the related order cache on versions of WC after 8.1 but before 8.4.
if ( ! wcs_is_woocommerce_pre( '8.1' ) && wcs_is_woocommerce_pre( '8.4' ) ) {
delete_post_meta( $subscription->get_id(), "_subscription_{$relationship_type}_order_ids_cache" );
}
}
}

View File

@@ -83,7 +83,9 @@ class WCS_Email_Cancelled_Subscription extends WC_Email {
return;
}
update_post_meta( $subscription->get_id(), '_cancelled_email_sent', 'true' );
$subscription->set_cancelled_email_sent( 'true' );
$subscription->save();
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
}

View File

@@ -979,3 +979,19 @@ function wcs_order_contains_early_renewal( $order ) {
*/
return apply_filters( 'woocommerce_subscriptions_is_early_renewal_order', $is_early_renewal, $order );
}
/**
* Generates a key for grouping subscription products with the same billing schedule.
*
* Used by the orders/<id>/subscriptions REST API endpoint to group order items into subscriptions.
*
* @see https://woocommerce.com/document/subscriptions/develop/multiple-subscriptions/#section-3
*
* @param WC_Order_Item_Product $item The order item to generate the key for.
* @param int $renewal_time The timestamp of the first renewal payment.
*
* @return string The item's subscription grouping key.
*/
function wcs_get_subscription_item_grouping_key( $item, $renewal_time = '' ) {
return apply_filters( 'woocommerce_subscriptions_item_grouping_key', wcs_get_subscription_grouping_key( $item->get_product(), $renewal_time ), $item );
}

View File

@@ -437,3 +437,66 @@ function wcs_calculate_min_max_variations( $variations_data ) {
'identical' => $subscription_details_identical,
);
}
/**
* Generates a key for grouping subscription products with the same billing schedule.
*
* Used in a frontend cart and checkout context to group items by a recurring cart key for use in generating recurring carts.
* Used by the orders/<id>/subscriptions REST API endpoint to group order items into subscriptions.
*
* @see https://woocommerce.com/document/subscriptions/develop/multiple-subscriptions/#section-3
*
* @param WC_Product $product The product to generate the key for.
* @param int $renewal_time The timestamp of the first renewal payment.
*
* @return string The subscription product grouping key.
*/
function wcs_get_subscription_grouping_key( $product, $renewal_time = 0 ) {
$key = '';
$renewal_time = ! empty( $renewal_time ) ? $renewal_time : WC_Subscriptions_Product::get_first_renewal_payment_time( $product );
$interval = WC_Subscriptions_Product::get_interval( $product );
$period = WC_Subscriptions_Product::get_period( $product );
$length = WC_Subscriptions_Product::get_length( $product );
$trial_period = WC_Subscriptions_Product::get_trial_period( $product );
$trial_length = WC_Subscriptions_Product::get_trial_length( $product );
if ( $renewal_time > 0 ) {
$key .= gmdate( 'Y_m_d_', $renewal_time );
}
// First start with the billing interval and period.
switch ( $interval ) {
case 1:
if ( 'day' === $period ) {
$key .= 'daily';
} else {
$key .= sprintf( '%sly', $period );
}
break;
case 2:
$key .= sprintf( 'every_2nd_%s', $period );
break;
case 3:
$key .= sprintf( 'every_3rd_%s', $period ); // or sometimes two exceptions it would seem
break;
default:
$key .= sprintf( 'every_%dth_%s', $interval, $period );
break;
}
if ( $length > 0 ) {
$key .= '_for_';
$key .= sprintf( '%d_%s', $length, $period );
if ( $length > 1 ) {
$key .= 's';
}
}
if ( $trial_length > 0 ) {
$key .= sprintf( '_after_a_%d_%s_trial', $trial_length, $trial_period );
}
return apply_filters( 'wcs_subscription_product_grouping_key', $key, $product, $renewal_time );
}

View File

@@ -6,5 +6,5 @@
* Author: Automattic
* Author URI: https://woocommerce.com/
* Requires WP: 5.6
* Version: 6.4.0
* Version: 6.5.0
*/

View File

@@ -5,7 +5,7 @@
* Description: Sell products and services with recurring payments in your WooCommerce Store.
* Author: WooCommerce
* Author URI: https://woocommerce.com/
* Version: 5.6.0
* Version: 5.7.0
*
* WC requires at least: 7.7.0
* WC tested up to: 8.2.0
@@ -77,7 +77,7 @@ class WC_Subscriptions {
public static $plugin_file = __FILE__;
/** @var string */
public static $version = '5.6.0'; // WRCS: DEFINED_VERSION.
public static $version = '5.7.0'; // WRCS: DEFINED_VERSION.
/** @var string */
public static $wc_minimum_supported_version = '7.7';