diff --git a/changelog.txt b/changelog.txt index e1209c4..7cdabaa 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,44 @@ *** WooCommerce Subscriptions Changelog *** +2017.10.13 - version 2.2.13 +* Fix: Ensure wcs_get_subscriptions() returns the correct results when called with the 'customer_id' and 'product_id' arguments PR#2337 +* Fix: Always set the order key when manually creating subscriptions from the admin dashboard PR#2350 +* Fix: Delay granting download permissions until after the switch is complete - fixes missing download permissions after a switch PR#2339 +* Tweak: Display subscription IDs in date update exceptions PR#2342 +* Tweak: Cache the flag used to determine if subscriptions exist for a slight performance improvement PR#2360 +* Tweak: [WC3.2] Add support for applying subscription coupon types to subscriptions and orders via admin edit subscription/order screens PR#2371 + +2017.09.15 - version 2.2.12 +* Fix: Add missing argument number to filter for print_switch_link() - fixes PHP Warning: Missing argument 2 for WC_Subscriptions_Switcher::print_switch_link() PR#2266 +* Fix: Store decimal price values in dot separated format in the database PR#2242 +* Fix: Maintain backwards compatibility by triggering woocommerce_add_order_item_meta hooks when adding line items to a subscription from checkout PR#2267 +* Fix: PayPal RT: Fix rounding errors and undefined index notice PR#2216 +* Fix: Fix empty needle PHP notice when empty strings are returned from WC()->countries->inc_tax_or_vat() PR#1745 +* Fix: Ensure updated subscription billing and shipping names are searchable in admin subscriptions table PR#2278 +* Fix: Fix PayPal Standard cancellation IPN handling after paying for a failed PayPal Standard renewal order PR#2284 +* Fix: Add the billing interval to trial period expiration to fix issues with calculating Upcoming Recurring Revenue report data PR#2245 +* Fix: Allow payment on a subscription's most recent order for all order types not just renewal and/or parent orders PR#2295 +* Fix: Ensure switch cart items form a separate recurring cart - switch items are processed through the checkout separately so should have separate recurring carts PR#2313 +* Fix: [API] Save the subscription object before updating the dates PR#2308 +* Fix: Fix the including of the WCS_Report_Dashboard class to ensure it's only included once PR#2300 +* Fix: Never trigger gateway renewal payment hook on a subscription with an ended status PR#2318 +* Fix: Only get parent order where a parent id exists PR#2322 +* Fix: Set switch order item legacy values property correctly PR#2329 +* Fix: Don't throw exception when an old PayPal Standard is suspended after a switch PR#2335 +* Fix: Don't duplicate download permissions by checking for pre-existing download permissions on subscription when new download files are added to a product PR#2317 +* Fix: Make WCS options translatable PR#2302 +* Fix: Add wcs_update_order_item_type() to fix all the order item type change issues PR#2338 +* Fix: Only display/add shipping if the recurring cart needs shipping PR#2269 +* Tweak: Add a link to the wcs-ipn-failures log file on the failed IPN admin notice PR#2321 +* Tweak: Update subscriptions shortcode PR#2306 +* Tweak: Group payment method meta in subscription billing metabox by gateway ID PR#2305 +* Tweak: Disable subscription report caching after errors PR#2297 +* Tweak: Permanently delete subscriptions when an order is deleted PR#2288 +* Tweak: Add wcs_renewal_order_payment_update_date_created filter PR#2289 +* Tweak: Update WooCommerce.com support form links PR#2291 +* Tweak: Refactor WC_Subscriptions_Manager::prepare_renewal() and add process_renewal() PR#2280 +* Tweak: Apply Select2 to country fields on Edit Subscription screen PR#1745 + 2017.08.01 - version 2.2.11 * Fix: Do not save subscription product meta data on other post types, including WooCommerce Tab Manager and Jetpack post types. PR#2203 * Fix: Do not apply 'woocommerce_get_price' or 'woocommerce_product_get_price' filters to tax inclusive/exclusive prices to avoid ever applying them twice or to non price prices, like sign-up fees. Introduced in Subscriptions v2.2.5. PR#2261 @@ -450,7 +489,7 @@ 2015.12.16 - version 2.0.7 * New: Add a payment gateway filter to the dashboard admin subscriptions table * New: Implement soft caching for get_related_orders() -* Tweak: Better "Name Your Price" extension switching compatibility +* Tweak: Better "Name Your Price" extension switching compatibility * Tweak: Trash a user's subscriptions when a user is deleted * Tweak: Limit the `wcs_do_subscriptions_exist()` query to 1 result * Tweak: Mention subscription string methods in code comments/doc to help avoid some confusion @@ -478,7 +517,7 @@ * Fix: Add the correct `subscription_switch` meta to all subscription switches when there are multiple switches in the same order * Fix: Allow autocomplete of orders that have multiple switches in the same order. Fixes an issue where switch emails were not being sent when multiple switched items were processed in the same order * Fix: Adjust logic around switch label so that switching to $0 per period displays "Downgrade". Fixes an issue where "Crossgrade" was incorrectly displayed when downgrading to $0 per period - * Fix: Don't initiate auto-switch when a subscription needs payment + * Fix: Don't initiate auto-switch when a subscription needs payment * Fix: Use the 'wc-pending' status rather than 'pending' (default WordPress) status when manually creating a subscription. Fixes an issue with display of pending subscriptions on the admin subscription list table * Fix: Replace use of `__DIR__` with `dirname( __FILE__ )` to maintain compatibility with PHP 5.2.4 * Fix: Fix the logic checking for sync day in future by comparing the full date not just the day then the month/year if that day is after the current day. This ensures we don't see a day in the future with a month and year in the past or same as today as being a date in the future diff --git a/includes/admin/class-wc-subscriptions-admin.php b/includes/admin/class-wc-subscriptions-admin.php index 6287ac2..58fede2 100644 --- a/includes/admin/class-wc-subscriptions-admin.php +++ b/includes/admin/class-wc-subscriptions-admin.php @@ -210,7 +210,7 @@ class WC_Subscriptions_Admin { ?>

- +

- + +

