diff --git a/changelog.txt b/changelog.txt index 641bb8d..bef1310 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,27 @@ *** WooCommerce Subscriptions Changelog *** +2025-03-24 - version 7.3.0 +* Tweak: Adjust the warning that appears on the reports page when HPOS is enabled but Compatibility Mode is disabled (provide a direct link to the relevant settings). +* Update: Improved subscription search performance for WP Post stores by removing unnecessary _order_key and _billing_email meta queries. +* Update: Make it possible to dispatch the Cancelled Subscription email more than once (when initially set to pending-cancellation, and again when it reaches final cancellation). +* Update: Reduced duplicate queries when fetching multiple subscription related orders types. +* Update: Removed unnecessary get_time() calls to reduce redundant get_last_order() queries in the Subscriptions list table. +* Update: Improved performance on the Orders list table when rendering the Subscription Relationship column. +* Update: Improved performance of the Generate Related Order Cache tool found under WooCommerce > Status > Tools. +* Fix: Do not schedule updates to the report data cache if reporting is not available (ie, if HPOS is enabled but Compatibility Mode is not). +* Fix: Resolved deprecated dynamic property warnings in WCS_Email_Payment_Retry and WCS_Email_Customer_Payment_Retry. +* Fix: Added support for previewing payment retry emails in WooCommerce email settings. +* Fix: Updated subscription email item table template to align with WooCommerce 9.7 email improvements. +* Fix: Prevent PHP warning on cart page shipping method updates by removing unused method: maybe_restore_shipping_methods. +* Fix: Removed unnecessary setting of renewal order paid date on status transition, relying on WooCommerce core behavior instead. +* Fix: Ensure the order_awaiting_payment session arg is restored when loading a renewal cart from the session to prevent duplicate orders. +* Fix: Ensure custom placeholders (time_until_renewal, customers_first_name) are included in customer notification email previews. +* Fix: For stores with HPOS + compatibility mode enabled, using the bulk delete related orders cache tool was not correctly deleting the meta from the WP Posts table. +* Fix: Prevent empty strings being saved in related orders cache ID meta when backfilling order data to the WP Posts table. +* Fix: Correctly load product names with HTML on the cart and checkout shipping rates. +* Dev: Fix Node version mismatch between package.json and .nvmrc (both are now set to v16.17.1). +* Dev: Update subscriptions-core to 8.1.0 + 2025-02-13 - version 7.2.1 * Fix: Revert a change released in 7.2.0 which triggered the "woocommerce_cart_item_name" filter with the wrong number of parameters. * Dev: Update subscriptions-core to 8.0.1. diff --git a/includes/admin/class-wcs-admin-reports.php b/includes/admin/class-wcs-admin-reports.php index 1853abc..37cc1d2 100644 --- a/includes/admin/class-wcs-admin-reports.php +++ b/includes/admin/class-wcs-admin-reports.php @@ -57,10 +57,10 @@ class WCS_Admin_Reports { '

%s

%s

', _x( 'WooCommerce Subscriptions - Reports Not Available', 'heading used in an admin notice', 'woocommerce-subscriptions' ), sprintf( - // translators: placeholders $1 and $2 are opening tags linking to the WooCommerce documentation on HPOS and data synchronization. Placeholder $3 is a closing link () tag. - __( 'Subscription reports are incompatible with the %1$sWooCommerce data storage features%3$s enabled on your store. Please enable %2$stable synchronization%3$s if you wish to use subscription reports.', 'woocommerce-subscriptions' ), + // translators: placeholders $1 and $2 are opening tags linking to the WooCommerce documentation on HPOS, and to the Advanced Feature settings screen. Placeholder $3 is a closing link () tag. + __( 'Subscription reports are incompatible with the %1$sWooCommerce data storage features%3$s enabled on your store. Please %2$senable compatibility mode%3$s if you wish to use subscription reports.', 'woocommerce-subscriptions' ), '', - '', + '', '' ) ) diff --git a/includes/admin/reports/class-wcs-report-cache-manager.php b/includes/admin/reports/class-wcs-report-cache-manager.php index 6d52bdc..27aee37 100644 --- a/includes/admin/reports/class-wcs-report-cache-manager.php +++ b/includes/admin/reports/class-wcs-report-cache-manager.php @@ -78,6 +78,11 @@ class WCS_Report_Cache_Manager { * @since 2.1 */ public function __construct() { + // Our reports integration does not work if A) HPOS is enabled and B) compatibility mode is disabled. + // In these cases, there is no reason to cache report data/to update data that was already cached. + if ( wcs_is_custom_order_tables_usage_enabled() && ! wcs_is_custom_order_tables_data_sync_enabled() ) { + return; + } // Use the old hooks if ( wcs_is_woocommerce_pre( '3.0' ) ) { diff --git a/includes/api/class-wc-rest-subscription-system-status-manager.php b/includes/api/class-wc-rest-subscription-system-status-manager.php index 65ea247..8af138d 100644 --- a/includes/api/class-wc-rest-subscription-system-status-manager.php +++ b/includes/api/class-wc-rest-subscription-system-status-manager.php @@ -54,7 +54,7 @@ class WC_REST_Subscription_System_Status_Manager { * @return WP_REST_Response */ public static function add_subscription_fields_to_response( $response ) { - $count_by_status = array_filter( (array) WC_Data_Store::load( 'subscription' )->get_subscriptions_count_by_status() ); + $count_by_status = WCS_Admin_System_Status::get_subscription_status_counts(); $response->data['subscriptions'] = array( 'wcs_debug' => defined( 'WCS_DEBUG' ) ? WCS_DEBUG : false, diff --git a/includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php b/includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php index 22b6a48..7a196b0 100644 --- a/includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php +++ b/includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php @@ -15,6 +15,13 @@ if ( ! defined( 'ABSPATH' ) ) { */ class WCS_Email_Customer_Payment_Retry extends WCS_Email_Customer_Renewal_Invoice { + /** + * The retry object. + * + * @var WCS_Retry + */ + public $retry; + /** * Constructor */ diff --git a/includes/payment-retry/emails/class-wcs-email-payment-retry.php b/includes/payment-retry/emails/class-wcs-email-payment-retry.php index 71722f4..03a3a1f 100644 --- a/includes/payment-retry/emails/class-wcs-email-payment-retry.php +++ b/includes/payment-retry/emails/class-wcs-email-payment-retry.php @@ -18,6 +18,13 @@ if ( ! defined( 'ABSPATH' ) ) { */ class WCS_Email_Payment_Retry extends WC_Email_Failed_Order { + /** + * The retry object associated with the order. + * + * @var WCS_Retry + */ + public $retry; + /** * Constructor */ diff --git a/languages/woocommerce-subscriptions.pot b/languages/woocommerce-subscriptions.pot index a68deae..41f61a2 100644 --- a/languages/woocommerce-subscriptions.pot +++ b/languages/woocommerce-subscriptions.pot @@ -2,16 +2,16 @@ # This file is distributed under the same license as the WooCommerce Subscriptions plugin. msgid "" msgstr "" -"Project-Id-Version: WooCommerce Subscriptions 7.2.1\n" +"Project-Id-Version: WooCommerce Subscriptions 7.3.0\n" "Report-Msgid-Bugs-To: https://woocommerce.com/contact-us\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2025-02-13T11:09:03+00:00\n" +"POT-Creation-Date: 2025-03-24T04:14:22+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"X-Generator: WP-CLI 2.11.0\n" +"X-Generator: WP-CLI 2.9.0\n" "X-Domain: woocommerce-subscriptions\n" #. Plugin Name of the plugin @@ -29,7 +29,7 @@ msgstr "" #. Author of the plugin #: includes/admin/class-wcs-admin-reports.php:136 -#: includes/admin/reports/class-wcs-report-cache-manager.php:262 +#: includes/admin/reports/class-wcs-report-cache-manager.php:267 msgid "WooCommerce" msgstr "" @@ -42,9 +42,9 @@ msgctxt "heading used in an admin notice" msgid "WooCommerce Subscriptions - Reports Not Available" msgstr "" -#. translators: placeholders $1 and $2 are opening tags linking to the WooCommerce documentation on HPOS and data synchronization. Placeholder $3 is a closing link () tag. +#. translators: placeholders $1 and $2 are opening tags linking to the WooCommerce documentation on HPOS, and to the Advanced Feature settings screen. Placeholder $3 is a closing link () tag. #: includes/admin/class-wcs-admin-reports.php:61 -msgid "Subscription reports are incompatible with the %1$sWooCommerce data storage features%3$s enabled on your store. Please enable %2$stable synchronization%3$s if you wish to use subscription reports." +msgid "Subscription reports are incompatible with the %1$sWooCommerce data storage features%3$s enabled on your store. Please %2$senable compatibility mode%3$s if you wish to use subscription reports." msgstr "" #: includes/admin/class-wcs-admin-reports.php:81 @@ -52,7 +52,7 @@ msgstr "" #: includes/api/class-wc-rest-subscriptions-settings.php:29 #: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1028 #: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1180 -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:59 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:100 #: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-wc-admin-manager.php:41 #: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-wc-admin-manager.php:51 #: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-wc-admin-manager.php:93 @@ -89,34 +89,34 @@ msgstr "" msgid "Failed Payment Retries" msgstr "" -#: includes/admin/reports/class-wcs-report-cache-manager.php:265 +#: includes/admin/reports/class-wcs-report-cache-manager.php:270 msgid "Please note: data for this report is cached. The data displayed may be out of date by up to 24 hours. The cache is updated each morning at 4am in your site's timezone." msgstr "" -#: includes/admin/reports/class-wcs-report-cache-manager.php:314 +#: includes/admin/reports/class-wcs-report-cache-manager.php:319 msgctxt "Whether the Report Cache has been enabled" msgid "Report Cache Enabled" msgstr "" -#: includes/admin/reports/class-wcs-report-cache-manager.php:316 +#: includes/admin/reports/class-wcs-report-cache-manager.php:321 #: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1722 #: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1791 -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:98 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:139 msgid "Yes" msgstr "" -#: includes/admin/reports/class-wcs-report-cache-manager.php:316 +#: includes/admin/reports/class-wcs-report-cache-manager.php:321 #: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1722 -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:98 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:139 msgid "No" msgstr "" -#: includes/admin/reports/class-wcs-report-cache-manager.php:320 +#: includes/admin/reports/class-wcs-report-cache-manager.php:325 msgid "Cache Update Failures" msgstr "" #. translators: %d refers to the number of times we have detected cache update failures -#: includes/admin/reports/class-wcs-report-cache-manager.php:323 +#: includes/admin/reports/class-wcs-report-cache-manager.php:328 msgid "%d failures" msgid_plural "%d failure" msgstr[0] "" @@ -1137,7 +1137,7 @@ msgid "Set a maximum number of times a customer can suspend their account for ea msgstr "" #: includes/class-wcs-customer-suspension-manager.php:111 -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1384 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1382 msgid "Suspend" msgstr "" @@ -1271,7 +1271,6 @@ msgid "Welcome to WooCommerce Subscriptions %s!" msgstr "" #: includes/class-wcs-upgrade-notice-manager.php:112 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:355 #: vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php:232 msgid "Learn more" msgstr "" @@ -1337,7 +1336,7 @@ msgstr "" #: includes/early-renewal/wcs-early-renewal-functions.php:136 #: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-related-orders-row.php:18 #: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/views/html-unknown-related-orders-row.php:18 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php:172 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php:154 #: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:36 #: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:45 #: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:34 @@ -1651,35 +1650,35 @@ msgstr "" msgid "No retries found in trash" msgstr "" -#: includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php:24 +#: includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php:31 msgid "Customer Payment Retry" msgstr "" -#: includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php:25 +#: includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php:32 msgid "Sent to a customer when an attempt to automatically process a subscription renewal payment has failed and a retry rule has been applied to retry the payment in the future. The email contains the renewal order information, date of the scheduled retry and payment links to allow the customer to pay for the renewal order manually instead of waiting for the automatic retry." msgstr "" -#: includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php:32 +#: includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php:39 msgid "Automatic payment failed for {order_number}, we will retry {retry_time}" msgstr "" -#: includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php:33 +#: includes/payment-retry/emails/class-wcs-email-customer-payment-retry.php:40 msgid "Automatic payment failed for order {order_number}" msgstr "" -#: includes/payment-retry/emails/class-wcs-email-payment-retry.php:26 +#: includes/payment-retry/emails/class-wcs-email-payment-retry.php:33 msgid "Payment Retry" msgstr "" -#: includes/payment-retry/emails/class-wcs-email-payment-retry.php:27 +#: includes/payment-retry/emails/class-wcs-email-payment-retry.php:34 msgid "Payment retry emails are sent to chosen recipient(s) when an attempt to automatically process a subscription renewal payment has failed and a retry rule has been applied to retry the payment in the future." msgstr "" -#: includes/payment-retry/emails/class-wcs-email-payment-retry.php:29 +#: includes/payment-retry/emails/class-wcs-email-payment-retry.php:36 msgid "Automatic renewal payment failed" msgstr "" -#: includes/payment-retry/emails/class-wcs-email-payment-retry.php:30 +#: includes/payment-retry/emails/class-wcs-email-payment-retry.php:37 msgid "[{site_title}] Automatic payment failed for {order_number}, retry scheduled to run {retry_time}" msgstr "" @@ -1925,46 +1924,6 @@ 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:290 -msgctxt "table heading" -msgid "Start Date" -msgstr "" - -#: tests/unit/scheduler/scheduler.php:66 -#: vendor/woocommerce/subscriptions-core/wcs-functions.php:291 -msgctxt "table heading" -msgid "Trial End" -msgstr "" - -#: tests/unit/scheduler/scheduler.php:67 -#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:43 -#: vendor/woocommerce/subscriptions-core/wcs-functions.php:292 -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:293 -msgctxt "table heading" -msgid "Last Order Date" -msgstr "" - -#: tests/unit/scheduler/scheduler.php:69 -#: vendor/woocommerce/subscriptions-core/wcs-functions.php:294 -msgctxt "table heading" -msgid "Cancelled Date" -msgstr "" - -#: tests/unit/scheduler/scheduler.php:70 -#: vendor/woocommerce/subscriptions-core/wcs-functions.php:295 -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." @@ -2047,7 +2006,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:372 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2479 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2416 #: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:25 msgid "Free trial" msgstr "" @@ -2244,25 +2203,25 @@ msgid "You do not have permission to view those subscriptions." msgstr "" #: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1721 -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:96 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:137 msgctxt "label that indicates whether debugging is turned on for the plugin" msgid "WCS_DEBUG" msgstr "" #: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1727 -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:110 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:151 msgctxt "Live or Staging, Label on WooCommerce -> System Status page" msgid "Subscriptions Mode" msgstr "" #: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1728 -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:112 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:153 msgctxt "refers to staging site" msgid "Staging" msgstr "" #: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:1728 -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:112 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:153 msgctxt "refers to live site" msgid "Live" msgstr "" @@ -2451,20 +2410,20 @@ msgid "Delete Permanently" msgstr "" #: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:331 -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1772 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1770 msgctxt "an action on a subscription" msgid "Activate" msgstr "" #: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:332 -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1773 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1771 msgctxt "an action on a subscription" msgid "Put on-hold" msgstr "" #: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:333 -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1385 -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1774 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1383 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1772 #: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:1955 #: vendor/woocommerce/subscriptions-core/includes/wcs-user-functions.php:329 #: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:79 @@ -2500,9 +2459,9 @@ msgstr "" #: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:469 #: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php:394 -#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:21 -#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:21 -#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:21 +#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:39 +#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:24 +#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:24 #: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:21 #: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:21 msgid "Subscription" @@ -2589,130 +2548,130 @@ 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:652 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2217 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2251 msgid "Via %s" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:695 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:696 msgid "Y/m/d g:i:s A" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:712 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:711 msgid "Subscription payment overdue.
" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:717 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:716 msgid "This date should be treated as an estimate only. The payment gateway for this subscription controls when payments are processed.
" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1113 -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1116 -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1119 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1111 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1114 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1117 msgid "Subscription updated." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1114 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1112 msgid "Custom field updated." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1115 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1113 msgid "Custom field deleted." msgstr "" #. translators: placeholder is previous post title -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1118 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1116 msgctxt "used in post updated messages" msgid "Subscription restored to revision from %s" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1120 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1118 msgid "Subscription saved." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1121 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1119 msgid "Subscription submitted." msgstr "" #. translators: php date string -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1123 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1121 msgid "Subscription scheduled for: %1$s." msgstr "" #. translators: php date string -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1123 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1121 msgctxt "used in \"Subscription scheduled for \"" msgid "M j, Y @ G:i" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1124 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1122 msgid "Subscription draft updated." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1167 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1165 msgid "Any Payment Method" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1168 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1166 msgid "None" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1174 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2199 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1172 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2233 #: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:170 msgid "Manual Renewal" msgstr "" #. translators: 1: user display name 2: user ID 3: user email -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1338 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1336 msgid "%1$s (#%2$s – %3$s)" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1345 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1343 #: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:96 msgid "Search for a customer…" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1383 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1381 #: vendor/woocommerce/subscriptions-core/includes/wcs-user-functions.php:311 msgid "Reactivate" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1386 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1384 msgid "Trash" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1387 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1385 msgid "Delete Permanently" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1406 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1404 #: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:765 msgid "Restore this item from the Trash" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1408 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1406 #: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-product.php:766 msgid "Restore" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1413 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1411 msgid "Move this item to the Trash" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1427 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1425 msgid "Delete this item permanently" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1438 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1436 msgid "Cancel Now" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1504 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1502 msgctxt "Used in order note. Reason why status changed." msgid "Subscription status changed by bulk edit:" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1622 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1620 msgid "All" msgstr "" @@ -2720,85 +2679,85 @@ msgstr "" msgid "Subscription variations" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:60 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:101 msgid "This section shows any information about Subscriptions." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:64 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:105 msgid "Store Setup" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:65 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:106 msgid "This section shows general information about the store." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:69 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:110 msgid "Subscriptions by Payment Gateway" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:70 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:111 msgid "This section shows information about Subscription payment methods." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:74 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:115 msgid "Payment Gateway Support" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:75 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:116 msgid "This section shows information about payment gateway feature support." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:122 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:168 msgctxt "Live URL, Label on WooCommerce -> System Status page" msgid "Subscriptions Live URL" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:135 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:181 msgctxt "Subscriptions-core Version, Label on WooCommerce -> System Status page" msgid "Subscriptions-core Library Version" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:151 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:197 msgctxt "label for the system status page" msgid "Subscriptions Template Theme Overrides" msgstr "" #. translators: placeholders are opening/closing tags linking to documentation on outdated templates. -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:161 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:207 msgid "%1$sLearn how to update%2$s" msgstr "" #. translators: %1$s is the file version, %2$s is the core version -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:206 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:252 msgid "version %1$s is out of date. The core version is %2$s" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:227 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:272 msgctxt "label for the system status page" msgid "Subscription Statuses" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:248 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:293 msgctxt "label for the system status page" msgid "WooCommerce Account Connected" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:271 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:316 msgctxt "label for the system status page" msgid "Active Product Key" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:291 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:340 msgctxt "label for the system status page" msgid "Other" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:325 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:374 msgctxt "label for the system status page" msgid "PayPal Reference Transactions Enabled" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:353 +#: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php:402 msgctxt "label for the system status page" msgid "Country / State" msgstr "" @@ -2845,7 +2804,7 @@ msgid "This tool will add notifications to pending, active, and on-hold subscrip msgstr "" #: vendor/woocommerce/subscriptions-core/includes/admin/debug-tools/class-wcs-notifications-debug-tool-processor.php:314 -#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:61 +#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:114 msgid "Note:" msgstr "" @@ -3100,115 +3059,115 @@ msgid "Error during subscription status transition." msgstr "" #. translators: placeholder is human time diff (e.g. "3 weeks") -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1314 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1325 #: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-manager.php:2402 msgid "In %s" msgstr "" #. translators: placeholder is human time diff (e.g. "3 weeks") -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1317 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1328 #: vendor/woocommerce/subscriptions-core/includes/wcs-formatting-functions.php:246 msgid "%s ago" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1324 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1335 msgid "Not yet ended" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1327 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1338 msgid "Not cancelled" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1332 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1343 msgctxt "original denotes there is no date to display" msgid "-" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1440 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1451 msgid "The creation date of a subscription can not be deleted, only updated." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1443 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1454 msgid "The start date of a subscription can not be deleted, only updated." msgstr "" #. translators: %s: date type (e.g. "trial_end"). -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1448 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1459 msgid "The %s date of a subscription can not be deleted. You must delete the order." msgstr "" #. translators: %d: subscription ID. #. translators: %d: order ID. -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1457 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2640 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1468 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2674 msgid "Subscription #%d: " msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1920 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1931 msgid "Payment status marked complete." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1962 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1973 msgid "Payment failed." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1967 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1978 msgid "Subscription Cancelled: maximum number of failed payments reached." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2081 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2092 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:2296 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2330 #: vendor/woocommerce/subscriptions-core/wcs-functions.php:853 msgid "Payment method meta must be an array." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2532 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2566 msgid "Invalid format. First parameter needs to be an array." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2536 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2570 msgid "Invalid data. First parameter was empty when passed to update_dates()." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2543 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2577 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:2570 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2604 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:2608 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2642 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:2614 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2648 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:2619 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2653 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:2625 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2659 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:2630 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2664 msgid "The %s date must occur after the start date." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2660 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2694 #: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-checkout.php:348 msgid "Backordered" msgstr "" @@ -3271,28 +3230,24 @@ msgid "That product can not be added to your cart as it already contains a subsc msgstr "" #: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart-validator.php:179 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:1539 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:1473 msgid "That subscription product can not be added to your cart as it already contains a subscription renewal." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:540 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:536 msgid "Initial Shipment" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:979 -msgid "Please enter a valid postcode/ZIP." -msgstr "" - -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:1177 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:1111 msgid "Invalid recurring shipping method." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2215 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2149 msgid "now" msgstr "" #. translators: placeholder is a number of days. -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2374 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2311 #: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:58 msgid "%s day" msgid_plural "%s days" @@ -3300,7 +3255,7 @@ msgstr[0] "" msgstr[1] "" #. translators: placeholder is a number of weeks. -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2378 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2315 #: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:60 msgid "%s week" msgid_plural "%s weeks" @@ -3308,7 +3263,7 @@ msgstr[0] "" msgstr[1] "" #. translators: placeholder is a number of months. -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2382 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2319 #: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:62 msgid "%s month" msgid_plural "%s months" @@ -3316,7 +3271,7 @@ msgstr[0] "" msgstr[1] "" #. translators: placeholder is a number of years. -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2386 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2323 #: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:64 msgid "%s year" msgid_plural "%s years" @@ -3324,49 +3279,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:2408 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2345 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:2412 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2349 msgid "every %1$s on %2$s" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2421 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2358 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:2425 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2362 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:2433 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2370 msgid "on the last day of every %1$s month" msgstr "" #. translators: on the, 1$: day of every, 2$: month (e.g. "on the 23rd day of every 2nd month"). -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2439 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2376 msgid "on the %1$s day of every %2$s month" msgstr "" #. translators: on, 1$: , 2$: each year (e.g. "on March 15th each year"). -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2450 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2387 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:2457 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2394 msgid "on %1$s %2$s every %3$s year" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2489 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2426 msgid "Sign up fee" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2499 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2436 msgid "Renews" msgstr "" @@ -3647,61 +3602,49 @@ msgstr "" msgid "Discount" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:247 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:244 msgid "Send trial is ending notification" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:251 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:248 msgid "Send upcoming subscription expiration notification" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:255 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:252 msgid "Send upcoming renewal notification" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:271 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:268 msgid "Customer Notifications" msgstr "" #. translators: Link to WC Settings > Email. -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:275 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:272 msgid "To enable/disable individual notifications and customize templates, visit the
Email settings." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:278 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:275 msgid "Enable Reminders" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:279 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:276 msgid "Send notification emails to customers for subscription renewals and expirations." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:288 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:285 msgid "Reminder Timing" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:289 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:286 msgid "How long before the event should the notification be sent." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:294 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:291 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-notification.php:60 #: vendor/woocommerce/subscriptions-core/includes/privacy/class-wcs-privacy.php:281 msgid "N/A" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:343 -msgid "WooCommerce Subscriptions: Introducing customer email notifications!" -msgstr "" - -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:344 -msgid "You can now send email notifications for subscription renewals, expirations, and free trials. Go to the \"Customer Notifications\" settings section to configure when your customers receive these important updates." -msgstr "" - -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php:350 -msgid "Manage settings" -msgstr "" - #: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:185 msgid "Subscription Product length." msgstr "" @@ -4089,15 +4032,15 @@ msgstr "" msgid "All orders types" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:2449 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:2455 msgid "Renewal Order" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:2451 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:2457 msgid "Resubscribe Order" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:2453 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php:2459 msgid "Parent Order" msgstr "" @@ -4200,11 +4143,11 @@ msgid "This variation can not be removed because it is associated with existing msgstr "" #. translators: placeholder is order ID -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php:175 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php:157 msgid "Order %s created to record renewal." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php:195 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php:177 msgid "Subscription renewal orders cannot be cancelled." msgstr "" @@ -4326,55 +4269,55 @@ msgid "Weekly" msgstr "" #: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-initial-payment.php:85 -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:199 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:200 msgid "That doesn't appear to be your order." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:214 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:215 msgid "This order can no longer be paid because the corresponding subscription does not require payment at this time." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:235 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:236 msgid "Complete checkout to renew your subscription." msgstr "" #. translators: placeholder is an item name -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:318 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:333 msgid "The %s product has been deleted and can no longer be renewed. Please choose a new product or contact us for assistance." msgstr "" #. translators: %s is subscription's number -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:353 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:368 msgid "Subscription #%s has not been added to the cart." msgstr "" #. translators: %s is order's number -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:356 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:371 msgid "Order #%s has not been added to the cart." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:395 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:410 msgid "We couldn't find the original subscription for an item in your cart. The item was removed." msgid_plural "We couldn't find the original subscriptions for items in your cart. The items were removed." msgstr[0] "" msgstr[1] "" -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:402 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:417 msgid "We couldn't find the original renewal order for an item in your cart. The item was removed." msgid_plural "We couldn't find the original renewal orders for items in your cart. The items were removed." msgstr[0] "" msgstr[1] "" -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:698 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:713 msgid "All linked subscription items have been removed from the cart." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:727 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:742 msgctxt "Used in WooCommerce by removed item notification: \"_All linked subscription items were_ removed. Undo?\" Filter for item title." msgid "All linked subscription items were" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:1554 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php:1569 msgctxt "The place order button text while renewing a subscription" msgid "Renew subscription" msgstr "" @@ -4697,31 +4640,31 @@ msgstr "" msgid "Something went wrong when trying to restore subscription %d from the trash. It could not be restored." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php:115 +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php:131 msgid "Generate Related Order Cache" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php:115 +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php:131 msgid "This will generate the persistent cache of all renewal, switch, resubscribe and other order types for all subscriptions in your store. The caches will be generated overtime in the background (via Action Scheduler)." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php:116 +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php:132 msgid "Delete Related Order Cache" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php:116 +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php:132 msgid "This will clear the persistent cache of all renewal, switch, resubscribe and other order types for all subscriptions in your store. Expect slower performance of checkout, renewal and other subscription related functions after taking this action. The caches will be regenerated overtime as related order queries are run." msgstr "" #. translators: %s: Order date -#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php:265 +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php:272 msgid "Subscription – %s" msgstr "" #. translators: %s: Order date #. translators: placeholders are strftime() strings. -#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php:265 -#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:261 +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php:272 +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:309 msgctxt "Order date parsed by DateTime::format" msgid "M d, Y @ h:i A" msgstr "" @@ -4754,7 +4697,15 @@ 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:145 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:58 +msgid "Always Send" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:60 +msgid "Send this email whenever a subscription is updated to \"Pending Cancellation\" or \"Cancelled\"." +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:168 #: 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 @@ -4762,14 +4713,14 @@ msgctxt "an email notification" msgid "Enable/Disable" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:147 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:170 #: 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:151 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:174 #: 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" @@ -4777,13 +4728,13 @@ msgid "Recipient(s)" msgstr "" #. translators: placeholder is admin email -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:154 +#: 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: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:159 +#: 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:155 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:155 msgctxt "of an email" @@ -4791,13 +4742,13 @@ msgid "Subject" msgstr "" #. translators: %s: default e-mail subject. -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:162 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:185 #: 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:167 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:190 #: 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" @@ -4805,39 +4756,39 @@ msgid "Email Heading" msgstr "" #. translators: %s: default e-mail heading. -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:170 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:193 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:175 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:198 #: 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:177 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:200 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-notification.php:68 #: 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:181 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:204 #: 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:182 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:205 #: 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:183 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:206 #: 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" @@ -6374,45 +6325,45 @@ msgstr "" msgid "Invalid sort order type: %1$s. The $sort_order argument must be %2$s or %3$s." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:143 +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:191 msgctxt "In wcs_copy_order_meta error message. Refers to origin and target order objects." msgid "Invalid data. Orders expected aren't orders." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:147 +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:195 msgctxt "Refers to the type of the copy being performed: \"copy_order\", \"subscription\", \"renewal_order\", \"resubscribe_order\"" msgid "Invalid data. Type of copy is not a string." msgstr "" #. translators: placeholder %1 is the order type. %2 is the subscription ID we attempted to create the order for. -#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:229 +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:277 msgid "There was an error fetching the new order (%1$s) for subscription %2$d." msgstr "" #. translators: placeholder is a date. -#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:266 +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:314 msgid "Subscription Renewal Order – %s" msgstr "" #. translators: placeholder is a date. -#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:270 +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:318 msgid "Resubscribe Order – %s" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:289 +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:337 msgid "$type passed to the function was not a string." msgstr "" #. translators: placeholder is an order type. -#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:294 +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:342 msgid "\"%s\" is not a valid new order type." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:545 +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:592 msgid "Invalid data. No valid subscription / order was passed in." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:549 +#: vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php:596 msgid "Invalid data. No valid item id was passed in." msgstr "" @@ -6645,14 +6596,14 @@ msgid "There are no shipping methods available. Please double check your address msgstr "" #: vendor/woocommerce/subscriptions-core/templates/checkout/form-change-payment-method.php:19 -#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:36 +#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:67 #: vendor/woocommerce/subscriptions-core/templates/myaccount/subscription-totals-table.php:20 msgctxt "table headings in notification email" msgid "Product" msgstr "" #: vendor/woocommerce/subscriptions-core/templates/checkout/form-change-payment-method.php:20 -#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:37 +#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:68 msgctxt "table headings in notification email" msgid "Quantity" msgstr "" @@ -6717,14 +6668,15 @@ msgid "Payment Method: %s" msgstr "" #. translators: $1: customer's billing first name and last name -#: vendor/woocommerce/subscriptions-core/templates/emails/admin-new-renewal-order.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/admin-new-renewal-order.php:22 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/admin-new-renewal-order.php:16 msgctxt "Used in admin email: new renewal order" msgid "You have received a subscription renewal order from %1$s. Their order is as follows:" msgstr "" +#. translators: $1: customer's first name and last name #. translators: $1: customer's first name and last name, $2: how many subscriptions customer switched -#: vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php:18 +#: vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php:28 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/admin-new-switch-order.php:18 msgctxt "Used in switch notification admin email" msgid "Customer %1$s has switched their subscription. The details of their new subscription are as follows:" @@ -6732,19 +6684,25 @@ msgid_plural "Customer %1$s has switched %2$d of their subscriptions. The detail msgstr[0] "" msgstr[1] "" -#: vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php:20 +#. translators: $1: customer's first name and last name, $2: how many subscriptions customer switched +#: vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php:31 +msgctxt "Used in switch notification admin email" +msgid "Customer %1$s has switched %2$d of their subscriptions. The details of their new subscriptions are as follows:" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php:37 msgid "Switch Order Details" msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php:28 -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-switch-order.php:26 +#: vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php:53 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-switch-order.php:39 msgid "New subscription details" msgstr "" #. translators: %1$s: an order number, %2$s: the customer's full name, %3$s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' #: vendor/woocommerce/subscriptions-core/templates/emails/admin-payment-retry.php:23 msgctxt "In customer renewal invoice email" -msgid "The automatic recurring payment for order #%d from %s has failed. The payment will be retried %3$s." +msgid "The automatic recurring payment for order #%1$d from %2$s has failed. The payment will be retried %3$s." msgstr "" #: vendor/woocommerce/subscriptions-core/templates/emails/admin-payment-retry.php:24 @@ -6752,38 +6710,52 @@ msgstr "" msgid "The renewal order is as follows:" msgstr "" +#. translators: $1$s customer's billing first name and last name %2$s: date on which the subscription ends. +#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:21 +msgid "A subscription belonging to %1$s is now pending cancellation, and will end on %2$s. Their subscription's details are as follows:" +msgstr "" + +#. translators: $1$s customer's billing first name and last name. #. translators: $1: customer's billing first name and last name -#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:28 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/cancelled-subscription.php:16 msgid "A subscription belonging to %1$s has been cancelled. Their subscription's details are as follows:" msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:22 -#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:38 -#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:22 -#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:22 +#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:40 +#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:69 +#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:25 +#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:25 msgctxt "table headings in notification email" msgid "Price" msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:24 +#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:41 +#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:26 +#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:26 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:293 +msgctxt "table heading" +msgid "Last Order Date" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:42 msgctxt "table headings in notification email" msgid "End of Prepaid Term" msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:41 -#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:41 -#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:41 +#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:59 +#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:44 +#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:44 msgid "-" msgstr "" #. translators: %s: Customer first name -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-renewal-order.php:17 -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-switch-order.php:17 -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-on-hold-renewal-order.php:17 -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-payment-retry.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-renewal-order.php:22 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-switch-order.php:22 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-on-hold-renewal-order.php:20 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-payment-retry.php:17 #: vendor/woocommerce/subscriptions-core/templates/emails/customer-processing-renewal-order.php:17 -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:17 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-completed-renewal-order.php:16 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-completed-switch-order.php:16 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-on-hold-renewal-order.php:16 @@ -6793,19 +6765,19 @@ msgstr "" msgid "Hi %s," msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-renewal-order.php:18 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-renewal-order.php:23 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-completed-renewal-order.php:17 msgid "We have finished processing your subscription renewal order." msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-switch-order.php:18 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-completed-switch-order.php:23 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-completed-switch-order.php:17 msgid "You have successfully changed your subscription items. Your new order and subscription details are shown below for your reference:" msgstr "" #. translators: %s: Customer first name -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-auto-renewal.php:24 -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-renewal.php:24 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-auto-renewal.php:26 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-renewal.php:25 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-notification-auto-renewal.php:19 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-notification-manual-renewal.php:19 msgid "Hi %s." @@ -6817,85 +6789,85 @@ msgid "Your subscription will automatically renew in %1$s — t msgstr "" #. translators: %s: link to subscription detail in the customer's dashboard. -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-auto-renewal.php:73 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-auto-renewal.php:74 msgid "You can manage this subscription from your %s" msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-auto-renewal.php:74 -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-auto-trial-ending.php:56 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-auto-renewal.php:75 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-auto-trial-ending.php:54 msgid "account dashboard" msgstr "" #. translators: %s: Customer first name -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-auto-trial-ending.php:24 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-auto-trial-ending.php:25 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-notification-auto-trial-ending.php:19 msgid "Hi, %s." msgstr "" #. translators: %1$s: human readable time difference (eg 3 days, 1 day), %2$s: date in local format. -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-auto-trial-ending.php:37 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-auto-trial-ending.php:36 msgid "Your paid subscription begins when your free trial expires in %1$s — that’s %2$s." msgstr "" #. translators: %1$s: link to account dashboard. -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-auto-trial-ending.php:55 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-auto-trial-ending.php:53 msgid "Payment will be deducted using the payment method on file. You can manage this subscription from your %1$s." msgstr "" #. translators: %s: Customer first name -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-expiring-subscription.php:24 -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-trial-ending.php:24 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-expiring-subscription.php:23 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-trial-ending.php:25 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-notification-expiring-subscription.php:19 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-notification-manual-trial-ending.php:19 msgid "Heads up, %s." msgstr "" #. translators: %1$s: human readable time difference (eg 3 days, 1 day), %2$s: date in local format. -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-expiring-subscription.php:37 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-expiring-subscription.php:36 msgid "Your subscription expires in %1$s — that’s %2$s." msgstr "" #. translators: %1$s: human readable time difference (eg 3 days, 1 day), %2$s: date in local format. -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-renewal.php:37 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-renewal.php:38 msgid "Your subscription is up for renewal in %1$s — that’s %2$s." msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-renewal.php:52 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-renewal.php:53 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-notification-manual-renewal.php:40 msgid "This subscription will not renew automatically." msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-renewal.php:58 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-renewal.php:59 msgid "You can renew it manually in a few short steps via the Subscriptions tab in your account dashboard." msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-renewal.php:75 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-renewal.php:76 msgid "Renew Subscription" msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-renewal.php:77 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-renewal.php:78 msgid "Manage Subscription" msgstr "" #. translators: %1$s: human readable time difference (eg 3 days, 1 day), %2$s: date in local format. -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-trial-ending.php:37 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-notification-manual-trial-ending.php:36 msgid "Your free trial expires in %1$s — that’s %2$s." msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-on-hold-renewal-order.php:18 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-on-hold-renewal-order.php:21 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-on-hold-renewal-order.php:17 msgid "Thanks for your renewal order. It’s on-hold until we confirm that payment has been received. In the meantime, here’s a reminder of your order:" msgstr "" #. translators: %s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-payment-retry.php:18 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-payment-retry.php:19 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-payment-retry.php:18 msgctxt "In customer renewal invoice email" msgid "The automatic payment to renew your subscription has failed. We will retry the payment %s." msgstr "" #. translators: %1$s %2$s: link markup to checkout payment url, note: no full stop due to url at the end -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-payment-retry.php:21 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-payment-retry.php:22 msgctxt "In customer renewal invoice email" msgid "To reactivate the subscription now, you can also log in and pay for the renewal from your account page: %1$sPay Now »%2$s" msgstr "" @@ -6906,55 +6878,67 @@ msgstr "" msgid "Just to let you know — we've received your subscription renewal order #%s, and it is now being processed:" msgstr "" +#. translators: %1$s: name of the blog, %2$s: link to checkout payment url, note: no full stop due to url at the end. #. translators: %1$s: name of the blog, %2$s: link to checkout payment url, note: no full stop due to url at the end -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:22 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:25 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-renewal-invoice.php:20 msgctxt "In customer renewal invoice email" msgid "An order has been created for you to renew your subscription on %1$s. To pay for this invoice please use the following link: %2$s" msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:24 -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:33 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:32 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:54 msgid "Pay Now »" msgstr "" +#. translators: %1$s: name of the blog, %2$s: link to checkout payment url, note: no full stop due to url at the end. #. translators: %1$s: name of the blog, %2$s: link to checkout payment url, note: no full stop due to url at the end -#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:31 +#: vendor/woocommerce/subscriptions-core/templates/emails/customer-renewal-invoice.php:47 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/customer-renewal-invoice.php:23 msgctxt "In customer renewal invoice email" msgid "The automatic payment to renew your subscription with %1$s has failed. To reactivate the subscription, please log in and pay for the renewal from your account page: %2$s" msgstr "" -#. translators: $1-$2: opening and closing tags $3: order's order number $4: date of order in tags $2: subscription's order number -#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:27 -msgctxt "Used in email notification" -msgid "Subscription %1$s#%2$s%3$s" +#. translators: %s: Order or subscription ID. +#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:31 +msgid "Subscription #%s" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:36 +msgid "Order summary" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:36 +msgid "Subscription summary" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/templates/emails/email-order-details.php:106 +msgid "Customer note" msgstr "" #. translators: $1: customer's billing first name and last name -#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:17 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/expired-subscription.php:16 msgid "A subscription belonging to %1$s has expired. Their subscription's details are as follows:" msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:24 +#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:27 msgctxt "table headings in notification email" msgid "End Date" msgstr "" #. translators: $1: customer's billing first name and last name -#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:16 +#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:17 #: vendor/woocommerce/subscriptions-core/templates/emails/plain/on-hold-subscription.php:16 msgid "A subscription belonging to %1$s has been suspended by the user. Their subscription's details are as follows:" msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:24 +#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:27 msgctxt "table headings in notification email" msgid "Date Suspended" msgstr "" @@ -7176,6 +7160,12 @@ msgstr "" msgid "View subscription number %s" msgstr "" +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:43 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:292 +msgctxt "table heading" +msgid "Next Payment" +msgstr "" + #: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:49 #: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:54 #: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:43 @@ -7365,6 +7355,26 @@ msgstr "" msgid "Can not get address type display name. Address type is not a string." msgstr "" +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:290 +msgctxt "table heading" +msgid "Start Date" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:291 +msgctxt "table heading" +msgid "Trial End" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:294 +msgctxt "table heading" +msgid "Cancelled Date" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:295 +msgctxt "table heading" +msgid "End Date" +msgstr "" + #: vendor/woocommerce/subscriptions-core/wcs-functions.php:330 msgid "Date type is not a string." msgstr "" diff --git a/vendor/autoload.php b/vendor/autoload.php index 04da0da..c213c7a 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) { require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit0c80b12786c5f329cae617490ce0ac6d::getLoader(); +return ComposerAutoloaderInit2b7b846857cbbe9f2e962ff7f867dff1::getLoader(); diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php index 51e734a..6d29bff 100644 --- a/vendor/composer/InstalledVersions.php +++ b/vendor/composer/InstalledVersions.php @@ -32,6 +32,11 @@ class InstalledVersions */ private static $installed; + /** + * @var bool + */ + private static $installedIsLocalDir; + /** * @var bool|null */ @@ -309,6 +314,12 @@ class InstalledVersions { self::$installed = $data; self::$installedByVendor = array(); + + // when using reload, we disable the duplicate protection to ensure that self::$installed data is + // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not, + // so we have to assume it does not, and that may result in duplicate data being returned when listing + // all installed packages for example + self::$installedIsLocalDir = false; } /** @@ -322,19 +333,27 @@ class InstalledVersions } $installed = array(); + $copiedLocalDir = false; if (self::$canGetVendors) { + $selfDir = strtr(__DIR__, '\\', '/'); foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + $vendorDir = strtr($vendorDir, '\\', '/'); 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} $required */ $required = require $vendorDir.'/composer/installed.php'; - $installed[] = self::$installedByVendor[$vendorDir] = $required; - if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { - self::$installed = $installed[count($installed) - 1]; + self::$installedByVendor[$vendorDir] = $required; + $installed[] = $required; + if (self::$installed === null && $vendorDir.'/composer' === $selfDir) { + self::$installed = $required; + self::$installedIsLocalDir = true; } } + if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) { + $copiedLocalDir = true; + } } } @@ -350,7 +369,7 @@ class InstalledVersions } } - if (self::$installed !== array()) { + if (self::$installed !== array() && !$copiedLocalDir) { $installed[] = self::$installed; } diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index c9da981..25557c3 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit0c80b12786c5f329cae617490ce0ac6d +class ComposerAutoloaderInit2b7b846857cbbe9f2e962ff7f867dff1 { private static $loader; @@ -24,12 +24,12 @@ class ComposerAutoloaderInit0c80b12786c5f329cae617490ce0ac6d require __DIR__ . '/platform_check.php'; - spl_autoload_register(array('ComposerAutoloaderInit0c80b12786c5f329cae617490ce0ac6d', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInit2b7b846857cbbe9f2e962ff7f867dff1', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); - spl_autoload_unregister(array('ComposerAutoloaderInit0c80b12786c5f329cae617490ce0ac6d', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit2b7b846857cbbe9f2e962ff7f867dff1', 'loadClassLoader')); require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit0c80b12786c5f329cae617490ce0ac6d::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInit2b7b846857cbbe9f2e962ff7f867dff1::getInitializer($loader)); $loader->register(true); diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 53d0947..0c37b7c 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInit0c80b12786c5f329cae617490ce0ac6d +class ComposerStaticInit2b7b846857cbbe9f2e962ff7f867dff1 { public static $prefixLengthsPsr4 = array ( 'C' => @@ -126,9 +126,9 @@ class ComposerStaticInit0c80b12786c5f329cae617490ce0ac6d public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit0c80b12786c5f329cae617490ce0ac6d::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit0c80b12786c5f329cae617490ce0ac6d::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInit0c80b12786c5f329cae617490ce0ac6d::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInit2b7b846857cbbe9f2e962ff7f867dff1::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit2b7b846857cbbe9f2e962ff7f867dff1::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit2b7b846857cbbe9f2e962ff7f867dff1::$classMap; }, null, ClassLoader::class); } diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index ee8fff9..8bea489 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -151,17 +151,17 @@ }, { "name": "woocommerce/subscriptions-core", - "version": "8.0.1", - "version_normalized": "8.0.1.0", + "version": "8.1.0", + "version_normalized": "8.1.0.0", "source": { "type": "git", "url": "https://github.com/Automattic/woocommerce-subscriptions-core.git", - "reference": "554c03a5e7591c448d495ee41ee12015f65cad5a" + "reference": "e12381a3ac3cde2ad2ff2e762a0e28c3bee02e5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/554c03a5e7591c448d495ee41ee12015f65cad5a", - "reference": "554c03a5e7591c448d495ee41ee12015f65cad5a", + "url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/e12381a3ac3cde2ad2ff2e762a0e28c3bee02e5c", + "reference": "e12381a3ac3cde2ad2ff2e762a0e28c3bee02e5c", "shasum": "" }, "require": { @@ -174,7 +174,7 @@ "woocommerce/woocommerce-sniffs": "0.1.0", "yoast/phpunit-polyfills": "1.1.0" }, - "time": "2025-02-13T10:49:47+00:00", + "time": "2025-03-24T00:03:20+00:00", "type": "wordpress-plugin", "extra": { "phpcodesniffer-search-depth": 2 @@ -204,7 +204,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/8.0.1", + "source": "https://github.com/Automattic/woocommerce-subscriptions-core/tree/8.1.0", "issues": "https://github.com/Automattic/woocommerce-subscriptions-core/issues" }, "install-path": "../woocommerce/subscriptions-core" diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index b1031d0..f2c3519 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -1,9 +1,9 @@ array( 'name' => 'woocommerce/woocommerce-subscriptions', - 'pretty_version' => 'dev-release/7.2.1', - 'version' => 'dev-release/7.2.1', - 'reference' => 'c1ca6ecf1cb1adeb0725e3d5ad543424e73b041e', + 'pretty_version' => 'dev-release/7.3.0', + 'version' => 'dev-release/7.3.0', + 'reference' => 'ef3998fdc41ca6a6013d950438fd9a34a3204a06', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -20,18 +20,18 @@ 'dev_requirement' => false, ), 'woocommerce/subscriptions-core' => array( - 'pretty_version' => '8.0.1', - 'version' => '8.0.1.0', - 'reference' => '554c03a5e7591c448d495ee41ee12015f65cad5a', + 'pretty_version' => '8.1.0', + 'version' => '8.1.0.0', + 'reference' => 'e12381a3ac3cde2ad2ff2e762a0e28c3bee02e5c', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../woocommerce/subscriptions-core', 'aliases' => array(), 'dev_requirement' => false, ), 'woocommerce/woocommerce-subscriptions' => array( - 'pretty_version' => 'dev-release/7.2.1', - 'version' => 'dev-release/7.2.1', - 'reference' => 'c1ca6ecf1cb1adeb0725e3d5ad543424e73b041e', + 'pretty_version' => 'dev-release/7.3.0', + 'version' => 'dev-release/7.3.0', + 'reference' => 'ef3998fdc41ca6a6013d950438fd9a34a3204a06', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), diff --git a/vendor/woocommerce/subscriptions-core/.nvmrc b/vendor/woocommerce/subscriptions-core/.nvmrc index b009dfb..c85fa1b 100644 --- a/vendor/woocommerce/subscriptions-core/.nvmrc +++ b/vendor/woocommerce/subscriptions-core/.nvmrc @@ -1 +1 @@ -lts/* +16.17.1 diff --git a/vendor/woocommerce/subscriptions-core/assets/js/admin/admin-pointers.js b/vendor/woocommerce/subscriptions-core/assets/js/admin/admin-pointers.js index ac18742..de42650 100644 --- a/vendor/woocommerce/subscriptions-core/assets/js/admin/admin-pointers.js +++ b/vendor/woocommerce/subscriptions-core/assets/js/admin/admin-pointers.js @@ -1,6 +1,15 @@ jQuery( function ( $ ) { + let observer = null; + if ( arePointersEnabled() ) { - setTimeout( showSubscriptionPointers, 800 ); // give TinyMCE a chance to finish loading + observer = new MutationObserver( showSubscriptionPointers ); + + observer.observe( document.getElementById( 'poststuff' ), { + attributes: true, + childList: true, + characterData: false, + subtree:true, + } ); } $( 'select#product-type' ).on( 'change', function () { @@ -62,5 +71,9 @@ jQuery( function ( $ ) { pointer: 'wcs_pointer', action: 'dismiss-wp-pointer', } ); + + if ( observer ) { + observer.disconnect(); + } } } ); diff --git a/vendor/woocommerce/subscriptions-core/changelog.txt b/vendor/woocommerce/subscriptions-core/changelog.txt index 0655f57..ca838d3 100644 --- a/vendor/woocommerce/subscriptions-core/changelog.txt +++ b/vendor/woocommerce/subscriptions-core/changelog.txt @@ -1,5 +1,23 @@ *** WooCommerce Subscriptions Core Changelog *** += 8.1.0 - 2025-03-24 = +* Update - Improved subscription search performance for WP Post stores by removing unnecessary _order_key and _billing_email meta queries. +* Update - Make it possible to dispatch the Cancelled Subscription email more than once (when initially set to pending-cancellation, and again when it reaches final cancellation). +* Update - Reduced duplicate queries when fetching multiple subscription related orders types. +* Update - Removed unnecessary get_time() calls to reduce redundant get_last_order() queries in the Subscriptions list table. +* Update - Improved performance on the Orders list table when rendering the Subscription Relationship column. +* Update - Improved performance of the Generate Related Order Cache tool found under WooCommerce > Status > Tools. +* Fix - Added support for previewing payment retry emails in WooCommerce email settings. +* Fix - Updated subscription email item table template to align with WooCommerce 9.7 email improvements. +* Fix - Prevent PHP warning on cart page shipping method updates by removing unused method: maybe_restore_shipping_methods. +* Fix - Removed unnecessary setting of renewal order paid date on status transition, relying on WooCommerce core behavior instead. +* Fix - Ensure the order_awaiting_payment session arg is restored when loading a renewal cart from the session to prevent duplicate orders. +* Fix - Ensure custom placeholders (time_until_renewal, customers_first_name) are included in customer notification email previews. +* Fix - For stores with HPOS + compatibility mode enabled, using the bulk delete related orders cache tool was not correctly deleting the meta from the WP Posts table. +* Fix - Prevent empty strings being saved in related orders cache ID meta when backfilling order data to the WP Posts table. +* Fix - Correctly load product names with HTML on the cart and checkout shipping rates. +* Dev - Fix Node version mismatch between package.json and .nvmrc (both are now set to v16.17.1). + = 8.0.1 - 2025-02-13 = * Fix - Revert a change released in 7.2.0 which triggered the "woocommerce_cart_item_name" filter with the wrong number of parameters. @@ -13,6 +31,7 @@ * Fix - After enabling the Customer Notification feature or changing the reminder timer setting, ensure notification emails are scheduled for subscriptions with pending cancellation status. * Update - Include subscription items table in all customer notification emails. * Update - Subscription notes for unsent customer notification emails now only occurs if WCS_DEBUG is enabled. +* Update - Improved performance of Subscriptions-related aspects of the WooCommerce System Status Report. * Dev - Introduces a new `woocommerce_subscription_valid_customer_notification_types` filter to modify which notification types are scheduled in Action Scheduler. = 7.9.0 - 2025-01-10 = diff --git a/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-related-order-store.php b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-related-order-store.php index b9618c2..5824dac 100644 --- a/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-related-order-store.php +++ b/vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-related-order-store.php @@ -148,4 +148,22 @@ abstract class WCS_Related_Order_Store { throw new InvalidArgumentException( sprintf( __( 'Invalid relation type: %1$s. Order relationship type must be one of: %2$s.', 'woocommerce-subscriptions' ), $relation_type, implode( ', ', $this->get_relation_types() ) ) ); } } + + /** + * Get related order IDs grouped by relation type. + * + * @param WC_Order $subscription The subscription to find related orders. + * @param array $relation_type An array of relation types to fetch. Must be an array containing 'renewal', 'switch' or 'resubscribe' unless custom relationships are implemented. + * + * @return array An associative array where keys are relation types and values are arrays of related order IDs. + */ + public function get_related_order_ids_by_types( WC_Order $subscription, $relation_types ) { + $related_orders = []; + + foreach ( $relation_types as $relation_type ) { + $related_orders[ $relation_type ] = $this->get_related_order_ids( $subscription, $relation_type ); + } + + return $related_orders; + } } diff --git a/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php index 0a29754..9b02dbc 100644 --- a/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php +++ b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php @@ -684,43 +684,41 @@ class WCS_Admin_Post_Types { * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.0 */ public static function get_date_column_content( $subscription, $column ) { + $date_type_map = array( 'last_payment_date' => 'last_order_date_created' ); + $date_type = array_key_exists( $column, $date_type_map ) ? $date_type_map[ $column ] : $column; + $date_timestamp = $subscription->get_time( $date_type ); - $date_type_map = array( 'last_payment_date' => 'last_order_date_created' ); - $date_type = array_key_exists( $column, $date_type_map ) ? $date_type_map[ $column ] : $column; - $datetime = wcs_get_datetime_from( $subscription->get_time( $date_type ) ); + if ( 0 === $date_timestamp ) { + return '-'; + } - if ( 0 == $subscription->get_time( $date_type, 'gmt' ) ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison - $column_content = '-'; - } else { - $accurate_date = $datetime->date_i18n( __( 'Y/m/d g:i:s A', 'woocommerce-subscriptions' ) ); - $fuzzy_human_date = $subscription->get_date_to_display( $date_type ); - $column_content = sprintf( - '', - esc_attr( $column ), - esc_attr( $accurate_date ), - esc_html( $fuzzy_human_date ) - ); + $datetime = wcs_get_datetime_from( $date_timestamp ); + $accurate_date = $datetime->date_i18n( __( 'Y/m/d g:i:s A', 'woocommerce-subscriptions' ) ); + $fuzzy_human_date = $subscription->format_date_to_display( $date_timestamp, $date_type ); + $column_content = sprintf( + '', + esc_attr( $column ), + esc_attr( $accurate_date ), + esc_html( $fuzzy_human_date ) + ); - // Custom handling for `Next payment` date column. - if ( 'next_payment_date' === $column ) { - $subscription_is_active = $subscription->has_status( 'active' ); + // Custom handling for `Next payment` date column. + if ( 'next_payment_date' === $column && $subscription->has_status( 'active' ) ) { + $tooltip_message = ''; + $tooltip_classes = 'woocommerce-help-tip'; - $tooltip_message = ''; - $tooltip_classes = 'woocommerce-help-tip'; + if ( $datetime->getTimestamp() < time() ) { + $tooltip_message .= __( 'Subscription payment overdue.
', 'woocommerce-subscriptions' ); + $tooltip_classes .= ' wcs-payment-overdue'; + } - if ( $subscription_is_active && $datetime->getTimestamp() < time() ) { - $tooltip_message .= __( 'Subscription payment overdue.
', 'woocommerce-subscriptions' ); - $tooltip_classes .= ' wcs-payment-overdue'; - } + if ( $subscription->payment_method_supports( 'gateway_scheduled_payments' ) && ! $subscription->is_manual() ) { + $tooltip_message .= __( 'This date should be treated as an estimate only. The payment gateway for this subscription controls when payments are processed.
', 'woocommerce-subscriptions' ); + $tooltip_classes .= ' wcs-offsite-renewal'; + } - if ( $subscription->payment_method_supports( 'gateway_scheduled_payments' ) && ! $subscription->is_manual() && $subscription_is_active ) { - $tooltip_message .= __( 'This date should be treated as an estimate only. The payment gateway for this subscription controls when payments are processed.
', 'woocommerce-subscriptions' ); - $tooltip_classes .= ' wcs-offsite-renewal'; - } - - if ( $tooltip_message ) { - $column_content .= '
'; - } + if ( $tooltip_message ) { + $column_content .= '
'; } } diff --git a/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php index 0adb756..1b031ca 100644 --- a/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php +++ b/vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-system-status.php @@ -16,6 +16,35 @@ class WCS_Admin_System_Status { */ const WCS_PRODUCT_ID = 27147; + /** + * Contains pre-determined SSR report data. + * + * @var array + */ + private static $report_data = []; + + /** + * Used to cache the result of the comparatively expensive queries executed by + * the get_subscriptions_by_gateway() method. + * + * This cache is short-lived by design, as we don't necessarily want to cache this + * across requests (in some troubleshooting/debug scenarios, that could be confusing + * for the troubleshooter), which is why a transient or WP caching functions are not + * used. + * + * @var null|array + */ + private static $statuses_by_gateway = null; + + /** + * Used to cache the subscriptions-by-status counts. + * + * As with with self::$statuses_by_gateway, the cache is deliberately short-lived. + * + * @var null|array + */ + private static $subscription_status_counts = null; + /** * Attach callbacks * @@ -28,9 +57,21 @@ class WCS_Admin_System_Status { /** * Renders the Subscription information in the WC status page * - * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.0 + * @since 1.0.0 Migrated from WooCommerce Subscriptions v2.3.0 + * @since 7.2.0 Uses supplied report data if available. + * + * @param mixed $report Pre-determined SSR report data. */ - public static function render_system_status_items() { + public static function render_system_status_items( $report = null ) { + /** + * From WooCommerce 9.8.0, we will be supplied with SSR data fetched via a (programmatic) + * REST API request. Using this when available can help prevent duplicated work. + * + * @see WC_REST_Subscription_System_Status_Manager::add_subscription_fields_to_response() + */ + if ( is_array( $report ) && is_array( $report['subscriptions'] ) && ! empty( $report['subscriptions'] ) ) { + self::$report_data = $report['subscriptions']; + } $store_data = []; $subscriptions_data = []; @@ -118,10 +159,15 @@ class WCS_Admin_System_Status { * @param array $debug_data */ private static function set_live_site_url( &$debug_data ) { + // Use pre-determined SSR data if possible. + $site_url = isset( self::$report_data['live_url'] ) + ? self::$report_data['live_url'] + : WCS_Staging::get_site_url_from_source( 'subscriptions_install' ); + $debug_data['wcs_live_site_url'] = array( 'name' => _x( 'Subscriptions Live URL', 'Live URL, Label on WooCommerce -> System Status page', 'woocommerce-subscriptions' ), 'label' => 'Subscriptions Live URL', - 'note' => '
' . esc_html( WCS_Staging::get_site_url_from_source( 'subscriptions_install' ) ) . '', + 'note' => '' . esc_html( $site_url ) . '', 'mark' => '', 'mark_icon' => '', ); @@ -222,7 +268,6 @@ class WCS_Admin_System_Status { * Add a breakdown of Subscriptions per status. */ private static function set_subscription_statuses( &$debug_data ) { - $debug_data['wcs_subscriptions_by_status'] = array( 'name' => _x( 'Subscription Statuses', 'label for the system status page', 'woocommerce-subscriptions' ), 'label' => 'Subscription Statuses', @@ -281,7 +326,11 @@ class WCS_Admin_System_Status { private static function set_subscriptions_by_payment_gateway( &$debug_data ) { $gateways = WC()->payment_gateways->get_available_payment_gateways(); - foreach ( self::get_subscriptions_by_gateway() as $payment_method => $status_counts ) { + $subscriptions_by_gateway = isset( self::$report_data['subscriptions_by_payment_gateway'] ) + ? self::$report_data['subscriptions_by_payment_gateway'] + : self::get_subscriptions_by_gateway(); + + foreach ( $subscriptions_by_gateway as $payment_method => $status_counts ) { if ( isset( $gateways[ $payment_method ] ) ) { $payment_method_name = $gateways[ $payment_method ]->method_title; $payment_method_label = $gateways[ $payment_method ]->method_title; @@ -361,10 +410,17 @@ class WCS_Admin_System_Status { /** * Gets the store's subscription broken down by payment gateway and status. * - * @since 1.0.0 - Migrated from WooCommerce Subscriptions v3.1.0 + * @since 1.0.0 Migrated from WooCommerce Subscriptions v3.1.0. + * @since 7.2.0 Information is cached per request. + * * @return array The subscription gateway and status data array( 'gateway_id' => array( 'status' => count ) ); */ public static function get_subscriptions_by_gateway() { + // Return cached result if possible. + if ( isset( self::$statuses_by_gateway ) ) { + return self::$statuses_by_gateway; + } + global $wpdb; $subscription_gateway_data = []; $is_hpos_in_use = wcs_is_custom_order_tables_usage_enabled(); @@ -408,6 +464,7 @@ class WCS_Admin_System_Status { $subscription_gateway_data[ $result['payment_method'] ][ $result[ $order_status_column_name ] ] = $result['count']; } + self::$statuses_by_gateway = $subscription_gateway_data; return $subscription_gateway_data; } @@ -418,7 +475,9 @@ class WCS_Admin_System_Status { * @return array */ public static function get_subscription_statuses() { - $subscriptions_by_status = WC_Data_Store::load( 'subscription' )->get_subscriptions_count_by_status(); + // We don't look inside self::$report_data here, because the REST API report itself + // also uses self::get_subscription_status_counts(). + $subscriptions_by_status = self::get_subscription_status_counts(); $subscriptions_by_status_output = array(); foreach ( $subscriptions_by_status as $status => $count ) { @@ -429,4 +488,36 @@ class WCS_Admin_System_Status { return $subscriptions_by_status_output; } + + /** + * Returns a cached array of subscription statuses along with the corresponding number + * of subscriptions for each (the values). + * + * Example: + * + * [ + * 'wc-active' => 100, + * 'wc-cancelled' => 200, + * '...' => 300, + * ] + * + * @param bool $fresh If cached results should be discarded. + * + * @return array + */ + public static function get_subscription_status_counts( bool $fresh = false ): array { + // Return cached result if possible. + if ( ! $fresh && isset( self::$subscription_status_counts ) ) { + return self::$subscription_status_counts; + } + + try { + self::$subscription_status_counts = WC_Data_Store::load( 'subscription' )->get_subscriptions_count_by_status(); + } catch ( Exception $e ) { + // If an exception was raised, don't cache the result. + return []; + } + + return self::$subscription_status_counts; + } } diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php index 7060524..eb1b0b2 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php @@ -1295,18 +1295,29 @@ class WC_Subscription extends WC_Order { * @param string $date_type 'date_created', 'trial_end', 'next_payment', 'last_order_date_created', 'end' or 'end_of_prepaid_term' */ public function get_date_to_display( $date_type = 'next_payment' ) { - - $date_type = wcs_normalise_date_type_key( $date_type, true ); - + $date_type = wcs_normalise_date_type_key( $date_type, true ); $timestamp_gmt = $this->get_time( $date_type, 'gmt' ); + return $this->format_date_to_display( $timestamp_gmt, $date_type ); + } + + /** + * Formats a subscription date timestamp for display. + * + * @param int $timestamp The subscription date in a timestamp format. + * @param string $date_type The subscription date type to display. @see WC_Subscription::get_valid_date_types() + * + * @return string The formatted date to display. + */ + public function format_date_to_display( $timestamp_gmt, $date_type ) { + $date_type = wcs_normalise_date_type_key( $date_type, true ); + // Don't display next payment date when the subscription is inactive - if ( 'next_payment' == $date_type && ! $this->has_status( 'active' ) ) { + if ( 'next_payment' === $date_type && ! $this->has_status( 'active' ) ) { $timestamp_gmt = 0; } if ( $timestamp_gmt > 0 ) { - $time_diff = $timestamp_gmt - current_time( 'timestamp', true ); if ( $time_diff > 0 && $time_diff < WEEK_IN_SECONDS ) { @@ -1316,7 +1327,7 @@ class WC_Subscription extends WC_Order { // translators: placeholder is human time diff (e.g. "3 weeks") $date_to_display = sprintf( __( '%s ago', 'woocommerce-subscriptions' ), human_time_diff( current_time( 'timestamp', true ), $timestamp_gmt ) ); } else { - $date_to_display = date_i18n( wc_date_format(), $this->get_time( $date_type, 'site' ) ); + $date_to_display = date_i18n( wc_date_format(), $timestamp_gmt + wc_timezone_offset() ); } } else { switch ( $date_type ) { @@ -2074,25 +2085,31 @@ class WC_Subscription extends WC_Order { * @return array */ public function get_related_orders( $return_fields = 'ids', $order_types = array( 'parent', 'renewal', 'switch' ) ) { - - $return_fields = ( 'ids' == $return_fields ) ? $return_fields : 'all'; + $return_fields = ( 'ids' === $return_fields ) ? $return_fields : 'all'; + $related_orders = []; if ( 'all' === $order_types ) { wcs_deprecated_argument( __METHOD__, '2.3.0', sprintf( __( '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.', 'woocommerce-subscriptions' ), __CLASS__ ) ); $order_types = array( 'parent', 'renewal', 'switch' ); } elseif ( ! is_array( $order_types ) ) { - // Accept either an array or string (to make it more convenient for singular types, like 'parent' or 'any') + // Accept either an array or string (to make it more convenient for singular types, like 'parent' or 'any'). $order_types = array( $order_types ); } - $related_orders = array(); - foreach ( $order_types as $order_type ) { - $related_orders_for_order_type = array(); - foreach ( $this->get_related_order_ids( $order_type ) as $order_id ) { - if ( 'all' === $return_fields && $order = wc_get_order( $order_id ) ) { - $related_orders_for_order_type[ $order_id ] = $order; - } elseif ( 'ids' === $return_fields ) { + foreach ( $this->get_related_order_ids( $order_types, 'grouped' ) as $order_type => $order_ids ) { + $related_orders_for_order_type = []; + + foreach ( $order_ids as $order_id ) { + if ( 'ids' === $return_fields ) { $related_orders_for_order_type[ $order_id ] = $order_id; + continue; + } + + // Handle the "all" return type by fetching the order object. + $order = wc_get_order( $order_id ); + + if ( $order ) { + $related_orders_for_order_type[ $order_id ] = $order; } } @@ -2107,25 +2124,42 @@ class WC_Subscription extends WC_Order { /** * Get the related order IDs for a subscription based on an order type. * - * @param string $order_type Can include 'any', 'parent', 'renewal', 'resubscribe' and/or 'switch'. Defaults to 'any'. - * @return array List of related order IDs. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.0 + * @since 7.2.1 - The $order_type parameter can now be an array of order types and the $return_type parameter was added. + * + * @param string|array $order_type Can include 'any', 'parent', 'renewal', 'resubscribe' and/or 'switch'. Defaults to 'any'. + * @param string $return_type The format to return the related order IDs in. Can be 'flat' or 'grouped'. Defaults to 'flat'. + * + * @return array List of related order IDs. */ - protected function get_related_order_ids( $order_type = 'any' ) { + protected function get_related_order_ids( $order_type = 'any', $return_type = 'flat' ) { + $order_types = is_array( $order_type ) ? $order_type : [ $order_type ]; + $related_order_ids = []; - $related_order_ids = array(); - - if ( in_array( $order_type, array( 'any', 'parent' ) ) && $this->get_parent_id() ) { - $related_order_ids[ $this->get_parent_id() ] = $this->get_parent_id(); + // For backwards compatibility, replace 'any' with the actual order types. + if ( in_array( 'any', $order_types, true ) ) { + $order_types = array_diff( $order_types, [ 'any' ] ); // Remove 'any'. + $order_types = array_unique( array_merge( $order_types, [ 'parent', 'renewal', 'resubscribe', 'switch' ] ) ); // Add the 'any' order types. } - if ( 'parent' !== $order_type ) { + // Get the parent order ID first. + if ( in_array( 'parent', $order_types, true ) ) { + // Remove the parent order type from the list of order types. + $order_types = array_diff( $order_types, [ 'parent' ] ); + $parent_id = $this->get_parent_id(); - $relation_types = ( 'any' === $order_type ) ? array( 'renewal', 'resubscribe', 'switch' ) : array( $order_type ); + // Because the call requested the parent order, if there is no parent ID, we need to return an empty array. + $related_order_ids['parent'] = $parent_id ? [ $parent_id ] : []; + } - foreach ( $relation_types as $relation_type ) { - $related_order_ids = array_merge( $related_order_ids, WCS_Related_Order_Store::instance()->get_related_order_ids( $this, $relation_type ) ); - } + if ( ! empty( $order_types ) ) { + // Get the related order IDs based on the remaining order types. + $related_order_ids += WCS_Related_Order_Store::instance()->get_related_order_ids_by_types( $this, $order_types ); + } + + if ( 'flat' === $return_type && ! empty( $related_order_ids ) ) { + // Flatten the grouped order IDs into a single array. + $related_order_ids = array_merge( ...array_values( $related_order_ids ) ); } return $related_order_ids; diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php index 9329303..c623c0a 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php @@ -368,7 +368,6 @@ class WC_Subscriptions_Cart { } $recurring_cart->fee_total = 0; - self::maybe_restore_shipping_methods(); $recurring_cart->calculate_totals(); // Store this groups cart details @@ -385,9 +384,6 @@ class WC_Subscriptions_Cart { // Reset flags when we're done processing recurring carts. self::$calculation_type = self::$recurring_cart_key = 'none'; - // We need to reset the packages and totals stored in WC()->shipping too - self::maybe_restore_shipping_methods(); - // Only calculate the initial order cart shipping if we need to show shipping. if ( WC()->cart->show_shipping() ) { WC()->cart->calculate_shipping(); @@ -954,68 +950,6 @@ class WC_Subscriptions_Cart { return $needs_payment; } - /** - * Restore shipping method, as well as cost and tax estimate when on the cart page. - * - * The WC_Shortcode_Cart actually calculates shipping when the "Calculate Shipping" form is submitted on the - * cart page. Because of that, our own @see self::calculate_totals() method calculates incorrect values on - * the cart page because it triggers the method multiple times for multiple different pricing structures. - * This uses the same logic found in WC_Shortcode_Cart::output() to determine the correct estimate. - * - * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.4.10 - */ - private static function maybe_restore_shipping_methods() { - WC()->shipping->reset_shipping(); - - if ( ! empty( $_POST['calc_shipping'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-cart' ) && function_exists( 'WC' ) ) { - - try { - $country = wc_clean( $_POST['calc_shipping_country'] ); - $state = isset( $_POST['calc_shipping_state'] ) ? wc_clean( $_POST['calc_shipping_state'] ) : ''; - $postcode = apply_filters( 'woocommerce_shipping_calculator_enable_postcode', true ) ? wc_clean( $_POST['calc_shipping_postcode'] ) : ''; - $city = apply_filters( 'woocommerce_shipping_calculator_enable_city', false ) ? wc_clean( $_POST['calc_shipping_city'] ) : ''; - - if ( $postcode && ! WC_Validation::is_postcode( $postcode, $country ) ) { - throw new Exception( __( 'Please enter a valid postcode/ZIP.', 'woocommerce-subscriptions' ) ); - } elseif ( $postcode ) { - $postcode = wc_format_postcode( $postcode, $country ); - } - - if ( $country ) { - WC()->customer->set_location( $country, $state, $postcode, $city ); - WC()->customer->set_shipping_location( $country, $state, $postcode, $city ); - } else { - WC()->customer->set_to_base(); - WC()->customer->set_shipping_to_base(); - } - - WC()->customer->calculated_shipping( true ); - - do_action( 'woocommerce_calculated_shipping' ); - - } catch ( Exception $e ) { - if ( ! empty( $e ) ) { - wc_add_notice( $e->getMessage(), 'error' ); - } - } - } - - // If we had one time shipping in the carts, we may have wiped the WC chosen shippings. Restore them. - self::maybe_restore_chosen_shipping_method(); - - if ( isset( $_POST['shipping_method'] ) && is_array( $_POST['shipping_method'] ) ) { - - // Now make sure the correct shipping method is set - $chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods', array() ); - - foreach ( $_POST['shipping_method'] as $i => $value ) { - $chosen_shipping_methods[ $i ] = wc_clean( $value ); - } - - WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods ); - } - } - /** * Make sure cart product prices correctly include/exclude taxes. * @@ -2353,8 +2287,11 @@ class WC_Subscriptions_Cart { * WC()->shipping->reset() on it, which will wipe the preferences saved. That can cause the chosen shipping method for the one * time shipping feature to be lost, and the first default to be applied instead. To counter that, we save the chosen shipping * method to a key that's not going to get wiped by WC's method, and then later restore it. + * + * @deprecated 7.3.0 - no longer in use internally */ public static function maybe_restore_chosen_shipping_method() { + wcs_deprecated_function( __METHOD__, '7.3.0', 'The use of this function is no longer recommended and will be removed in a future version.' ); $chosen_shipping_method_cache = WC()->session->get( 'wcs_shipping_methods', false ); if ( false !== $chosen_shipping_method_cache ) { diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php index 2ce4dba..038c746 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php @@ -16,7 +16,7 @@ class WC_Subscriptions_Core_Plugin { * The version of subscriptions-core library. * @var string */ - protected $library_version = '8.0.1'; // WRCS: DEFINED_VERSION. + protected $library_version = '8.1.0'; // WRCS: DEFINED_VERSION. /** * The subscription scheduler instance. diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php index 39f2af0..286e707 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email-notifications.php @@ -53,9 +53,6 @@ class WC_Subscriptions_Email_Notifications { // Add settings UI. add_filter( 'woocommerce_subscription_settings', [ __CLASS__, 'add_settings' ], 20 ); - // Add admin notice. - add_action( 'admin_notices', [ __CLASS__, 'maybe_add_admin_notice' ] ); - // Bump settings update time whenever related options change. add_action( 'update_option_' . WC_Subscriptions_Admin::$option_prefix . self::$offset_setting_string, [ __CLASS__, 'set_notification_settings_update_time' ], 10, 3 ); add_action( 'update_option_' . WC_Subscriptions_Admin::$option_prefix . self::$switch_setting_string, [ __CLASS__, 'set_notification_settings_update_time' ], 10, 3 ); @@ -307,58 +304,4 @@ class WC_Subscriptions_Email_Notifications { WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Admin::$option_prefix . '_miscellaneous', $notification_settings, 'multiple_settings', 'sectionend' ); return $settings; } - - /** - * Maybe add an admin notice to inform the store manager about the existance of the notifications feature. - */ - public static function maybe_add_admin_notice() { - - // If the notifications feature is enabled, don't show the notice. - if ( self::notifications_globally_enabled() ) { - return; - } - - // Prevent showing the notice on the Subscriptions settings page. - if ( isset( $_GET['page'], $_GET['tab'] ) && 'wc-settings' === $_GET['page'] && 'subscriptions' === $_GET['tab'] ) { - return; - } - - $option_name = 'wcs_hide_customer_notifications_notice'; - $nonce = '_wcsnonce'; - $action = 'wcs_hide_customer_notifications_notice_action'; - - // First, check if the notice is being dismissed. - $nonce_argument = sanitize_text_field( wp_unslash( $_GET[ $nonce ] ?? '' ) ); - if ( isset( $_GET[ $action ], $nonce_argument ) && wp_verify_nonce( $nonce_argument, $action ) ) { - update_option( $option_name, 'yes' ); - wp_safe_redirect( remove_query_arg( [ $action, $nonce ] ) ); - return; - } - - if ( 'yes' === get_option( $option_name ) ) { - return; - } - - $admin_notice = new WCS_Admin_Notice( 'notice', array(), wp_nonce_url( add_query_arg( $action, 'dismiss' ), $action, $nonce ) ); - $notice_title = __( 'WooCommerce Subscriptions: Introducing customer email notifications!', 'woocommerce-subscriptions' ); - $notice_content = __( 'You can now send email notifications for subscription renewals, expirations, and free trials. Go to the "Customer Notifications" settings section to configure when your customers receive these important updates.', 'woocommerce-subscriptions' ); - $html_content = sprintf( '

%1$s

%2$s

', $notice_title, $notice_content ); - $admin_notice->set_html_content( $html_content ); - $admin_notice->set_actions( - array( - array( - 'name' => __( 'Manage settings', 'woocommerce-subscriptions' ), - 'url' => admin_url( 'admin.php?page=wc-settings&tab=subscriptions' ), - 'class' => 'button button-primary', - ), - array( - 'name' => __( 'Learn more', 'woocommerce-subscriptions' ), - 'url' => 'https://woocommerce.com/document/subscriptions/subscriptions-notifications/', - 'class' => 'button', - ), - ) - ); - - $admin_notice->display(); - } } diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email.php index 03a8f9c..9b6dbb2 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email.php @@ -117,15 +117,12 @@ class WC_Subscriptions_Email { /** * Init the mailer and call for the cancelled email notification hook. * - * @param $subscription WC Subscription + * @param WC_Subscription $subscription The subscription being examined. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function send_cancelled_email( $subscription ) { WC()->mailer(); - - if ( $subscription->has_status( array( 'pending-cancel', 'cancelled' ) ) && 'true' !== $subscription->get_cancelled_email_sent() ) { - do_action( 'cancelled_subscription_notification', $subscription ); - } + do_action( 'cancelled_subscription_notification', $subscription ); } /** @@ -244,26 +241,24 @@ class WC_Subscriptions_Email { $order = wc_get_order( $order ); } - if ( is_a( $order, 'WC_Abstract_Order' ) ) { - $show_download_links_callback = ( isset( $args['show_download_links'] ) && $args['show_download_links'] ) ? '__return_true' : '__return_false'; - $show_purchase_note_callback = ( isset( $args['show_purchase_note'] ) && $args['show_purchase_note'] ) ? '__return_true' : '__return_false'; - - unset( $args['show_download_links'] ); - unset( $args['show_purchase_note'] ); - - add_filter( 'woocommerce_order_is_download_permitted', $show_download_links_callback ); - add_filter( 'woocommerce_order_is_paid', $show_purchase_note_callback ); - - if ( function_exists( 'wc_get_email_order_items' ) ) { // WC 3.0+ - $items_table = wc_get_email_order_items( $order, $args ); - } else { - $items_table = $order->email_order_items_table( $args ); - } - - remove_filter( 'woocommerce_order_is_download_permitted', $show_download_links_callback ); - remove_filter( 'woocommerce_order_is_paid', $show_purchase_note_callback ); + if ( ! is_a( $order, 'WC_Abstract_Order' ) ) { + return $items_table; } + $show_download_links_callback = ( isset( $args['show_download_links'] ) && $args['show_download_links'] ) ? '__return_true' : '__return_false'; + $show_purchase_note_callback = ( isset( $args['show_purchase_note'] ) && $args['show_purchase_note'] ) ? '__return_true' : '__return_false'; + + unset( $args['show_download_links'] ); + unset( $args['show_purchase_note'] ); + + add_filter( 'woocommerce_order_is_download_permitted', $show_download_links_callback ); + add_filter( 'woocommerce_order_is_paid', $show_purchase_note_callback ); + + $items_table = wc_get_email_order_items( $order, $args ); + + remove_filter( 'woocommerce_order_is_download_permitted', $show_download_links_callback ); + remove_filter( 'woocommerce_order_is_paid', $show_purchase_note_callback ); + return $items_table; } @@ -277,13 +272,14 @@ class WC_Subscriptions_Email { * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.1 */ public static function order_details( $order, $sent_to_admin = false, $plain_text = false, $email = '' ) { - - $order_items_table_args = array( + $email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' ); + $image_size = $email_improvements_enabled ? 48 : 32; // These image sizes are defaults for WC core emails. @see wc_get_email_order_items(). + $order_items_table_args = array( 'show_download_links' => ( $sent_to_admin ) ? false : $order->is_download_permitted(), 'show_sku' => $sent_to_admin, 'show_purchase_note' => ( $sent_to_admin ) ? false : $order->has_status( apply_filters( 'woocommerce_order_is_paid_statuses', array( 'processing', 'completed' ) ) ), - 'show_image' => '', - 'image_size' => '', + 'show_image' => $email_improvements_enabled, + 'image_size' => array( $image_size, $image_size ), 'plain_text' => $plain_text, ); diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php index e220d57..8bb97a3 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-order.php @@ -451,7 +451,7 @@ class WC_Subscriptions_Order { */ public static function add_contains_subscription_column_content_orders_table( string $column_name, WC_Order $order ) { if ( 'subscription_relationship' === $column_name ) { - self::render_contains_subscription_column_content( $order->get_id() ); + self::render_contains_subscription_column_content( $order ); } } @@ -2442,14 +2442,20 @@ class WC_Subscriptions_Order { * * @since 6.3.0 * - * @param integer $order_id The ID of the order in the current row. + * @param WC_Order $order The order in the current row. */ - private static function render_contains_subscription_column_content( int $order_id ) { - if ( wcs_order_contains_subscription( $order_id, 'renewal' ) ) { + private static function render_contains_subscription_column_content( $order ) { + $order = ! is_object( $order ) ? wc_get_order( $order ) : $order; + + if ( ! $order ) { + return; + } + + if ( wcs_order_contains_renewal( $order ) ) { echo ''; - } elseif ( wcs_order_contains_subscription( $order_id, 'resubscribe' ) ) { + } elseif ( wcs_order_contains_resubscribe( $order ) ) { echo ''; - } elseif ( wcs_order_contains_subscription( $order_id, 'parent' ) ) { + } elseif ( apply_filters( 'woocommerce_subscriptions_orders_list_render_parent_order_relation', false, $order ) && wcs_order_contains_parent( $order ) ) { echo ''; } else { echo ''; diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php index 6f2b62b..9359b03 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-renewal-order.php @@ -96,27 +96,9 @@ class WC_Subscriptions_Renewal_Order { $order_needed_payment = in_array( $orders_old_status, apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'on-hold', 'failed' ), $order ) ); if ( $order_completed && $order_needed_payment ) { - - if ( wcs_is_woocommerce_pre( '3.0' ) ) { - $update_post_data = array( - 'ID' => $order_id, - 'post_date' => current_time( 'mysql', 0 ), - 'post_date_gmt' => current_time( 'mysql', 1 ), - ); - - wp_update_post( $update_post_data ); - update_post_meta( $order_id, '_paid_date', current_time( 'mysql' ) ); - } else { - - $current_time = current_time( 'timestamp', 1 ); - - // Prior to WC 3.0, we need to update the post date (i.e. the date created) to have a reliable representation of the paid date (both because it was in GMT and because it was always set). That's not needed in WC 3.0, but some plugins and store owners still rely on it being updated, so we want to make it possible to update it with 3.0 also. - if ( apply_filters( 'wcs_renewal_order_payment_update_date_created', false, $order, $subscriptions ) ) { - $order->set_date_created( $current_time ); - } - - // In WC 3.0, only the paid date prop represents the paid date, the post date isn't used anymore, also the paid date is stored and referenced as a MySQL date string in site timezone and a GMT timestamp - $order->set_date_paid( $current_time ); + // Prior to WC 3.0, we need to update the post date (i.e. the date created) to have a reliable representation of the paid date (both because it was in GMT and because it was always set). That's not needed in WC 3.0, but some plugins and store owners still rely on it being updated, so we want to make it possible to update it with 3.0 also. + if ( apply_filters( 'wcs_renewal_order_payment_update_date_created', false, $order, $subscriptions ) ) { + $order->set_date_created( time() ); $order->save(); } } diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php index c311eb2..0bfb8f7 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-cart-renewal.php @@ -113,6 +113,7 @@ class WCS_Cart_Renewal { // Make sure renewal meta data persists between sessions add_filter( 'woocommerce_get_cart_item_from_session', array( &$this, 'get_cart_item_from_session' ), 10, 3 ); add_action( 'woocommerce_cart_loaded_from_session', array( &$this, 'cart_items_loaded_from_session' ), 10 ); + add_action( 'woocommerce_cart_loaded_from_session', array( $this, 'restore_order_awaiting_payment' ), 10 ); // Make sure fees are added to the cart add_action( 'woocommerce_cart_calculate_fees', array( &$this, 'maybe_add_fees' ), 10, 1 ); @@ -248,14 +249,28 @@ class WCS_Cart_Renewal { * @internal Core checkout uses order_awaiting_payment, Blocks checkout uses store_api_draft_order. Both validate the * cart hash to ensure the order matches the cart. * - * @param int $order_id The order ID that is awaiting payment, or 0 to unset it. + * @param int|WC_Order $order_id The order that is awaiting payment, or 0 to unset it. */ protected function set_order_awaiting_payment( $order_id ) { + $order = null; + + if ( is_a( $order_id, 'WC_Abstract_Order' ) ) { + $order = $order_id; + $order_id = $order->get_id(); + } elseif ( ! empty( $order_id ) ) { + $order = wc_get_order( $order_id ); + } + + // Only ever set the order awaiting payment to 0 or an Order ID - not a subscription. + if ( $order && ! wcs_is_order( $order ) ) { + return; + } + WC()->session->set( 'order_awaiting_payment', $order_id ); WC()->session->set( 'store_api_draft_order', $order_id ); if ( $order_id ) { - $this->set_cart_hash( $order_id ); + $this->set_cart_hash( $order ); } } @@ -1654,6 +1669,40 @@ class WCS_Cart_Renewal { return $has_status; } + /** + * Restores the order awaiting payment session args if the cart contains a subscription-related order. + * + * It's possible the that order_awaiting_payment and store_api_draft_order session args are not set if those session args are lost due + * to session destruction. + * + * This function checks the cart that is being loaded from the session and if the cart contains a subscription-related order and if the + * current user has permission to pay for it. If so, it restores the order awaiting payment session args. + * + * @param WC_Cart $cart The cart object. + */ + public function restore_order_awaiting_payment( $cart ) { + if ( ! is_a( $cart, WC_Cart::class ) ) { + return; + } + + foreach ( $cart->get_cart() as $cart_item ) { + $order = $this->get_order( $cart_item ); + + if ( ! $order ) { + continue; + } + + // If the current user has permission to pay for the order, restore the order awaiting payment session arg. + if ( wcs_is_order( $order ) && $this->validate_current_user( $order ) ) { + $this->set_order_awaiting_payment( $order ); + } + + // Once we found an order, exit even if the user doesn't have permission to pay for it. + return; + + } + } + /* Deprecated */ /** diff --git a/vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-orders-table-subscription-data-store.php b/vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-orders-table-subscription-data-store.php index f0edd69..a5915ee 100644 --- a/vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-orders-table-subscription-data-store.php +++ b/vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-orders-table-subscription-data-store.php @@ -872,6 +872,11 @@ class WCS_Orders_Table_Subscription_Data_Store extends \Automattic\WooCommerce\I global $wpdb; $wpdb->delete( self::get_meta_table_name(), [ 'meta_key' => $meta_key ], [ '%s' ] ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key + + // If custom order tables is enabled and data syncing is enabled, delete the meta from the custom order tables. + if ( wcs_is_custom_order_tables_usage_enabled() && wcs_is_custom_order_tables_data_sync_enabled() ) { + $this->get_cpt_data_store_instance()->delete_all_metadata_by_key( $meta_key ); + } } /** diff --git a/vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php b/vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php index dd994ef..e9bcd39 100644 --- a/vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php +++ b/vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-related-order-store-cached-cpt.php @@ -46,6 +46,22 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp */ private static $override_ignored_props = false; + /** + * A list of subscription IDs that are requesting multiple related order caches to be read. + * + * This is used by @see get_related_order_ids_by_types() to enable fetching multiple related order caches without reading the subscriptions meta query multiple times. + * + * @var array $batch_processing_subscriptions An array of subscription IDs. + */ + private static $batch_processing_related_orders = []; + + /** + * A cache of subscription meta data. Used when fetching multiple related order caches for a subscription to avoid multiple database queries. + * + * @var array $subscription_meta_cache An array of subscription meta data. + */ + private static $subscription_meta_cache = []; + /** * Constructor */ @@ -290,7 +306,7 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp } } - $subscription_data_store = WC_Data_Store::load( 'subscription' ); + $subscription_data_store = $subscription->get_data_store(); $current_metadata = $this->get_related_order_metadata( $subscription, $relation_type ); $new_metadata = array( 'key' => $this->get_cache_meta_key( $relation_type ), @@ -302,16 +318,24 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp $this->update_modified_date_for_related_order_cache( $subscription, $related_order_ids, $current_metadata ); } - // Check if HPOS and data syncing is enabled then manually backfill the related orders cache values to WP Posts table. - $this->maybe_backfill_related_order_cache( $subscription, $relation_type, $new_metadata ); - // If there is metadata for this key, update it, otherwise add it. if ( $current_metadata ) { $new_metadata['id'] = $current_metadata->meta_id; - return $subscription_data_store->update_meta( $subscription, (object) $new_metadata ); + $return = $subscription_data_store->update_meta( $subscription, (object) $new_metadata ); } else { - return $subscription_data_store->add_meta( $subscription, (object) $new_metadata ); + $return = $subscription_data_store->add_meta( $subscription, (object) $new_metadata ); } + + /** + * Trigger update actions after modifying the subscription's related order cache metadata. + * + * This ensures that functions fired after a subscription update, such as webhooks and those in the DataSynchronizer, + * which sync CPT post data to HPOS tables, are executed. + */ + do_action( 'woocommerce_update_order', $subscription->get_id(), $subscription ); + do_action( 'woocommerce_update_subscription', $subscription->get_id(), $subscription ); + + return $return; } /** @@ -328,8 +352,12 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp * @param WC_Subscription $subscription The subscription object to backfill. * @param string $relation_type The related order relationship type. Can be 'renewal', 'switch' or 'resubscribe'. * @param array $metadata The metadata to set update/add in the CPT data store. Should be an array with 'key' and 'value' keys. + * + * @deprecated 7.3.0 - Backfilling is already handled by the Order/Subscriptions Data Store. */ protected function maybe_backfill_related_order_cache( $subscription, $relation_type, $metadata ) { + wcs_deprecated_function( __METHOD__, '7.3.0' ); + if ( ! wcs_is_custom_order_tables_usage_enabled() || ! wcs_is_custom_order_tables_data_sync_enabled() || empty( $metadata['key'] ) ) { return; } @@ -373,7 +401,7 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp $metadata = $this->get_related_order_metadata( $subscription, $possible_relation_type ); if ( $metadata ) { - WC_Data_Store::load( 'subscription' )->delete_meta( $subscription, (object) [ 'id' => $metadata->meta_id ] ); + $subscription->get_data_store()->delete_meta( $subscription, (object) [ 'id' => $metadata->meta_id ] ); } } } @@ -539,7 +567,7 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp $ids = wcs_get_orders_with_meta_query( [ 'limit' => $limit, - 'fields' => 'ids', + 'return' => 'ids', 'orderby' => 'ID', 'order' => 'ASC', 'type' => 'shop_subscription', @@ -617,12 +645,11 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp public function update_items_cache( $subscription_id ) { $subscription = wcs_get_subscription( $subscription_id ); - if ( $subscription ) { - foreach ( $this->get_relation_types() as $relation_type ) { - // Getting the related IDs also sets the cache when it's not already set - $this->get_related_order_ids( $subscription, $relation_type ); - } + if ( ! $subscription ) { + return; } + + $this->get_related_order_ids_by_types( $subscription, $this->get_relation_types() ); } /** @@ -643,22 +670,9 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp */ protected function get_related_order_metadata( WC_Subscription $subscription, $relation_type, $data_store = null ) { $cache_meta_key = $this->get_cache_meta_key( $relation_type ); - $data_store = empty( $data_store ) ? WC_Data_Store::load( 'subscription' ) : $data_store; + $data_store = $data_store ?? $subscription->get_data_store(); - /** - * Bypass the related order cache keys being ignored when fetching subscription meta. - * - * By default the related order cache keys are ignored via $this->add_related_order_cache_props(). In order to fetch the subscription's - * meta with those keys, we need to bypass that function. - * - * We use a static variable because it is possible to have multiple instances of this class in memory, and we want to make sure we bypass - * the function in all instances. - */ - self::$override_ignored_props = true; - $subscription_meta = $data_store->read_meta( $subscription ); - self::$override_ignored_props = false; - - foreach ( $subscription_meta as $meta ) { + foreach ( $this->get_subscription_meta( $subscription, $data_store ) as $meta ) { if ( isset( $meta->meta_key ) && $cache_meta_key === $meta->meta_key ) { return $meta; } @@ -690,4 +704,124 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp $subscription->save(); } } + + /** + * Gets the subscription's meta data. + * + * @param WC_Subscription $subscription The subscription to get the meta for. + * @param mixed $data_store The data store to use to get the meta. Defaults to the current subscription's data store. + * + * @return array The subscription's meta data. + */ + private function get_subscription_meta( WC_Subscription $subscription, $data_store ) { + $subscription_id = $subscription->get_id(); + $cache_key = $this->get_batch_processing_cache_key( $subscription, $data_store ); + $is_batch_processing = $this->is_batch_processing( $cache_key ); + + // If we are in batch processing mode, and there are cached results return the cached meta data. + if ( $is_batch_processing && isset( self::$subscription_meta_cache[ $cache_key ] ) ) { + return self::$subscription_meta_cache[ $cache_key ]; + } + + /** + * Bypass the related order cache keys being ignored when fetching subscription meta. + * + * By default the related order cache keys are ignored via $this->add_related_order_cache_props(). In order to fetch the subscription's + * meta with those keys, we need to bypass that function. + * + * We use a static variable because it is possible to have multiple instances of this class in memory, and we want to make sure we bypass + * the function in all instances. + */ + self::$override_ignored_props = true; + $subscription_meta = $data_store->read_meta( $subscription ); + self::$override_ignored_props = false; + + // If we are in batch processing mode, cache the meta data so it can be returned for subsequent calls. + if ( $is_batch_processing ) { + self::$subscription_meta_cache[ $cache_key ] = $subscription_meta; + } + + return $subscription_meta; + } + + /** + * Gets the related order IDs for a subscription by multiple relation types. + * + * This function is a more efficient way to get related order IDs for multiple relation types at once. + * It will only query the database once for all cache data, and then return the related order IDs for each relation type. + * + * The alternative of calling the get_related_order_ids() function for each relation type will result in a full subscription meta read for each relation type. + * + * @param WC_Order $subscription The subscription to get related order IDs for. + * @param array $related_order_types The related order types to get IDs for. Must be an array of supported relation types. + * + * @return array An array of related order IDs for each relation type. + */ + public function get_related_order_ids_by_types( WC_Order $subscription, $related_order_types ) { + $subscription_id = $subscription->get_id(); + $related_order_ids = []; + + // Declare batch processing mode for this subscription. + $cache_key = $this->start_batch_processing_mode( $subscription ); + + foreach ( $related_order_types as $relation_type ) { + $related_order_ids[ $relation_type ] = $this->get_related_order_ids( $subscription, $relation_type ); + } + + $this->stop_batch_processing_mode( $cache_key ); + + return $related_order_ids; + } + + /** + * Starts batch processing mode for a subscription. + * + * @param WC_Subscription $subscription The subscription to start batch processing mode for. + * @return string The cache key for the subscription. + */ + private function start_batch_processing_mode( $subscription ) { + $cache_key = $this->get_batch_processing_cache_key( $subscription ); + + self::$batch_processing_related_orders[ $cache_key ] = true; + return $cache_key; + } + + /** + * Stops batch processing mode for a subscription. + * + * Destroys the cache and removes the cache key. + * + * @param string $cache_key The batch processing cache key. + */ + private function stop_batch_processing_mode( $cache_key ) { + unset( self::$batch_processing_related_orders[ $cache_key ] ); + unset( self::$subscription_meta_cache[ $cache_key ] ); + } + + /** + * Checks if batch processing mode is active for a subscription. + * + * @param string $cache_key The batch processing cache key. + * @return bool True if batch processing mode is active, false otherwise. + */ + private function is_batch_processing( $cache_key ) { + return isset( self::$batch_processing_related_orders[ $cache_key ] ); + } + + /** + * Gets the batch processing cache key for a subscription. + * + * The cache key is a unique combination of the subscription ID and the data store class name. + * + * @param WC_Subscription $subscription The subscription to get the cache key for. + * @param bool|object $data_store The data store which will be used to read the subscription meta. Defaults to the current subscription's data store. + * + * @return string The cache key for the subscription. + */ + private function get_batch_processing_cache_key( $subscription, $data_store = null ) { + // If no data store is provided, use the subscription object's data store or load the default data store if no subscription data store is found. + $data_store = $data_store ?? $subscription->get_data_store() ?? WC_Data_Store::load( 'subscriptions' ); + $data_store_class = is_a( $data_store, 'WC_Data_Store' ) ? $data_store->get_current_class_name() : ''; + return $data_store_class . '-' . $subscription->get_id(); + } } diff --git a/vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php b/vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php index cd65a37..017b585 100644 --- a/vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php +++ b/vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php @@ -77,6 +77,13 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements '_subscription_switch_order_ids_cache' => 'switch_order_ids_cache', ); + /** + * The data store instance for the custom order tables. + * + * @var WCS_Orders_Table_Subscription_Data_Store + */ + protected $orders_table_data_store; + /** * Constructor. */ @@ -535,12 +542,16 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements $subscription_ids = array(); - $search_fields = array_map( 'wc_clean', apply_filters( 'woocommerce_shop_subscription_search_fields', array( - '_order_key', - '_billing_address_index', - '_shipping_address_index', - '_billing_email', - ) ) ); + $search_fields = array_map( + 'wc_clean', + apply_filters( + 'woocommerce_shop_subscription_search_fields', + [ + '_billing_address_index', + '_shipping_address_index', + ] + ) + ); if ( is_numeric( $term ) ) { $subscription_ids[] = absint( $term ); @@ -611,6 +622,11 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements $meta_value = null; // Delete any values. $delete_all = true; delete_metadata( 'post', $id, $meta_key, $meta_value, $delete_all ); + + // If custom order tables is not enabled, but Data Syncing is enabled, delete the meta from the custom order tables. + if ( ! wcs_is_custom_order_tables_usage_enabled() && wcs_is_custom_order_tables_data_sync_enabled() ) { + $this->get_cot_data_store_instance()->delete_all_metadata_by_key( $meta_key ); + } } /** @@ -711,7 +727,10 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements */ 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 ); + + if ( '' !== $renewal_order_ids ) { + update_post_meta( $subscription->get_id(), '_subscription_renewal_order_ids_cache', $renewal_order_ids ); + } } /** @@ -725,7 +744,10 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements */ 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 ); + + if ( '' !== $resubscribe_order_ids ) { + update_post_meta( $subscription->get_id(), '_subscription_resubscribe_order_ids_cache', $resubscribe_order_ids ); + } } /** @@ -739,7 +761,10 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements */ 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 ); + + if ( '' !== $switch_order_ids ) { + update_post_meta( $subscription->get_id(), '_subscription_switch_order_ids_cache', $switch_order_ids ); + } } /** @@ -763,4 +788,17 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements delete_post_meta( $subscription->get_id(), "_subscription_{$relationship_type}_order_ids_cache" ); } } + + /** + * Get the data store instance for Order Tables data store. + * + * @return WCS_Orders_Table_Subscription_Data_Store + */ + public function get_cot_data_store_instance() { + if ( ! isset( $this->orders_table_data_store ) ) { + $this->orders_table_data_store = new WCS_Orders_Table_Subscription_Data_Store(); + } + + return $this->orders_table_data_store; + } } diff --git a/vendor/woocommerce/subscriptions-core/includes/emails/class-wc-subscriptions-email-preview.php b/vendor/woocommerce/subscriptions-core/includes/emails/class-wc-subscriptions-email-preview.php index 386bb62..0923f8c 100644 --- a/vendor/woocommerce/subscriptions-core/includes/emails/class-wc-subscriptions-email-preview.php +++ b/vendor/woocommerce/subscriptions-core/includes/emails/class-wc-subscriptions-email-preview.php @@ -49,8 +49,14 @@ class WC_Subscriptions_Email_Preview { case 'WCS_Email_Customer_Notification_Auto_Renewal': $email->set_object( $this->get_dummy_subscription() ); break; + case 'WCS_Email_Customer_Payment_Retry': + case 'WCS_Email_Payment_Retry': + $email->retry = $this->get_dummy_retry( $email->object ); + break; } + $this->add_placeholders( $email ); + add_filter( 'woocommerce_mail_content', [ $this, 'clean_up_filters' ] ); return $email; @@ -139,13 +145,55 @@ class WC_Subscriptions_Email_Preview { return apply_filters( 'woocommerce_subscriptions_email_preview_dummy_address', $address, $this->email_type ); } + /** + * Creates a dummy retry for use when previewing failed subscription payment retry emails. + * + * @param WC_Order $order The order object to create a dummy retry for. + * @return WCS_Retry The dummy retry object. + */ + private function get_dummy_retry( $order ) { + + if ( ! class_exists( 'WCS_Retry_Manager' ) ) { + return null; + } + + $order_id = is_a( $order, 'WC_Order' ) ? $order->get_id() : 12345; + $retry_rule = WCS_Retry_Manager::rules()->get_rule( 1, $order_id ); + + if ( is_a( $retry_rule, 'WCS_Retry_Rule' ) ) { + $interval = $retry_rule->get_retry_interval(); + $raw_retry_rule = $retry_rule->get_raw_data(); + } else { + // If the retry rule is not found, use a default interval of 12 hours and an empty raw rule. + $interval = 12 * HOUR_IN_SECONDS; + $raw_retry_rule = []; + } + + return new WCS_Retry( + [ + 'status' => 'pending', + 'order_id' => $order_id, + 'date_gmt' => gmdate( 'Y-m-d H:i:s', time() + $interval ), + 'rule_raw' => $raw_retry_rule, + ] + ); + } + /** * Check if the email being previewed is a subscription email. * - * @return bool + * Subscription emails include: + * - WC_Subscriptions_Email::$email_classes - core subscription emails. + * - WC_Subscriptions_Email_Notifications::$email_classes - subscription notification emails (pre-renewal emails). + * - WCS_Email_Customer_Payment_Retry - customer payment retry emails. + * - WCS_Email_Payment_Retry - admin payment retry emails. + * + * @return bool Whether the email being previewed is a subscription email. */ private function is_subscription_email() { - return isset( WC_Subscriptions_Email::$email_classes[ $this->email_type ] ) || isset( WC_Subscriptions_Email_Notifications::$email_classes[ $this->email_type ] ); + return isset( WC_Subscriptions_Email::$email_classes[ $this->email_type ] ) + || isset( WC_Subscriptions_Email_Notifications::$email_classes[ $this->email_type ] ) + || in_array( $this->email_type, [ 'WCS_Email_Customer_Payment_Retry', 'WCS_Email_Payment_Retry' ], true ); } /** @@ -204,4 +252,52 @@ class WC_Subscriptions_Email_Preview { return $can_renew_early; } + + /** + * Adds custom placeholders for subscription emails. + * + * @param WC_Email $email The email object. + */ + private function add_placeholders( $email ) { + if ( ! isset( $email->placeholders ) ) { + return; + } + + $placeholders = []; + + switch ( $this->email_type ) { + case 'WCS_Email_Customer_Notification_Subscription_Expiration': + case 'WCS_Email_Customer_Notification_Manual_Trial_Expiration': + case 'WCS_Email_Customer_Notification_Auto_Trial_Expiration': + case 'WCS_Email_Customer_Notification_Manual_Renewal': + case 'WCS_Email_Customer_Notification_Auto_Renewal': + // Pull the real values from the email object (Order or Subscription) if available. + if ( is_a( $email->object, 'WC_Subscription' ) ) { + $time_until_renewal = $email->get_time_until_date( $email->object, 'next_payment' ); + $customer_first_name = $email->object->get_billing_first_name(); + } else { + $time_until_renewal = human_time_diff( time(), time() + WEEK_IN_SECONDS ); + $customer_first_name = 'John'; + } + + $placeholders['{time_until_renewal}'] = $time_until_renewal; + $placeholders['{customers_first_name}'] = $customer_first_name; + break; + case 'WCS_Email_Customer_Payment_Retry': + case 'WCS_Email_Payment_Retry': + $retry_time = is_a( $email->retry, 'WCS_Retry' ) + ? $email->retry->get_time() + : time() + ( 12 * HOUR_IN_SECONDS ); + + $placeholders['{retry_time}'] = wcs_get_human_time_diff( $retry_time ); + break; + } + + // Merge placeholders without overriding existing ones, and only adding those in the email. + $email->placeholders = wp_parse_args( + $placeholders, + $email->placeholders + ); + } } + diff --git a/vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php b/vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php index c076933..985b361 100644 --- a/vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php +++ b/vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php @@ -37,6 +37,7 @@ class WCS_Email_Cancelled_Subscription extends WC_Email { add_action( 'cancelled_subscription_notification', array( $this, 'trigger' ) ); parent::__construct(); + $this->add_always_send_field(); $this->recipient = $this->get_option( 'recipient' ); @@ -45,6 +46,22 @@ class WCS_Email_Cancelled_Subscription extends WC_Email { } } + /** + * For the cancellation email, we add an extra setting to let the merchant decide if + * they should *always* received cancellation emails (the default being to send them + * only once, when they are first set to Pending Cancellation or Cancelled). + * + * @return void + */ + private function add_always_send_field() { + $this->form_fields['always_send'] = [ + 'title' => __( 'Always Send', 'woocommerce-subscriptions' ), + 'type' => 'checkbox', + 'label' => __( 'Send this email whenever a subscription is updated to "Pending Cancellation" or "Cancelled".', 'woocommerce-subscriptions' ), + 'default' => 'no', + ]; + } + /** * Get the default e-mail subject. * @@ -79,7 +96,13 @@ class WCS_Email_Cancelled_Subscription extends WC_Email { $subscription = wcs_get_subscription_from_key( $subscription ); } - if ( ! $this->is_enabled() || ! $this->get_recipient() ) { + if ( ! $this->is_enabled() || ! $this->get_recipient() || ! $subscription->has_status( array( 'pending-cancel', 'cancelled' ) ) ) { + return; + } + + // Unless the merchant has requested that these emails should always be sent, avoid sending them twice for the same subscription + // (which would otherwise happen once when the subscription is sent to 'pending-cancel', and again when it finally cancels). + if ( 'yes' !== $this->get_option( 'always_send' ) && 'true' === $subscription->get_cancelled_email_sent() ) { return; } diff --git a/vendor/woocommerce/subscriptions-core/includes/wcs-cart-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-cart-functions.php index 0f5dcca..2364232 100644 --- a/vendor/woocommerce/subscriptions-core/includes/wcs-cart-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-cart-functions.php @@ -108,7 +108,7 @@ function wcs_cart_totals_shipping_html() { - ' . esc_html( $package_details ) . '

'; ?> + ' . wp_kses_post( $package_details ) . '

'; ?> diff --git a/vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php index 15ff0b4..bbfabc1 100644 --- a/vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php @@ -68,21 +68,69 @@ function wcs_get_subscriptions_for_order( $order, $args = array() ) { $all_relation_types = WCS_Related_Order_Store::instance()->get_relation_types(); $relation_types = $get_all ? $all_relation_types : array_intersect( $all_relation_types, $args['order_type'] ); + $subscription_ids = wcs_get_subscription_ids_for_order( $order, $relation_types ); - foreach ( $relation_types as $relation_type ) { - - $subscription_ids = WCS_Related_Order_Store::instance()->get_related_subscription_ids( $order, $relation_type ); - - foreach ( $subscription_ids as $subscription_id ) { - if ( wcs_is_subscription( $subscription_id ) ) { - $subscriptions[ $subscription_id ] = wcs_get_subscription( $subscription_id ); - } + foreach ( $subscription_ids as $subscription_id ) { + if ( wcs_is_subscription( $subscription_id ) ) { + $subscriptions[ $subscription_id ] = wcs_get_subscription( $subscription_id ); } } return $subscriptions; } +/** + * Get the subscription IDs for an order. + * + * @param WC_Order $order The order to get the subscription IDs for. + * @param string|array $order_types The order types to get the subscription IDs for. Defaults to 'any' which will return all subscription IDs linked to the order. + * + * @return array The subscription IDs. + */ +function wcs_get_subscription_ids_for_order( $order, $order_types = [ 'any' ] ) { + $subscription_ids = []; + + if ( ! is_a( $order, 'WC_Abstract_Order' ) ) { + $order = wc_get_order( $order ); + } + + if ( ! wcs_is_order( $order ) ) { + return $subscription_ids; + } + + if ( ! is_array( $order_types ) ) { + $order_types = [ $order_types ]; + } + + $get_all = in_array( 'any', $order_types, true ); + $relation_types = WCS_Related_Order_Store::instance()->get_relation_types(); + $valid_order_types = $get_all ? $relation_types : array_intersect( $relation_types, $order_types ); + + foreach ( $valid_order_types as $order_type ) { + $subscription_ids = array_merge( $subscription_ids, WCS_Related_Order_Store::instance()->get_related_subscription_ids( $order, $order_type ) ); + } + + if ( $get_all || in_array( 'parent', $order_types, true ) ) { + $subscription_ids_for_parent_order = wc_get_orders( + [ + 'parent' => $order->get_id(), + 'type' => 'shop_subscription', + 'status' => 'any', + 'limit' => -1, + 'return' => 'ids', + ] + ); + + if ( is_array( $subscription_ids_for_parent_order ) ) { + $subscription_ids = array_merge( $subscription_ids, $subscription_ids_for_parent_order ); + } + } + + rsort( $subscription_ids ); + + return $subscription_ids; +} + /** * Copy the billing, shipping or all addresses from one order or subscription to another. * @@ -365,10 +413,7 @@ function wcs_order_contains_subscription( $order, $order_type = array( 'parent', $contains_subscription = false; $get_all = in_array( 'any', $order_type, true ); - if ( ( in_array( 'parent', $order_type, true ) || $get_all ) && count( wcs_get_subscriptions_for_order( $order->get_id(), array( 'order_type' => 'parent' ) ) ) > 0 ) { - $contains_subscription = true; - - } elseif ( ( in_array( 'renewal', $order_type, true ) || $get_all ) && wcs_order_contains_renewal( $order ) ) { + if ( ( in_array( 'renewal', $order_type, true ) || $get_all ) && wcs_order_contains_renewal( $order ) ) { $contains_subscription = true; } elseif ( ( in_array( 'resubscribe', $order_type, true ) || $get_all ) && wcs_order_contains_resubscribe( $order ) ) { @@ -377,6 +422,8 @@ function wcs_order_contains_subscription( $order, $order_type = array( 'parent', } elseif ( ( in_array( 'switch', $order_type, true ) || $get_all ) && wcs_order_contains_switch( $order ) ) { $contains_subscription = true; + } elseif ( ( in_array( 'parent', $order_type, true ) || $get_all ) && wcs_order_contains_parent( $order ) ) { + $contains_subscription = true; } return $contains_subscription; @@ -1055,3 +1102,41 @@ function wcs_set_recurring_item_total( &$item ) { ] ); } + +/** + * Checks if an order is a Subscriptions parent/initial order. + * + * @param WC_Order|int $order The WC_Order object or ID of a WC_Order order. + * + * @return bool Whether the order contains a parent. + */ +function wcs_order_contains_parent( $order ) { + $order = ! is_object( $order ) ? wc_get_order( $order ) : $order; + + if ( ! $order || ! wcs_is_order( $order ) ) { + return false; + } + + // Check if the order ID is the parent of a subscription. + $is_parent_order = wc_get_orders( + [ + 'parent' => $order->get_id(), + 'type' => 'shop_subscription', + 'status' => 'any', + 'limit' => 1, + 'return' => 'ids', + ] + ); + + /** + * Allow third-parties to filter whether this order should be considered a parent order. + * + * @since 7.3.0 + * + * @param bool $is_parent_order True if parent meta was found on the order, otherwise false. + * @param WC_Order $order The WC_Order object. + * + * @return bool True if the order contains a parent, otherwise false. + */ + return apply_filters( 'woocommerce_subscriptions_is_parent_order', ! empty( $is_parent_order ), $order ); +} diff --git a/vendor/woocommerce/subscriptions-core/includes/wcs-renewal-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-renewal-functions.php index 7220cd5..b4d6090 100644 --- a/vendor/woocommerce/subscriptions-core/includes/wcs-renewal-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-renewal-functions.php @@ -56,20 +56,18 @@ function wcs_create_renewal_order( $subscription ) { * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ function wcs_order_contains_renewal( $order ) { + $is_renewal_order = false; if ( ! is_a( $order, 'WC_Abstract_Order' ) ) { $order = wc_get_order( $order ); } - $related_subscriptions = wcs_get_subscriptions_for_renewal_order( $order ); - - if ( wcs_is_order( $order ) && ! empty( $related_subscriptions ) ) { - $is_renewal = true; - } else { - $is_renewal = false; + if ( $order ) { + $related_subscription_ids = wcs_get_subscription_ids_for_order( $order, 'renewal' ); + $is_renewal_order = ! empty( $related_subscription_ids ); } - return apply_filters( 'woocommerce_subscriptions_is_renewal_order', $is_renewal, $order ); + return apply_filters( 'woocommerce_subscriptions_is_renewal_order', $is_renewal_order, $order ); } /** diff --git a/vendor/woocommerce/subscriptions-core/includes/wcs-resubscribe-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-resubscribe-functions.php index a4200d9..a1c3dd2 100644 --- a/vendor/woocommerce/subscriptions-core/includes/wcs-resubscribe-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-resubscribe-functions.php @@ -21,17 +21,15 @@ if ( ! defined( 'ABSPATH' ) ) { * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ function wcs_order_contains_resubscribe( $order ) { + $is_resubscribe_order = false; if ( ! is_a( $order, 'WC_Abstract_Order' ) ) { $order = wc_get_order( $order ); } - $related_subscriptions = wcs_get_subscriptions_for_resubscribe_order( $order ); - - if ( wcs_is_order( $order ) && ! empty( $related_subscriptions ) ) { - $is_resubscribe_order = true; - } else { - $is_resubscribe_order = false; + if ( $order ) { + $related_subscription_ids = wcs_get_subscription_ids_for_order( $order, 'resubscribe' ); + $is_resubscribe_order = ! empty( $related_subscription_ids ); } return apply_filters( 'woocommerce_subscriptions_is_resubscribe_order', $is_resubscribe_order, $order ); diff --git a/vendor/woocommerce/subscriptions-core/includes/wcs-switch-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-switch-functions.php index 261c1a3..3ed0d7f 100644 --- a/vendor/woocommerce/subscriptions-core/includes/wcs-switch-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-switch-functions.php @@ -19,24 +19,15 @@ if ( ! defined( 'ABSPATH' ) ) { * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ function wcs_order_contains_switch( $order ) { + $is_switch_order = false; if ( ! is_a( $order, 'WC_Abstract_Order' ) ) { $order = wc_get_order( $order ); } - if ( ! wcs_is_order( $order ) || wcs_order_contains_renewal( $order ) ) { - - $is_switch_order = false; - - } else { - - $switched_subscriptions = wcs_get_subscriptions_for_switch_order( $order ); - - if ( ! empty( $switched_subscriptions ) ) { - $is_switch_order = true; - } else { - $is_switch_order = false; - } + if ( $order ) { + $related_subscription_ids = wcs_get_subscription_ids_for_order( $order, 'switch' ); + $is_switch_order = ! empty( $related_subscription_ids ); } return apply_filters( 'woocommerce_subscriptions_is_switch_order', $is_switch_order, $order ); diff --git a/vendor/woocommerce/subscriptions-core/templates/cart/cart-recurring-shipping.php b/vendor/woocommerce/subscriptions-core/templates/cart/cart-recurring-shipping.php index dc8a421..dbb11ec 100644 --- a/vendor/woocommerce/subscriptions-core/templates/cart/cart-recurring-shipping.php +++ b/vendor/woocommerce/subscriptions-core/templates/cart/cart-recurring-shipping.php @@ -35,7 +35,7 @@ if ( ! defined( 'ABSPATH' ) ) { - ' . esc_html( $package_details ) . '

'; ?> + ' . wp_kses_post( $package_details ) . '

'; ?> diff --git a/vendor/woocommerce/subscriptions-core/templates/emails/admin-new-renewal-order.php b/vendor/woocommerce/subscriptions-core/templates/emails/admin-new-renewal-order.php index 04db295..dddf05e 100644 --- a/vendor/woocommerce/subscriptions-core/templates/emails/admin-new-renewal-order.php +++ b/vendor/woocommerce/subscriptions-core/templates/emails/admin-new-renewal-order.php @@ -2,35 +2,52 @@ /** * Admin new renewal order email * - * @author Brent Shepherd + * Based on the WooCommerce core admin-new-order.php template. + * * @package WooCommerce_Subscriptions/Templates/Emails - * @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.6.0 + * @version 7.3.0 - Updated for WC core email improvements. */ -if ( ! defined( 'ABSPATH' ) ) { - exit; // Exit if accessed directly -} +defined( 'ABSPATH' ) || exit; + +$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' ); + +/* + * @hooked WC_Emails::email_header() Output the email header + */ do_action( 'woocommerce_email_header', $email_heading, $email ); ?> +' : ''; ?> -

get_formatted_billing_full_name() ) );?>

+

get_formatted_billing_full_name() ) ); ?>

+' : ''; ?> ' : ''; echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) ); + echo $email_improvements_enabled ? '' : ''; } do_action( 'woocommerce_email_footer', $email ); diff --git a/vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php b/vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php index 7ef783d..df69ba1 100644 --- a/vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php +++ b/vendor/woocommerce/subscriptions-core/templates/emails/admin-new-switch-order.php @@ -1,27 +1,52 @@ -

get_formatted_billing_full_name(), $switched_count ) );?>

+echo $email_improvements_enabled ? '