diff --git a/changelog.txt b/changelog.txt index 5d6289d..eeaf2f0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,18 @@ *** Woo Subscriptions Changelog *** +2023-11-09 - version 5.7.0 +* Add: Introduce a new REST API endpoint to create subscription(s) from a given order. This endpoint is available at POST `/wc/v3/orders/{order_id}/subscriptions` and accepts a single order ID. +* Add: When a customer toggles automatic renewals on or off via their My Account page, add a note to the subscription to record that event. +* Fix: Set and update a subscription's trial end date via the REST API. +* Fix: Ensure the `woocommerce_subscription_renewal_payment_complete` hook is always triggered when processing early renewals via the checkout page (introduced in 5.6.0). +* Fix: When a subscription is flagged as requiring manual payments, allow admin users to turn on automatic payments for a subscription via the Edit Subscription page by selecting a new payment method. +* Fix: When processing an early renewal order, make sure the suspension count is reset back to 0 on payment complete. +* Fix: Ensure proper backfilling of subscription metadata (i.e. dates and cache) to the postmeta table when HPOS is enabled and compatibility mode (data syncing) is turned on. +* Fix: Fetch and update the `_cancelled_email_sent` meta in a HPOS compatibile way. +* Dev: Introduce a new wcs_get_subscription_grouping_key() function to generate a unique key for a subscription based on its billing schedule. This function uses the existing recurring cart key concept. +* Dev: Deprecate the WC_Subscriptions_Synchroniser::add_to_recurring_cart_key(). Use WC_Subscriptions_Synchroniser::add_to_recurring_product_grouping_key() instead. +* Dev: Update subscriptions-core to 6.5.0. + 2023-10-18 - version 5.6.0 * Add: Introduce the "Subscription Relationship" column under the Orders list admin page when HPOS is enabled. * Add: Use admin theme color and the correct WooCommerce colors. diff --git a/includes/api/class-wc-rest-subscriptions-controller.php b/includes/api/class-wc-rest-subscriptions-controller.php index d1af3ff..e10ac83 100644 --- a/includes/api/class-wc-rest-subscriptions-controller.php +++ b/includes/api/class-wc-rest-subscriptions-controller.php @@ -60,6 +60,16 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller { ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); + + register_rest_route( $this->namespace, "/orders/(?P[\d]+)/{$this->rest_base}", array( + array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'create_subscriptions_from_order' ), + 'permission_callback' => array( $this, 'create_item_permissions_check' ), + 'args' => $this->get_collection_params(), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) ); } /** @@ -261,7 +271,7 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller { $this->update_address( $subscription, $value, $key ); break; case 'start_date': - case 'trial_end': + case 'trial_end_date': case 'next_payment_date': case 'cancelled_date': case 'end_date': @@ -413,8 +423,8 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller { 'type' => 'date-time', 'context' => array( 'view', 'edit' ), ), - 'trial_date' => array( - 'description' => __( "The subscription's trial date, as GMT.", 'woocommerce-subscriptions' ), + 'trial_end_date' => array( + 'description' => __( "The subscription's trial end date, as GMT.", 'woocommerce-subscriptions' ), 'type' => 'date-time', 'context' => array( 'view', 'edit' ), ), @@ -512,4 +522,196 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller { throw new WC_REST_Exception( 'woocommerce_rest_invalid_payment_data', sprintf( __( 'Subscription payment method could not be set to %1$s with error message: %2$s', 'woocommerce-subscriptions' ), $payment_method, $e->getMessage() ), 400 ); } } + + /** + * Creates subscriptions from an order. + * + * @param WP_REST_Request $request + * @return array Subscriptions created from the order. + */ + public function create_subscriptions_from_order( $request ) { + $order_id = absint( $request->get_param( 'id' ) ); + + if ( empty( $order_id ) ) { + return new WP_Error( 'woocommerce_rest_order_invalid_id', __( 'Invalid order ID.', 'woocommerce-subscriptions' ), array( 'status' => 404 ) ); + } + + $order = wc_get_order( $order_id ); + + if ( ! $order || ! wcs_is_order( $order ) ) { + return new WP_Error( 'woocommerce_rest_order_invalid_id', sprintf( __( 'Failed to load order object with the ID %d.', 'woocommerce-subscriptions' ), $order_id ), array( 'status' => 404 ) ); + } + + if ( ! $order->get_customer_id() ) { + return new WP_Error( 'woocommerce_rest_invalid_order', __( 'Order does not have a customer associated with it. Subscriptions require a customer.', 'woocommerce-subscriptions' ), array( 'status' => 404 ) ); + } + + if ( wcs_order_contains_subscription( $order, 'any' ) ) { + return new WP_Error( 'woocommerce_rest_invalid_order', __( 'Order already has subscriptions associated with it.', 'woocommerce-subscriptions' ), array( 'status' => 404 ) ); + } + + $subscription_groups = []; + $subscriptions = []; + + // Group the order items into subscription groups. + foreach ( $order->get_items() as $item ) { + $product = $item->get_product(); + + if ( ! WC_Subscriptions_Product::is_subscription( $product ) ) { + continue; + } + + $subscription_groups[ wcs_get_subscription_item_grouping_key( $item ) ][] = $item; + } + + // Return a 204 if there are no subscriptions to be created. + if ( empty( $subscription_groups ) ) { + $response = rest_ensure_response( $subscriptions ); + $response->set_status( 204 ); + return $response; + } + + /** + * Start creating any subscriptions start transaction if available. + * + * To ensure data integrity, if any subscription fails to be created, the transaction will be rolled back. This will enable + * the client to resubmit the request without having to worry about duplicate subscriptions being created. + */ + $transaction = new WCS_SQL_Transaction(); + $transaction->start(); + + try { + // Create subscriptions. + foreach ( $subscription_groups as $items ) { + // Get the first item in the group to use as the base for the subscription. + $product = $items[0]->get_product(); + $start_date = wcs_get_datetime_utc_string( $order->get_date_created( 'edit' ) ); + $subscription = wcs_create_subscription( [ + 'order_id' => $order_id, + 'created_via' => 'rest-api', + 'start_date' => $start_date, + 'status' => $order->is_paid() ? 'active' : 'pending', + 'billing_period' => WC_Subscriptions_Product::get_period( $product ), + 'billing_interval' => WC_Subscriptions_Product::get_interval( $product ), + 'customer_note' => $order->get_customer_note(), + ] ); + + if ( is_wp_error( $subscription ) ) { + throw new Exception( $subscription->get_error_message() ); + } + + wcs_copy_order_address( $order, $subscription ); + + $subscription->update_dates( + array( + 'trial_end' => WC_Subscriptions_Product::get_trial_expiration_date( $product, $start_date ), + 'next_payment' => WC_Subscriptions_Product::get_first_renewal_payment_date( $product, $start_date ), + 'end' => WC_Subscriptions_Product::get_expiration_date( $product, $start_date ), + ) + ); + + $subscription->set_payment_method( $order->get_payment_method() ); + + wcs_copy_order_meta( $order, $subscription, 'subscription' ); + + // Add items. + $subscription_needs_shipping = false; + foreach ( $items as $item ) { + // Create order line item. + $item_id = wc_add_order_item( + $subscription->get_id(), + [ + 'order_item_name' => $item->get_name(), + 'order_item_type' => $item->get_type(), + ] + ); + + $subscription_item = $subscription->get_item( $item_id ); + + wcs_copy_order_item( $item, $subscription_item ); + $subscription_item->save(); + + // Check if this subscription will need shipping. + if ( ! $subscription_needs_shipping ) { + $product = $item->get_product(); + + if ( $product ) { + $subscription_needs_shipping = $product->needs_shipping() && ! WC_Subscriptions_Product::needs_one_time_shipping( $product ); + } + } + } + + // Add coupons. + foreach ( $order->get_coupons() as $coupon_item ) { + $coupon = new WC_Coupon( $coupon_item->get_code() ); + + try { + // validate_subscription_coupon_for_order will throw an exception if the coupon cannot be applied to the subscription. + WC_Subscriptions_Coupon::validate_subscription_coupon_for_order( true, $coupon, $subscription ); + + $subscription->apply_coupon( $coupon->get_code() ); + } catch ( Exception $e ) { + // Do nothing. The coupon will not be applied to the subscription. + } + } + + // Add shipping. + if ( $subscription_needs_shipping ) { + foreach ( $order->get_shipping_methods() as $shipping_item ) { + $rate = new WC_Shipping_Rate( $shipping_item->get_method_id(), $shipping_item->get_method_title(), $shipping_item->get_total(), $shipping_item->get_taxes(), $shipping_item->get_instance_id() ); + + $item = new WC_Order_Item_Shipping(); + $item->set_order_id( $subscription->get_id() ); + $item->set_shipping_rate( $rate ); + + $subscription->add_item( $item ); + } + } + + // Add fees. + foreach ( $order->get_fees() as $fee_item ) { + if ( ! apply_filters( 'wcs_should_copy_fee_item_to_subscription', true, $fee_item, $subscription, $order ) ) { + continue; + } + + $item = new WC_Order_Item_Fee(); + $item->set_props( + array( + 'name' => $fee_item->get_name(), + 'tax_class' => $fee_item->get_tax_class(), + 'amount' => $fee_item->get_amount(), + 'total' => $fee_item->get_total(), + 'total_tax' => $fee_item->get_total_tax(), + 'taxes' => $fee_item->get_taxes(), + ) + ); + + $subscription->add_item( $item ); + } + + $subscription->calculate_totals(); + $subscription->save(); + + /** + * Fires after a single subscription is created or updated via the REST API. + * + * @param WC_Subscription $object Inserted subscription. + * @param WP_REST_Request $request Request object. + * @param boolean $creating True when creating object, false when updating. + */ + do_action( "woocommerce_rest_insert_{$this->post_type}_object", $subscription, $request, true ); + + $response = $this->prepare_object_for_response( wcs_get_subscription( $subscription->get_id() ), $request ); + $subscriptions[] = $this->prepare_response_for_collection( $response ); + } + } catch ( Exception $e ) { + $transaction->rollback(); + return new WP_Error( 'woocommerce_rest_invalid_subscription_data', $e->getMessage(), array( 'status' => 404 ) ); + } + + // If we got here, the subscription was created without problems + $transaction->commit(); + + return rest_ensure_response( $subscriptions ); + } } diff --git a/includes/early-renewal/class-wcs-cart-early-renewal.php b/includes/early-renewal/class-wcs-cart-early-renewal.php index 58121ed..6a479a7 100644 --- a/includes/early-renewal/class-wcs-cart-early-renewal.php +++ b/includes/early-renewal/class-wcs-cart-early-renewal.php @@ -479,6 +479,9 @@ class WCS_Cart_Early_Renewal extends WCS_Cart_Renewal { // Payment success - if payment was successful and dates haven't been updated for this order, update the subscription dates and store meta to prevent dates being updated multiple times for the same order. if ( $subscription && $order->is_paid() && ! $order->meta_exists( self::SUBSCRIPTION_DATES_UPDATED_META_KEY ) ) { + // Call the subscription payment complete function to trigger the payment complete hook and reset suspension counts and update user roles. + $subscription->payment_complete(); + wcs_update_dates_after_early_renewal( $subscription, $order ); $order->update_meta_data( self::SUBSCRIPTION_DATES_UPDATED_META_KEY, wc_bool_to_string( true ) ); diff --git a/languages/woocommerce-subscriptions.pot b/languages/woocommerce-subscriptions.pot index 8be5155..0c407d3 100644 --- a/languages/woocommerce-subscriptions.pot +++ b/languages/woocommerce-subscriptions.pot @@ -2,14 +2,14 @@ # This file is distributed under the same license as the Woo Subscriptions plugin. msgid "" msgstr "" -"Project-Id-Version: Woo Subscriptions 5.6.0\n" +"Project-Id-Version: Woo Subscriptions 5.7.0\n" "Report-Msgid-Bugs-To: https://woocommerce.com/contact-us\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2023-10-18T04:37:04+00:00\n" +"POT-Creation-Date: 2023-11-09T05:16:09+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.8.1\n" "X-Domain: woocommerce-subscriptions\n" @@ -669,55 +669,55 @@ msgstr "" msgid "Payment Gateway Feature Support." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:155 +#: includes/api/class-wc-rest-subscriptions-controller.php:165 msgid "Invalid subscription ID." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:161 +#: includes/api/class-wc-rest-subscriptions-controller.php:171 msgid "Failed to load subscription object with the ID %d." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:323 +#: includes/api/class-wc-rest-subscriptions-controller.php:333 msgid "Subscription dates could not be set. Error message: %s" msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:359 +#: includes/api/class-wc-rest-subscriptions-controller.php:369 msgid "Subscription status." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:362 +#: includes/api/class-wc-rest-subscriptions-controller.php:372 msgid "Where the subscription was created." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:363 +#: includes/api/class-wc-rest-subscriptions-controller.php:373 msgid "Currency the subscription was created with, in ISO format." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:364 +#: includes/api/class-wc-rest-subscriptions-controller.php:374 msgid "The date the subscription was created, in the site's timezone." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:365 +#: includes/api/class-wc-rest-subscriptions-controller.php:375 msgid "The date the subscription was created, as GMT." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:366 +#: includes/api/class-wc-rest-subscriptions-controller.php:376 msgid "The date the subscription was last modified, in the site's timezone." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:367 +#: includes/api/class-wc-rest-subscriptions-controller.php:377 msgid "The date the subscription was last modified, as GMT." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:368 +#: includes/api/class-wc-rest-subscriptions-controller.php:378 msgid "User ID who owns the subscription." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:378 +#: includes/api/class-wc-rest-subscriptions-controller.php:388 msgid "The status to transition a subscription to." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:384 +#: includes/api/class-wc-rest-subscriptions-controller.php:394 #: includes/api/legacy/class-wc-rest-subscriptions-controller.php:350 #: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:506 #: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:179 @@ -725,7 +725,7 @@ msgstr "" msgid "The number of billing periods between subscription renewals." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:389 +#: includes/api/class-wc-rest-subscriptions-controller.php:399 #: includes/api/legacy/class-wc-rest-subscriptions-controller.php:355 #: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:511 #: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-extend-store-endpoint.php:172 @@ -733,56 +733,72 @@ msgstr "" msgid "Billing period for the subscription." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:395 +#: includes/api/class-wc-rest-subscriptions-controller.php:405 #: includes/api/legacy/class-wc-rest-subscriptions-controller.php:361 #: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:517 msgid "Subscription payment details." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:400 +#: includes/api/class-wc-rest-subscriptions-controller.php:410 msgid "Payment method meta and token in a post_meta_key: token format." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:405 +#: includes/api/class-wc-rest-subscriptions-controller.php:415 msgid "Payment method meta and token in a user_meta_key : token format." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:412 +#: includes/api/class-wc-rest-subscriptions-controller.php:422 msgid "The subscription's start date, as GMT." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:417 -msgid "The subscription's trial date, as GMT." -msgstr "" - -#: includes/api/class-wc-rest-subscriptions-controller.php:422 -msgid "The subscription's next payment date, as GMT." -msgstr "" - #: includes/api/class-wc-rest-subscriptions-controller.php:427 -msgid "The subscription's cancelled date, as GMT." +msgid "The subscription's trial end date, as GMT." msgstr "" #: includes/api/class-wc-rest-subscriptions-controller.php:432 +msgid "The subscription's next payment date, as GMT." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:437 +msgid "The subscription's cancelled date, as GMT." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:442 msgid "The subscription's end date, as GMT." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:451 +#: includes/api/class-wc-rest-subscriptions-controller.php:461 msgid "Limit result set to subscriptions which have specific statuses." msgstr "" #. translators: placeholder is the payment method ID. -#: includes/api/class-wc-rest-subscriptions-controller.php:495 +#: includes/api/class-wc-rest-subscriptions-controller.php:505 msgid "The %s payment gateway does not support admin changing the payment method." msgstr "" #. translators: 1$: gateway id, 2$: error message -#: includes/api/class-wc-rest-subscriptions-controller.php:512 +#: includes/api/class-wc-rest-subscriptions-controller.php:522 #: includes/api/legacy/class-wc-rest-subscriptions-controller.php:336 #: includes/api/v1/class-wc-rest-subscriptions-v1-controller.php:405 msgid "Subscription payment method could not be set to %1$s with error message: %2$s" msgstr "" +#: includes/api/class-wc-rest-subscriptions-controller.php:536 +msgid "Invalid order ID." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:542 +msgid "Failed to load order object with the ID %d." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:546 +msgid "Order does not have a customer associated with it. Subscriptions require a customer." +msgstr "" + +#: includes/api/class-wc-rest-subscriptions-controller.php:550 +msgid "Order already has subscriptions associated with it." +msgstr "" + #: includes/api/legacy/class-wc-api-subscriptions.php:102 #: vendor/woocommerce/subscriptions-core/wcs-functions.php:136 msgid "Invalid subscription status given." @@ -1287,11 +1303,11 @@ msgid "Order %s created to record early renewal." msgstr "" #: includes/early-renewal/class-wcs-cart-early-renewal.php:294 -#: includes/early-renewal/class-wcs-cart-early-renewal.php:624 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:627 msgid "Cancel" msgstr "" -#: includes/early-renewal/class-wcs-cart-early-renewal.php:592 +#: includes/early-renewal/class-wcs-cart-early-renewal.php:595 msgctxt "used in order note as reason for why subscription status changed" msgid "Customer requested to renew early:" msgstr "" @@ -1718,13 +1734,13 @@ msgid "When switching to a subscription with a length, you can take into account msgstr "" #: includes/switching/class-wc-subscriptions-switcher.php:437 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:225 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:226 msgctxt "when to prorate first payment / subscription length" msgid "For Virtual Subscription Products Only" msgstr "" #: includes/switching/class-wc-subscriptions-switcher.php:438 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:226 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:227 msgctxt "when to prorate first payment / subscription length" msgid "For All Subscription Products" msgstr "" @@ -1870,6 +1886,46 @@ msgstr "" msgid "Want to renew early via the checkout? Click %shere.%s" msgstr "" +#: tests/unit/scheduler/scheduler.php:65 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:291 +msgctxt "table heading" +msgid "Start Date" +msgstr "" + +#: tests/unit/scheduler/scheduler.php:66 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:292 +msgctxt "table heading" +msgid "Trial End" +msgstr "" + +#: tests/unit/scheduler/scheduler.php:67 +#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:40 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:293 +msgctxt "table heading" +msgid "Next Payment" +msgstr "" + +#: tests/unit/scheduler/scheduler.php:68 +#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:23 +#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:23 +#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:23 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:294 +msgctxt "table heading" +msgid "Last Order Date" +msgstr "" + +#: tests/unit/scheduler/scheduler.php:69 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:295 +msgctxt "table heading" +msgid "Cancelled Date" +msgstr "" + +#: tests/unit/scheduler/scheduler.php:70 +#: vendor/woocommerce/subscriptions-core/wcs-functions.php:296 +msgctxt "table heading" +msgid "End Date" +msgstr "" + #. translators: 1: relation type, 2: list of valid relation types. #: vendor/woocommerce/subscriptions-core/includes/abstracts/abstract-wcs-related-order-store.php:148 msgid "Invalid relation type: %1$s. Order relationship type must be one of: %2$s." @@ -1952,7 +2008,7 @@ msgid "Optionally include an amount to be charged at the outset of the subscript msgstr "" #: vendor/woocommerce/subscriptions-core/includes/admin/class-wc-subscriptions-admin.php:371 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2469 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2422 #: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-price.php:25 msgid "Free trial" msgstr "" @@ -2463,7 +2519,7 @@ msgstr[1] "" #. translators: placeholder is the display name of a payment gateway a subscription was paid by #. translators: %s: payment method. #: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:646 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2047 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2052 msgid "Via %s" msgstr "" @@ -2531,7 +2587,7 @@ msgid "None" msgstr "" #: vendor/woocommerce/subscriptions-core/includes/admin/class-wcs-admin-post-types.php:1129 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2029 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2034 #: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:170 msgid "Manual Renewal" msgstr "" @@ -2783,14 +2839,14 @@ msgid "No billing address set." msgstr "" #: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:188 -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:39 -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:52 -msgid "Payment Method" +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:36 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:47 +msgid "Payment method" msgstr "" #. translators: %s: gateway ID. #: vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:193 -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:54 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:49 msgctxt "The gateway ID displayed on the Edit Subscriptions screen when editing payment method." msgid "Gateway ID: [%s]" msgstr "" @@ -2950,7 +3006,7 @@ msgstr "" #. translators: %d: subscription ID. #. translators: %d: order ID. #: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1365 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2470 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2475 msgid "Subscription #%d: " msgstr "" @@ -2958,67 +3014,67 @@ msgstr "" msgid "Payment status marked complete." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1807 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1812 msgid "Payment failed." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1812 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1817 msgid "Subscription Cancelled: maximum number of failed payments reached." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1922 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:1927 msgid "The \"all\" value for $order_type parameter is deprecated. It was a misnomer, as it did not return resubscribe orders. It was also inconsistent with order type values accepted by wcs_get_subscription_orders(). Use array( \"parent\", \"renewal\", \"switch\" ) to maintain previous behaviour, or \"any\" to receive all order types, including switch and resubscribe." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2126 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2131 #: vendor/woocommerce/subscriptions-core/wcs-functions.php:835 msgid "Payment method meta must be an array." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2362 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2367 msgid "Invalid format. First parameter needs to be an array." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2366 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2371 msgid "Invalid data. First parameter was empty when passed to update_dates()." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2373 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2378 msgid "Invalid data. First parameter has a date that is not in the registered date types." msgstr "" #. translators: placeholder is date type (e.g. "end", "next_payment"...) -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2400 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2405 msgctxt "appears in an error message if date is wrong format" msgid "Invalid %s date. The date must be of the format: \"Y-m-d H:i:s\"." msgstr "" #. translators: %s: date type (e.g. "end"). -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2438 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2443 msgid "The %s date must occur after the cancellation date." msgstr "" #. translators: %s: date type (e.g. "end"). -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2444 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2449 msgid "The %s date must occur after the last payment date." msgstr "" #. translators: %s: date type (e.g. "end"). -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2449 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2454 msgid "The %s date must occur after the next payment date." msgstr "" #. translators: %s: date type (e.g. "end"). -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2455 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2460 msgid "The %s date must occur after the trial end date." msgstr "" #. translators: %s: date type (e.g. "next_payment"). -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2460 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2465 msgid "The %s date must occur after the start date." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2490 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php:2495 #: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-checkout.php:348 msgid "Backordered" msgstr "" @@ -3069,7 +3125,7 @@ msgid "Your cart has been emptied of subscription products. Only one subscriptio msgstr "" #: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart-validator.php:128 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:1529 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:1482 msgid "That subscription product can not be added to your cart as it already contains a subscription renewal." msgstr "" @@ -3081,16 +3137,16 @@ msgstr "" msgid "Please enter a valid postcode/ZIP." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:1167 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:1120 msgid "Invalid recurring shipping method." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2205 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2158 msgid "now" msgstr "" #. translators: placeholder is a number of days. -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2364 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2317 #: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:58 msgid "%s day" msgid_plural "%s days" @@ -3098,7 +3154,7 @@ msgstr[0] "" msgstr[1] "" #. translators: placeholder is a number of weeks. -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2368 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2321 #: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:60 msgid "%s week" msgid_plural "%s weeks" @@ -3106,7 +3162,7 @@ msgstr[0] "" msgstr[1] "" #. translators: placeholder is a number of months. -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2372 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2325 #: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:62 msgid "%s month" msgid_plural "%s months" @@ -3114,7 +3170,7 @@ msgstr[0] "" msgstr[1] "" #. translators: placeholder is a number of years. -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2376 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2329 #: vendor/woocommerce/subscriptions-core/includes/wcs-time-functions.php:64 msgid "%s year" msgid_plural "%s years" @@ -3122,49 +3178,49 @@ msgstr[0] "" msgstr[1] "" #. translators: 1$: day of the week (e.g. "every Wednesday"). -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2398 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2351 msgid "every %1$s" msgstr "" #. translators: 1$: period, 2$: day of the week (e.g. "every 2nd week on Wednesday"). -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2402 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2355 msgid "every %1$s on %2$s" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2411 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2364 msgid "on the last day of each month" msgstr "" #. translators: 1$: day of the month (e.g. "23rd") (e.g. "every 23rd of each month"). -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2415 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2368 msgid "on the %1$s of each month" msgstr "" #. translators: 1$: interval (e.g. "3rd") (e.g. "on the last day of every 3rd month"). -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2423 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2376 msgid "on the last day of every %1$s month" msgstr "" #. translators: on the, 1$: 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:2429 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2382 msgid "on the %1$s day of every %2$s month" msgstr "" #. translators: on, 1$: , 2$: each year (e.g. "on March 15th each year"). -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2440 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2393 msgid "on %1$s %2$s each year" msgstr "" #. translators: 1$: month (e.g. "March"), 2$: day of the month (e.g. "23rd), 3$: interval year (r.g March 23rd every 2nd year"). -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2447 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2400 msgid "on %1$s %2$s every %3$s year" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2479 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2432 msgid "Sign up fee" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2489 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php:2442 msgid "Renews" msgstr "" @@ -3965,92 +4021,92 @@ msgctxt "used in subscription product edit screen" msgid "Align the payment date for this subscription to a specific day of the year. If the date has already taken place this year, the first payment will be processed in %s. Set the day to 0 to disable payment syncing for this product." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:199 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:200 msgid "Synchronisation" msgstr "" #. translators: placeholders are opening and closing link tags -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:202 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:203 msgctxt "used in the general subscription options page" msgid "Align subscription renewal to a specific day of the week, month or year. For example, the first day of the month. %1$sLearn more%2$s." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:208 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:209 msgid "Align Subscription Renewal Day" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:215 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:216 msgid "Prorate First Renewal" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:216 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:217 msgid "If a subscription is synchronised to a specific day of the week, month or year, charge a prorated amount for the subscription at the time of sign up." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:223 -msgctxt "when to prorate first payment / subscription length" -msgid "Never (do not charge any recurring amount)" -msgstr "" - #: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:224 msgctxt "when to prorate first payment / subscription length" +msgid "Never (do not charge any recurring amount)" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:225 +msgctxt "when to prorate first payment / subscription length" msgid "Never (charge the full recurring amount at sign-up)" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:232 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:233 msgid "Sign-up grace period" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:233 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:234 msgctxt "there's a number immediately in front of this text" msgid "days prior to Renewal Day" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:237 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:238 msgid "Subscriptions created within this many days prior to the Renewal Day will not be charged at sign-up. Set to zero for all new Subscriptions to be charged the full recurring amount. Must be a positive number." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:306 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:307 msgid "Month for Synchronisation" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:314 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:315 #: vendor/woocommerce/subscriptions-core/templates/admin/deprecated/html-variation-synchronisation.php:36 #: vendor/woocommerce/subscriptions-core/templates/admin/html-variation-synchronisation.php:42 msgctxt "input field placeholder for day field for annual subscriptions" msgid "Day" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:745 -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:762 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:746 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:763 msgid "Do not synchronise" msgstr "" #. translators: placeholder is a day of the week -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:770 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:771 msgid "%s each week" msgstr "" #. translators: placeholder is a number of day with language specific suffix applied (e.g. "1st", "3rd", "5th", etc...) -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:776 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:777 msgid "%s day of the month" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:778 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:779 msgid "Last day of the month" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:826 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:827 msgid "Today!" msgstr "" #. translators: placeholder is a date -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:833 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:834 msgid "First payment prorated. Next payment: %s" msgstr "" #. translators: placeholder is a date -#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:836 +#: vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php:837 msgid "First payment: %s" msgstr "" @@ -4152,10 +4208,15 @@ msgctxt "The place order button text while resubscribing to a subscription" msgid "Resubscribe" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:123 +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:116 msgid "Please choose a valid payment gateway to change to." msgstr "" +#. Translators: Placeholder is the payment gateway title. +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php:149 +msgid "Admin turned on automatic renewals by changing payment method to \"%s\" via the Edit Subscription screen." +msgstr "" + #: vendor/woocommerce/subscriptions-core/includes/class-wcs-failed-scheduled-action-manager.php:158 msgid "Ignore this error" msgstr "" @@ -4181,15 +4242,23 @@ msgstr "" msgid "Limit to one of any status" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:153 -msgid "Auto Renewal Toggle" +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:101 +msgid "Customer turned off automatic renewals via their My Account page." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:154 -msgid "Display the auto renewal toggle" +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:126 +msgid "Customer turned on automatic renewals via their My Account page." msgstr "" #: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:155 +msgid "Auto Renewal Toggle" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:156 +msgid "Display the auto renewal toggle" +msgstr "" + +#: vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php:157 msgid "Allow customers to turn on and off automatic renewals from their View Subscription page." msgstr "" @@ -4443,12 +4512,12 @@ msgid "This will clear the persistent cache of all renewal, switch, resubscribe msgstr "" #. translators: %s: Order date -#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php:248 +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php:265 msgid "Subscription – %s" msgstr "" #. translators: %s: Order date -#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php:248 +#: vendor/woocommerce/subscriptions-core/includes/data-stores/class-wcs-subscription-data-store-cpt.php:265 msgctxt "Order date parsed by DateTime::format" msgid "M d, Y @ h:i A" msgstr "" @@ -4481,7 +4550,7 @@ msgctxt "default email subject for cancelled emails sent to the admin" msgid "[%s] Subscription Cancelled" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:143 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:145 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-renewal-invoice.php:210 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:141 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:141 @@ -4489,14 +4558,14 @@ msgctxt "an email notification" msgid "Enable/Disable" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:145 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:147 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-customer-renewal-invoice.php:212 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:143 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:143 msgid "Enable this email notification" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:149 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:151 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:147 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:147 msgctxt "of an email" @@ -4504,13 +4573,13 @@ msgid "Recipient(s)" msgstr "" #. translators: placeholder is admin email -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:152 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:154 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:150 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:150 msgid "Enter recipients (comma separated) for this email. Defaults to %s." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:157 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:159 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:155 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:155 msgctxt "of an email" @@ -4518,13 +4587,13 @@ msgid "Subject" msgstr "" #. translators: %s: default e-mail subject. -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:160 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:162 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:158 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:158 msgid "This controls the email subject line. Leave blank to use the default subject: %s." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:165 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:167 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:163 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:163 msgctxt "Name the setting that controls the main heading contained within the email notification" @@ -4532,38 +4601,38 @@ msgid "Email Heading" msgstr "" #. translators: %s: default e-mail heading. -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:168 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:170 msgid "This controls the main heading contained within the email notification. Leave blank to use the default heading: %s." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:173 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:175 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:171 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:171 msgctxt "text, html or multipart" msgid "Email type" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:175 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:177 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:173 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:173 msgid "Choose which format of email to send." msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:179 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:181 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:177 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:177 msgctxt "email type" msgid "Plain text" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:180 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:182 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:178 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:178 msgctxt "email type" msgid "HTML" msgstr "" -#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:181 +#: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-cancelled-subscription.php:183 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-expired-subscription.php:179 #: vendor/woocommerce/subscriptions-core/includes/emails/class-wcs-email-on-hold-subscription.php:179 msgctxt "email type" @@ -6325,14 +6394,6 @@ msgctxt "table headings in notification email" msgid "Price" msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:23 -#: vendor/woocommerce/subscriptions-core/templates/emails/expired-subscription.php:23 -#: vendor/woocommerce/subscriptions-core/templates/emails/on-hold-subscription.php:23 -#: vendor/woocommerce/subscriptions-core/wcs-functions.php:294 -msgctxt "table heading" -msgid "Last Order Date" -msgstr "" - #: vendor/woocommerce/subscriptions-core/templates/emails/cancelled-subscription.php:24 msgctxt "table headings in notification email" msgid "End of Prepaid Term" @@ -6615,12 +6676,6 @@ msgstr "" msgid "ID" msgstr "" -#: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:40 -#: vendor/woocommerce/subscriptions-core/wcs-functions.php:293 -msgctxt "table heading" -msgid "Next Payment" -msgstr "" - #: vendor/woocommerce/subscriptions-core/templates/myaccount/my-subscriptions.php:46 #: vendor/woocommerce/subscriptions-core/templates/myaccount/related-orders.php:53 #: vendor/woocommerce/subscriptions-core/templates/myaccount/related-subscriptions.php:42 @@ -6800,26 +6855,6 @@ msgstr "" msgid "Can not get address type display name. Address type is not a string." msgstr "" -#: vendor/woocommerce/subscriptions-core/wcs-functions.php:291 -msgctxt "table heading" -msgid "Start Date" -msgstr "" - -#: vendor/woocommerce/subscriptions-core/wcs-functions.php:292 -msgctxt "table heading" -msgid "Trial End" -msgstr "" - -#: vendor/woocommerce/subscriptions-core/wcs-functions.php:295 -msgctxt "table heading" -msgid "Cancelled Date" -msgstr "" - -#: vendor/woocommerce/subscriptions-core/wcs-functions.php:296 -msgctxt "table heading" -msgid "End Date" -msgstr "" - #: vendor/woocommerce/subscriptions-core/wcs-functions.php:331 msgid "Date type is not a string." msgstr "" diff --git a/vendor/autoload.php b/vendor/autoload.php index 39bd684..5d87e63 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -2,24 +2,6 @@ // autoload.php @generated by Composer -if (PHP_VERSION_ID < 50600) { - if (!headers_sent()) { - header('HTTP/1.1 500 Internal Server Error'); - } - $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; - if (!ini_get('display_errors')) { - if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { - fwrite(STDERR, $err); - } elseif (!headers_sent()) { - echo $err; - } - } - trigger_error( - $err, - E_USER_ERROR - ); -} - require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit59c7b20d3f201de5581a0bc09b6c2289::getLoader(); +return ComposerAutoloaderInitfe47e554dced83cd1f1961109287683e::getLoader(); diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php index a72151c..6d0c3f2 100644 --- a/vendor/composer/ClassLoader.php +++ b/vendor/composer/ClassLoader.php @@ -42,79 +42,30 @@ namespace Composer\Autoload; */ class ClassLoader { - /** @var \Closure(string):void */ - private static $includeFile; - - /** @var ?string */ private $vendorDir; // PSR-4 - /** - * @var array[] - * @psalm-var array> - */ private $prefixLengthsPsr4 = array(); - /** - * @var array[] - * @psalm-var array> - */ private $prefixDirsPsr4 = array(); - /** - * @var array[] - * @psalm-var array - */ private $fallbackDirsPsr4 = array(); // PSR-0 - /** - * @var array[] - * @psalm-var array> - */ private $prefixesPsr0 = array(); - /** - * @var array[] - * @psalm-var array - */ private $fallbackDirsPsr0 = array(); - /** @var bool */ private $useIncludePath = false; - - /** - * @var string[] - * @psalm-var array - */ private $classMap = array(); - - /** @var bool */ private $classMapAuthoritative = false; - - /** - * @var bool[] - * @psalm-var array - */ private $missingClasses = array(); - - /** @var ?string */ private $apcuPrefix; - /** - * @var self[] - */ private static $registeredLoaders = array(); - /** - * @param ?string $vendorDir - */ public function __construct($vendorDir = null) { $this->vendorDir = $vendorDir; - self::initializeIncludeClosure(); } - /** - * @return string[] - */ public function getPrefixes() { if (!empty($this->prefixesPsr0)) { @@ -124,47 +75,28 @@ class ClassLoader return array(); } - /** - * @return array[] - * @psalm-return array> - */ public function getPrefixesPsr4() { return $this->prefixDirsPsr4; } - /** - * @return array[] - * @psalm-return array - */ public function getFallbackDirs() { return $this->fallbackDirsPsr0; } - /** - * @return array[] - * @psalm-return array - */ public function getFallbackDirsPsr4() { return $this->fallbackDirsPsr4; } - /** - * @return string[] Array of classname => path - * @psalm-return array - */ public function getClassMap() { return $this->classMap; } /** - * @param string[] $classMap Class to filename map - * @psalm-param array $classMap - * - * @return void + * @param array $classMap Class to filename map */ public function addClassMap(array $classMap) { @@ -179,11 +111,9 @@ class ClassLoader * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. * - * @param string $prefix The prefix - * @param string[]|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories - * - * @return void + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories */ public function add($prefix, $paths, $prepend = false) { @@ -226,13 +156,11 @@ class ClassLoader * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param string[]|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException - * - * @return void */ public function addPsr4($prefix, $paths, $prepend = false) { @@ -276,10 +204,8 @@ class ClassLoader * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * - * @param string $prefix The prefix - * @param string[]|string $paths The PSR-0 base directories - * - * @return void + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories */ public function set($prefix, $paths) { @@ -294,12 +220,10 @@ class ClassLoader * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param string[]|string $paths The PSR-4 base directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException - * - * @return void */ public function setPsr4($prefix, $paths) { @@ -319,8 +243,6 @@ class ClassLoader * Turns on searching the include path for class files. * * @param bool $useIncludePath - * - * @return void */ public function setUseIncludePath($useIncludePath) { @@ -343,8 +265,6 @@ class ClassLoader * that have not been registered with the class map. * * @param bool $classMapAuthoritative - * - * @return void */ public function setClassMapAuthoritative($classMapAuthoritative) { @@ -365,8 +285,6 @@ class ClassLoader * APCu prefix to use to cache found/not-found classes, if the extension is enabled. * * @param string|null $apcuPrefix - * - * @return void */ public function setApcuPrefix($apcuPrefix) { @@ -387,8 +305,6 @@ class ClassLoader * Registers this instance as an autoloader. * * @param bool $prepend Whether to prepend the autoloader or not - * - * @return void */ public function register($prepend = false) { @@ -408,8 +324,6 @@ class ClassLoader /** * Unregisters this instance as an autoloader. - * - * @return void */ public function unregister() { @@ -429,8 +343,7 @@ class ClassLoader public function loadClass($class) { if ($file = $this->findFile($class)) { - $includeFile = self::$includeFile; - $includeFile($file); + includeFile($file); return true; } @@ -490,11 +403,6 @@ class ClassLoader return self::$registeredLoaders; } - /** - * @param string $class - * @param string $ext - * @return string|false - */ private function findFileWithExtension($class, $ext) { // PSR-4 lookup @@ -560,26 +468,14 @@ class ClassLoader return false; } - - /** - * @return void - */ - private static function initializeIncludeClosure() - { - if (self::$includeFile !== null) { - return; - } - - /** - * Scope isolated include. - * - * Prevents access to $this/self from included files. - * - * @param string $file - * @return void - */ - self::$includeFile = \Closure::bind(static function($file) { - include $file; - }, null, null); - } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; } diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php index 51e734a..b3a4e16 100644 --- a/vendor/composer/InstalledVersions.php +++ b/vendor/composer/InstalledVersions.php @@ -20,27 +20,12 @@ use Composer\Semver\VersionParser; * * See also https://getcomposer.org/doc/07-runtime.md#installed-versions * - * To require its presence, you can require `composer-runtime-api ^2.0` - * - * @final + * To require it's presence, you can require `composer-runtime-api ^2.0` */ class InstalledVersions { - /** - * @var mixed[]|null - * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null - */ private static $installed; - - /** - * @var bool|null - */ private static $canGetVendors; - - /** - * @var array[] - * @psalm-var array}> - */ private static $installedByVendor = array(); /** @@ -98,7 +83,7 @@ class InstalledVersions { foreach (self::getInstalled() as $installed) { if (isset($installed['versions'][$packageName])) { - return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; + return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); } } @@ -119,7 +104,7 @@ class InstalledVersions */ public static function satisfies(VersionParser $parser, $packageName, $constraint) { - $constraint = $parser->parseConstraints((string) $constraint); + $constraint = $parser->parseConstraints($constraint); $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); return $provided->matches($constraint); @@ -243,7 +228,7 @@ class InstalledVersions /** * @return array - * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string} */ public static function getRootPackage() { @@ -257,7 +242,7 @@ class InstalledVersions * * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. * @return array[] - * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} + * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array} */ public static function getRawData() { @@ -280,7 +265,7 @@ class InstalledVersions * Returns the raw data of all installed.php which are currently loaded for custom implementations * * @return array[] - * @psalm-return list}> + * @psalm-return list}> */ public static function getAllRawData() { @@ -303,7 +288,7 @@ class InstalledVersions * @param array[] $data A vendor/composer/installed.php data set * @return void * - * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data + * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array} $data */ public static function reload($data) { @@ -313,7 +298,7 @@ class InstalledVersions /** * @return array[] - * @psalm-return list}> + * @psalm-return list}> */ private static function getInstalled() { @@ -328,9 +313,7 @@ class InstalledVersions if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) { - /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ - $required = require $vendorDir.'/composer/installed.php'; - $installed[] = self::$installedByVendor[$vendorDir] = $required; + $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { self::$installed = $installed[count($installed) - 1]; } @@ -342,17 +325,12 @@ class InstalledVersions // only require the installed.php file if this file is loaded from its dumped location, // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 if (substr(__DIR__, -8, 1) !== 'C') { - /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ - $required = require __DIR__ . '/installed.php'; - self::$installed = $required; + self::$installed = require __DIR__ . '/installed.php'; } else { self::$installed = array(); } } - - if (self::$installed !== array()) { - $installed[] = self::$installed; - } + $installed[] = self::$installed; return $installed; } diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index a27be98..db9b014 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -2,7 +2,7 @@ // autoload_classmap.php @generated by Composer -$vendorDir = dirname(__DIR__); +$vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php index 15a2ff3..b7fc012 100644 --- a/vendor/composer/autoload_namespaces.php +++ b/vendor/composer/autoload_namespaces.php @@ -2,7 +2,7 @@ // autoload_namespaces.php @generated by Composer -$vendorDir = dirname(__DIR__); +$vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index e480e28..12ea9cc 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -2,7 +2,7 @@ // autoload_psr4.php @generated by Composer -$vendorDir = dirname(__DIR__); +$vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index be67390..9ca2568 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit59c7b20d3f201de5581a0bc09b6c2289 +class ComposerAutoloaderInitfe47e554dced83cd1f1961109287683e { private static $loader; @@ -24,12 +24,31 @@ class ComposerAutoloaderInit59c7b20d3f201de5581a0bc09b6c2289 require __DIR__ . '/platform_check.php'; - spl_autoload_register(array('ComposerAutoloaderInit59c7b20d3f201de5581a0bc09b6c2289', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); - spl_autoload_unregister(array('ComposerAutoloaderInit59c7b20d3f201de5581a0bc09b6c2289', 'loadClassLoader')); + spl_autoload_register(array('ComposerAutoloaderInitfe47e554dced83cd1f1961109287683e', 'loadClassLoader'), true, true); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); + spl_autoload_unregister(array('ComposerAutoloaderInitfe47e554dced83cd1f1961109287683e', 'loadClassLoader')); - require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit59c7b20d3f201de5581a0bc09b6c2289::getInitializer($loader)); + $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInitfe47e554dced83cd1f1961109287683e::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } $loader->register(true); diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 04f4f08..9972558 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInit59c7b20d3f201de5581a0bc09b6c2289 +class ComposerStaticInitfe47e554dced83cd1f1961109287683e { public static $prefixLengthsPsr4 = array ( 'C' => @@ -129,9 +129,9 @@ class ComposerStaticInit59c7b20d3f201de5581a0bc09b6c2289 public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit59c7b20d3f201de5581a0bc09b6c2289::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit59c7b20d3f201de5581a0bc09b6c2289::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInit59c7b20d3f201de5581a0bc09b6c2289::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInitfe47e554dced83cd1f1961109287683e::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitfe47e554dced83cd1f1961109287683e::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInitfe47e554dced83cd1f1961109287683e::$classMap; }, null, ClassLoader::class); } diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 896edf6..b187f19 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -156,17 +156,17 @@ }, { "name": "woocommerce/subscriptions-core", - "version": "6.4.0", - "version_normalized": "6.4.0.0", + "version": "6.5.0", + "version_normalized": "6.5.0.0", "source": { "type": "git", "url": "https://github.com/Automattic/woocommerce-subscriptions-core.git", - "reference": "a94c9aab6d47f32461974ed09a4d3cad590f25b0" + "reference": "19ca9b7cf2b48cba4abd6ecf811475382b9d6673" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/a94c9aab6d47f32461974ed09a4d3cad590f25b0", - "reference": "a94c9aab6d47f32461974ed09a4d3cad590f25b0", + "url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/19ca9b7cf2b48cba4abd6ecf811475382b9d6673", + "reference": "19ca9b7cf2b48cba4abd6ecf811475382b9d6673", "shasum": "" }, "require": { @@ -177,9 +177,9 @@ "dave-liddament/sarb": "^1.1", "phpunit/phpunit": "9.5.14", "woocommerce/woocommerce-sniffs": "0.1.0", - "yoast/phpunit-polyfills": "1.0.3" + "yoast/phpunit-polyfills": "1.1.0" }, - "time": "2023-10-18T03:32:50+00:00", + "time": "2023-11-09T04:27:49+00:00", "type": "wordpress-plugin", "extra": { "phpcodesniffer-search-depth": 2 @@ -209,7 +209,7 @@ "description": "Sell products and services with recurring payments in your WooCommerce Store.", "homepage": "https://github.com/Automattic/woocommerce-subscriptions-core", "support": { - "source": "https://github.com/Automattic/woocommerce-subscriptions-core/tree/6.4.0", + "source": "https://github.com/Automattic/woocommerce-subscriptions-core/tree/6.5.0", "issues": "https://github.com/Automattic/woocommerce-subscriptions-core/issues" }, "install-path": "../woocommerce/subscriptions-core" diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index e2b887e..8b2317c 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -1,22 +1,22 @@ array( - 'name' => 'woocommerce/woocommerce-subscriptions', - 'pretty_version' => 'dev-release/5.6.0', - 'version' => 'dev-release/5.6.0', - 'reference' => '434da4e19c4fde75e431338fa82595320bd5b6c1', + 'pretty_version' => 'dev-release/5.7.0', + 'version' => 'dev-release/5.7.0', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), + 'reference' => '05388f52bd8a4479997a2672e130fb44de3548f4', + 'name' => 'woocommerce/woocommerce-subscriptions', 'dev' => false, ), 'versions' => array( 'composer/installers' => array( 'pretty_version' => 'v1.12.0', 'version' => '1.12.0.0', - 'reference' => 'd20a64ed3c94748397ff5973488761b22f6d3f19', 'type' => 'composer-plugin', 'install_path' => __DIR__ . '/./installers', 'aliases' => array(), + 'reference' => 'd20a64ed3c94748397ff5973488761b22f6d3f19', 'dev_requirement' => false, ), 'roundcube/plugin-installer' => array( @@ -32,21 +32,21 @@ ), ), 'woocommerce/subscriptions-core' => array( - 'pretty_version' => '6.4.0', - 'version' => '6.4.0.0', - 'reference' => 'a94c9aab6d47f32461974ed09a4d3cad590f25b0', + 'pretty_version' => '6.5.0', + 'version' => '6.5.0.0', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../woocommerce/subscriptions-core', 'aliases' => array(), + 'reference' => '19ca9b7cf2b48cba4abd6ecf811475382b9d6673', 'dev_requirement' => false, ), 'woocommerce/woocommerce-subscriptions' => array( - 'pretty_version' => 'dev-release/5.6.0', - 'version' => 'dev-release/5.6.0', - 'reference' => '434da4e19c4fde75e431338fa82595320bd5b6c1', + 'pretty_version' => 'dev-release/5.7.0', + 'version' => 'dev-release/5.7.0', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), + 'reference' => '05388f52bd8a4479997a2672e130fb44de3548f4', 'dev_requirement' => false, ), ), diff --git a/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-subscription.js b/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-subscription.js index 95a5cbf..fc61749 100644 --- a/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-subscription.js +++ b/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-subscription.js @@ -351,4 +351,17 @@ jQuery( function ( $ ) { ); } } ); + + /** + * When the auto-renewal is toggled on or off, show or hide the chosen payment methods meta fields. + */ + $( '#wc-subscription-auto-renew' ).on( 'change', function() { + var $payment_method_meta_elements = $( '#wcs_' + $( '#_payment_method' ).val() + '_fields' ); + + if ( $( this ).is( ':checked' ) ) { + $payment_method_meta_elements.fadeIn(); + } else { + $payment_method_meta_elements.fadeOut(); + } + } ); } ); diff --git a/vendor/woocommerce/subscriptions-core/changelog.txt b/vendor/woocommerce/subscriptions-core/changelog.txt index eb0d465..ae4cd03 100644 --- a/vendor/woocommerce/subscriptions-core/changelog.txt +++ b/vendor/woocommerce/subscriptions-core/changelog.txt @@ -1,5 +1,14 @@ *** WooCommerce Subscriptions Core Changelog *** += 6.5.0 - 2023-11-09 = +* Add - When a customer toggles automatic renewals on or off via their My Account page, add a note to the subscription to record that event. +* Fix - When a subscription is flagged as requiring manual payments, allow admin users to turn on automatic payments for a subscription via the Edit Subscription page by selecting a new payment method. +* Fix - When processing an early renewal order, make sure the suspension count is reset back to 0 on payment complete. +* Fix - Ensure proper backfilling of subscription metadata (i.e. dates and cache) to the postmeta table when HPOS is enabled and compatibility mode (data syncing) is turned on. +* Fix - Fetch and update the `_cancelled_email_sent` meta in a HPOS compatibile way. +* Dev - Introduce a new wcs_get_subscription_grouping_key() function to generate a unique key for a subscription based on its billing schedule. This function uses the existing recurring cart key concept. +* Dev - Deprecate the WC_Subscriptions_Synchroniser::add_to_recurring_cart_key(). Use WC_Subscriptions_Synchroniser::add_to_recurring_product_grouping_key() instead. + = 6.4.0 - 2023-10-18 = * Add - Use admin theme color and the correct WooCommerce colors. * Fix - Resolve an issue that would cause 3rd party plugin edit product fields with the show_if_variable-subscription class to be incorrectly hidden. diff --git a/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php b/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php index 21acd95..ece838f 100644 --- a/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php +++ b/vendor/woocommerce/subscriptions-core/includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php @@ -185,7 +185,7 @@ class WCS_Meta_Box_Subscription_Data extends WC_Meta_Box_Order_Data { echo '

' . esc_html( $field['label'] ) . ': ' . wp_kses_post( make_clickable( esc_html( $field_value ) ) ) . '

'; } - echo 'get_payment_method() ) ? ' class="' . esc_attr( $subscription->get_payment_method() ) . '"' : '' ) . '>' . esc_html__( 'Payment Method', 'woocommerce-subscriptions' ) . ':' . wp_kses_post( nl2br( $subscription->get_payment_method_to_display() ) ); // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison + echo 'get_payment_method() ) ? ' class="' . esc_attr( $subscription->get_payment_method() ) . '"' : '' ) . '>' . esc_html__( 'Payment method', 'woocommerce-subscriptions' ) . ':' . wp_kses_post( nl2br( $subscription->get_payment_method_to_display() ) ); // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison // Display help tip if ( '' != $subscription->get_payment_method() && ! $subscription->is_manual() ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php index 56c423f..5c29a61 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscription.php @@ -1778,7 +1778,12 @@ class WC_Subscription extends WC_Order { // Add order note depending on initial payment $this->add_order_note( __( 'Payment status marked complete.', 'woocommerce-subscriptions' ) ); - $this->update_status( 'active' ); // also saves the subscription + // $this->update_status() only calls save if the status has changed. + if ( 'active' !== $this->get_status( 'edit' ) ) { + $this->update_status( 'active' ); + } else { + $this->save(); + } do_action( 'woocommerce_subscription_payment_complete', $this ); 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 aea97ce..6212a7b 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-cart.php @@ -1022,59 +1022,12 @@ class WC_Subscriptions_Cart { * Subscriptions groups products by billing schedule when calculating cart totals, so that shipping and other "per order" amounts * can be calculated for each group of items for each renewal. This method constructs a cart key based on the billing schedule * to allow products on the same billing schedule to be grouped together - free trials and synchronisation is accounted for by - * using the first renewal date (if any) for the susbcription. + * using the first renewal date (if any) for the subscription. * * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function get_recurring_cart_key( $cart_item, $renewal_time = '' ) { - - $cart_key = ''; - - $product = $cart_item['data']; - $renewal_time = ! empty( $renewal_time ) ? $renewal_time : WC_Subscriptions_Product::get_first_renewal_payment_time( $product ); - $interval = WC_Subscriptions_Product::get_interval( $product ); - $period = WC_Subscriptions_Product::get_period( $product ); - $length = WC_Subscriptions_Product::get_length( $product ); - $trial_period = WC_Subscriptions_Product::get_trial_period( $product ); - $trial_length = WC_Subscriptions_Product::get_trial_length( $product ); - - if ( $renewal_time > 0 ) { - $cart_key .= gmdate( 'Y_m_d_', $renewal_time ); - } - - // First start with the billing interval and period - switch ( $interval ) { - case 1: - if ( 'day' == $period ) { - $cart_key .= 'daily'; // always gotta be one exception - } else { - $cart_key .= sprintf( '%sly', $period ); - } - break; - case 2: - $cart_key .= sprintf( 'every_2nd_%s', $period ); - break; - case 3: - $cart_key .= sprintf( 'every_3rd_%s', $period ); // or sometimes two exceptions it would seem - break; - default: - $cart_key .= sprintf( 'every_%dth_%s', $interval, $period ); - break; - } - - if ( $length > 0 ) { - $cart_key .= '_for_'; - $cart_key .= sprintf( '%d_%s', $length, $period ); - if ( $length > 1 ) { - $cart_key .= 's'; - } - } - - if ( $trial_length > 0 ) { - $cart_key .= sprintf( '_after_a_%d_%s_trial', $trial_length, $trial_period ); - } - - return apply_filters( 'woocommerce_subscriptions_recurring_cart_key', $cart_key, $cart_item ); + return apply_filters( 'woocommerce_subscriptions_recurring_cart_key', wcs_get_subscription_grouping_key( $cart_item['data'], $renewal_time ), $cart_item ); } /** 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 80adb87..3f2bb93 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-core-plugin.php @@ -16,7 +16,7 @@ class WC_Subscriptions_Core_Plugin { * The version of subscriptions-core library. * @var string */ - protected $library_version = '6.4.0'; // WRCS: DEFINED_VERSION. + protected $library_version = '6.5.0'; // WRCS: DEFINED_VERSION. /** * The subscription scheduler instance. 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 77d42e3..7a72f93 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-email.php @@ -110,7 +110,7 @@ class WC_Subscriptions_Email { public static function send_cancelled_email( $subscription ) { WC()->mailer(); - if ( $subscription->has_status( array( 'pending-cancel', 'cancelled' ) ) && 'true' !== get_post_meta( $subscription->get_id(), '_cancelled_email_sent', true ) ) { + if ( $subscription->has_status( array( 'pending-cancel', 'cancelled' ) ) && 'true' !== $subscription->get_cancelled_email_sent() ) { do_action( 'cancelled_subscription_notification', $subscription ); } } diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php index a9c785e..eea9c2b 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wc-subscriptions-synchroniser.php @@ -112,7 +112,8 @@ class WC_Subscriptions_Synchroniser { // If it's an initial sync order and the total is zero, and nothing needs to be shipped, do not reduce stock add_filter( 'woocommerce_order_item_quantity', __CLASS__ . '::maybe_do_not_reduce_stock', 10, 3 ); - add_filter( 'woocommerce_subscriptions_recurring_cart_key', __CLASS__ . '::add_to_recurring_cart_key', 10, 2 ); + add_filter( 'woocommerce_subscriptions_recurring_cart_key', __CLASS__ . '::add_to_recurring_product_grouping_key', 10, 2 ); + add_filter( 'woocommerce_subscriptions_item_grouping_key', __CLASS__ . '::add_to_recurring_product_grouping_key', 10, 2 ); // Add defaults for our options. add_filter( 'default_option_' . self::$setting_id_days_no_fee, array( __CLASS__, 'option_default' ), 10, 3 ); @@ -1207,18 +1208,27 @@ class WC_Subscriptions_Synchroniser { } /** - * If the cart item is synced, add a '_synced' string to the recurring cart key. + * Alters the subscription grouping key to ensure synced products are grouped separately. * - * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 + * @param string $key The subscription product's grouping key. + * @param array|WC_Order_Item_Product $item The cart item or order item that the key is being generated for. + * + * @return string The subscription product grouping key with a synced product flag if the product is synced. */ - public static function add_to_recurring_cart_key( $cart_key, $cart_item ) { - $product = $cart_item['data']; + public static function add_to_recurring_product_grouping_key( $key, $item ) { + $product = false; - if ( false === strpos( $cart_key, '_synced' ) && self::is_product_synced( $product ) ) { - $cart_key .= '_synced'; + if ( is_a( $item, 'WC_Order_Item_Product' ) ) { + $product = $item->get_product(); + } elseif ( is_array( $item ) && isset( $item['data'] ) ) { + $product = $item['data']; } - return $cart_key; + if ( $product && false === strpos( $key, '_synced' ) && self::is_product_synced( $product ) ) { + $key .= '_synced'; + } + + return $key; } /** @@ -1591,4 +1601,19 @@ class WC_Subscriptions_Synchroniser { return $end_date; } + /** + * Alters the recurring cart item key to ensure synced products are grouped separately. + * + * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 + * @deprecated 6.5.0 + * + * @param string $cart_key The recurring cart item key. + * @param array $cart_item The cart item's data. + * + * @return string The cart item recurring cart key with a synced product flag if the product is synced. + */ + public static function add_to_recurring_cart_key( $cart_key, $cart_item ) { + wcs_deprecated_function( __METHOD__, '6.5.0', __CLASS__ . '::add_to_recurring_product_grouping_key' ); + return self::add_to_recurring_product_grouping_key( $cart_key, $cart_item ); + } } diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php index e20a1f2..290dd61 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-change-payment-method-admin.php @@ -18,7 +18,6 @@ class WCS_Change_Payment_Method_Admin { * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function display_fields( $subscription ) { - $payment_method = $subscription->get_payment_method(); $valid_payment_methods = self::get_valid_payment_methods( $subscription ); @@ -34,22 +33,18 @@ class WCS_Change_Payment_Method_Admin { echo '