+ '; @@ -250,45 +259,48 @@ class WCS_Meta_Box_Subscription_Data extends WC_Meta_Box_Order_Data { /** * Save meta box data + * + * @param int $post_id + * @param WP_Post $post */ - public static function save( $post_id, $post = '' ) { - global $wpdb; - + public static function save( $post_id, $post = null ) { if ( 'shop_subscription' != $post->post_type || empty( $_POST['woocommerce_meta_nonce'] ) || ! wp_verify_nonce( $_POST['woocommerce_meta_nonce'], 'woocommerce_save_data' ) ) { return; } self::init_address_fields(); - // Add key - add_post_meta( $post_id, '_order_key', uniqid( 'order_' ), true ); + // Get subscription object. + $subscription = wcs_get_subscription( $post_id ); + + // Ensure there is an order key. + if ( ! $subscription->get_order_key() ) { + $key = 'wc_' . apply_filters( 'woocommerce_generate_order_key', uniqid( 'order_' ) ); + wcs_set_objects_property( $subscription, 'order_key', $key ); + } // Update meta update_post_meta( $post_id, '_customer_user', absint( $_POST['customer_user'] ) ); - if ( self::$billing_fields ) { - foreach ( self::$billing_fields as $key => $field ) { - - if ( ! isset( $_POST[ '_billing_' . $key ] ) ) { - continue; - } - - update_post_meta( $post_id, '_billing_' . $key, wc_clean( $_POST[ '_billing_' . $key ] ) ); + // Handle the billing fields. + foreach ( self::$billing_fields as $key => $field ) { + $prefixed_key = "_billing_{$key}"; + if ( ! isset( $_POST[ $prefixed_key ] ) ) { + continue; } + + wcs_set_objects_property( $subscription, $prefixed_key, wc_clean( $_POST[ $prefixed_key ] ) ); } - if ( self::$shipping_fields ) { - foreach ( self::$shipping_fields as $key => $field ) { - - if ( ! isset( $_POST[ '_shipping_' . $key ] ) ) { - continue; - } - - update_post_meta( $post_id, '_shipping_' . $key, wc_clean( $_POST[ '_shipping_' . $key ] ) ); + // Handle the shipping fields. + foreach ( self::$shipping_fields as $key => $field ) { + $prefixed_key = "_shipping_{$key}"; + if ( ! isset( $_POST[ $prefixed_key ] ) ) { + continue; } - } - $subscription = wcs_get_subscription( $post_id ); + wcs_set_objects_property( $subscription, $prefixed_key, wc_clean( $_POST[ $prefixed_key ] ) ); + } try { WCS_Change_Payment_Method_Admin::save_meta( $subscription ); @@ -305,5 +317,4 @@ class WCS_Meta_Box_Subscription_Data extends WC_Meta_Box_Order_Data { do_action( 'woocommerce_process_shop_subscription_meta', $post_id, $post ); } - } diff --git a/includes/admin/reports/class-wcs-report-cache-manager.php b/includes/admin/reports/class-wcs-report-cache-manager.php index 1e37876..53caad1 100644 --- a/includes/admin/reports/class-wcs-report-cache-manager.php +++ b/includes/admin/reports/class-wcs-report-cache-manager.php @@ -73,7 +73,6 @@ class WCS_Report_Cache_Manager { * Attach callbacks to manage cache updates * * @since 2.1 - * @return null */ public function __construct() { @@ -101,6 +100,9 @@ class WCS_Report_Cache_Manager { // Notify store owners that report data can be out-of-date add_action( 'admin_notices', array( $this, 'admin_notices' ), 0 ); + + // Add system status information. + add_filter( 'wcs_system_status', array( $this, 'add_system_status_info' ) ); } /** @@ -131,7 +133,6 @@ class WCS_Report_Cache_Manager { * @see $this->set_reports_to_update(). * * @since 2.1 - * @return null */ public function schedule_cache_updates() { @@ -185,6 +186,15 @@ class WCS_Report_Cache_Manager { * @return null */ public function update_cache( $report_class ) { + /** + * Filter whether Report Cache Updates are enabled. + * + * @param bool $enabled Whether report updates are enabled. + * @param string $report_class The report class to use. + */ + if ( ! apply_filters( 'wcs_report_cache_updates_enabled', 'yes' === get_option( 'woocommerce_subscriptions_cache_updates_enabled', 'yes' ), $report_class ) ) { + return; + } // Validate the report class $valid_report_class = false; @@ -200,6 +210,9 @@ class WCS_Report_Cache_Manager { return; } + // Hook our error catcher. + add_action( 'shutdown', array( $this, 'catch_unexpected_shutdown' ) ); + // Load report class dependencies require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' ); require_once( WC()->plugin_path() . '/includes/admin/reports/class-wc-admin-report.php' ); @@ -226,6 +239,9 @@ class WCS_Report_Cache_Manager { $report->get_data( array( 'no_cache' => true ) ); } } + + // Remove our error catcher. + remove_action( 'shutdown', array( $this, 'catch_unexpected_shutdown' ) ); } /** @@ -274,5 +290,68 @@ class WCS_Report_Cache_Manager { wcs_add_admin_notice( __( 'Please note: data for this report is cached. The data displayed may be out of date by up to 24 hours. The cache is updated each morning at 4am in your site\'s timezone.', 'woocommerce-subscriptions' ) ); } } + + /** + * Handle error instances that lead to an unexpected shutdown. + * + * This attempts to detect if there was an error, and proactively prevent errors + * from piling up. + * + * @author Jeremy Pry + */ + public function catch_unexpected_shutdown() { + $error = error_get_last(); + if ( null === $error || ! isset( $error['type'] ) ) { + return; + } + + // Check for the error types that matter to us. + if ( $error['type'] & ( E_ERROR | E_PARSE | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR ) ) { + $failures = get_option( 'woocommerce_subscriptions_cache_updates_failures', 0 ); + $failures++; + update_option( 'woocommerce_subscriptions_cache_updates_failures', $failures, false ); + + /** + * Filter the allowed number of detected failures before we turn off cache updates. + * + * @param int $threshold The failure count threshold. + */ + if ( $failures > apply_filters( 'woocommerce_subscriptions_cache_updates_failures_threshold', 2 ) ) { + update_option( 'woocommerce_subscriptions_cache_updates_enabled', 'no', false ); + } + } + } + + /** + * Add system status information to include failure count and cache update status. + * + * @author Jeremy Pry + * + * @param array $data Existing status data. + * + * @return array Filtered status data. + */ + public function add_system_status_info( $data ) { + $cache_enabled = ( 'yes' === get_option( 'woocommerce_subscriptions_cache_updates_enabled', 'yes' ) ); + $failures = get_option( 'woocommerce_subscriptions_cache_updates_failures', 0 ); + $new_data = array( + 'wcs_report_cache_enabled' => array( + 'name' => _x( 'Report Cache Enabled', 'Whether the Report Cache has been enabled', 'woocommerce-subscriptions' ), + 'note' => $cache_enabled ? __( 'Yes', 'woocommerce-subscriptions' ) : __( 'No', 'woocommerce-subscriptions' ), + 'success' => $cache_enabled, + ), + 'wcs_cache_update_failures' => array( + 'name' => __( 'Cache Update Failures', 'woocommerce-subscriptions' ), + /* translators: %d refers to the number of times we have detected cache update failures */ + 'note' => sprintf( _n( '%d failures', '%d failure', $failures, 'woocommerce-subscriptions' ), $failures ), + 'success' => 0 === $failures, + ), + ); + + $data = array_merge( $data, $new_data ); + + return $data; + } } + return new WCS_Report_Cache_Manager(); diff --git a/includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php b/includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php index 6bb2a8f..c1dfab0 100644 --- a/includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php +++ b/includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php @@ -46,13 +46,18 @@ class WC_Report_Upcoming_Recurring_Revenue extends WC_Admin_Report { $next_payment_timestamp = strtotime( $r->scheduled_date ); + //Remove the time part of the end date, if there is one + if ( '0' !== $scheduled_ends[ $key ] ) { + $scheduled_ends[ $key ] = date( 'Y-m-d', strtotime( $scheduled_ends[ $key ] ) ); + } + // Keep calculating all the new payments until we hit the end date of the search do { $next_payment_timestamp = wcs_add_time( $billing_intervals[ $key ], $billing_periods[ $key ], $next_payment_timestamp ); // If there are more renewals add them to the existing object or create a new one - if ( $next_payment_timestamp <= $this->end_date && isset( $scheduled_ends[ $key ] ) && ( 0 == $scheduled_ends[ $key ] || $next_payment_timestamp < strtotime( $scheduled_ends[ $key ] ) ) ) { + if ( $next_payment_timestamp < $this->end_date && isset( $scheduled_ends[ $key ] ) && ( 0 == $scheduled_ends[ $key ] || $next_payment_timestamp < strtotime( $scheduled_ends[ $key ] ) ) ) { $update_key = date( 'Y-m-d', $next_payment_timestamp ); if ( $next_payment_timestamp >= $this->start_date ) { @@ -69,7 +74,7 @@ class WC_Report_Upcoming_Recurring_Revenue extends WC_Admin_Report { $total_renewal_count += 1; } } - } while ( $next_payment_timestamp <= $this->end_date && isset( $scheduled_ends[ $key ] ) && ( 0 == $scheduled_ends[ $key ] || $next_payment_timestamp < strtotime( $scheduled_ends[ $key ] ) ) ); + } while ( $next_payment_timestamp < $this->end_date && isset( $scheduled_ends[ $key ] ) && ( 0 == $scheduled_ends[ $key ] || $next_payment_timestamp < strtotime( $scheduled_ends[ $key ] ) ) ); } } diff --git a/includes/api/class-wc-rest-subscriptions-controller.php b/includes/api/class-wc-rest-subscriptions-controller.php index 9aa749d..89a2bce 100644 --- a/includes/api/class-wc-rest-subscriptions-controller.php +++ b/includes/api/class-wc-rest-subscriptions-controller.php @@ -125,8 +125,6 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_V1_Controller { $subscription->set_total( wc_format_decimal( $request['order_total'], get_option( 'woocommerce_price_num_decimals' ) ) ); } - $subscription->save(); - // Store the post meta on the subscription after it's saved, this is to avoid compat. issue with the filters in WC_Subscriptions::set_payment_method_meta() expecting the $subscription to have an ID (therefore it needs to be called after the WC_Subscription has been saved) $payment_data = ( ! empty( $request['payment_details'] ) ) ? $request['payment_details'] : array(); if ( empty( $payment_data['payment_details']['method_id'] ) && ! empty( $request['payment_method'] ) ) { @@ -375,6 +373,8 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_V1_Controller { } } + $subscription->save(); + try { if ( ! empty( $dates_to_update ) ) { $subscription->update_dates( $dates_to_update ); diff --git a/includes/class-wc-subscription.php b/includes/class-wc-subscription.php index 6dc6171..90189a7 100644 --- a/includes/class-wc-subscription.php +++ b/includes/class-wc-subscription.php @@ -1285,7 +1285,7 @@ class WC_Subscription extends WC_Order { } if ( ! empty( $message ) ) { - throw new Exception( $message ); + throw new Exception( sprintf( __( 'Subscription #%d: ', 'woocommerce-subscriptions' ), $this->get_id() ) . $message ); } $this->set_date_prop( $date_type, 0 ); @@ -1789,10 +1789,17 @@ class WC_Subscription extends WC_Order { /** * Get parent order object. * - * @return WC_Order + * @return mixed WC_Order|bool */ public function get_parent() { - return wc_get_order( $this->get_parent_id() ); + $parent_id = $this->get_parent_id(); + $order = false; + + if ( $parent_id > 0 ) { + $order = wc_get_order( $parent_id ); + } + + return $order; } /** @@ -2335,7 +2342,7 @@ class WC_Subscription extends WC_Order { // Don't validate dates while the subscription is being read, only dates set outside of instantiation require the strict validation rules to apply if ( $this->object_read && ! empty( $messages ) ) { - throw new Exception( join( ' ', $messages ) ); + throw new Exception( sprintf( __( 'Subscription #%d: ', 'woocommerce-subscriptions' ), $this->get_id() ) . join( ' ', $messages ) ); } return array_merge( $dates, $delete_date_types ); @@ -2480,5 +2487,4 @@ class WC_Subscription extends WC_Order { return $datetime; } - } diff --git a/includes/class-wc-subscriptions-cart.php b/includes/class-wc-subscriptions-cart.php index f1ba565..1dfb8f9 100644 --- a/includes/class-wc-subscriptions-cart.php +++ b/includes/class-wc-subscriptions-cart.php @@ -400,9 +400,11 @@ class WC_Subscriptions_Cart { $needs_shipping = false; } } elseif ( 'recurring_total' == self::$calculation_type ) { - if ( true == $needs_shipping && ! self::cart_contains_subscriptions_needing_shipping() ) { + $cart = ( isset( self::$cached_recurring_cart ) ) ? self::$cached_recurring_cart : WC()->cart; + + if ( true == $needs_shipping && ! self::cart_contains_subscriptions_needing_shipping( $cart ) ) { $needs_shipping = false; - } elseif ( false == $needs_shipping && self::cart_contains_subscriptions_needing_shipping() ) { + } elseif ( false == $needs_shipping && self::cart_contains_subscriptions_needing_shipping( $cart ) ) { $needs_shipping = true; } } @@ -591,16 +593,20 @@ class WC_Subscriptions_Cart { * * @since 1.5.4 */ - public static function cart_contains_subscriptions_needing_shipping() { + public static function cart_contains_subscriptions_needing_shipping( $cart = null ) { if ( 'no' === get_option( 'woocommerce_calc_shipping' ) ) { return false; } + if ( null === $cart ) { + $cart = WC()->cart; + } + $cart_contains_subscriptions_needing_shipping = false; if ( self::cart_contains_subscription() ) { - foreach ( WC()->cart->cart_contents as $cart_item_key => $values ) { + foreach ( $cart->cart_contents as $cart_item_key => $values ) { $_product = $values['data']; if ( WC_Subscriptions_Product::is_subscription( $_product ) && $_product->needs_shipping() && false === WC_Subscriptions_Product::needs_one_time_shipping( $_product ) ) { $cart_contains_subscriptions_needing_shipping = true; @@ -690,10 +696,13 @@ class WC_Subscriptions_Cart { ) ); - if ( false !== strpos( $product_subtotal, WC()->countries->inc_tax_or_vat() ) ) { + $inc_tax_or_vat_string = WC()->countries->inc_tax_or_vat(); + $ex_tax_or_vat_string = WC()->countries->ex_tax_or_vat(); + + if ( ! empty( $inc_tax_or_vat_string ) && false !== strpos( $product_subtotal, $inc_tax_or_vat_string ) ) { $product_subtotal = str_replace( WC()->countries->inc_tax_or_vat(), '', $product_subtotal ) . ' ' . WC()->countries->inc_tax_or_vat() . ''; } - if ( false !== strpos( $product_subtotal, WC()->countries->ex_tax_or_vat() ) ) { + if ( ! empty( $ex_tax_or_vat_string ) && false !== strpos( $product_subtotal, $ex_tax_or_vat_string ) ) { $product_subtotal = str_replace( WC()->countries->ex_tax_or_vat(), '', $product_subtotal ) . ' ' . WC()->countries->ex_tax_or_vat() . ''; } diff --git a/includes/class-wc-subscriptions-checkout.php b/includes/class-wc-subscriptions-checkout.php index 200a5ef..960b916 100644 --- a/includes/class-wc-subscriptions-checkout.php +++ b/includes/class-wc-subscriptions-checkout.php @@ -352,8 +352,10 @@ class WC_Subscriptions_Checkout { // Allow plugins to add order item meta if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + do_action( 'woocommerce_add_order_item_meta', $item_id, $cart_item, $cart_item_key ); do_action( 'woocommerce_add_subscription_item_meta', $item_id, $cart_item, $cart_item_key ); } else { + wc_do_deprecated_action( 'woocommerce_add_order_item_meta', array( $item_id, $cart_item, $cart_item_key ), '3.0', 'CRUD and woocommerce_checkout_create_order_line_item action instead' ); wc_do_deprecated_action( 'woocommerce_add_subscription_item_meta', array( $item_id, $cart_item, $cart_item_key ), '3.0', 'CRUD and woocommerce_checkout_create_order_line_item action instead' ); } diff --git a/includes/class-wc-subscriptions-coupon.php b/includes/class-wc-subscriptions-coupon.php index bc304c9..37eca16 100644 --- a/includes/class-wc-subscriptions-coupon.php +++ b/includes/class-wc-subscriptions-coupon.php @@ -36,7 +36,7 @@ class WC_Subscriptions_Coupon { add_filter( 'woocommerce_coupon_get_discount_amount', __CLASS__ . '::get_discount_amount', 10, 5 ); // Validate subscription coupons - add_filter( 'woocommerce_coupon_is_valid', __CLASS__ . '::validate_subscription_coupon', 10, 2 ); + add_filter( 'woocommerce_coupon_is_valid', __CLASS__ . '::validate_subscription_coupon', 10, 3 ); // Remove coupons which don't apply to certain cart calculations add_action( 'woocommerce_before_calculate_totals', __CLASS__ . '::remove_coupons', 10 ); @@ -75,11 +75,33 @@ class WC_Subscriptions_Coupon { * * @since 2.0.10 */ - public static function get_discount_amount( $discount, $discounting_amount, $cart_item, $single, $coupon ) { + public static function get_discount_amount( $discount, $discounting_amount, $item, $single, $coupon ) { + + if ( is_a( $item, 'WC_Order_Item' ) ) { // WC 3.2 support for applying coupons to line items via admin edit subscription|order screen + $discount = self::get_discount_amount_for_line_item( $item, $discount, $discounting_amount, $single, $coupon ); + } else { + $discount = self::get_discount_amount_for_cart_item( $item, $discount, $discounting_amount, $single, $coupon ); + } + + return $discount; + } + + /** + * Get the discount amount which applies for a cart item for subscription coupon types + * + * @since 2.2.13 + * @param array $cart_item + * @param float $discount the original discount amount + * @param float $discounting_amount the cart item price/total which the coupon should apply to + * @param boolean $single True if discounting a single qty item, false if it's the line + * @param WC_Coupon $coupon + * @return float the discount amount which applies to the cart item + */ + public static function get_discount_amount_for_cart_item( $cart_item, $discount, $discounting_amount, $single, $coupon ) { $coupon_type = wcs_get_coupon_property( $coupon, 'discount_type' ); - // Only deal with subscriptions coupon types + // Only deal with subscriptions coupon types which apply to cart items if ( ! in_array( $coupon_type, array( 'recurring_fee', 'recurring_percent', 'sign_up_fee', 'sign_up_fee_percent', 'renewal_fee', 'renewal_percent', 'renewal_cart' ) ) ) { return $discount; } @@ -200,6 +222,50 @@ class WC_Subscriptions_Coupon { return $discount_amount; } + /** + * Get the discount amount which applies for a line item for subscription coupon types + * + * Uses methods and data structures introduced in WC 3.0. + * + * @since 2.2.13 + * @param WC_Order_Item $line_item + * @param float $discount the original discount amount + * @param float $discounting_amount the line item price/total + * @param boolean $single True if discounting a single qty item, false if it's the line + * @param WC_Coupon $coupon + * @return float the discount amount which applies to the line item + */ + public static function get_discount_amount_for_line_item( $line_item, $discount, $discounting_amount, $single, $coupon ) { + + if ( ! is_callable( array( $line_item, 'get_order' ) ) ) { + return $discount; + } + + $coupon_type = wcs_get_coupon_property( $coupon, 'discount_type' ); + $order = $line_item->get_order(); + $product = $line_item->get_product(); + + // Recurring coupons can be applied to subscriptions or any order which contains a subscription + if ( in_array( $coupon_type, array( 'recurring_fee', 'recurring_percent' ) ) && ( wcs_is_subscription( $order ) || wcs_order_contains_subscription( $order, 'any' ) ) ) { + if ( 'recurring_fee' === $coupon_type ) { + $discount = min( $coupon->get_amount(), $discounting_amount ); + $discount = $single ? $discount : $discount * $line_item->get_quantity(); + } else { // recurring_percent + $discount = (float) $coupon->get_amount() * ( $discounting_amount / 100 ); + } + // Sign-up fee coupons apply to parent order line items which are subscription products and have a signup fee + } elseif ( in_array( $coupon_type, array( 'sign_up_fee', 'sign_up_fee_percent' ) ) && WC_Subscriptions_Product::is_subscription( $product ) && wcs_order_contains_subscription( $order, 'parent' ) && 0 !== WC_Subscriptions_Product::get_sign_up_fee( $product ) ) { + if ( 'sign_up_fee' === $coupon_type ) { + $discount = min( $coupon->get_amount(), WC_Subscriptions_Product::get_sign_up_fee( $product ) ); + $discount = $single ? $discount : $discount * $line_item->get_quantity(); + } else { // sign_up_fee_percent + $discount = (float) $coupon->get_amount() * ( WC_Subscriptions_Product::get_sign_up_fee( $product ) / 100 ); + } + } + + return $discount; + } + /** * Determine if the cart contains a discount code of a given coupon type. * @@ -239,14 +305,46 @@ class WC_Subscriptions_Coupon { /** * Check if a subscription coupon is valid before applying * + * @param boolean $valid + * @param WC_Coupon $coupon + * @param WC_Discounts $discount Added in WC 3.2 the WC_Discounts object contains information about the coupon being applied to either carts or orders - Optional + * @return boolean Whether the coupon is valid or not * @since 1.2 */ - public static function validate_subscription_coupon( $valid, $coupon ) { + public static function validate_subscription_coupon( $valid, $coupon, $discount = null ) { if ( ! apply_filters( 'woocommerce_subscriptions_validate_coupon_type', true, $coupon, $valid ) ) { return $valid; } + if ( is_a( $discount, 'WC_Discounts' ) ) { // WC 3.2+ + $discount_items = $discount->get_items(); + + if ( is_array( $discount_items ) && ! empty( $discount_items ) ) { + $item = reset( $discount_items ); + + if ( isset( $item->object ) && is_a( $item->object, 'WC_Order_Item' ) ) { + $valid = self::validate_subscription_coupon_for_order( $valid, $coupon, $item->object->get_order() ); + } else { + $valid = self::validate_subscription_coupon_for_cart( $valid, $coupon ); + } + } + } else { + $valid = self::validate_subscription_coupon_for_cart( $valid, $coupon ); + } + + return $valid; + } + + /** + * Check if a subscription coupon is valid for the cart. + * + * @since 2.2.13 + * @param boolean $valid + * @param WC_Coupon $coupon + * @return bool whether the coupon is valid + */ + public static function validate_subscription_coupon_for_cart( $valid, $coupon ) { self::$coupon_error = ''; $coupon_type = wcs_get_coupon_property( $coupon, 'discount_type' ); @@ -289,6 +387,37 @@ class WC_Subscriptions_Coupon { return $valid; } + /** + * Check if a subscription coupon is valid for an order/subscription. + * + * @since 2.2.13 + * @param WC_Coupon $coupon The subscription coupon being validated. Can accept recurring_fee, recurring_percent, sign_up_fee or sign_up_fee_percent coupon types. + * @param WC_Order|WC_Subscription $order The order or subscription object to which the coupon is being applied + * @return bool whether the coupon is valid + */ + public static function validate_subscription_coupon_for_order( $valid, $coupon, $order ) { + $coupon_type = wcs_get_coupon_property( $coupon, 'discount_type' ); + $error_message = ''; + + // Recurring coupons can be applied to subscriptions and renewal orders + if ( in_array( $coupon_type, array( 'recurring_fee', 'recurring_percent' ) ) && ! ( wcs_is_subscription( $order ) || wcs_order_contains_subscription( $order, 'any' ) ) ) { + $error_message = __( 'Sorry, recurring coupons can only be applied to subscriptions or subscription orders.', 'woocommerce-subscriptions' ); + // Sign-up fee coupons can be applied to parent orders which contain subscription products with at least one sign up fee + } elseif ( in_array( $coupon_type, array( 'sign_up_fee', 'sign_up_fee_percent' ) ) && ! ( wcs_order_contains_subscription( $order, 'parent' ) || 0 !== WC_Subscriptions_Order::get_sign_up_fee( $order ) ) ) { + // translators: placeholder is coupon code + $error_message = sprintf( __( 'Sorry, "%s" can only be applied to subscription parent orders which contain a product with signup fees.', 'woocommerce-subscriptions' ), wcs_get_coupon_property( $coupon, 'code' ) ); + // Only recurring coupons can be applied to subscriptions + } elseif ( ! in_array( $coupon_type, array( 'recurring_fee', 'recurring_percent' ) ) && wcs_is_subscription( $order ) ) { + $error_message = __( 'Sorry, only recurring coupons can only be applied to subscriptions.', 'woocommerce-subscriptions' ); + } + + if ( ! empty( $error_message ) ) { + throw new Exception( $error_message ); + } + + return $valid; + } + /** * Returns a subscription coupon-specific error if validation failed * diff --git a/includes/class-wc-subscriptions-manager.php b/includes/class-wc-subscriptions-manager.php index 8edbcca..682f443 100644 --- a/includes/class-wc-subscriptions-manager.php +++ b/includes/class-wc-subscriptions-manager.php @@ -50,6 +50,9 @@ class WC_Subscriptions_Manager { // Order is trashed, trash subscription add_action( 'wp_trash_post', __CLASS__ . '::maybe_trash_subscription', 10 ); + // When order is deleted, delete the subscription. + add_action( 'before_delete_post', array( __CLASS__, 'maybe_delete_subscription' ) ); + // When a user is being deleted from the site, via standard WordPress functions, make sure their subscriptions are cancelled add_action( 'delete_user', __CLASS__ . '::trash_users_subscriptions' ); @@ -71,27 +74,40 @@ class WC_Subscriptions_Manager { /** * Sets up renewal for subscriptions managed by Subscriptions. * - * This function is hooked early on the scheduled subscription payment hook and will: - * - place the subscription on-hold - * - create a renewal order, with the pending status if it requires payment, or processing/complete - * if the recurring total is $0. + * This function is hooked early on the scheduled subscription payment hook. * * @param int $subscription_id The ID of a 'shop_subscription' post * @since 2.0 */ public static function prepare_renewal( $subscription_id ) { + $order_note = _x( 'Subscription renewal payment due:', 'used in order note as reason for why subscription status changed', 'woocommerce-subscriptions' ); + + $renewal_order = self::process_renewal( $subscription_id, 'active', $order_note ); + + // Backward compatibility with Subscriptions < 2.2.12 where we returned false for an unknown reason + if ( false === $renewal_order ) { + return $renewal_order; + } + } + + /** + * Process renewal for a subscription. + * + * @param int $subscription_id The ID of a 'shop_subscription' post + * @param string $required_status The subscription status required to process a renewal order + * @param string $order_note Reason for subscription status change + * @since 2.2.12 + */ + public static function process_renewal( $subscription_id, $required_status, $order_note ) { + $subscription = wcs_get_subscription( $subscription_id ); - if ( empty( $subscription ) || ! $subscription->has_status( 'active' ) ) { - return false; - } - // If the subscription is using manual payments, the gateway isn't active or it manages scheduled payments - if ( 0 == $subscription->get_total() || $subscription->is_manual() || '' == $subscription->get_payment_method() || ! $subscription->payment_method_supports( 'gateway_scheduled_payments' ) ) { + if ( ! empty( $subscription ) && $subscription->has_status( $required_status ) && ( 0 == $subscription->get_total() || $subscription->is_manual() || '' == $subscription->get_payment_method() || ! $subscription->payment_method_supports( 'gateway_scheduled_payments' ) ) ) { // Always put the subscription on hold in case something goes wrong while trying to process renewal - $subscription->update_status( 'on-hold', _x( 'Subscription renewal payment due:', 'used in order note as reason for why subscription status changed', 'woocommerce-subscriptions' ) ); + $subscription->update_status( 'on-hold', $order_note ); // Generate a renewal order for payment gateways to use to record the payment (and determine how much is due) $renewal_order = wcs_create_renewal_order( $subscription ); @@ -101,7 +117,7 @@ class WC_Subscriptions_Manager { $renewal_order = wcs_create_renewal_order( $subscription ); if ( is_wp_error( $renewal_order ) ) { - throw new Exception( __( 'Error: Unable to create renewal order from scheduled payment. Please try again.', 'woocommerce-subscriptions' ) ); + throw new Exception( sprintf( __( 'Error: Unable to create renewal order with note "%s"', 'woocommerce-subscriptions' ), $order_note ) ); } } @@ -123,7 +139,11 @@ class WC_Subscriptions_Manager { } } } + } else { + $renewal_order = false; } + + return $renewal_order; } /** @@ -754,8 +774,9 @@ class WC_Subscriptions_Manager { } /** - * Clear all subscriptions attached to an order when it's deleted. Also make sure - * all related scheduled actions are cancelled when deleting a susbcription. + * Trash all subscriptions attached to an order when it's trashed. + * + * Also make sure all related scheduled actions are cancelled when deleting a subscription. * * @param int $post_id The post ID of the WC Subscription or WC Order being trashed * @since 1.0 @@ -771,6 +792,27 @@ class WC_Subscriptions_Manager { } } + /** + * Delete related subscriptions when an order is deleted. + * + * @author Jeremy Pry + * + * @param int $post_id The post ID being deleted. + */ + public static function maybe_delete_subscription( $post_id ) { + if ( 'shop_order' !== get_post_type( $post_id ) ) { + return; + } + + /** @var WC_Subscription[] $subscriptions */ + $subscriptions = wcs_get_subscriptions_for_order( $post_id, array( + 'subscription_status' => array( 'any', 'trash' ), + ) ); + foreach ( $subscriptions as $subscription ) { + wp_delete_post( $subscription->get_id() ); + } + } + /** * Make sure a subscription is cancelled before it is trashed or deleted * diff --git a/includes/class-wc-subscriptions-order.php b/includes/class-wc-subscriptions-order.php index 772e497..f7e3fac 100644 --- a/includes/class-wc-subscriptions-order.php +++ b/includes/class-wc-subscriptions-order.php @@ -797,7 +797,7 @@ class WC_Subscriptions_Order { $subscriptions = wcs_get_subscriptions_for_order( wcs_get_objects_property( $order, 'id' ), array( 'order_type' => 'any' ) ); foreach ( $subscriptions as $subscription ) { - if ( wcs_get_objects_property( $order, 'id' ) != $subscription->get_last_order() ) { + if ( wcs_get_objects_property( $order, 'id' ) != $subscription->get_last_order( 'ids', 'any' ) ) { unset( $actions['pay'] ); break; } diff --git a/includes/class-wc-subscriptions-product.php b/includes/class-wc-subscriptions-product.php index a4fb111..c3ad593 100644 --- a/includes/class-wc-subscriptions-product.php +++ b/includes/class-wc-subscriptions-product.php @@ -556,7 +556,7 @@ class WC_Subscriptions_Product { $from_date = gmdate( 'Y-m-d H:i:s' ); } - // If the subscription has a free trial period, the first renewal is the same as the expiration of the free trial + // If the subscription has a free trial period, the first renewal payment date is the same as the expiration of the free trial if ( $trial_length > 0 ) { $first_renewal_timestamp = wcs_date_to_time( self::get_trial_expiration_date( $product_id, $from_date ) ); diff --git a/includes/class-wc-subscriptions-renewal-order.php b/includes/class-wc-subscriptions-renewal-order.php index c23b692..566a109 100644 --- a/includes/class-wc-subscriptions-renewal-order.php +++ b/includes/class-wc-subscriptions-renewal-order.php @@ -95,8 +95,16 @@ class WC_Subscriptions_Renewal_Order { wp_update_post( $update_post_data ); update_post_meta( $order_id, '_paid_date', current_time( 'mysql' ) ); } else { + + $current_time = current_time( 'timestamp', 1 ); + + // Prior to WC 3.0, we need to update the post date (i.e. the date created) to have a reliable representation of the paid date (both because it was in GMT and because it was always set). That's not needed in WC 3.0, but some plugins and store owners still rely on it being updated, so we want to make it possible to update it with 3.0 also. + if ( apply_filters( 'wcs_renewal_order_payment_update_date_created', false, $order, $subscriptions ) ) { + $order->set_date_created( $current_time ); + } + // In WC 3.0, only the paid date prop represents the paid date, the post date isn't used anymore, also the paid date is stored and referenced as a MySQL date string in site timezone and a GMT timestamp - $order->set_date_paid( current_time( 'timestamp', 1 ) ); + $order->set_date_paid( $current_time ); $order->save(); } } diff --git a/includes/class-wc-subscriptions-switcher.php b/includes/class-wc-subscriptions-switcher.php index 859f7cb..5b0d92d 100644 --- a/includes/class-wc-subscriptions-switcher.php +++ b/includes/class-wc-subscriptions-switcher.php @@ -120,6 +120,10 @@ class WC_Subscriptions_Switcher { add_action( 'woocommerce_cart_totals_after_shipping', __CLASS__ . '::maybe_unset_free_trial' ); add_action( 'woocommerce_review_order_before_shipping', __CLASS__ . '::maybe_set_free_trial' ); add_action( 'woocommerce_review_order_after_shipping', __CLASS__ . '::maybe_unset_free_trial' ); + + // Grant download permissions after the switch is complete. + add_action( 'woocommerce_grant_product_download_permissions', __CLASS__ . '::delay_granting_download_permissions', 9, 1 ); + add_action( 'woocommerce_subscriptions_switch_completed', __CLASS__ . '::grant_download_permissions', 9, 1 ); } /** @@ -758,10 +762,10 @@ class WC_Subscriptions_Switcher { // Add the new item if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { $item_id = WC_Subscriptions_Checkout::add_cart_item( $subscription, $cart_item, $cart_item_key ); - wc_update_order_item( $item_id, array( 'order_item_type' => 'line_item_pending_switch' ) ); + wcs_update_order_item_type( $item_id, 'line_item_pending_switch', $subscription->get_id() ); } else { $item = new WC_Order_Item_Pending_Switch; - $item->legacy_values = $cart_item['data']; // @deprecated For legacy actions. + $item->legacy_values = $cart_item; // @deprecated For legacy actions. $item->legacy_cart_item_key = $cart_item_key; // @deprecated For legacy actions. $item->set_props( array( 'quantity' => $cart_item['quantity'], @@ -856,7 +860,7 @@ class WC_Subscriptions_Switcher { foreach ( $subscription->get_shipping_methods() as $shipping_line_item_id => $shipping_meta ) { if ( ! in_array( $shipping_line_item_id, $current_shipping_line_items ) ) { - wc_update_order_item( $shipping_line_item_id, array( 'order_item_type' => 'shipping_pending_switch' ) ); + wcs_update_order_item_type( $shipping_line_item_id, 'shipping_pending_switch', $subscription->get_id() ); $new_shipping_line_items[] = $shipping_line_item_id; } } @@ -904,7 +908,7 @@ class WC_Subscriptions_Switcher { // First, archive all the shipping methods foreach ( $subscription->get_shipping_methods() as $shipping_method_id => $shipping_method ) { - wc_update_order_item( $shipping_method_id, array( 'order_item_type' => 'shipping_switched' ) ); + wcs_update_order_item_type( $shipping_method_id, 'shipping_switched', $subscription->get_id() ); } // Then zero the order_shipping total so we have a clean slate to add to @@ -1576,6 +1580,11 @@ class WC_Subscriptions_Switcher { add_filter( 'woocommerce_subscriptions_recurring_cart_key', __METHOD__, 10, 2 ); } + // Append switch data to the recurring cart key so switch items are separated from other subscriptions in the cart. Switch items are processed through the checkout separately so should have separate recurring carts. + if ( isset( $cart_item['subscription_switch']['subscription_id'] ) ) { + $cart_key .= '_switch_' . $cart_item['subscription_switch']['subscription_id']; + } + return $cart_key; } @@ -1902,7 +1911,7 @@ class WC_Subscriptions_Switcher { // If we are adding a line item to an existing subscription if ( isset( $switched_item_data['add_line_item'] ) ) { - wc_update_order_item( $switched_item_data['add_line_item'], array( 'order_item_type' => 'line_item' ) ); + wcs_update_order_item_type( $switched_item_data['add_line_item'], 'line_item', $subscription->get_id() ); do_action( 'woocommerce_subscription_item_switched', $order, $subscription, $switched_item_data['add_line_item'], $switched_item_data['remove_line_item'] ); } @@ -1921,7 +1930,7 @@ class WC_Subscriptions_Switcher { $new_item_name = wcs_get_order_item_name( $switch_order_item, array( 'attributes' => true ) ); remove_filter( 'woocommerce_subscriptions_hide_switch_itemmeta', '__return_true' ); - wc_update_order_item( $switched_item_data['remove_line_item'], array( 'order_item_type' => 'line_item_switched' ) ); + wcs_update_order_item_type( $switched_item_data['remove_line_item'], 'line_item_switched', $subscription->get_id() ); // translators: 1$: old item, 2$: new item when switching $add_note = sprintf( _x( 'Customer switched from: %1$s to %2$s.', 'used in order notes', 'woocommerce-subscriptions' ), $old_item_name, $new_item_name ); @@ -1967,12 +1976,12 @@ class WC_Subscriptions_Switcher { // Archive the old subscription shipping methods foreach ( $subscription->get_shipping_methods() as $shipping_line_item_id => $item ) { - wc_update_order_item( $shipping_line_item_id, array( 'order_item_type' => 'shipping_switched' ) ); + wcs_update_order_item_type( $shipping_line_item_id, 'shipping_switched', $subscription->get_id() ); } // Flip the switched shipping line items "on" foreach ( $switch_data['shipping_line_items'] as $shipping_line_item_id ) { - wc_update_order_item( $shipping_line_item_id, array( 'order_item_type' => 'shipping' ) ); + wcs_update_order_item_type( $shipping_line_item_id, 'shipping', $subscription->get_id() ); } } @@ -2101,6 +2110,31 @@ class WC_Subscriptions_Switcher { } } + /** + * Delay granting download permissions to the subscription until the switch is processed. + * + * @param int $order_id The order the download permissions are being granted for. + * @since 2.2.13 + */ + public static function delay_granting_download_permissions( $order_id ) { + if ( wcs_order_contains_switch( $order_id ) ) { + remove_action( 'woocommerce_grant_product_download_permissions', 'WCS_Download_Handler::save_downloadable_product_permissions' ); + } + } + + /** + * Grant the download permissions to the subscription after the switch is processed. + * + * @param WC_Order The switch order. + * @since 2.2.13 + */ + public static function grant_download_permissions( $order ) { + WCS_Download_Handler::save_downloadable_product_permissions( wcs_get_objects_property( $order, 'id' ) ); + + // reattach the hook detached in @see self::delay_granting_download_permissions() + add_action( 'woocommerce_grant_product_download_permissions', 'WCS_Download_Handler::save_downloadable_product_permissions' ); + } + /** Deprecated Methods **/ /** @@ -2234,7 +2268,7 @@ class WC_Subscriptions_Switcher { $old_subscription_item_name = wcs_get_order_item_name( $old_order_item, array( 'attributes' => true ) ); remove_filter( 'woocommerce_subscriptions_hide_switch_itemmeta', '__return_true' ); - wc_update_order_item( $switch_item_data['subscription_item_id'], array( 'order_item_type' => 'line_item_switched' ) ); + wcs_update_order_item_type( $switch_item_data['subscription_item_id'], 'line_item_switched', $subscription->get_id() ); // translators: 1$: old item, 2$: new item when switching $subscription->add_order_note( sprintf( _x( 'Customer switched from: %1$s to %2$s.', 'used in order notes', 'woocommerce-subscriptions' ), $old_subscription_item_name, $new_order_item_name ) ); @@ -2253,7 +2287,7 @@ class WC_Subscriptions_Switcher { protected static function switch_shipping_line_items_pre_2_1_2( $subscription, $shipping_methods ) { // Archive the old subscription shipping methods foreach ( $subscription->get_shipping_methods() as $shipping_line_item_id => $item ) { - wc_update_order_item( $shipping_line_item_id, array( 'order_item_type' => 'shipping_switched' ) ); + wcs_update_order_item_type( $shipping_line_item_id, 'shipping_switched', $subscription->get_id() ); } // Add the new shipping line item diff --git a/includes/class-wcs-cached-data-manager.php b/includes/class-wcs-cached-data-manager.php index f227581..f76eec1 100644 --- a/includes/class-wcs-cached-data-manager.php +++ b/includes/class-wcs-cached-data-manager.php @@ -18,7 +18,7 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager { // Add filters for update / delete / trash post to purge cache add_action( 'trashed_post', array( $this, 'purge_delete' ), 9999 ); // trashed posts aren't included in 'any' queries add_action( 'untrashed_post', array( $this, 'purge_delete' ), 9999 ); // however untrashed posts are - add_action( 'deleted_post', array( $this, 'purge_delete' ), 9999 ); // if forced delete is enabled + add_action( 'before_delete_post', array( $this, 'purge_delete' ), 9999 ); // if forced delete is enabled add_action( 'updated_post_meta', array( $this, 'purge_from_metadata' ), 9999, 4 ); // tied to '_subscription_renewal', '_subscription_resubscribe' & '_subscription_switch' keys add_action( 'deleted_post_meta', array( $this, 'purge_from_metadata' ), 9999, 4 ); // tied to '_subscription_renewal', '_subscription_resubscribe' & '_subscription_switch' keys add_action( 'added_post_meta', array( $this, 'purge_from_metadata' ), 9999, 4 ); // tied to '_subscription_renewal', '_subscription_resubscribe' & '_subscription_switch' keys @@ -74,13 +74,17 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager { * @param $post_id integer the ID of a post */ public function purge_delete( $post_id ) { - if ( 'shop_order' !== get_post_type( $post_id ) ) { - return; + if ( 'shop_order' === get_post_type( $post_id ) ) { + foreach ( wcs_get_subscriptions_for_order( $post_id, array( 'order_type' => 'any' ) ) as $subscription ) { + $this->log( 'Calling purge delete on ' . current_filter() . ' for ' . $subscription->get_id() ); + $this->clear_related_order_cache( $subscription ); + } } - foreach ( wcs_get_subscriptions_for_order( $post_id, array( 'order_type' => 'any' ) ) as $subscription ) { - $this->log( 'Calling purge delete on ' . current_filter() . ' for ' . $subscription->get_id() ); - $this->clear_related_order_cache( $subscription ); + // Purge wcs_do_subscriptions_exist cache, but only on the before_delete_post hook. + if ( 'shop_subscription' === get_post_type( $post_id ) && doing_action( 'before_delete_post' ) ) { + $this->log( "Subscription {$post_id} deleted. Purging subscription cache." ); + $this->delete_cached( 'wcs_do_subscriptions_exist' ); } } diff --git a/includes/class-wcs-change-payment-method-admin.php b/includes/class-wcs-change-payment-method-admin.php index 22dfce8..f9d966d 100644 --- a/includes/class-wcs-change-payment-method-admin.php +++ b/includes/class-wcs-change-payment-method-admin.php @@ -67,7 +67,7 @@ class WCS_Change_Payment_Method_Admin { foreach ( $meta as $meta_key => $meta_data ) { - $field_id = sprintf( '_payment_method_meta[%s][%s]', $meta_table , $meta_key ); + $field_id = sprintf( '_payment_method_meta[%s][%s][%s]', $payment_method_id, $meta_table, $meta_key ); $field_label = ( ! empty( $meta_data['label'] ) ) ? $meta_data['label'] : $meta_key ; $field_value = ( ! empty( $meta_data['value'] ) ) ? $meta_data['value'] : null ; $field_disabled = ( isset( $meta_data['disabled'] ) && true == $meta_data['disabled'] ) ? ' readonly' : ''; @@ -76,7 +76,6 @@ class WCS_Change_Payment_Method_Admin { echo ''; echo ''; echo '

'; - } } @@ -122,7 +121,7 @@ class WCS_Change_Payment_Method_Admin { } foreach ( $meta as $meta_key => $meta_data ) { - $payment_method_meta[ $meta_table ][ $meta_key ]['value'] = isset( $_POST['_payment_method_meta'][ $meta_table ][ $meta_key ] ) ? $_POST['_payment_method_meta'][ $meta_table ][ $meta_key ] : ''; + $payment_method_meta[ $meta_table ][ $meta_key ]['value'] = isset( $_POST['_payment_method_meta'][ $payment_method ][ $meta_table ][ $meta_key ] ) ? $_POST['_payment_method_meta'][ $payment_method ][ $meta_table ][ $meta_key ] : ''; } } } diff --git a/includes/class-wcs-download-handler.php b/includes/class-wcs-download-handler.php index d031fb3..1a51fae 100644 --- a/includes/class-wcs-download-handler.php +++ b/includes/class-wcs-download-handler.php @@ -217,17 +217,28 @@ class WCS_Download_Handler { if ( ! empty( $new_download_ids ) ) { - $existing_permissions = $wpdb->get_col( $wpdb->prepare( "SELECT order_id from {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE product_id = %d GROUP BY order_id", $product_id ) ); + $existing_permissions = $wpdb->get_results( $wpdb->prepare( "SELECT order_id, download_id from {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE product_id = %d", $product_id ) ); $subscriptions = wcs_get_subscriptions_for_product( $product_id ); + // Arrange download id permissions by order id + $permissions_by_order_id = array(); + + foreach ( $existing_permissions as $permission_data ) { + + $permissions_by_order_id[ $permission_data->order_id ][] = $permission_data->download_id; + } + foreach ( $subscriptions as $subscription_id ) { // Grant permissions to subscriptions which have no permissions for this product, pre WC3.0, or all subscriptions, post WC3.0, as WC doesn't grant them retrospectively anymore. - if ( ! in_array( $subscription_id, $existing_permissions ) || false === WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { + if ( ! in_array( $subscription_id, array_keys( $permissions_by_order_id ) ) || false === WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) { $subscription = wcs_get_subscription( $subscription_id ); foreach ( $new_download_ids as $download_id ) { - if ( $subscription && apply_filters( 'woocommerce_process_product_file_download_paths_grant_access_to_new_file', true, $download_id, $product_id, $subscription ) ) { + + $has_permission = isset( $permissions_by_order_id[ $subscription_id ] ) && in_array( $download_id, $permissions_by_order_id[ $subscription_id ] ); + + if ( $subscription && ! $has_permission && apply_filters( 'woocommerce_process_product_file_download_paths_grant_access_to_new_file', true, $download_id, $product_id, $subscription ) ) { wc_downloadable_file_permission( $download_id, $product_id, $subscription ); } } diff --git a/includes/class-wcs-remove-item.php b/includes/class-wcs-remove-item.php index fcf5e4e..56b3281 100644 --- a/includes/class-wcs-remove-item.php +++ b/includes/class-wcs-remove-item.php @@ -79,8 +79,7 @@ class WCS_Remove_Item { if ( ! empty( $removed_item[ $item_id ] ) && $subscription->get_id() == $removed_item[ $item_id ] ) { // restore the item - wc_update_order_item( $item_id, array( 'order_item_type' => 'line_item' ) ); - unset( $removed_item[ $item_id ] ); + wcs_update_order_item_type( $item_id, 'line_item', $subscription->get_id() ); WC()->session->set( 'removed_subscription_items', $removed_item ); @@ -119,7 +118,7 @@ class WCS_Remove_Item { WCS_Download_Handler::revoke_downloadable_file_permission( $product_id, $subscription->get_id(), $subscription->get_user_id() ); // remove the line item from subscription but preserve its data in the DB - wc_update_order_item( $item_id, array( 'order_item_type' => 'line_item_removed' ) ); + wcs_update_order_item_type( $item_id, 'line_item_removed', $subscription->get_id() ); // translators: 1$: product name, 2$: product id $subscription->add_order_note( sprintf( _x( 'Customer removed "%1$s" (Product ID: #%2$d) via the My Account page.', 'used in order note', 'woocommerce-subscriptions' ), wcs_get_line_item_name( $line_item ), $product_id ) ); diff --git a/includes/emails/class-wcs-email-customer-renewal-invoice.php b/includes/emails/class-wcs-email-customer-renewal-invoice.php index 62d5251..82caa1c 100644 --- a/includes/emails/class-wcs-email-customer-renewal-invoice.php +++ b/includes/emails/class-wcs-email-customer-renewal-invoice.php @@ -15,6 +15,18 @@ if ( ! defined( 'ABSPATH' ) ) { */ class WCS_Email_Customer_Renewal_Invoice extends WC_Email_Customer_Invoice { + /** + * Strings to find in subjects/headings. + * @var array + */ + public $find = array(); + + /** + * Strings to replace in subjects/headings. + * @var array + */ + public $replace = array(); + // fields used in WC_Email_Customer_Invoice this class doesn't need var $subject_paid = null; var $heading_paid = null; diff --git a/includes/gateways/class-wc-subscriptions-payment-gateways.php b/includes/gateways/class-wc-subscriptions-payment-gateways.php index a3a501f..fa8aa4e 100644 --- a/includes/gateways/class-wc-subscriptions-payment-gateways.php +++ b/includes/gateways/class-wc-subscriptions-payment-gateways.php @@ -204,7 +204,7 @@ class WC_Subscriptions_Payment_Gateways { throw new InvalidArgumentException( sprintf( __( 'Subscription doesn\'t exist in scheduled action: %d', 'woocommerce-subscriptions' ), $subscription_id ) ); } - if ( ! $subscription->is_manual() ) { + if ( ! $subscription->is_manual() && ! $subscription->has_status( wcs_get_subscription_ended_statuses() ) ) { self::trigger_gateway_renewal_payment_hook( $subscription->get_last_order( 'all', 'renewal' ) ); } } diff --git a/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php b/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php index 57bcbf1..d16feb9 100644 --- a/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php +++ b/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php @@ -170,20 +170,24 @@ class WCS_PayPal_Admin { ); } - $last_ipn_error = get_option( 'wcs_fatal_error_handling_ipn', '' ); + $last_ipn_error = get_option( 'wcs_fatal_error_handling_ipn', '' ); + $failed_ipn_log_handle = 'wcs-ipn-failures'; if ( ! empty( $last_ipn_error ) && ( false == get_option( 'wcs_fatal_error_handling_ipn_ignored', false ) || isset( $_GET['wcs_reveal_your_ipn_secrets'] ) ) ) { $notices[] = array( 'type' => 'error', - 'text' => sprintf( esc_html__( '%sA fatal error has occurred when processing a recent subscription payment with PayPal. Please %sopen a new ticket at WooCommerce Support%s immediately to get this resolved.%sIn order to get the quickest possible response please attach a %sTemporary Admin Login%s and a copy of your PHP error logs to your support ticket.%sLast recorded error: %s', 'woocommerce-subscriptions' ), + 'text' => sprintf( esc_html__( '%sA fatal error has occurred when processing a recent subscription payment with PayPal. Please %sopen a new ticket at WooCommerce Support%s immediately to get this resolved.%sIn order to get the quickest possible response please attach a %sTemporary Admin Login%s and a copy of your PHP error logs to your support ticket.%sLast recorded error: %sTo see the full error, view the %s log file from the %sWooCommerce logs screen.%s', 'woocommerce-subscriptions' ), '

', - '', + '', '', '
', '', '', '

', - '' . esc_html( $last_ipn_error ) . '
' . esc_html__( 'Ignore this error (not recommended!)', 'woocommerce-subscriptions' ) . ' ' . esc_html__( 'Open up a ticket now!', 'woocommerce-subscriptions' ) . '
' + '' . esc_html( $last_ipn_error ) . '

', + '' . $failed_ipn_log_handle . '', + '', + '

' . esc_html__( 'Ignore this error (not recommended!)', 'woocommerce-subscriptions' ) . ' ' . esc_html__( 'Open up a ticket now!', 'woocommerce-subscriptions' ) . '
' ), ); } diff --git a/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php b/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php index 60c299b..99aed88 100644 --- a/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php +++ b/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php @@ -109,7 +109,7 @@ class WCS_PayPal_Reference_Transaction_API_Request { if ( 0 == $args['order']->get_total() ) { $this->add_parameters( array( - 'PAYMENTREQUEST_0_AMT' => 0, // a zero amount is use so that no DoExpressCheckout action is required and instead CreateBillingAgreement is used to first create a billing agreement not attached to any order and then DoReferenceTransaction is used to charge both the initial order and renewal order amounts + 'PAYMENTREQUEST_0_AMT' => 0, // a zero amount is used so that no DoExpressCheckout action is required and instead CreateBillingAgreement is used to first create a billing agreement not attached to any order and then DoReferenceTransaction is used to charge both the initial order and renewal order amounts 'PAYMENTREQUEST_0_ITEMAMT' => 0, 'PAYMENTREQUEST_0_SHIPPINGAMT' => 0, 'PAYMENTREQUEST_0_TAXAMT' => 0, @@ -277,7 +277,7 @@ class WCS_PayPal_Reference_Transaction_API_Request { ); } - if ( $this->skip_line_items( $order ) ) { + if ( $this->skip_line_items( $order, $order_items ) ) { $total_amount = $this->round( $order->get_total() ); @@ -292,7 +292,6 @@ class WCS_PayPal_Reference_Transaction_API_Request { $item_names = array(); foreach ( $order_items as $item ) { - $item_names[] = sprintf( '%1$s x %2$s', $item['NAME'], $item['QTY'] ); } @@ -306,7 +305,7 @@ class WCS_PayPal_Reference_Transaction_API_Request { ), 0, $use_deprecated_params ); // add order-level parameters - // - Do not sent the TAXAMT due to rounding errors + // - Do not send the TAXAMT due to rounding errors if ( $use_deprecated_params ) { $this->add_parameters( array( 'AMT' => $total_amount, @@ -334,7 +333,6 @@ class WCS_PayPal_Reference_Transaction_API_Request { // add individual order items foreach ( $order_items as $item ) { - $this->add_line_item_parameters( $item, $item_count++, $use_deprecated_params ); $calculated_total += $this->round( $item['AMT'] * $item['QTY'] ); } @@ -370,11 +368,6 @@ class WCS_PayPal_Reference_Transaction_API_Request { 'CUSTOM' => json_encode( array( 'order_id' => wcs_get_objects_property( $order, 'id' ), 'order_key' => wcs_get_objects_property( $order, 'order_key' ) ) ), ) ); } - - // offset the discrepency between the WooCommerce cart total and PayPal's calculated total by adjusting the cost of the first item - if ( $total_amount !== $calculated_total ) { - $this->parameters['L_PAYMENTREQUEST_0_AMT0'] = $this->parameters['L_PAYMENTREQUEST_0_AMT0'] - ( $calculated_total - $total_amount ); - } } } @@ -633,10 +626,27 @@ class WCS_PayPal_Reference_Transaction_API_Request { * @param WC_Order $order Optional. The WC_Order object. Default null. * @return bool true if line items should be skipped, false otherwise */ - private function skip_line_items( $order = null ) { + private function skip_line_items( $order = null, $order_items = null ) { $skip_line_items = wcs_get_objects_property( $order, 'prices_include_tax' ); + // Also check actual totals add up just in case totals have been manually modified to amounts that can not round correctly, see https://github.com/Prospress/woocommerce-subscriptions/issues/2213 + if ( true != $skip_line_items && ! is_null( $order ) && ! is_null( $order_items ) ) { + + $calculated_total = 0; + + foreach ( $order_items as $item ) { + $calculated_total += $this->round( $item['AMT'] * $item['QTY'] ); + } + + $calculated_total += $this->round( $order->get_total_shipping() ) + $this->round( $order->get_total_tax() ); + $total_amount = $this->round( $order->get_total() ); + + if ( $total_amount !== $calculated_total ) { + $skip_line_items = true; + } + } + /** * Filter whether line items should be skipped or not * diff --git a/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php b/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php index 565049c..e43a28a 100644 --- a/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php +++ b/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php @@ -93,9 +93,34 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler { return; } + // If the IPN is for a cancellation after a failed payment on a PayPal Standard subscription created with Subscriptions < 2.0, the subscription won't be found, but that doesn't mean we should throw an exception, we should just ignore it + if ( empty( $subscription ) && in_array( $transaction_details['txn_type'], array( 'subscr_cancel', 'subscr_eot' ) ) ) { + + // Check if the reason the subscription can't be found is because it has since been changed to a new PayPal Subscription and this IPN is for the cancellation after a renewal sign-up + $subscription_id_and_key = self::get_order_id_and_key( $transaction_details, 'shop_subscription', '_old_paypal_subscriber_id' ); + + if ( ! empty( $subscription_id_and_key['order_id'] ) ) { + WC_Gateway_Paypal::log( 'IPN subscription cancellation request ignored - new PayPal Profile ID linked to this subscription, for subscription ' . $subscription_id_and_key['order_id'] ); + return; + } + } + + // If the IPN is for a suspension after a switch on a PayPal Standard subscription created with Subscriptions < 2.0, the subscription won't be found, but that doesn't mean we should throw an exception, we should just ignore it + if ( empty( $subscription ) && 'recurring_payment_suspended' === $transaction_details['txn_type'] ) { + + // Check if the reason the subscription can't be found is because it has since been changed after a successful subscription switch + $subscription_id_and_key = self::get_order_id_and_key( $transaction_details, 'shop_subscription', '_switched_paypal_subscription_id' ); + + if ( ! empty( $subscription_id_and_key['order_id'] ) ) { + WC_Gateway_Paypal::log( 'IPN subscription suspension request ignored - subscription payment gateway changed via switch' . $subscription_id_and_key['order_id'] ); + return; + } + } + if ( empty( $subscription ) ) { - WC_Gateway_Paypal::log( 'Subscription IPN Error: Could not find matching Subscription.' ); - exit; + $message = 'Subscription IPN Error: Could not find matching Subscription.'; // We dont' want this to be translated, we need it in English for support + WC_Gateway_Paypal::log( $message ); + throw new Exception( $message ); } if ( $subscription->get_order_key() != $subscription_key ) { @@ -517,7 +542,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler { * * @since 2.0 */ - public static function get_order_id_and_key( $args, $order_type = 'shop_order' ) { + public static function get_order_id_and_key( $args, $order_type = 'shop_order', $meta_key = '_paypal_subscription_id' ) { $order_id = $order_key = ''; @@ -536,7 +561,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler { 'numberposts' => 1, 'orderby' => 'ID', 'order' => 'ASC', - 'meta_key' => '_paypal_subscription_id', + 'meta_key' => $meta_key, 'meta_value' => $subscription_id, 'post_type' => $order_type, 'post_status' => 'any', @@ -574,12 +599,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler { } } } else { // WC < 2.3.11, we could have a variety of payloads, but something has gone wrong if we got to here as we should only be here on new purchases where the '_paypal_subscription_id' is not already set, so throw an exception - - $message = __( 'Invalid PayPal IPN Payload: unable to find matching subscription.', 'woocommerce-subscriptions' ); - - WC_Gateway_Paypal::log( $message ); - - throw new Exception( $message ); + WC_Gateway_Paypal::log( __( 'Invalid PayPal IPN Payload: unable to find matching subscription.', 'woocommerce-subscriptions' ) ); } } diff --git a/includes/gateways/paypal/includes/class-wcs-paypal-standard-switcher.php b/includes/gateways/paypal/includes/class-wcs-paypal-standard-switcher.php index 8531830..b3f209b 100644 --- a/includes/gateways/paypal/includes/class-wcs-paypal-standard-switcher.php +++ b/includes/gateways/paypal/includes/class-wcs-paypal-standard-switcher.php @@ -168,6 +168,7 @@ class WCS_PayPal_Standard_Switcher { if ( ! wcs_is_paypal_profile_a( $paypal_id, 'billing_agreement' ) ) { update_post_meta( $order_id, '_old_payment_method', 'paypal_standard' ); update_post_meta( $order_id, '_old_paypal_subscription_id', $paypal_id ); + update_post_meta( $subscription->get_id(), '_switched_paypal_subscription_id', $paypal_id ); } } } diff --git a/includes/wcs-cart-functions.php b/includes/wcs-cart-functions.php index 0e6a90f..545dacf 100644 --- a/includes/wcs-cart-functions.php +++ b/includes/wcs-cart-functions.php @@ -41,7 +41,7 @@ function wcs_cart_totals_shipping_html() { foreach ( WC()->cart->recurring_carts as $recurring_cart_key => $recurring_cart ) { // Create shipping packages for each subscription item - if ( WC_Subscriptions_Cart::cart_contains_subscriptions_needing_shipping() && 0 !== $recurring_cart->next_payment_date ) { + if ( WC_Subscriptions_Cart::cart_contains_subscriptions_needing_shipping( $recurring_cart ) && 0 !== $recurring_cart->next_payment_date ) { // This will get a package with the 'recurring_cart_key' set to 'none' (because WC_Subscriptions_Cart::display_recurring_totals() set WC_Subscriptions_Cart::$calculation_type to 'recurring_total', but WC_Subscriptions_Cart::$recurring_cart_key has not been set), which ensures that it's a unique package, which we need in order to get all the available packages, not just the package for the recurring cart calculation we completed previously where WC_Subscriptions_Cart::filter_package_rates() removed all unchosen rates and which WC then cached $packages = $recurring_cart->get_shipping_packages(); diff --git a/includes/wcs-compatibility-functions.php b/includes/wcs-compatibility-functions.php index 33dc8e6..24dbb02 100644 --- a/includes/wcs-compatibility-functions.php +++ b/includes/wcs-compatibility-functions.php @@ -218,7 +218,7 @@ function wcs_get_objects_property( $object, $property, $single = 'single', $defa * @param string $key The meta key name without '_' prefix * @param mixed $value The data to set as the value of the meta * @param string $save Whether to write the data to the database or not. Use 'save' to write to the database, anything else to only update it in memory. - * @param int $meta_id The meta ID of exiting meta data if you wish to overwrite an existing piece of meta. + * @param int $meta_id The meta ID of existing meta data if you wish to overwrite an existing piece of meta. * @param string $prefix_meta_key Whether the key should be prefixed with an '_' when stored in meta. Defaulted to 'prefix_meta_key', pass any other value to bypass automatic prefixing (optional) * @since 2.2.0 * @return mixed diff --git a/includes/wcs-order-functions.php b/includes/wcs-order-functions.php index 1eb3a9c..88172f2 100644 --- a/includes/wcs-order-functions.php +++ b/includes/wcs-order-functions.php @@ -546,6 +546,24 @@ function wcs_get_order_item( $item_id, $order ) { return $item; } +/** + * A wrapper for wc_update_order_item() which consistently deletes the cached item after update, unlike WC. + * + * @param int $item_id The ID of an order item + * @param string $new_type The new type to set as the 'order_item_type' value on the order item. + * @param int $order_or_subscription_id The order or subscription ID the line item belongs to - optional. Deletes the order item cache if provided. + * @since 2.2.12 + */ +function wcs_update_order_item_type( $item_id, $new_type, $order_or_subscription_id = 0 ) { + wc_update_order_item( $item_id, array( 'order_item_type' => $new_type ) ); + wp_cache_delete( 'item-' . $item_id, 'order-items' ); + + // When possible, also clear the order items' cache for the object to which this item relates (double cache :sob:) + if ( ! empty( $order_or_subscription_id ) ) { + wp_cache_delete( 'order-items-' . $order_or_subscription_id, 'orders' ); + } +} + /** * Get an instance of WC_Order_Item_Meta for an order item * diff --git a/languages/woocommerce-subscriptions.pot b/languages/woocommerce-subscriptions.pot index f825176..fb84530 100644 --- a/languages/woocommerce-subscriptions.pot +++ b/languages/woocommerce-subscriptions.pot @@ -2,10 +2,10 @@ # This file is distributed under the same license as the WooCommerce Subscriptions package. msgid "" msgstr "" -"Project-Id-Version: WooCommerce Subscriptions 2.2.11\n" +"Project-Id-Version: WooCommerce Subscriptions 2.2.13\n" "Report-Msgid-Bugs-To: " "https://github.com/Prospress/woocommerce-subscriptions/issues\n" -"POT-Creation-Date: 2017-08-01 04:27:16+00:00\n" +"POT-Creation-Date: 2017-10-13 08:02:19+00:00\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -38,12 +38,12 @@ msgid "Subscription interval" msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:220 -#: includes/admin/class-wc-subscriptions-admin.php:355 +#: includes/admin/class-wc-subscriptions-admin.php:356 msgid "Subscription period" msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:234 -#: includes/admin/class-wc-subscriptions-admin.php:356 +#: includes/admin/class-wc-subscriptions-admin.php:357 #: templates/admin/html-variation-price.php:64 msgid "Subscription length" msgstr "" @@ -68,21 +68,21 @@ msgid "" "product has a free trial or the payment dates are synced." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:259 +#: includes/admin/class-wc-subscriptions-admin.php:260 #: templates/admin/html-variation-price.php:23 msgid "Free trial" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:262 +#: includes/admin/class-wc-subscriptions-admin.php:263 #: templates/admin/deprecated/html-variation-price.php:115 msgid "Subscription Trial Period" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:294 +#: includes/admin/class-wc-subscriptions-admin.php:295 msgid "One time shipping" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:295 +#: includes/admin/class-wc-subscriptions-admin.php:296 msgid "" "Shipping for subscription products is normally charged on the initial order " "and all renewal orders. Enable this to only charge shipping once on the " @@ -90,53 +90,53 @@ msgid "" "not have a free trial or a synced renewal date." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:352 +#: includes/admin/class-wc-subscriptions-admin.php:353 msgid "Subscription pricing" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:353 +#: includes/admin/class-wc-subscriptions-admin.php:354 msgid "Subscription sign-up fee" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:354 +#: includes/admin/class-wc-subscriptions-admin.php:355 msgid "Subscription billing interval" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:357 +#: includes/admin/class-wc-subscriptions-admin.php:358 msgid "Free trial length" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:358 +#: includes/admin/class-wc-subscriptions-admin.php:359 msgid "Free trial period" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:675 +#: includes/admin/class-wc-subscriptions-admin.php:680 msgid "" "Unable to change subscription status to \"%s\". Please assign a customer to " "the subscription to activate it." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:717 +#: includes/admin/class-wc-subscriptions-admin.php:722 msgid "" "Trashing this order will also trash the subscriptions purchased with the " "order." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:730 +#: includes/admin/class-wc-subscriptions-admin.php:735 msgid "Enter the new period, either day, week, month or year:" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:731 +#: includes/admin/class-wc-subscriptions-admin.php:736 msgid "Enter a new length (e.g. 5):" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:732 +#: includes/admin/class-wc-subscriptions-admin.php:737 msgid "" "Enter a new interval as a single number (e.g. to charge every 2nd month, " "enter 2):" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:737 +#: includes/admin/class-wc-subscriptions-admin.php:742 msgid "" "You are about to trash one or more orders which contain a subscription.\n" "\n" @@ -144,7 +144,7 @@ msgid "" "orders." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:750 +#: includes/admin/class-wc-subscriptions-admin.php:755 msgid "" "WARNING: Bad things are about to happen!\n" "\n" @@ -156,13 +156,13 @@ msgid "" "gateway." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:751 +#: includes/admin/class-wc-subscriptions-admin.php:756 msgid "" "You are deleting a subscription item. You will also need to manually cancel " "and trash the subscription on the Manage Subscriptions screen." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:758 +#: includes/admin/class-wc-subscriptions-admin.php:763 msgid "" "Warning: Deleting a user will also delete the user's subscriptions. The " "user's orders will remain but be reassigned to the 'Guest' user.\n" @@ -171,59 +171,59 @@ msgid "" "subscriptions?" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:821 +#: includes/admin/class-wc-subscriptions-admin.php:826 msgid "Active subscriber?" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:864 +#: includes/admin/class-wc-subscriptions-admin.php:869 msgid "Manage Subscriptions" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:868 -#: woocommerce-subscriptions.php:235 +#: includes/admin/class-wc-subscriptions-admin.php:873 +#: woocommerce-subscriptions.php:236 msgid "Search Subscriptions" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:888 -#: includes/admin/class-wc-subscriptions-admin.php:984 -#: includes/admin/class-wcs-admin-reports.php:55 +#: includes/admin/class-wc-subscriptions-admin.php:893 +#: includes/admin/class-wc-subscriptions-admin.php:989 +#: includes/admin/class-wcs-admin-reports.php:51 #: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:654 #: includes/class-wcs-query.php:95 includes/class-wcs-query.php:115 #: includes/class-wcs-query.php:117 templates/admin/status.php:9 -#: woocommerce-subscriptions.php:226 woocommerce-subscriptions.php:239 +#: woocommerce-subscriptions.php:227 woocommerce-subscriptions.php:240 msgid "Subscriptions" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1024 +#: includes/admin/class-wc-subscriptions-admin.php:1029 msgid "Button Text" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1031 +#: includes/admin/class-wc-subscriptions-admin.php:1036 msgid "Add to Cart Button Text" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1032 +#: includes/admin/class-wc-subscriptions-admin.php:1037 msgid "" "A product displays a button with the text \"Add to Cart\". By default, a " "subscription changes this to \"Sign Up Now\". You can customise the button " "text for subscriptions here." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1036 -#: includes/admin/class-wc-subscriptions-admin.php:1047 +#: includes/admin/class-wc-subscriptions-admin.php:1041 +#: includes/admin/class-wc-subscriptions-admin.php:1052 #: includes/class-wc-product-subscription-variation.php:98 #: includes/class-wc-product-subscription.php:72 #: includes/class-wc-product-variable-subscription.php:63 #: includes/class-wc-subscriptions-product.php:96 -#: woocommerce-subscriptions.php:485 +#: woocommerce-subscriptions.php:487 msgid "Sign Up Now" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1042 +#: includes/admin/class-wc-subscriptions-admin.php:1047 msgid "Place Order Button Text" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1043 +#: includes/admin/class-wc-subscriptions-admin.php:1048 msgid "" "Use this field to customise the text displayed on the checkout button when " "an order contains a subscription. Normally the checkout submission button " @@ -231,11 +231,11 @@ msgid "" "changed to \"Sign Up Now\"." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1055 +#: includes/admin/class-wc-subscriptions-admin.php:1060 msgid "Roles" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1058 +#: includes/admin/class-wc-subscriptions-admin.php:1063 #. translators: placeholders are tags msgid "" "Choose the default roles to assign to active and inactive subscribers. For " @@ -244,46 +244,46 @@ msgid "" "allocated these roles to prevent locking out administrators." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1063 +#: includes/admin/class-wc-subscriptions-admin.php:1068 msgid "Subscriber Default Role" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1064 +#: includes/admin/class-wc-subscriptions-admin.php:1069 msgid "" "When a subscription is activated, either manually or after a successful " "purchase, new users will be assigned this role." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1075 +#: includes/admin/class-wc-subscriptions-admin.php:1080 msgid "Inactive Subscriber Role" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1076 +#: includes/admin/class-wc-subscriptions-admin.php:1081 msgid "" "If a subscriber's subscription is manually cancelled or expires, she will " "be assigned this role." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1096 +#: includes/admin/class-wc-subscriptions-admin.php:1101 msgid "Manual Renewal Payments" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1097 +#: includes/admin/class-wc-subscriptions-admin.php:1102 msgid "Accept Manual Renewals" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1102 +#: includes/admin/class-wc-subscriptions-admin.php:1107 #. translators: placeholders are opening and closing link tags msgid "" "With manual renewals, a customer's subscription is put on-hold until they " "login and pay to renew it. %sLearn more%s." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1108 +#: includes/admin/class-wc-subscriptions-admin.php:1113 msgid "Turn off Automatic Payments" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1113 +#: includes/admin/class-wc-subscriptions-admin.php:1118 #. translators: placeholders are opening and closing link tags msgid "" "If you don't want new subscription purchases to automatically charge " @@ -292,11 +292,11 @@ msgid "" "more%s." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1128 +#: includes/admin/class-wc-subscriptions-admin.php:1133 msgid "Customer Suspensions" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1135 +#: includes/admin/class-wc-subscriptions-admin.php:1140 msgid "" "Set a maximum number of times a customer can suspend their account for each " "billing period. For example, for a value of 3 and a subscription billed " @@ -306,28 +306,28 @@ msgid "" "this to 0 to turn off the customer suspension feature completely." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1139 +#: includes/admin/class-wc-subscriptions-admin.php:1144 msgid "Mixed Checkout" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1140 +#: includes/admin/class-wc-subscriptions-admin.php:1145 msgid "Allow subscriptions and products to be purchased simultaneously." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1144 +#: includes/admin/class-wc-subscriptions-admin.php:1149 msgid "Allow subscriptions and products to be purchased in a single transaction." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1148 +#: includes/admin/class-wc-subscriptions-admin.php:1153 #: includes/upgrades/templates/wcs-about-2-0.php:108 msgid "Drip Downloadable Content" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1149 +#: includes/admin/class-wc-subscriptions-admin.php:1154 msgid "Enable dripping for downloadable content on subscription products." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1153 +#: includes/admin/class-wc-subscriptions-admin.php:1158 msgid "" "Enabling this grants access to new downloadable files added to a product " "only after the next renewal is processed.%sBy default, access to new " @@ -335,7 +335,7 @@ msgid "" "customer that has an active subscription with that product." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1189 +#: includes/admin/class-wc-subscriptions-admin.php:1194 #. translators: $1-$2: opening and closing tags, $3-$4: opening and #. closing tags msgid "" @@ -343,71 +343,73 @@ msgid "" "start selling subscriptions!%4$s" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1194 +#: includes/admin/class-wc-subscriptions-admin.php:1199 msgid "Add a Subscription Product" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1195 +#: includes/admin/class-wc-subscriptions-admin.php:1200 #: includes/upgrades/templates/wcs-about-2-0.php:35 #: includes/upgrades/templates/wcs-about.php:34 -#: woocommerce-subscriptions.php:1024 +#: woocommerce-subscriptions.php:1026 msgid "Settings" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1281 +#: includes/admin/class-wc-subscriptions-admin.php:1286 #. translators: placeholder is a number msgid "We can't find a subscription with ID #%d. Perhaps it was deleted?" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1314 #: includes/admin/class-wc-subscriptions-admin.php:1319 +#: includes/admin/class-wc-subscriptions-admin.php:1324 #. translators: placeholders are opening link tag, ID of sub, and closing link #. tag msgid "Showing orders for %sSubscription %s%s" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1343 +#: includes/admin/class-wc-subscriptions-admin.php:1348 #. translators: number of 1$: days, 2$: weeks, 3$: months, 4$: years msgid "The trial period can not exceed: %1s, %2s, %3s or %4s." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1348 +#: includes/admin/class-wc-subscriptions-admin.php:1353 #. translators: placeholder is a time period (e.g. "4 weeks") msgid "The trial period can not exceed %s." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1401 -#: includes/admin/class-wc-subscriptions-admin.php:1429 -#: includes/admin/class-wc-subscriptions-admin.php:1482 +#: includes/admin/class-wc-subscriptions-admin.php:1412 +#: includes/admin/class-wc-subscriptions-admin.php:1440 +#: includes/admin/class-wc-subscriptions-admin.php:1493 +#: includes/admin/reports/class-wcs-report-cache-manager.php:340 msgid "Yes" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1401 -#: includes/admin/class-wc-subscriptions-admin.php:1429 +#: includes/admin/class-wc-subscriptions-admin.php:1412 +#: includes/admin/class-wc-subscriptions-admin.php:1440 +#: includes/admin/reports/class-wcs-report-cache-manager.php:340 msgid "No" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1465 +#: includes/admin/class-wc-subscriptions-admin.php:1476 msgid "Automatic Recurring Payments" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1482 +#: includes/admin/class-wc-subscriptions-admin.php:1493 msgid "" "Supports automatic renewal payments with the WooCommerce Subscriptions " "extension." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1562 +#: includes/admin/class-wc-subscriptions-admin.php:1573 msgid "Subscription items can no longer be edited." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1566 +#: includes/admin/class-wc-subscriptions-admin.php:1577 msgid "" "This subscription is no longer editable because the payment gateway does " "not allow modification of recurring amounts." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1585 +#: includes/admin/class-wc-subscriptions-admin.php:1596 #. translators: $1-2: opening and closing tags of a link that takes to Woo #. marketplace / Stripe product page msgid "" @@ -416,18 +418,18 @@ msgid "" "the %1$sfree Stripe extension%2$s." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1590 +#: includes/admin/class-wc-subscriptions-admin.php:1601 msgid "Recurring Payments" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1598 +#: includes/admin/class-wc-subscriptions-admin.php:1609 #. translators: placeholders are opening and closing link tags msgid "" "Payment gateways which don't support automatic recurring payments can be " "used to process %smanual subscription renewal payments%s." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1605 +#: includes/admin/class-wc-subscriptions-admin.php:1616 #. translators: $1-$2: opening and closing tags. Link to documents->payment #. gateways, 3$-4$: opening and closing tags. Link to WooCommerce extensions #. shop page @@ -525,7 +527,7 @@ msgstr[1] "" #: includes/admin/class-wcs-admin-post-types.php:408 #: includes/admin/meta-boxes/views/html-related-orders-table.php:20 #: templates/myaccount/my-subscriptions.php:26 -#: templates/myaccount/my-subscriptions.php:40 +#: templates/myaccount/my-subscriptions.php:41 #: templates/myaccount/related-orders.php:24 #: templates/myaccount/related-orders.php:45 #: templates/myaccount/related-subscriptions.php:21 @@ -542,7 +544,7 @@ msgstr "" #: templates/emails/subscription-info.php:18 #: templates/myaccount/my-subscriptions.php:25 #: templates/myaccount/related-subscriptions.php:20 -#: woocommerce-subscriptions.php:227 +#: woocommerce-subscriptions.php:228 msgid "Subscription" msgstr "" @@ -637,7 +639,7 @@ msgstr[0] "" msgstr[1] "" #: includes/admin/class-wcs-admin-post-types.php:587 -#: templates/myaccount/my-subscriptions.php:48 +#: templates/myaccount/my-subscriptions.php:49 #. translators: placeholder is the display name of a payment gateway a #. subscription was paid by msgid "Via %s" @@ -692,32 +694,32 @@ msgstr "" msgid "None" msgstr "" -#: includes/admin/class-wcs-admin-reports.php:58 +#: includes/admin/class-wcs-admin-reports.php:54 msgid "Subscription Events by Date" msgstr "" -#: includes/admin/class-wcs-admin-reports.php:64 +#: includes/admin/class-wcs-admin-reports.php:60 msgid "Upcoming Recurring Revenue" msgstr "" -#: includes/admin/class-wcs-admin-reports.php:70 +#: includes/admin/class-wcs-admin-reports.php:66 msgid "Retention Rate" msgstr "" -#: includes/admin/class-wcs-admin-reports.php:76 +#: includes/admin/class-wcs-admin-reports.php:72 msgid "Subscriptions by Product" msgstr "" -#: includes/admin/class-wcs-admin-reports.php:82 +#: includes/admin/class-wcs-admin-reports.php:78 msgid "Subscriptions by Customer" msgstr "" -#: includes/admin/class-wcs-admin-reports.php:92 +#: includes/admin/class-wcs-admin-reports.php:88 msgid "Failed Payment Retries" msgstr "" -#: includes/admin/class-wcs-admin-reports.php:132 -#: includes/admin/reports/class-wcs-report-cache-manager.php:271 +#: includes/admin/class-wcs-admin-reports.php:128 +#: includes/admin/reports/class-wcs-report-cache-manager.php:287 msgid "WooCommerce" msgstr "" @@ -737,45 +739,63 @@ msgstr "" msgid "Subscription status:" msgstr "" -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:105 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:106 msgid "Billing Details" msgstr "" -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:111 -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:113 -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:183 -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:185 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:107 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:179 +#: includes/payment-retry/class-wcs-retry-post-store.php:38 +msgid "Edit" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:108 +msgid "Load billing address" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:115 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:117 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:188 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:190 msgid "Address" msgstr "" -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:113 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:117 msgid "No billing address set." msgstr "" -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:133 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:137 #: includes/class-wcs-change-payment-method-admin.php:38 #: includes/class-wcs-change-payment-method-admin.php:51 msgid "Payment Method" msgstr "" -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:172 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:178 msgid "Shipping Details" msgstr "" -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:185 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:180 +msgid "Copy from billing" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:181 +msgid "Load shipping address" +msgstr "" + +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:190 msgid "No shipping address set." msgstr "" -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:207 -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:234 -msgid "Customer Note:" +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:212 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:242 +msgid "Customer Provided Note" msgstr "" -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:235 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:243 msgid "Customer's notes about the order" msgstr "" -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:303 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:315 #. translators: placeholder is error message from the payment gateway or #. subscriptions when updating the status msgid "Error updating some information: %s" @@ -798,7 +818,7 @@ msgstr "" #: includes/admin/meta-boxes/views/html-related-orders-table.php:19 #: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:515 #: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:173 -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:197 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:202 #: templates/myaccount/related-orders.php:23 #: templates/myaccount/related-orders.php:42 msgid "Date" @@ -868,13 +888,25 @@ msgstr "" msgid "Error: unable to find timezone of your browser." msgstr "" -#: includes/admin/reports/class-wcs-report-cache-manager.php:274 +#: includes/admin/reports/class-wcs-report-cache-manager.php:290 msgid "" "Please note: data for this report is cached. The data displayed may be out " "of date by up to 24 hours. The cache is updated each morning at 4am in your " "site's timezone." msgstr "" +#: includes/admin/reports/class-wcs-report-cache-manager.php:344 +msgid "Cache Update Failures" +msgstr "" + +#: includes/admin/reports/class-wcs-report-cache-manager.php:346 +#. translators: %d refers to the number of times we have detected cache update +#. failures +msgid "%d failures" +msgid_plural "%d failure" +msgstr[0] "" +msgstr[1] "" + #: includes/admin/reports/class-wcs-report-dashboard.php:78 msgid "%s signup subscription signups this month" msgid_plural "%s signups subscription signups this month" @@ -1150,7 +1182,7 @@ msgstr "" #: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:519 #: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:177 -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:201 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:206 msgid "Export CSV" msgstr "" @@ -1205,7 +1237,7 @@ msgid "" msgstr "" #: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:102 -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:86 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:91 msgid "%s renewal orders" msgstr "" @@ -1259,35 +1291,35 @@ msgstr "" msgid "Recovered Renewal Revenue" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:81 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:86 msgid "%s renewal income in this period" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:91 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:96 msgid "%s average renewal amount" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:167 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:172 msgid "Next 12 Months" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:168 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:173 msgid "Next 30 Days" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:169 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:174 msgid "Next Month" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:170 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:175 msgid "Next 7 Days" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:235 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:240 msgid "Renewals count" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:244 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:249 msgid "Renewals amount" msgstr "" @@ -1295,12 +1327,12 @@ msgstr "" msgid "Customer ID is invalid." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:216 +#: includes/api/class-wc-rest-subscriptions-controller.php:214 #: includes/api/legacy/class-wc-rest-subscriptions-controller.php:171 msgid "Invalid subscription id." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:287 +#: includes/api/class-wc-rest-subscriptions-controller.php:285 #: includes/api/legacy/class-wc-api-subscriptions.php:307 #: includes/api/legacy/class-wc-rest-subscriptions-controller.php:303 msgid "" @@ -1308,7 +1340,7 @@ msgid "" "Subscription." msgstr "" -#: includes/api/class-wc-rest-subscriptions-controller.php:318 +#: includes/api/class-wc-rest-subscriptions-controller.php:316 #: includes/api/legacy/class-wc-rest-subscriptions-controller.php:333 #. translators: 1$: gateway id, 2$: error message msgid "" @@ -1418,7 +1450,7 @@ msgid "Status set to %s." msgstr "" #: includes/class-wc-subscription.php:1148 -#: includes/class-wc-subscriptions-manager.php:2221 +#: includes/class-wc-subscriptions-manager.php:2263 #: includes/wcs-formatting-functions.php:228 #. translators: placeholder is human time diff (e.g. "3 weeks") msgid "In %s" @@ -1446,6 +1478,11 @@ msgstr "" msgid "The %s date of a subscription can not be deleted. You must delete the order." msgstr "" +#: includes/class-wc-subscription.php:1288 +#: includes/class-wc-subscription.php:2345 +msgid "Subscription #%d: " +msgstr "" + #: includes/class-wc-subscription.php:1682 msgid "Sign-up complete." msgstr "" @@ -1462,50 +1499,50 @@ msgstr "" msgid "Subscription Cancelled: maximum number of failed payments reached." msgstr "" -#: includes/class-wc-subscription.php:1922 -#: includes/class-wcs-change-payment-method-admin.php:156 +#: includes/class-wc-subscription.php:1929 +#: includes/class-wcs-change-payment-method-admin.php:155 msgid "Manual Renewal" msgstr "" -#: includes/class-wc-subscription.php:2001 +#: includes/class-wc-subscription.php:2008 msgid "Payment method meta must be an array." msgstr "" -#: includes/class-wc-subscription.php:2236 +#: includes/class-wc-subscription.php:2243 msgid "Invalid format. First parameter needs to be an array." msgstr "" -#: includes/class-wc-subscription.php:2240 +#: includes/class-wc-subscription.php:2247 msgid "Invalid data. First parameter was empty when passed to update_dates()." msgstr "" -#: includes/class-wc-subscription.php:2247 +#: includes/class-wc-subscription.php:2254 msgid "" "Invalid data. First parameter has a date that is not in the registered date " "types." msgstr "" -#: includes/class-wc-subscription.php:2311 +#: includes/class-wc-subscription.php:2318 msgid "The %s date must occur after the cancellation date." msgstr "" -#: includes/class-wc-subscription.php:2316 +#: includes/class-wc-subscription.php:2323 msgid "The %s date must occur after the last payment date." msgstr "" -#: includes/class-wc-subscription.php:2320 +#: includes/class-wc-subscription.php:2327 msgid "The %s date must occur after the next payment date." msgstr "" -#: includes/class-wc-subscription.php:2325 +#: includes/class-wc-subscription.php:2332 msgid "The %s date must occur after the trial end date." msgstr "" -#: includes/class-wc-subscription.php:2329 +#: includes/class-wc-subscription.php:2336 msgid "The %s date must occur after the start date." msgstr "" -#: includes/class-wc-subscription.php:2358 +#: includes/class-wc-subscription.php:2365 #: includes/class-wc-subscriptions-checkout.php:313 #: includes/wcs-order-functions.php:279 msgid "Backordered" @@ -1527,21 +1564,21 @@ msgstr "" msgid "Update the %1$s used for %2$sall%3$s of my active subscriptions" msgstr "" -#: includes/class-wc-subscriptions-cart.php:863 +#: includes/class-wc-subscriptions-cart.php:872 msgid "Please enter a valid postcode/ZIP." msgstr "" -#: includes/class-wc-subscriptions-cart.php:1034 +#: includes/class-wc-subscriptions-cart.php:1043 msgid "" "That subscription product can not be added to your cart as it already " "contains a subscription renewal." msgstr "" -#: includes/class-wc-subscriptions-cart.php:1122 +#: includes/class-wc-subscriptions-cart.php:1131 msgid "Invalid recurring shipping method." msgstr "" -#: includes/class-wc-subscriptions-cart.php:1888 +#: includes/class-wc-subscriptions-cart.php:1897 msgid "now" msgstr "" @@ -1645,134 +1682,149 @@ msgstr "" msgid "Recurring Product % Discount" msgstr "" -#: includes/class-wc-subscriptions-coupon.php:258 +#: includes/class-wc-subscriptions-coupon.php:356 msgid "" "Sorry, this coupon is only valid for an initial payment and the cart does " "not require an initial payment." msgstr "" -#: includes/class-wc-subscriptions-coupon.php:264 +#: includes/class-wc-subscriptions-coupon.php:362 msgid "Sorry, this coupon is only valid for new subscriptions." msgstr "" -#: includes/class-wc-subscriptions-coupon.php:269 +#: includes/class-wc-subscriptions-coupon.php:367 msgid "Sorry, this coupon is only valid for subscription products." msgstr "" -#: includes/class-wc-subscriptions-coupon.php:275 +#: includes/class-wc-subscriptions-coupon.php:373 #. translators: 1$: coupon code that is being removed msgid "Sorry, the \"%1$s\" coupon is only valid for renewals." msgstr "" -#: includes/class-wc-subscriptions-coupon.php:280 +#: includes/class-wc-subscriptions-coupon.php:378 msgid "" "Sorry, this coupon is only valid for subscription products with a sign-up " "fee." msgstr "" -#: includes/class-wc-subscriptions-coupon.php:505 +#: includes/class-wc-subscriptions-coupon.php:404 +msgid "" +"Sorry, recurring coupons can only be applied to subscriptions or " +"subscription orders." +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:408 +#. translators: placeholder is coupon code +msgid "" +"Sorry, \"%s\" can only be applied to subscription parent orders which " +"contain a product with signup fees." +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:411 +msgid "Sorry, only recurring coupons can only be applied to subscriptions." +msgstr "" + +#: includes/class-wc-subscriptions-coupon.php:634 msgid "Renewal % discount" msgstr "" -#: includes/class-wc-subscriptions-coupon.php:506 +#: includes/class-wc-subscriptions-coupon.php:635 msgid "Renewal product discount" msgstr "" -#: includes/class-wc-subscriptions-coupon.php:507 +#: includes/class-wc-subscriptions-coupon.php:636 msgid "Renewal cart discount" msgstr "" -#: includes/class-wc-subscriptions-coupon.php:524 +#: includes/class-wc-subscriptions-coupon.php:653 msgid "Renewal Discount" msgstr "" -#: includes/class-wc-subscriptions-manager.php:104 -msgid "" -"Error: Unable to create renewal order from scheduled payment. Please try " -"again." +#: includes/class-wc-subscriptions-manager.php:120 +msgid "Error: Unable to create renewal order with note \"%s\"" msgstr "" -#: includes/class-wc-subscriptions-manager.php:145 +#: includes/class-wc-subscriptions-manager.php:165 #: includes/gateways/class-wc-subscriptions-payment-gateways.php:204 msgid "Subscription doesn't exist in scheduled action: %d" msgstr "" -#: includes/class-wc-subscriptions-manager.php:282 +#: includes/class-wc-subscriptions-manager.php:302 #. translators: $1: order number, $2: error message msgid "Failed to activate subscription status for order #%1$s: %2$s" msgstr "" -#: includes/class-wc-subscriptions-manager.php:310 +#: includes/class-wc-subscriptions-manager.php:330 #. translators: $1: order number, $2: error message msgid "Failed to update subscription status after order #%1$s was put on-hold: %2$s" msgstr "" -#: includes/class-wc-subscriptions-manager.php:338 +#: includes/class-wc-subscriptions-manager.php:358 #. translators: $1: order number, $2: error message msgid "Failed to cancel subscription after order #%1$s was cancelled: %2$s" msgstr "" -#: includes/class-wc-subscriptions-manager.php:366 +#: includes/class-wc-subscriptions-manager.php:386 #. translators: $1: order number, $2: error message msgid "Failed to set subscription as expired for order #%1$s: %2$s" msgstr "" -#: includes/class-wc-subscriptions-manager.php:392 +#: includes/class-wc-subscriptions-manager.php:412 msgid "Subscription sign up failed." msgstr "" -#: includes/class-wc-subscriptions-manager.php:402 +#: includes/class-wc-subscriptions-manager.php:422 #. translators: $1: order number, $2: error message msgid "Failed to process failed payment on subscription for order #%1$s: %2$s" msgstr "" -#: includes/class-wc-subscriptions-manager.php:471 +#: includes/class-wc-subscriptions-manager.php:491 msgid "Error: Unable to create subscription. Please try again." msgstr "" -#: includes/class-wc-subscriptions-manager.php:490 +#: includes/class-wc-subscriptions-manager.php:510 msgid "Error: Unable to add product to created subscription. Please try again." msgstr "" -#: includes/class-wc-subscriptions-manager.php:535 +#: includes/class-wc-subscriptions-manager.php:555 msgid "Pending subscription created." msgstr "" -#: includes/class-wc-subscriptions-manager.php:1761 +#: includes/class-wc-subscriptions-manager.php:1803 #. translators: all fields are full html nodes: 1$: month input, 2$: day input, #. 3$: year input, 4$: hour input, 5$: minute input. Change the order if you'd #. like msgid "%1$s%2$s, %3$s @ %4$s : %5$s" msgstr "" -#: includes/class-wc-subscriptions-manager.php:1765 +#: includes/class-wc-subscriptions-manager.php:1807 #. translators: all fields are full html nodes: 1$: month input, 2$: day input, #. 3$: year input. Change the order if you'd like msgid "%1$s%2$s, %3$s" msgstr "" -#: includes/class-wc-subscriptions-manager.php:1770 +#: includes/class-wc-subscriptions-manager.php:1812 msgid "Change" msgstr "" -#: includes/class-wc-subscriptions-manager.php:2103 +#: includes/class-wc-subscriptions-manager.php:2145 #. translators: placeholder is subscription ID msgid "Failed sign-up for subscription %s." msgstr "" -#: includes/class-wc-subscriptions-manager.php:2194 +#: includes/class-wc-subscriptions-manager.php:2236 msgid "Invalid security token, please reload the page and try again." msgstr "" -#: includes/class-wc-subscriptions-manager.php:2198 +#: includes/class-wc-subscriptions-manager.php:2240 msgid "Only store managers can edit payment dates." msgstr "" -#: includes/class-wc-subscriptions-manager.php:2202 +#: includes/class-wc-subscriptions-manager.php:2244 msgid "Please enter all date fields." msgstr "" -#: includes/class-wc-subscriptions-manager.php:2227 +#: includes/class-wc-subscriptions-manager.php:2269 msgid "Date Changed" msgstr "" @@ -1908,27 +1960,27 @@ msgstr "" msgid "%1$s and a %2$s sign-up fee" msgstr "" -#: includes/class-wc-subscriptions-renewal-order.php:152 +#: includes/class-wc-subscriptions-renewal-order.php:160 #. translators: placeholder is order ID msgid "Order %s created to record renewal." msgstr "" -#: includes/class-wc-subscriptions-renewal-order.php:172 +#: includes/class-wc-subscriptions-renewal-order.php:180 msgid "Subscription renewal orders cannot be cancelled." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:170 +#: includes/class-wc-subscriptions-switcher.php:174 msgid "" "You have a subscription to this product. Choosing a new subscription will " "replace your existing subscription." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:172 +#: includes/class-wc-subscriptions-switcher.php:176 msgid "Choose a new subscription." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:194 -#: includes/class-wc-subscriptions-switcher.php:1016 +#: includes/class-wc-subscriptions-switcher.php:198 +#: includes/class-wc-subscriptions-switcher.php:1020 msgid "" "Your cart contained an invalid subscription switch request. It has been " "removed." @@ -1938,13 +1990,13 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: includes/class-wc-subscriptions-switcher.php:236 +#: includes/class-wc-subscriptions-switcher.php:240 msgid "" "You have already subscribed to this product and it is limited to one per " "customer. You can not purchase the product again." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:245 +#: includes/class-wc-subscriptions-switcher.php:249 #. translators: 1$: is the "You have already subscribed to this product" #. notice, 2$-4$: opening/closing link tags, 3$: an order number msgid "" @@ -1952,122 +2004,122 @@ msgid "" "subscription." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:324 +#: includes/class-wc-subscriptions-switcher.php:328 msgid "Switching" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:327 +#: includes/class-wc-subscriptions-switcher.php:331 #. translators: placeholders are opening and closing link tags msgid "" "Allow subscribers to switch (upgrade or downgrade) between different " "subscriptions. %sLearn more%s." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:332 +#: includes/class-wc-subscriptions-switcher.php:336 msgid "Allow Switching" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:333 +#: includes/class-wc-subscriptions-switcher.php:337 msgid "" "Allow subscribers to switch between subscriptions combined in a grouped " "product, different variations of a Variable subscription or don't allow " "switching." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:349 +#: includes/class-wc-subscriptions-switcher.php:353 msgid "Prorate Recurring Payment" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:350 +#: includes/class-wc-subscriptions-switcher.php:354 msgid "" "When switching to a subscription with a different recurring payment or " "billing period, should the price paid for the existing billing period be " "prorated when switching to the new subscription?" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:367 +#: includes/class-wc-subscriptions-switcher.php:371 msgid "Prorate Sign up Fee" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:368 +#: includes/class-wc-subscriptions-switcher.php:372 msgid "" "When switching to a subscription with a sign up fee, you can require the " "customer pay only the gap between the existing subscription's sign up fee " "and the new subscription's sign up fee (if any)." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:383 +#: includes/class-wc-subscriptions-switcher.php:387 msgid "Prorate Subscription Length" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:384 +#: includes/class-wc-subscriptions-switcher.php:388 msgid "" "When switching to a subscription with a length, you can take into account " "the payments already completed by the customer when determining how many " "payments the subscriber needs to make for the new subscription." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:399 +#: includes/class-wc-subscriptions-switcher.php:403 msgid "Switch Button Text" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:400 +#: includes/class-wc-subscriptions-switcher.php:404 msgid "" "Customise the text displayed on the button next to the subscription on the " "subscriber's account page. The default is \"Switch Subscription\", but you " "may wish to change this to \"Upgrade\" or \"Change Subscription\"." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:404 -#: includes/class-wc-subscriptions-switcher.php:430 -#: includes/class-wc-subscriptions-switcher.php:2323 +#: includes/class-wc-subscriptions-switcher.php:408 +#: includes/class-wc-subscriptions-switcher.php:434 +#: includes/class-wc-subscriptions-switcher.php:2357 msgid "Upgrade or Downgrade" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:881 +#: includes/class-wc-subscriptions-switcher.php:885 msgid "Switch order cancelled due to a new switch order being created #%s." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:968 +#: includes/class-wc-subscriptions-switcher.php:972 msgid "Switch Order" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:983 +#: includes/class-wc-subscriptions-switcher.php:987 msgid "Switched Subscription" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1088 +#: includes/class-wc-subscriptions-switcher.php:1092 msgid "You can only switch to a subscription product." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1094 +#: includes/class-wc-subscriptions-switcher.php:1098 msgid "We can not find your old subscription item." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1116 +#: includes/class-wc-subscriptions-switcher.php:1120 msgid "You can not switch to the same subscription." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1163 +#: includes/class-wc-subscriptions-switcher.php:1167 msgid "" "You can not switch this subscription. It appears you do not own the " "subscription." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1204 +#: includes/class-wc-subscriptions-switcher.php:1208 msgid "There was an error locating the switch details." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1914 -#: includes/class-wc-subscriptions-switcher.php:2229 +#: includes/class-wc-subscriptions-switcher.php:1923 +#: includes/class-wc-subscriptions-switcher.php:2263 msgid "The original subscription item being switched cannot be found." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1916 +#: includes/class-wc-subscriptions-switcher.php:1925 msgid "The item on the switch order cannot be found." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:2267 +#: includes/class-wc-subscriptions-switcher.php:2301 msgid "Failed to update the subscription shipping method." msgstr "" @@ -2148,7 +2200,7 @@ msgstr "" msgid "View and manage subscriptions" msgstr "" -#: includes/class-wcs-cached-data-manager.php:198 +#: includes/class-wcs-cached-data-manager.php:202 msgid "Weekly" msgstr "" @@ -2220,7 +2272,7 @@ msgstr "" msgid "Customer resubscribed in order #%s" msgstr "" -#: includes/class-wcs-change-payment-method-admin.php:113 +#: includes/class-wcs-change-payment-method-admin.php:112 msgid "Please choose a valid payment gateway to change to." msgstr "" @@ -2269,30 +2321,30 @@ msgstr "" msgid "%s ending in %s" msgstr "" -#: includes/class-wcs-remove-item.php:107 +#: includes/class-wcs-remove-item.php:106 msgid "Your request to undo your previous action was unsuccessful." msgstr "" -#: includes/class-wcs-remove-item.php:128 +#: includes/class-wcs-remove-item.php:127 #. translators: placeholders are 1$: item name, and, 2$: opening and, 3$: #. closing link tags msgid "You have successfully removed \"%1$s\" from your subscription. %2$sUndo?%3$s" msgstr "" -#: includes/class-wcs-remove-item.php:162 +#: includes/class-wcs-remove-item.php:161 #: includes/class-wcs-user-change-status-handler.php:99 msgid "Security error. Please contact us if you need assistance." msgstr "" -#: includes/class-wcs-remove-item.php:166 +#: includes/class-wcs-remove-item.php:165 msgid "You cannot modify a subscription that does not belong to you." msgstr "" -#: includes/class-wcs-remove-item.php:170 +#: includes/class-wcs-remove-item.php:169 msgid "You cannot remove an item that does not exist. " msgstr "" -#: includes/class-wcs-remove-item.php:174 +#: includes/class-wcs-remove-item.php:173 msgid "" "The item was not removed because this Subscription's payment method does " "not support removing an item." @@ -2352,7 +2404,7 @@ msgid "Subscription Cancelled" msgstr "" #: includes/emails/class-wcs-email-cancelled-subscription.php:128 -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:180 +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:192 #: includes/emails/class-wcs-email-expired-subscription.php:126 #: includes/emails/class-wcs-email-on-hold-subscription.php:126 msgid "Enable this email notification" @@ -2468,11 +2520,11 @@ msgstr "" msgid "Your {blogname} renewal order receipt from {order_date}" msgstr "" -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:28 +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:40 msgid "Customer Renewal Invoice" msgstr "" -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:29 +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:41 msgid "" "Sent to a customer when the subscription is due for renewal and the renewal " "requires a manual payment, either because it uses manual renewals or the " @@ -2481,11 +2533,11 @@ msgid "" "and payment links." msgstr "" -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:36 +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:48 msgid "Invoice for renewal order {order_number} from {order_date}" msgstr "" -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:37 +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:49 msgid "Invoice for renewal order {order_number}" msgstr "" @@ -2665,24 +2717,25 @@ msgid "" "subscription IDs. %1$sLearn more%2$s. %3$sDismiss%4$s." msgstr "" -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:178 +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:179 msgid "" "%sA fatal error has occurred when processing a recent subscription payment " "with PayPal. Please %sopen a new ticket at WooCommerce Support%s " "immediately to get this resolved.%sIn order to get the quickest possible " "response please attach a %sTemporary Admin Login%s and a copy of your PHP " -"error logs to your support ticket.%sLast recorded error: %s" +"error logs to your support ticket.%sLast recorded error: %sTo see the full " +"error, view the %s log file from the %sWooCommerce logs screen.%s" msgstr "" -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:186 +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:190 msgid "Ignore this error (not recommended!)" msgstr "" -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:186 +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:190 msgid "Open up a ticket now!" msgstr "" -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:265 +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:269 msgid "PayPal Subscription ID:" msgstr "" @@ -2690,12 +2743,12 @@ msgstr "" msgid "Total Discount" msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:302 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:301 #. translators: placeholder is blogname msgid "%s - Order" msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:518 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:511 msgid "SKU: %s" msgstr "" @@ -2708,32 +2761,32 @@ msgstr "" msgid "Billing agreement cancelled at PayPal." msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:245 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:270 msgid "IPN subscription sign up completed." msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:288 -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:365 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:313 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:390 msgid "IPN subscription payment completed." msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:327 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:352 msgid "IPN subscription failing payment method changed." msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:417 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:442 msgid "IPN subscription suspended." msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:440 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:465 msgid "IPN subscription cancelled." msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:456 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:481 msgid "IPN subscription payment failure." msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:578 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:602 msgid "Invalid PayPal IPN Payload: unable to find matching subscription." msgstr "" @@ -2819,10 +2872,6 @@ msgstr "" msgid "Add New Retry" msgstr "" -#: includes/payment-retry/class-wcs-retry-post-store.php:38 -msgid "Edit" -msgstr "" - #: includes/payment-retry/class-wcs-retry-post-store.php:39 msgid "Edit Retry" msgstr "" @@ -3912,12 +3961,12 @@ msgstr "" msgid "My Subscriptions" msgstr "" -#: templates/myaccount/my-subscriptions.php:36 +#: templates/myaccount/my-subscriptions.php:37 #: templates/myaccount/related-subscriptions.php:30 msgid "ID" msgstr "" -#: templates/myaccount/my-subscriptions.php:71 +#: templates/myaccount/my-subscriptions.php:72 #. translators: placeholders are opening and closing link tags to take to the #. shop page msgid "" @@ -3998,71 +4047,71 @@ msgstr "" msgid "Date type can not be an empty string." msgstr "" -#: woocommerce-subscriptions.php:241 +#: woocommerce-subscriptions.php:242 msgid "This is where subscriptions are stored." msgstr "" -#: woocommerce-subscriptions.php:285 +#: woocommerce-subscriptions.php:287 msgid "No Subscriptions found" msgstr "" -#: woocommerce-subscriptions.php:287 +#: woocommerce-subscriptions.php:289 msgid "" "Subscriptions will appear here for you to view and manage once purchased by " "a customer." msgstr "" -#: woocommerce-subscriptions.php:289 +#: woocommerce-subscriptions.php:291 #. translators: placeholders are opening and closing link tags msgid "%sLearn more about managing subscriptions »%s" msgstr "" -#: woocommerce-subscriptions.php:291 +#: woocommerce-subscriptions.php:293 #. translators: placeholders are opening and closing link tags msgid "%sAdd a subscription product »%s" msgstr "" -#: woocommerce-subscriptions.php:405 +#: woocommerce-subscriptions.php:407 msgid "" "A subscription renewal has been removed from your cart. Multiple " "subscriptions can not be purchased at the same time." msgstr "" -#: woocommerce-subscriptions.php:411 +#: woocommerce-subscriptions.php:413 msgid "" "A subscription has been removed from your cart. Due to payment gateway " "restrictions, different subscription products can not be purchased at the " "same time." msgstr "" -#: woocommerce-subscriptions.php:417 +#: woocommerce-subscriptions.php:419 msgid "" "A subscription has been removed from your cart. Products and subscriptions " "can not be purchased at the same time." msgstr "" -#: woocommerce-subscriptions.php:554 woocommerce-subscriptions.php:571 +#: woocommerce-subscriptions.php:556 woocommerce-subscriptions.php:573 #. translators: placeholder is a number, this is for the teens #. translators: placeholder is a number, numbers ending in 4-9, 0 msgid "%sth" msgstr "" -#: woocommerce-subscriptions.php:559 +#: woocommerce-subscriptions.php:561 #. translators: placeholder is a number, numbers ending in 1 msgid "%sst" msgstr "" -#: woocommerce-subscriptions.php:563 +#: woocommerce-subscriptions.php:565 #. translators: placeholder is a number, numbers ending in 2 msgid "%snd" msgstr "" -#: woocommerce-subscriptions.php:567 +#: woocommerce-subscriptions.php:569 #. translators: placeholder is a number, numbers ending in 3 msgid "%srd" msgstr "" -#: woocommerce-subscriptions.php:597 +#: woocommerce-subscriptions.php:599 #. translators: 1$-2$: opening and closing tags, 3$-4$: link tags, #. takes to woocommerce plugin on wp.org, 5$-6$: opening and closing link tags, #. leads to plugins.php in admin @@ -4072,7 +4121,7 @@ msgid "" "%5$sinstall & activate WooCommerce »%6$s" msgstr "" -#: woocommerce-subscriptions.php:604 +#: woocommerce-subscriptions.php:606 #. translators: 1$-2$: opening and closing tags, 3$-4$: opening and #. closing link tags, leads to plugin admin msgid "" @@ -4081,11 +4130,11 @@ msgid "" "WooCommerce to version 2.4 or newer »%4$s" msgstr "" -#: woocommerce-subscriptions.php:630 +#: woocommerce-subscriptions.php:632 msgid "Variable Subscription" msgstr "" -#: woocommerce-subscriptions.php:817 +#: woocommerce-subscriptions.php:819 #. translators: 1$-2$: opening and closing tags, 3$-4$: opening and #. closing link tags. Leads to duplicate site article on docs msgid "" @@ -4095,19 +4144,19 @@ msgid "" "environment. %3$sLearn more »%4$s." msgstr "" -#: woocommerce-subscriptions.php:819 +#: woocommerce-subscriptions.php:821 msgid "Quit nagging me (but don't enable automatic payments)" msgstr "" -#: woocommerce-subscriptions.php:820 +#: woocommerce-subscriptions.php:822 msgid "Enable automatic payments" msgstr "" -#: woocommerce-subscriptions.php:1026 +#: woocommerce-subscriptions.php:1028 msgid "Support" msgstr "" -#: woocommerce-subscriptions.php:1131 +#: woocommerce-subscriptions.php:1133 #. translators: placeholders are opening and closing tags. Leads to docs on #. version 2 msgid "" @@ -4118,14 +4167,14 @@ msgid "" "2.0 »%s" msgstr "" -#: woocommerce-subscriptions.php:1146 +#: woocommerce-subscriptions.php:1148 msgid "" "Warning! You are running version %s of WooCommerce Subscriptions plugin " "code but your database has been upgraded to Subscriptions version 2.0. This " "will cause major problems on your store." msgstr "" -#: woocommerce-subscriptions.php:1147 +#: woocommerce-subscriptions.php:1149 msgid "" "Please upgrade the WooCommerce Subscriptions plugin to version 2.0 or newer " "immediately. If you need assistance, after upgrading to Subscriptions v2.0, " @@ -4178,7 +4227,7 @@ msgctxt "example price" msgid "e.g. 9.90" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:776 +#: includes/admin/class-wc-subscriptions-admin.php:781 #. translators: placeholders are for HTML tags. They are 1$: "

", 2$: #. "

", 3$: "

", 4$: "", 5$: "", 6$: "", 7$: "", 8$: #. "

" @@ -4189,7 +4238,7 @@ msgid "" "%6$sVariable subscription%7$s.%8$s" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:778 +#: includes/admin/class-wc-subscriptions-admin.php:783 #. translators: placeholders are for HTML tags. They are 1$: "

", 2$: #. "

", 3$: "

", 4$: "

" msgctxt "used in admin pointer script params in javascript as price pointer content" @@ -4199,52 +4248,41 @@ msgid "" "sign-up fee and free trial.%4$s" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1089 +#: includes/admin/class-wc-subscriptions-admin.php:1094 msgctxt "option section heading" msgid "Renewals" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1121 +#: includes/admin/class-wc-subscriptions-admin.php:1126 msgctxt "options section heading" msgid "Miscellaneous" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1129 +#: includes/admin/class-wc-subscriptions-admin.php:1134 msgctxt "there's a number immediately in front of this text" msgid "suspensions per billing period." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1374 -msgctxt "in [subscriptions] shortcode" -msgid "No subscriptions found." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1383 -#. translators: order number -msgctxt "in [subscriptions] shortcode" -msgid "Subscription %s" -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:1400 -#: includes/admin/class-wc-subscriptions-admin.php:1428 +#: includes/admin/class-wc-subscriptions-admin.php:1411 +#: includes/admin/class-wc-subscriptions-admin.php:1439 msgctxt "label that indicates whether debugging is turned on for the plugin" msgid "WCS_DEBUG" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1406 -#: includes/admin/class-wc-subscriptions-admin.php:1434 +#: includes/admin/class-wc-subscriptions-admin.php:1417 +#: includes/admin/class-wc-subscriptions-admin.php:1445 msgctxt "Live or Staging, Label on WooCommerce -> System Status page" msgid "Subscriptions Mode" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1407 -#: includes/admin/class-wc-subscriptions-admin.php:1435 +#: includes/admin/class-wc-subscriptions-admin.php:1418 +#: includes/admin/class-wc-subscriptions-admin.php:1446 msgctxt "refers to staging site" msgid "Staging" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1407 -#: includes/admin/class-wc-subscriptions-admin.php:1435 +#: includes/admin/class-wc-subscriptions-admin.php:1418 +#: includes/admin/class-wc-subscriptions-admin.php:1446 msgctxt "refers to live site" msgid "Live" msgstr "" @@ -4271,7 +4309,7 @@ msgstr "" #: includes/admin/class-wcs-admin-post-types.php:246 #: includes/admin/class-wcs-admin-post-types.php:459 -#: includes/class-wc-subscriptions-manager.php:1771 +#: includes/class-wc-subscriptions-manager.php:1813 #: includes/wcs-user-functions.php:308 #: templates/myaccount/related-orders.php:67 msgctxt "an action on a subscription" @@ -4337,7 +4375,7 @@ msgctxt "edit subscription header" msgid "Subscription #%s details" msgstr "" -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:137 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:141 #: includes/class-wcs-change-payment-method-admin.php:52 msgctxt "" "The gateway ID displayed on the Edit Subscriptions screen when editing " @@ -4346,8 +4384,8 @@ msgid "Gateway ID: [%s]" msgstr "" #: includes/admin/meta-boxes/views/html-related-orders-row.php:19 -#: includes/class-wc-subscriptions-renewal-order.php:149 -#: templates/myaccount/my-subscriptions.php:37 +#: includes/class-wc-subscriptions-renewal-order.php:157 +#: templates/myaccount/my-subscriptions.php:38 #: templates/myaccount/related-orders.php:39 #: templates/myaccount/related-subscriptions.php:32 msgctxt "hash before order number" @@ -4405,7 +4443,7 @@ msgid "Price" msgstr "" #: templates/myaccount/my-subscriptions.php:27 -#: templates/myaccount/my-subscriptions.php:43 +#: templates/myaccount/my-subscriptions.php:44 #: templates/myaccount/related-subscriptions.php:22 #: templates/myaccount/related-subscriptions.php:38 wcs-functions.php:278 msgctxt "table heading" @@ -4422,6 +4460,11 @@ msgctxt "table heading" msgid "Cancelled Date" msgstr "" +#: includes/admin/reports/class-wcs-report-cache-manager.php:339 +msgctxt "Whether the Report Cache has been enabled" +msgid "Report Cache Enabled" +msgstr "" + #: includes/admin/reports/class-wcs-report-retention-rate.php:156 msgctxt "X axis label on retention rate graph" msgid "Number of days after sign-up" @@ -4453,7 +4496,7 @@ msgctxt "original denotes there is no date to display" msgid "-" msgstr "" -#: includes/class-wc-subscription.php:2274 +#: includes/class-wc-subscription.php:2281 #. translators: placeholder is date type (e.g. "end", "next_payment"...) 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\"." @@ -4476,9 +4519,9 @@ msgctxt "the page title of the change payment method form" msgid "Change Payment Method" msgstr "" -#: includes/class-wc-subscriptions-manager.php:94 -#: includes/class-wc-subscriptions-manager.php:1835 -#: includes/class-wc-subscriptions-manager.php:1853 +#: includes/class-wc-subscriptions-manager.php:84 +#: includes/class-wc-subscriptions-manager.php:1877 +#: includes/class-wc-subscriptions-manager.php:1895 msgctxt "used in order note as reason for why subscription status changed" msgid "Subscription renewal payment due:" msgstr "" @@ -4488,37 +4531,37 @@ msgctxt "used in order note as reason for why subscription status changed" msgid "Subscription renewal payment retry:" msgstr "" -#: includes/class-wc-subscriptions-manager.php:982 wcs-functions.php:209 +#: includes/class-wc-subscriptions-manager.php:1024 wcs-functions.php:209 msgctxt "Subscription status" msgid "Active" msgstr "" -#: includes/class-wc-subscriptions-manager.php:985 wcs-functions.php:211 +#: includes/class-wc-subscriptions-manager.php:1027 wcs-functions.php:211 msgctxt "Subscription status" msgid "Cancelled" msgstr "" -#: includes/class-wc-subscriptions-manager.php:988 wcs-functions.php:213 +#: includes/class-wc-subscriptions-manager.php:1030 wcs-functions.php:213 msgctxt "Subscription status" msgid "Expired" msgstr "" -#: includes/class-wc-subscriptions-manager.php:991 wcs-functions.php:208 +#: includes/class-wc-subscriptions-manager.php:1033 wcs-functions.php:208 msgctxt "Subscription status" msgid "Pending" msgstr "" -#: includes/class-wc-subscriptions-manager.php:994 +#: includes/class-wc-subscriptions-manager.php:1036 msgctxt "Subscription status" msgid "Failed" msgstr "" -#: includes/class-wc-subscriptions-manager.php:998 +#: includes/class-wc-subscriptions-manager.php:1040 msgctxt "Subscription status" msgid "On-hold" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:2464 wcs-functions.php:212 +#: includes/class-wc-subscriptions-switcher.php:2498 wcs-functions.php:212 msgctxt "Subscription status" msgid "Switched" msgstr "" @@ -4533,7 +4576,7 @@ msgctxt "Subscription status" msgid "Pending Cancellation" msgstr "" -#: includes/class-wc-subscriptions-manager.php:1748 +#: includes/class-wc-subscriptions-manager.php:1790 #. translators: 1$: month number (e.g. "01"), 2$: month abbreviation (e.g. #. "Jan") msgctxt "used in a select box" @@ -4570,100 +4613,100 @@ msgctxt "An order type" msgid "Non-subscription" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:340 -#: includes/class-wc-subscriptions-switcher.php:357 -#: includes/class-wc-subscriptions-switcher.php:391 +#: includes/class-wc-subscriptions-switcher.php:344 +#: includes/class-wc-subscriptions-switcher.php:361 +#: includes/class-wc-subscriptions-switcher.php:395 #: includes/class-wc-subscriptions-synchroniser.php:174 msgctxt "when to allow a setting" msgid "Never" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:341 +#: includes/class-wc-subscriptions-switcher.php:345 msgctxt "when to allow switching" msgid "Between Subscription Variations" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:342 +#: includes/class-wc-subscriptions-switcher.php:346 msgctxt "when to allow switching" msgid "Between Grouped Subscriptions" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:343 +#: includes/class-wc-subscriptions-switcher.php:347 msgctxt "when to allow switching" msgid "Between Both Variations & Grouped Subscriptions" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:358 +#: includes/class-wc-subscriptions-switcher.php:362 msgctxt "when to prorate recurring fee when switching" msgid "For Upgrades of Virtual Subscription Products Only" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:359 +#: includes/class-wc-subscriptions-switcher.php:363 msgctxt "when to prorate recurring fee when switching" msgid "For Upgrades of All Subscription Products" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:360 +#: includes/class-wc-subscriptions-switcher.php:364 msgctxt "when to prorate recurring fee when switching" msgid "For Upgrades & Downgrades of Virtual Subscription Products Only" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:361 +#: includes/class-wc-subscriptions-switcher.php:365 msgctxt "when to prorate recurring fee when switching" msgid "For Upgrades & Downgrades of All Subscription Products" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:375 +#: includes/class-wc-subscriptions-switcher.php:379 msgctxt "when to prorate signup fee when switching" msgid "Never (do not charge a sign up fee)" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:376 +#: includes/class-wc-subscriptions-switcher.php:380 msgctxt "when to prorate signup fee when switching" msgid "Never (charge the full sign up fee)" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:377 +#: includes/class-wc-subscriptions-switcher.php:381 msgctxt "when to prorate signup fee when switching" msgid "Always" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:392 +#: includes/class-wc-subscriptions-switcher.php:396 #: includes/class-wc-subscriptions-synchroniser.php:175 msgctxt "when to prorate first payment / subscription length" msgid "For Virtual Subscription Products Only" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:393 +#: includes/class-wc-subscriptions-switcher.php:397 #: includes/class-wc-subscriptions-synchroniser.php:176 msgctxt "when to prorate first payment / subscription length" msgid "For All Subscription Products" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1800 +#: includes/class-wc-subscriptions-switcher.php:1809 msgctxt "a switch order" msgid "Downgrade" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1803 +#: includes/class-wc-subscriptions-switcher.php:1812 msgctxt "a switch order" msgid "Upgrade" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1806 +#: includes/class-wc-subscriptions-switcher.php:1815 msgctxt "a switch order" msgid "Crossgrade" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1811 +#: includes/class-wc-subscriptions-switcher.php:1820 #. translators: %1: product subtotal, %2: HTML span tag, %3: direction #. (upgrade, downgrade, crossgrade), %4: closing HTML span tag msgctxt "product subtotal string" msgid "%1$s %2$s(%3$s)%4$s" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1927 -#: includes/class-wc-subscriptions-switcher.php:2240 +#: includes/class-wc-subscriptions-switcher.php:1936 +#: includes/class-wc-subscriptions-switcher.php:2274 #. translators: 1$: old item, 2$: new item when switching msgctxt "used in order notes" msgid "Customer switched from: %1$s to %2$s." @@ -4713,26 +4756,26 @@ msgctxt "hash before subscription ID" msgid "Subscription #%d does not exist." msgstr "" -#: includes/class-wcs-remove-item.php:104 +#: includes/class-wcs-remove-item.php:103 #. translators: 1$: product name, 2$: product id msgctxt "used in order note" msgid "Customer added \"%1$s\" (Product ID: #%2$d) via the My Account page." msgstr "" -#: includes/class-wcs-remove-item.php:125 +#: includes/class-wcs-remove-item.php:124 #. translators: 1$: product name, 2$: product id msgctxt "used in order note" msgid "Customer removed \"%1$s\" (Product ID: #%2$d) via the My Account page." msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:375 -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:384 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:400 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:409 #. translators: placeholder is payment status (e.g. "completed") msgctxt "used in order note" msgid "IPN subscription payment %s." msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:388 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:413 #. translators: placeholder is payment status (e.g. "completed") msgctxt "used in order note" msgid "IPN subscription payment %s for reason: %s." @@ -4786,7 +4829,7 @@ msgid "[%s] Subscription Cancelled" msgstr "" #: includes/emails/class-wcs-email-cancelled-subscription.php:126 -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:178 +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:190 #: includes/emails/class-wcs-email-expired-subscription.php:124 #: includes/emails/class-wcs-email-on-hold-subscription.php:124 msgctxt "an email notification" @@ -4886,10 +4929,10 @@ msgstr "" #: includes/gateways/paypal/class-wcs-paypal.php:344 #: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:208 -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:316 -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:327 -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:355 -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:367 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:315 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:326 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:353 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:365 #: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:144 #: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:147 #. translators: placeholder is for blog name @@ -4912,7 +4955,7 @@ msgctxt "data sent to paypal" msgid "Orders with %s" msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:398 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:391 #. translators: 1$: new status (e.g. "Cancel"), 2$: blog name msgctxt "data sent to paypal" msgid "%1$s subscription event triggered at %2$s" @@ -4935,7 +4978,7 @@ msgctxt "no information about something" msgid "N/A" msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:241 +#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:266 msgctxt "" "when it is a payment change, and there is a subscr_signup message, this " "will be a confirmation message that PayPal accepted it being the new " @@ -5021,7 +5064,7 @@ msgid "" msgstr "" #: includes/upgrades/templates/wcs-about-2-0.php:36 -#: woocommerce-subscriptions.php:1025 +#: woocommerce-subscriptions.php:1027 msgctxt "short for documents" msgid "Docs" msgstr "" @@ -5439,14 +5482,14 @@ msgctxt "subscription number in email table. (eg: #106)" msgid "#%s" msgstr "" -#: templates/myaccount/my-subscriptions.php:54 +#: templates/myaccount/my-subscriptions.php:55 #: templates/myaccount/related-orders.php:48 #: templates/myaccount/related-subscriptions.php:41 msgctxt "Used in data attribute. Escaped" msgid "Total" msgstr "" -#: templates/myaccount/my-subscriptions.php:58 +#: templates/myaccount/my-subscriptions.php:59 #: templates/myaccount/related-orders.php:73 #: templates/myaccount/related-subscriptions.php:45 msgctxt "view a subscription" @@ -5499,68 +5542,68 @@ msgctxt "The post title for the new subscription" msgid "Subscription – %s" msgstr "" -#: woocommerce-subscriptions.php:228 +#: woocommerce-subscriptions.php:229 msgctxt "custom post type setting" msgid "Add Subscription" msgstr "" -#: woocommerce-subscriptions.php:229 +#: woocommerce-subscriptions.php:230 msgctxt "custom post type setting" msgid "Add New Subscription" msgstr "" -#: woocommerce-subscriptions.php:230 +#: woocommerce-subscriptions.php:231 msgctxt "custom post type setting" msgid "Edit" msgstr "" -#: woocommerce-subscriptions.php:231 +#: woocommerce-subscriptions.php:232 msgctxt "custom post type setting" msgid "Edit Subscription" msgstr "" -#: woocommerce-subscriptions.php:232 +#: woocommerce-subscriptions.php:233 msgctxt "custom post type setting" msgid "New Subscription" msgstr "" -#: woocommerce-subscriptions.php:233 woocommerce-subscriptions.php:234 +#: woocommerce-subscriptions.php:234 woocommerce-subscriptions.php:235 msgctxt "custom post type setting" msgid "View Subscription" msgstr "" -#: woocommerce-subscriptions.php:237 +#: woocommerce-subscriptions.php:238 msgctxt "custom post type setting" msgid "No Subscriptions found in trash" msgstr "" -#: woocommerce-subscriptions.php:238 +#: woocommerce-subscriptions.php:239 msgctxt "custom post type setting" msgid "Parent Subscriptions" msgstr "" -#: woocommerce-subscriptions.php:305 +#: woocommerce-subscriptions.php:307 msgctxt "post status label including post count" msgid "Active (%s)" msgid_plural "Active (%s)" msgstr[0] "" msgstr[1] "" -#: woocommerce-subscriptions.php:306 +#: woocommerce-subscriptions.php:308 msgctxt "post status label including post count" msgid "Switched (%s)" msgid_plural "Switched (%s)" msgstr[0] "" msgstr[1] "" -#: woocommerce-subscriptions.php:307 +#: woocommerce-subscriptions.php:309 msgctxt "post status label including post count" msgid "Expired (%s)" msgid_plural "Expired (%s)" msgstr[0] "" msgstr[1] "" -#: woocommerce-subscriptions.php:308 +#: woocommerce-subscriptions.php:310 msgctxt "post status label including post count" msgid "Pending Cancellation (%s)" msgid_plural "Pending Cancellation (%s)" diff --git a/templates/admin/html-variation-price.php b/templates/admin/html-variation-price.php index 38116b9..79f304e 100644 --- a/templates/admin/html-variation-price.php +++ b/templates/admin/html-variation-price.php @@ -16,7 +16,7 @@ if ( ! defined( 'ABSPATH' ) ) {