'; if ( count( $valid_payment_methods ) > 1 ) { - - $found_method = false; - echo ''; + echo ''; echo ''; } elseif ( count( $valid_payment_methods ) == 1 ) { - echo '' . esc_html__( 'Payment Method', 'woocommerce-subscriptions' ) . ':
' . esc_html( current( $valid_payment_methods ) ); + echo '' . esc_html__( 'Payment method', 'woocommerce-subscriptions' ) . '
' . esc_html( current( $valid_payment_methods ) ); // translators: %s: gateway ID. echo wcs_help_tip( sprintf( _x( 'Gateway ID: [%s]', 'The gateway ID displayed on the Edit Subscriptions screen when editing payment method.', 'woocommerce-subscriptions' ), key( $valid_payment_methods ) ) ); echo ''; @@ -91,12 +86,10 @@ class WCS_Change_Payment_Method_Admin { } echo ''; - } } wp_nonce_field( 'wcs_change_payment_method_admin', '_wcsnonce' ); - } /** @@ -149,6 +142,13 @@ class WCS_Change_Payment_Method_Admin { // Update the payment method for manual only if it has changed. if ( ! $subscription->is_manual() || 'manual' !== $payment_method ) { + // If the subscription is being changed away from manual and it is flagged as requiring manual payments turn on automatic renewals. + if ( 'manual' !== $payment_method && $subscription->get_requires_manual_renewal() && ! wcs_is_manual_renewal_required() && $payment_gateway->supports( 'subscriptions' ) ) { + $subscription->set_requires_manual_renewal( false ); + // Translators: Placeholder is the payment gateway title. + $subscription->add_order_note( sprintf( __( 'Admin turned on automatic renewals by changing payment method to "%s" via the Edit Subscription screen.', 'woocommerce-subscriptions' ), $payment_gateway->get_title() ), false, true ); + } + $subscription->set_payment_method( $payment_gateway, $payment_method_meta ); $subscription->save(); } diff --git a/vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php b/vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php index 8fd707f..48c7a1c 100644 --- a/vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php +++ b/vendor/woocommerce/subscriptions-core/includes/class-wcs-my-account-auto-renew-toggle.php @@ -98,6 +98,7 @@ class WCS_My_Account_Auto_Renew_Toggle { if ( $subscription && self::can_user_toggle_auto_renewal( $subscription ) ) { $subscription->set_requires_manual_renewal( true ); + $subscription->add_order_note( __( 'Customer turned off automatic renewals via their My Account page.', 'woocommerce-subscriptions' ) ); $subscription->save(); self::send_ajax_response( $subscription ); @@ -122,6 +123,7 @@ class WCS_My_Account_Auto_Renew_Toggle { if ( wc_get_payment_gateway_by_order( $subscription ) && self::can_user_toggle_auto_renewal( $subscription ) ) { $subscription->set_requires_manual_renewal( false ); + $subscription->add_order_note( __( 'Customer turned on automatic renewals via their My Account page.', 'woocommerce-subscriptions' ) ); $subscription->save(); self::send_ajax_response( $subscription ); 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 666ed7c..13ba0ff 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 @@ -882,4 +882,112 @@ class WCS_Orders_Table_Subscription_Data_Store extends \Automattic\WooCommerce\I return $results ? array_combine( array_column( $results, 'status' ), array_map( 'absint', array_column( $results, 'cnt' ) ) ) : array(); } + + /** + * Fetches the subscription's start date. + * This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB. + * + * @param \WC_Subscription $subscription Subscription object. + * + * @return string + */ + public function get_schedule_start( $subscription ) { + return $subscription->get_date( 'start' ); + } + + /** + * Fetches the subscription's trial end date. + * This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB. + * + * @param \WC_Subscription $subscription Subscription object. + * + * @return string + */ + public function get_schedule_trial_end( $subscription ) { + return $subscription->get_date( 'trial_end' ); + } + + /** + * Fetches the subscription's next payment date. + * This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB. + * + * @param \WC_Subscription $subscription Subscription object. + * + * @return string + */ + public function get_schedule_next_payment( $subscription ) { + return $subscription->get_date( 'next_payment' ); + } + + /** + * Fetches the subscription's cancelled date. + * This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB. + * + * @param \WC_Subscription $subscription Subscription object. + * + * @return string + */ + public function get_schedule_cancelled( $subscription ) { + return $subscription->get_date( 'cancelled' ); + } + + /** + * Fetches the subscription's end date. + * This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB. + * + * @param \WC_Subscription $subscription Subscription object. + * + * @return string + */ + public function get_schedule_end( $subscription ) { + return $subscription->get_date( 'end' ); + } + + /** + * Fetches the subscription's payment retry date. + * This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB. + * + * @param \WC_Subscription $subscription Subscription object. + * + * @return string + */ + public function get_schedule_payment_retry( $subscription ) { + return $subscription->get_date( 'payment_retry' ); + } + + /** + * Returns a list of subscriptions's renewal order IDs stored in cache meta. + * This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB. + * + * @param \WC_Subscription $subscription Subscription object. + * + * @return array + */ + public function get_renewal_order_ids_cache( $subscription ) { + return $subscription->get_meta( '_subscription_renewal_order_ids_cache' ); + } + + /** + * Returns a list of subscriptions's resubscribe order IDs stored in cache meta. + * This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB. + * + * @param \WC_Subscription $subscription Subscription object. + * + * @return array + */ + public function get_resubscribe_order_ids_cache( $subscription ) { + return $subscription->get_meta( '_subscription_resubscribe_order_ids_cache' ); + } + + /** + * Returns a list of subscriptions's switch order IDs stored in cache meta. + * This method is called by @see parent::backfill_post_record() when backfilling subscriptions details to WP_Post DB. + * + * @param \WC_Subscription $subscription Subscription object. + * + * @return array + */ + public function get_switch_order_ids_cache( $subscription ) { + return $subscription->get_meta( '_subscription_switch_order_ids_cache' ); + } } 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 ffa8414..5f3c57c 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 @@ -60,6 +60,23 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements '_subscription_switch_data' => 'switch_data', ); + /** + * Custom setters for subscription internal props in the form meta_key => set_|get_{value}. + * + * @var string[] + */ + protected $internal_data_store_key_getters = array( + '_schedule_start' => 'schedule_start', + '_schedule_trial_end' => 'schedule_trial_end', + '_schedule_next_payment' => 'schedule_next_payment', + '_schedule_cancelled' => 'schedule_cancelled', + '_schedule_end' => 'schedule_end', + '_schedule_payment_retry' => 'schedule_payment_retry', + '_subscription_renewal_order_ids_cache' => 'renewal_order_ids_cache', + '_subscription_resubscribe_order_ids_cache' => 'resubscribe_order_ids_cache', + '_subscription_switch_order_ids_cache' => 'switch_order_ids_cache', + ); + /** * Constructor. */ @@ -604,4 +621,146 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements public function get_subscriptions_count_by_status() { return (array) wp_count_posts( 'shop_subscription' ); } + + /** + * Sets the subscription's start date. + * + * This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record() + * when backfilling subscription data to the WP_Post database. + * + * @param WC_Subscription $subscription + * @param string $date + */ + public function set_schedule_start( $subscription, $date ) { + update_post_meta( $subscription->get_id(), '_schedule_start', $date ); + } + + /** + * Sets the subscription's trial end date. + * + * This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record() + * when backfilling subscription data to the WP_Post database. + * + * @param WC_Subscription $subscription + * @param string $date + */ + public function set_schedule_trial_end( $subscription, $date ) { + update_post_meta( $subscription->get_id(), '_schedule_trial_end', $date ); + } + + /** + * Sets the subscription's next payment date. + * + * This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record() + * when backfilling subscription data to the WP_Post database. + * + * @param WC_Subscription $subscription + * @param string $date + */ + public function set_schedule_next_payment( $subscription, $date ) { + update_post_meta( $subscription->get_id(), '_schedule_next_payment', $date ); + } + + /** + * Sets the subscription's cancelled date. + * + * This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record() + * when backfilling subscription data to the WP_Post database. + * + * @param WC_Subscription $subscription + * @param string $date + */ + public function set_schedule_cancelled( $subscription, $date ) { + update_post_meta( $subscription->get_id(), '_schedule_cancelled', $date ); + } + + /** + * Sets the subscription's end date. + * + * This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record() + * when backfilling subscription data to the WP_Post database. + * + * @param WC_Subscription $subscription + * @param string $date + */ + public function set_schedule_end( $subscription, $date ) { + update_post_meta( $subscription->get_id(), '_schedule_end', $date ); + } + + /** + * Sets the subscription's payment retry date. + * + * This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record() + * when backfilling subscription data to the WP_Post database. + * + * @param WC_Subscription $subscription + * @param string $date + */ + public function set_schedule_payment_retry( $subscription, $date ) { + update_post_meta( $subscription->get_id(), '_schedule_payment_retry', $date ); + } + + /** + * Manually sets the list of subscription's renewal order IDs stored in cache. + * + * This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record() + * when backfilling subscription data to the WP_Post database. + * + * @param WC_Subscription $subscription + * @param array $renewal_order_ids + */ + public function set_renewal_order_ids_cache( $subscription, $renewal_order_ids ) { + $this->cleanup_backfill_related_order_cache_duplicates( $subscription, 'renewal' ); + update_post_meta( $subscription->get_id(), '_subscription_renewal_order_ids_cache', $renewal_order_ids ); + } + + /** + * Manually sets the list of subscription's resubscribe order IDs stored in cache. + * + * This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record() + * when backfilling subscription data to the WP_Post database. + * + * @param WC_Subscription $subscription + * @param array $resubscribe_order_ids + */ + public function set_resubscribe_order_ids_cache( $subscription, $resubscribe_order_ids ) { + $this->cleanup_backfill_related_order_cache_duplicates( $subscription, 'resubscribe' ); + update_post_meta( $subscription->get_id(), '_subscription_resubscribe_order_ids_cache', $resubscribe_order_ids ); + } + + /** + * Manually sets the list of subscription's switch order IDs stored in cache. + * + * This method is not intended for public use and is called by @see OrdersTableDataStore::backfill_post_record() + * when backfilling subscription data to the WP_Post database. + * + * @param WC_Subscription $subscription + * @param array $switch_order_ids + */ + public function set_switch_order_ids_cache( $subscription, $switch_order_ids ) { + $this->cleanup_backfill_related_order_cache_duplicates( $subscription, 'switch' ); + update_post_meta( $subscription->get_id(), '_subscription_switch_order_ids_cache', $switch_order_ids ); + } + + /** + * Deletes a subscription's related order cache - including any duplicates. + * + * WC core between v8.1 and v8.4 would duplicate related order cache meta when backfilling the post record. This method deletes all + * instances of a order type cache (duplicates included). It is intended to be called before setting the cache manually. + * + * Note: this function assumes that the fix to WC (listed below) will be included in 8.4. If it's pushed back, this function will need to be updated, + * if it's brought forward to 8.3, it can be updated but is not strictly required. + * + * @see https://github.com/woocommerce/woocommerce/pull/41281 + * @see https://github.com/Automattic/woocommerce-subscriptions-core/pull/538 + * + * @param WC_Subscription $subscription The Subscription. + * @param string $relationship_type The type of subscription related order relationship to delete. One of: 'renewal', 'resubscribe', 'switch'. + */ + private function cleanup_backfill_related_order_cache_duplicates( $subscription, $relationship_type ) { + // Delete the related order cache on versions of WC after 8.1 but before 8.4. + if ( ! wcs_is_woocommerce_pre( '8.1' ) && wcs_is_woocommerce_pre( '8.4' ) ) { + delete_post_meta( $subscription->get_id(), "_subscription_{$relationship_type}_order_ids_cache" ); + } + } } 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 e4a181a..c076933 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 @@ -83,7 +83,9 @@ class WCS_Email_Cancelled_Subscription extends WC_Email { return; } - update_post_meta( $subscription->get_id(), '_cancelled_email_sent', 'true' ); + $subscription->set_cancelled_email_sent( 'true' ); + $subscription->save(); + $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() ); } diff --git a/vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php index c14eda8..15f5d28 100644 --- a/vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-order-functions.php @@ -979,3 +979,19 @@ function wcs_order_contains_early_renewal( $order ) { */ return apply_filters( 'woocommerce_subscriptions_is_early_renewal_order', $is_early_renewal, $order ); } + +/** + * Generates a key for grouping subscription products with the same billing schedule. + * + * Used by the orders//subscriptions REST API endpoint to group order items into subscriptions. + * + * @see https://woocommerce.com/document/subscriptions/develop/multiple-subscriptions/#section-3 + * + * @param WC_Order_Item_Product $item The order item to generate the key for. + * @param int $renewal_time The timestamp of the first renewal payment. + * + * @return string The item's subscription grouping key. + */ +function wcs_get_subscription_item_grouping_key( $item, $renewal_time = '' ) { + return apply_filters( 'woocommerce_subscriptions_item_grouping_key', wcs_get_subscription_grouping_key( $item->get_product(), $renewal_time ), $item ); +} diff --git a/vendor/woocommerce/subscriptions-core/includes/wcs-product-functions.php b/vendor/woocommerce/subscriptions-core/includes/wcs-product-functions.php index 81bb6ea..8156b08 100644 --- a/vendor/woocommerce/subscriptions-core/includes/wcs-product-functions.php +++ b/vendor/woocommerce/subscriptions-core/includes/wcs-product-functions.php @@ -437,3 +437,66 @@ function wcs_calculate_min_max_variations( $variations_data ) { 'identical' => $subscription_details_identical, ); } + +/** + * Generates a key for grouping subscription products with the same billing schedule. + * + * Used in a frontend cart and checkout context to group items by a recurring cart key for use in generating recurring carts. + * Used by the orders//subscriptions REST API endpoint to group order items into subscriptions. + * + * @see https://woocommerce.com/document/subscriptions/develop/multiple-subscriptions/#section-3 + * + * @param WC_Product $product The product to generate the key for. + * @param int $renewal_time The timestamp of the first renewal payment. + * + * @return string The subscription product grouping key. + */ +function wcs_get_subscription_grouping_key( $product, $renewal_time = 0 ) { + $key = ''; + + $renewal_time = ! empty( $renewal_time ) ? $renewal_time : WC_Subscriptions_Product::get_first_renewal_payment_time( $product ); + $interval = WC_Subscriptions_Product::get_interval( $product ); + $period = WC_Subscriptions_Product::get_period( $product ); + $length = WC_Subscriptions_Product::get_length( $product ); + $trial_period = WC_Subscriptions_Product::get_trial_period( $product ); + $trial_length = WC_Subscriptions_Product::get_trial_length( $product ); + + if ( $renewal_time > 0 ) { + $key .= gmdate( 'Y_m_d_', $renewal_time ); + } + + // First start with the billing interval and period. + switch ( $interval ) { + case 1: + if ( 'day' === $period ) { + $key .= 'daily'; + } else { + $key .= sprintf( '%sly', $period ); + } + break; + case 2: + $key .= sprintf( 'every_2nd_%s', $period ); + break; + case 3: + $key .= sprintf( 'every_3rd_%s', $period ); // or sometimes two exceptions it would seem + break; + default: + $key .= sprintf( 'every_%dth_%s', $interval, $period ); + break; + } + + if ( $length > 0 ) { + $key .= '_for_'; + $key .= sprintf( '%d_%s', $length, $period ); + + if ( $length > 1 ) { + $key .= 's'; + } + } + + if ( $trial_length > 0 ) { + $key .= sprintf( '_after_a_%d_%s_trial', $trial_length, $trial_period ); + } + + return apply_filters( 'wcs_subscription_product_grouping_key', $key, $product, $renewal_time ); +} diff --git a/vendor/woocommerce/subscriptions-core/woocommerce-subscriptions-core.php b/vendor/woocommerce/subscriptions-core/woocommerce-subscriptions-core.php index a342cb6..34e276e 100644 --- a/vendor/woocommerce/subscriptions-core/woocommerce-subscriptions-core.php +++ b/vendor/woocommerce/subscriptions-core/woocommerce-subscriptions-core.php @@ -6,5 +6,5 @@ * Author: Automattic * Author URI: https://woocommerce.com/ * Requires WP: 5.6 - * Version: 6.4.0 + * Version: 6.5.0 */ diff --git a/woocommerce-subscriptions.php b/woocommerce-subscriptions.php index 80b9bd8..e62bd55 100644 --- a/woocommerce-subscriptions.php +++ b/woocommerce-subscriptions.php @@ -5,7 +5,7 @@ * Description: Sell products and services with recurring payments in your WooCommerce Store. * Author: WooCommerce * Author URI: https://woocommerce.com/ - * Version: 5.6.0 + * Version: 5.7.0 * * WC requires at least: 7.7.0 * WC tested up to: 8.2.0 @@ -77,7 +77,7 @@ class WC_Subscriptions { public static $plugin_file = __FILE__; /** @var string */ - public static $version = '5.6.0'; // WRCS: DEFINED_VERSION. + public static $version = '5.7.0'; // WRCS: DEFINED_VERSION. /** @var string */ public static $wc_minimum_supported_version = '7.7';