This commit is contained in:
Prospress Inc
2017-07-21 16:16:16 +02:00
committed by Remco Tolsma
parent 09e7f71161
commit ed27f81d70
31 changed files with 884 additions and 333 deletions

View File

@@ -1,5 +1,45 @@
*** WooCommerce Subscriptions Changelog ***
2017.07.20 - version 2.2.10
* Fix: Do not attempt to call WC 3.0 only method when WC 2.6 is active by fixing version check from 2.6 to 3.0. Props @lkraav. PR#2236
* Fix: Display "Limit Subscription" option on Edit Product screen even when Reviews are disabled. PR#2233
* Fix: Hide "from" price html string if all variations have identical price and billing schedule. PR#2142
* Fix: Guard against proration miscalculation in double switching within one billing period. PR#2225
* Tweak: Log old version and WooCommerce versions on update. PR#2230
2017.07.12 - version 2.2.9
* Fix: WooCommerce 3.1: Notices when loading the WooCommerce > Subscriptions administration page. PR#2206
* Fix: WooCommerce 3.1: Notices on cart redrection hook becuase of use of 'add_to_cart_fragments' hook. PR#2221
* Fix: WooCommerce 3.0: Fix download links in first (processing order) email. PR#2185
* Fix: WooCommerce 3.0: Repair subscriptions with missing _contains_synced_subscription meta not set when WooCommerce 3.0 was active with Subscriptions 2.2.0 through to 2.2.7. PR#2183
* Fix: WooCommerce 3.0: Fix inactive role being assigned to users when subscriptions are suspended with WooCommerce 3.0. PR#2195
* Tweak: New hook to allow feees to be modified on renewals and resubscribes: 'woocommerce_adjust_order_fees_for_setup_cart_for_renewal'. PR#2208
* Tweak: Truncate cache files after a threshold (50MB) to avoid growing indefinitely. PR#1774
* Fix: Set default recurring shipping method when initial shipping method is not available in the recurring options. PR#2214
* Fix: Get active price instead of only subscription price product meta to honour sale prices. Fixes prorated switching costs as well as incorrect price being displayed for variable products where one variation was cheaped because it was on sale. PR#2215
* Fix: Allow payment on only most recent order relating to a subscription that is pending payment to avoid assorted issues stemming from paying for older orders. PR#2209
* Fix: Remove old PayPal IPN payload handling to match changes in WooCommerce 3.1.1 and fix potential exploit. PR#2220
* Fix: Fix default value for product limitations for products which do not have the product limitation value saved or set on them. PR#2219
* Fix: Ignore URL scheme in duplicate site check to avoid incorrectly identifying site as a staging site with v2.2.8 when running on a site with WP_SITEURL set, but being overridden, either by a host like WP Engine, or by some other constant, like FORCE_SSL_ADMIN. PR#2227
2017.06.22 - version 2.2.8
* Fix: WooCommerce 3.0: Update use of deprecated 'woocommerce_stock_html' filter by using new wc_get_stock_html() method. PR#2175 & PR#2193
* Fix: Make sure subscriptions suspended at PayPal.com are also correctly suspended in WooCommerce. PR#2199
* Fix: Do not display manual gateways when paying for failed renewal with an automatic retry. PR#2177
* Fix: Compare the site URL stored by Subscriptions against the WP_SITEURL constant when that constant is set, instead of always comparing against the 'siteurl' option value. PR#2167
* Fix: Apply discounts from renewal orders rather than subscriptions for renewal carts so that any code or manual application of a discount to the renewal order is applied correctly. PR#2156
* Fix: Do not cancel auto-draft subscriptions before post deletion as they do not need to be cancelled and cancellation emails can cause confusion. PR#2173
* Fix: Add 3rd param to 'woocommerce_order_item_name' filter calls to make sure they match parameters on WooCommerce filters. PR#2159
* Fix: Only return parent product IDs if a parent product exists. Fixes broken switch URLs for grouped products. PR#2160
* Fix: Update subscription payment method when renewal has been paid and has pending status and retry. PR#2141
* Fix: Make sure trial calculations for synced variation products are correct with PayPal Standard. PR#2168
* Fix: Set correct PHPDoc for returned type in WC_Subscription::get_parent(). Props @davefx. PR#2169
* Fix: Set correct PHPDoc return type in wcs-renewal-functions.php. PR#2198
* Fix: Copy custom, non-prefixed, subscription meta data to renewal orders. PR#2157
* Fix: Take sale price into account when displaying "From" price for variable products. PR#2176
* Fix: Take sale price into account when switching. PR#2171
* Fix: Fix undefined var $switched_subscriptions. PR#2192
2017.05.26 - version 2.2.7
* Tweak: Integrate with My Account > Payment Methods actions to make sure when a customer deletes a payment method, subscriptions using that payment method are automatically updated to use a different token. Or if there are no other payment methods on the customer's account, a customer can't delete the payment method used for automatic payments. PR#1866
* Tweak: Do not display 'Free' on free shipping methods to improve compatibility with the approached used in WooCommerce 2.6 and newer. PR#1766

View File

@@ -564,70 +564,15 @@ class WCS_Admin_Post_Types {
break;
case 1 :
foreach ( $subscription_items as $item ) {
$_product = apply_filters( 'woocommerce_order_item_product', $the_subscription->get_product_from_item( $item ), $item );
$item_meta = wcs_get_order_item_meta( $item, $_product );
$item_meta_html = $item_meta->display( true, true );
$item_quantity = absint( $item['qty'] );
$item_name = '';
if ( wc_product_sku_enabled() && $_product && $_product->get_sku() ) {
$item_name .= $_product->get_sku() . ' - ';
}
$item_name .= apply_filters( 'woocommerce_order_item_name', $item['name'], $item );
$item_name = esc_html( $item_name );
if ( $item_quantity > 1 ) {
$item_name = sprintf( '%s × %s', absint( $item_quantity ), $item_name );
}
if ( $_product ) {
$item_name = sprintf( '<a href="%s">%s</a>', get_edit_post_link( ( $_product->is_type( 'variation' ) ) ? wcs_get_objects_property( $_product, 'parent_id' ) : $_product->get_id() ), $item_name );
}
$column_content .= '<div class="order-item">';
$column_content .= wp_kses( $item_name, array( 'a' => array( 'href' => array() ) ) );
if ( $item_meta_html ) {
$column_content .= wcs_help_tip( $item_meta_html );
}
$column_content .= '</div>';
$column_content .= self::get_item_display( $item, $the_subscription );
}
break;
default :
$column_content .= '<a href="#" class="show_order_items">' . esc_html( apply_filters( 'woocommerce_admin_order_item_count', sprintf( _n( '%d item', '%d items', $the_subscription->get_item_count(), 'woocommerce-subscriptions' ), $the_subscription->get_item_count() ), $the_subscription ) ) . '</a>';
$column_content .= '<table class="order_items" cellspacing="0">';
foreach ( $the_subscription->get_items() as $item ) {
$_product = apply_filters( 'woocommerce_order_item_product', $the_subscription->get_product_from_item( $item ), $item );
$item_meta = wcs_get_order_item_meta( $item, $_product );
$item_meta_html = $item_meta->display( true, true );
ob_start();
?>
<tr class="<?php echo esc_attr( apply_filters( 'woocommerce_admin_order_item_class', '', $item ) ); ?>">
<td class="qty"><?php echo absint( $item['qty'] ); ?></td>
<td class="name">
<?php
$item_name = '';
if ( wc_product_sku_enabled() && $_product && $_product->get_sku() ) {
$item_name .= $_product->get_sku() . ' - ';
}
$item_name .= apply_filters( 'woocommerce_order_item_name', $item['name'], $item );
$item_name = esc_html( $item_name );
if ( $_product ) {
$item_name = sprintf( '<a href="%s">%s</a>', get_edit_post_link( $_product->get_id() ), $item_name );
}
echo wp_kses( $item_name, array( 'a' => array( 'href' => array() ) ) );
if ( $item_meta_html ) {
echo wcs_help_tip( $item_meta_html );
} ?>
</td>
</tr>
<?php
$column_content .= ob_get_clean();
foreach ( $subscription_items as $item ) {
$column_content .= self::get_item_display( $item, $the_subscription, 'row' );
}
$column_content .= '</table>';
@@ -1018,6 +963,135 @@ class WCS_Admin_Post_Types {
return $actions;
}
/**
* Get the HTML for an order item to display on the Subscription list table.
*
* @param array $actions
* @param object $post
* @return array
*/
protected static function get_item_display( $item, $the_subscription, $element = 'div' ) {
$_product = apply_filters( 'woocommerce_order_item_product', $the_subscription->get_product_from_item( $item ), $item );
$item_meta_html = self::get_item_meta_html( $item, $_product );
if ( 'div' === $element ) {
$item_html = self::get_item_display_div( $item, self::get_item_name_html( $item, $_product ), $item_meta_html );
} else {
$item_html = self::get_item_display_row( $item, self::get_item_name_html( $item, $_product, 'do_not_include_quantity' ), $item_meta_html );
}
return $item_html;
}
/**
* Get the HTML for order item meta to display on the Subscription list table.
*
* @param WC_Order_Item $item
* @param WC_Product $product
* @return string
*/
protected static function get_item_meta_html( $item, $_product ) {
if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
$item_meta = wcs_get_order_item_meta( $item, $_product );
$item_meta_html = $item_meta->display( true, true );
} else {
$item_meta_html = wc_display_item_meta( $item, array(
'before' => '',
'after' => '',
'separator' => '\n',
'echo' => false,
) );
}
return $item_meta_html;
}
/**
* Get the HTML for order item meta to display on the Subscription list table.
*
* @param WC_Order_Item $item
* @param WC_Product $product
* @return string
*/
protected static function get_item_name_html( $item, $_product, $include_quantity = 'include_quantity' ) {
$item_quantity = absint( $item['qty'] );
$item_name = '';
if ( wc_product_sku_enabled() && $_product && $_product->get_sku() ) {
$item_name .= $_product->get_sku() . ' - ';
}
$item_name .= apply_filters( 'woocommerce_order_item_name', $item['name'], $item, false );
$item_name = esc_html( $item_name );
if ( 'include_quantity' === $include_quantity && $item_quantity > 1 ) {
$item_name = sprintf( '%s &times; %s', absint( $item_quantity ), $item_name );
}
if ( $_product ) {
$item_name = sprintf( '<a href="%s">%s</a>', get_edit_post_link( ( $_product->is_type( 'variation' ) ) ? wcs_get_objects_property( $_product, 'parent_id' ) : $_product->get_id() ), $item_name );
}
return $item_name;
}
/**
* Get the HTML for order item to display on the Subscription list table using a div element
* as the wrapper, which is done for subscriptions with a single line item.
*
* @param array $actions
* @param object $post
* @return array
*/
protected static function get_item_display_div( $item, $item_name, $item_meta_html ) {
$item_html = '<div class="order-item">';
$item_html .= wp_kses( $item_name, array( 'a' => array( 'href' => array() ) ) );
if ( $item_meta_html ) {
$item_html .= wcs_help_tip( $item_meta_html );
}
$item_html .= '</div>';
return $item_html;
}
/**
* Get the HTML for order item to display on the Subscription list table using a table element
* as the wrapper, which is done for subscriptions with multilpe line items.
*
* @param array $actions
* @param object $post
* @return array
*/
protected static function get_item_display_row( $item, $item_name, $item_meta_html ) {
ob_start();
?>
<tr class="<?php echo esc_attr( apply_filters( 'woocommerce_admin_order_item_class', '', $item ) ); ?>">
<td class="qty"><?php echo absint( $item['qty'] ); ?></td>
<td class="name">
<?php
echo wp_kses( $item_name, array( 'a' => array( 'href' => array() ) ) );
if ( $item_meta_html ) {
echo wcs_help_tip( $item_meta_html );
} ?>
</td>
</tr>
<?php
$item_html = ob_get_clean();
return $item_html;
}
}
new WCS_Admin_Post_Types();

View File

@@ -87,7 +87,8 @@ class WC_Product_Variable_Subscription extends WC_Product_Variable {
$price = WC_Subscriptions_Product::get_price( $this );
$price = 'incl' == $tax_display_mode ? wcs_get_price_including_tax( $this, array( 'price' => $price ) ) : wcs_get_price_excluding_tax( $this, array( 'price' => $price ) );
$price = apply_filters( 'woocommerce_variable_price_html', wcs_get_price_html_from_text( $this ) . wc_price( $price ) . $this->get_price_suffix(), $this );
$price = $this->get_price_prefix( $prices ) . wc_price( $price ) . $this->get_price_suffix();
$price = apply_filters( 'woocommerce_variable_price_html', $price, $this );
$price = WC_Subscriptions_Product::get_price_string( $this, array( 'price' => $price ) );
return apply_filters( 'woocommerce_variable_subscription_price_html', apply_filters( 'woocommerce_get_price_html', $price, $this ), $this );
@@ -226,4 +227,28 @@ class WC_Product_Variable_Subscription extends WC_Product_Variable {
// Sync prices with children
self::sync( $product_id );
}
/**
* Get the suffix to display before prices.
*
* @return string
*/
protected function get_price_prefix( $prices ) {
// Are the subscription details of all variations identical?
$child_variation_ids = array_keys( $prices['price'] );
$variation_hash = md5( json_encode( $child_variation_ids ) );
if ( empty( $this->min_max_variation_data[ $variation_hash ] ) ) {
$this->min_max_variation_data[ $variation_hash ] = wcs_get_min_max_variation_data( $this, $child_variation_ids );
}
if ( $this->min_max_variation_data[ $variation_hash ]['identical'] ) {
$prefix = '';
} else {
$prefix = wcs_get_price_html_from_text( $this );
}
return $prefix;
}
}

View File

@@ -480,7 +480,6 @@ class WC_Subscription extends WC_Order {
case 'on-hold' :
// Record date of suspension - 'post_modified' column?
$this->set_suspension_count( $this->get_suspension_count() + 1 );
wcs_maybe_make_user_inactive( $this->get_user_id() );
break;
case 'cancelled' :
case 'switched' :
@@ -498,7 +497,6 @@ class WC_Subscription extends WC_Order {
}
$this->update_dates( $dates_to_update );
wcs_maybe_make_user_inactive( $this->get_user_id() );
break;
}
@@ -1790,7 +1788,7 @@ class WC_Subscription extends WC_Order {
/**
* Get parent order object.
*
* @return int
* @return WC_Order
*/
public function get_parent() {
return wc_get_order( $this->get_parent_id() );
@@ -2047,7 +2045,15 @@ class WC_Subscription extends WC_Order {
* @return bool
*/
public function is_download_permitted() {
return apply_filters( 'woocommerce_order_is_download_permitted', ( $this->has_status( 'active' ) || $this->has_status( 'pending-cancel' ) ), $this );
$sending_email = did_action( 'woocommerce_email_before_order_table' ) > did_action( 'woocommerce_email_after_order_table' );
$is_download_permitted = $this->has_status( 'active' ) || $this->has_status( 'pending-cancel' );
// WC Emails are sent before the subscription status is updated to active etc. so we need a way to ensure download links are added to the emails before being sent
if ( $sending_email && ! $is_download_permitted ) {
$is_download_permitted = true;
}
return apply_filters( 'woocommerce_order_is_download_permitted', $is_download_permitted, $this );
}
/**

View File

@@ -48,6 +48,8 @@ class WC_Subscriptions_Coupon {
// WC 3.0 only sets a coupon type if it is a pre-defined supported type, so we need to temporarily add our pseudo types. We don't want to add these on admin pages.
add_filter( 'woocommerce_coupon_discount_types', __CLASS__ . '::add_pseudo_coupon_types' );
}
add_filter( 'woocommerce_cart_totals_coupon_label', __CLASS__ . '::get_pseudo_coupon_label', 10, 2 );
}
/**
@@ -441,14 +443,14 @@ class WC_Subscriptions_Coupon {
$subtotal = 0;
foreach ( $renewal_coupons as $subscription_id => $coupons ) {
foreach ( $renewal_coupons as $order_id => $coupons ) {
foreach ( $coupons as $coupon_code => $coupon_properties ) {
if ( $coupon_code == $code ) {
if ( $subscription = wcs_get_subscription( $subscription_id ) ) {
$subtotal = $subscription->get_subtotal();
if ( $order = wc_get_order( $order_id ) ) {
$subtotal = $order->get_subtotal();
}
break;
}
@@ -507,6 +509,24 @@ class WC_Subscriptions_Coupon {
);
}
/**
* Filter the default coupon cart label for renewal pseudo coupons
*
* @param string $label
* @param WC_Coupon $coupon
* @return string
* @since 2.2.8
*/
public static function get_pseudo_coupon_label( $label, $coupon ) {
// If the coupon is one of our pseudo coupons, rather than displaying "Coupon: discount_renewal" display a nicer label.
if ( 'renewal_cart' === wcs_get_coupon_property( $coupon, 'discount_type' ) ) {
$label = esc_html( __( 'Renewal Discount', 'woocommerce-subscriptions' ) );
}
return $label;
}
/* Deprecated */
/**

View File

@@ -779,7 +779,7 @@ class WC_Subscriptions_Manager {
*/
public static function maybe_cancel_subscription( $post_id ) {
if ( 'shop_subscription' == get_post_type( $post_id ) ) {
if ( 'shop_subscription' == get_post_type( $post_id ) && 'auto-draft' !== get_post_status( $post_id ) ) {
$subscription = wcs_get_subscription( $post_id );

View File

@@ -65,6 +65,8 @@ class WC_Subscriptions_Order {
add_action( 'woocommerce_subscription_details_after_subscription_table', __CLASS__ . '::get_related_orders_template', 10, 1 );
add_filter( 'woocommerce_my_account_my_orders_actions', __CLASS__ . '::maybe_remove_pay_action', 10, 2 );
add_action( 'woocommerce_order_partially_refunded', __CLASS__ . '::maybe_cancel_subscription_on_partial_refund' );
add_action( 'woocommerce_order_fully_refunded', __CLASS__ . '::maybe_cancel_subscription_on_full_refund' );
@@ -784,6 +786,27 @@ class WC_Subscriptions_Order {
}
}
/**
* Unset pay action for an order if a more recent order exists
*
* @since 2.2.9
*/
public static function maybe_remove_pay_action( $actions, $order ) {
if ( isset( $actions['pay'] ) && wcs_order_contains_subscription( $order, array( 'any' ) ) ) {
$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() ) {
unset( $actions['pay'] );
break;
}
}
}
return $actions;
}
/**
* Allow subscription order items to be edited in WC 2.2. until Subscriptions 2.0 introduces
* its own WC_Subscription object.

View File

@@ -382,14 +382,25 @@ class WC_Subscriptions_Product {
}
/**
* Returns the price per period for a product if it is a subscription.
* Returns the active price per period for a product if it is a subscription.
*
* @param mixed $product A WC_Product object or product ID
* @return float The price charged per period for the subscription, or an empty string if the product is not a subscription.
* @since 1.0
*/
public static function get_price( $product ) {
return apply_filters( 'woocommerce_subscriptions_product_price', self::get_meta_data( $product, 'subscription_price', 0 ), self::maybe_get_product_instance( $product ) );
$product = self::maybe_get_product_instance( $product );
$subscription_price = self::get_meta_data( $product, 'subscription_price', 0 );
$sale_price = self::get_sale_price( $product );
$active_price = ( $subscription_price ) ? $subscription_price : self::get_regular_price( $product );
if ( $product->is_on_sale() && $subscription_price > $sale_price ) {
$active_price = $sale_price;
}
return apply_filters( 'woocommerce_subscriptions_product_price', $active_price, $product );
}
/**
@@ -1057,7 +1068,7 @@ class WC_Subscriptions_Product {
global $wpdb;
$parent_product_ids = array();
if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) && $product->get_parent() ) {
$parent_product_ids[] = $product->get_parent();
} else {
$parent_product_ids = $wpdb->get_col( $wpdb->prepare(

View File

@@ -106,12 +106,16 @@ class WC_Subscriptions_Renewal_Order {
// Do we need to activate a subscription?
if ( $order_completed && ! $subscription->has_status( wcs_get_subscription_ended_statuses() ) && ! $subscription->has_status( 'active' ) ) {
// Included here because calling payment_complete sets the retry status to 'cancelled'
$is_failed_renewal_order = ( 'failed' === $orders_old_status ) ? true : false;
$is_failed_renewal_order = apply_filters( 'woocommerce_subscriptions_is_failed_renewal_order', $is_failed_renewal_order, $order_id, $orders_old_status );
if ( $order_needed_payment ) {
$subscription->payment_complete();
$was_activated = true;
}
if ( 'failed' === $orders_old_status ) {
if ( $is_failed_renewal_order ) {
do_action( 'woocommerce_subscriptions_paid_for_failed_renewal_order', wc_get_order( $order_id ), $subscription );
}
} elseif ( 'failed' == $orders_new_status ) {

View File

@@ -955,7 +955,7 @@ class WC_Subscriptions_Switcher {
public static function switch_order_meta_box_rows( $post ) {
$subscriptions = array();
$switched_ids = array();
$switched_subscriptions = array();
$orders = array();
// On the subscription page, just show related orders
@@ -1365,6 +1365,16 @@ class WC_Subscriptions_Switcher {
// Find the actual recurring amount charged for the old subscription (we need to use the '_recurring_line_total' meta here rather than '_subscription_recurring_amount' because we want the recurring amount to include extra from extensions, like Product Add-ons etc.)
$old_recurring_total = $existing_item['line_total'];
// Use previous parent or renewal order's actual line item total instead of what is due, to guard against not yet paid amounts in multi-switching
$last_order = $subscription->get_last_order( 'all' );
$last_order_items = $last_order->get_items();
foreach ( $last_order_items as $last_order_item ) {
if ( wcs_get_canonical_product_id( $last_order_item ) == $product_id ) {
$old_recurring_total = $last_order_item['line_total'];
break;
}
}
if ( $subscription->get_prices_include_tax() ) {
$old_recurring_total += $existing_item['line_tax'];
}
@@ -1384,8 +1394,10 @@ class WC_Subscriptions_Switcher {
$days_in_new_cycle = wcs_get_days_in_cycle( WC_Subscriptions_Product::get_period( $item_data ), WC_Subscriptions_Product::get_interval( $item_data ) );
}
// We need to use the cart items price to ensure we include extras added by extensions like Product Add-ons
// We need to use the cart items price to ensure we include extras added by extensions like Product Add-ons, but we don't want the sign-up fee accounted for in the price, so make sure WC_Subscriptions_Cart::set_subscription_prices_for_calculation() isn't adding that.
remove_filter( 'woocommerce_product_get_price', 'WC_Subscriptions_Cart::set_subscription_prices_for_calculation', 100 );
$new_price_per_day = ( WC_Subscriptions_Product::get_price( $item_data ) * $cart_item['quantity'] ) / $days_in_new_cycle;
add_filter( 'woocommerce_product_get_price', 'WC_Subscriptions_Cart::set_subscription_prices_for_calculation', 100, 2 );
if ( $old_price_per_day < $new_price_per_day ) {

View File

@@ -1043,10 +1043,14 @@ class WC_Subscriptions_Synchroniser {
* @since 2.2.3
*/
public static function maybe_add_meta_for_new_line_item( $item_id, $item, $subscription_id ) {
if ( is_callable( array( $item, 'get_product_id' ) ) && self::is_product_synced( $item->get_product_id() ) ) {
if ( is_callable( array( $item, 'get_product_id' ) ) ) {
$product_id = wcs_get_canonical_product_id( $item );
if ( self::is_product_synced( $product_id ) ) {
self::maybe_add_subscription_meta( $subscription_id );
}
}
}
/* Deprecated Functions */

View File

@@ -22,6 +22,9 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager {
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
add_action( 'admin_init', array( $this, 'initialize_cron_check_size' ) ); // setup cron task to truncate big logs.
add_filter( 'cron_schedules', array( $this, 'add_weekly_cron_schedule' ) ); // create a weekly cron schedule
}
/**
@@ -135,6 +138,70 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager {
delete_transient( $key );
}
/**
* If the log is bigger than a threshold it will be
* truncated to 0 bytes.
*/
public static function cleanup_logs() {
$file = wc_get_log_file_path( 'wcs-cache' );
$max_cache_size = apply_filters( 'wcs_max_log_size', 50 * 1024 * 1024 );
if ( filesize( $file ) >= $max_cache_size ) {
$size_to_keep = apply_filters( 'wcs_log_size_to_keep', 25 * 1024 );
$lines_to_keep = apply_filters( 'wcs_log_lines_to_keep', 1000 );
$fp = fopen( $file, 'r' );
fseek( $fp, -1 * $size_to_keep, SEEK_END );
$data = '';
while ( ! feof( $fp ) ) {
$data .= fread( $fp, $size_to_keep );
}
fclose( $fp );
// Remove first line (which is probably incomplete) and also any empty line
$lines = explode( "\n", $data );
$lines = array_filter( array_slice( $lines, 1 ) );
$lines = array_slice( $lines, -1000 );
$lines[] = '---- log file automatically truncated ' . gmdate( 'Y-m-d H:i:s' ) . ' ---';
file_put_contents( $file, implode( "\n", $lines ), LOCK_EX );
}
}
/**
* Check once each week if the log file has exceeded the limits.
*
* @since 2.2.9
*/
public function initialize_cron_check_size() {
$hook = 'wcs_cleanup_big_logs';
if ( ! wp_next_scheduled( $hook ) ) {
wp_schedule_event( time(), 'weekly', $hook );
}
add_action( $hook, __CLASS__ . '::cleanup_logs' );
}
/**
* Add a weekly schedule for clearing up the cache
*
* @param $scheduled array
* @since 2.2.9
*/
function add_weekly_cron_schedule( $schedules ) {
if ( ! isset( $schedules['weekly'] ) ) {
$schedules['weekly'] = array(
'interval' => WEEK_IN_SECONDS,
'display' => __( 'Weekly', 'woocommerce-subscriptions' ),
);
}
return $schedules;
}
/* Deprecated Functions */
/**

View File

@@ -98,7 +98,7 @@ class WCS_Cart_Renewal {
add_action( 'template_redirect', array( &$this, 'maybe_setup_cart' ), 100 );
// Apply renewal discounts as pseudo coupons
add_action( 'wcs_after_renewal_setup_cart_subscription', array( &$this, 'maybe_setup_discounts' ), 10, 1 );
add_action( 'wcs_after_renewal_setup_cart_subscription', array( &$this, 'maybe_setup_discounts' ), 10, 2 );
add_filter( 'woocommerce_get_shop_coupon_data', array( &$this, 'renewal_coupon_data' ), 10, 2 );
add_action( 'wcs_before_renewal_setup_cart_subscriptions', array( &$this, 'clear_coupons' ), 10 );
@@ -288,17 +288,20 @@ class WCS_Cart_Renewal {
* @param object $subscription subscription
* @since 2.0.10
*/
public function maybe_setup_discounts( $subscription ) {
public function maybe_setup_discounts( $subscription, $order = null ) {
if ( null === $order ) {
// If no order arg is passed, to honor backward compatibility, apply discounts which apply to the subscription
$order = $subscription;
}
if ( wcs_is_subscription( $subscription ) ) {
if ( wcs_is_subscription( $order ) || wcs_order_contains_renewal( $order ) ) {
$used_coupons = $subscription->get_used_coupons();
$subscription_discount = wcs_get_objects_property( $subscription, 'cart_discount' );
$used_coupons = $order->get_used_coupons();
$order_discount = wcs_get_objects_property( $order, 'cart_discount' );
// Add any used coupon discounts to the cart (as best we can) using our pseudo renewal coupons
if ( ! empty( $used_coupons ) ) {
$coupon_items = $subscription->get_items( 'coupon' );
$coupon_items = $order->get_items( 'coupon' );
foreach ( $coupon_items as $coupon_item ) {
@@ -309,7 +312,7 @@ class WCS_Cart_Renewal {
// If the coupon still exists we can use the existing/available coupon properties
if ( true === wcs_get_coupon_property( $coupon, 'exists' ) ) {
// But we only want to handle recurring coupons that have been applied to the subscription
// But we only want to handle recurring coupons that have been applied to the order
if ( in_array( $coupon_type, array( 'recurring_percent', 'recurring_fee' ) ) ) {
// Set the coupon type to be a renewal equivalent for correct validation and calculations
@@ -323,13 +326,14 @@ class WCS_Cart_Renewal {
$coupon_code = wcs_get_coupon_property( $coupon, 'code' );
}
} else {
// If the coupon doesn't exist we can only really apply the discount amount we know about - so we'll apply a cart style pseudo coupon and then set the amount
wcs_set_coupon_property( $coupon, 'discount_type', 'renewal_cart' );
wcs_set_coupon_property( $coupon, 'coupon_amount', $coupon_item['item_meta']['discount_amount']['0'] );
// Adjust coupon code to reflect that it is being applied to a renewal
$coupon_code = wcs_get_coupon_property( $coupon, 'code' );
$coupon_amount = is_callable( array( $coupon_item, 'get_discount' ) ) ? $coupon_item->get_discount() : $coupon_item['item_meta']['discount_amount']['0'];
wcs_set_coupon_property( $coupon, 'coupon_amount', $coupon_amount );
}
// Now that we have a coupon we know we want to apply
@@ -337,11 +341,11 @@ class WCS_Cart_Renewal {
// Set renewal order products as the product ids on the coupon
if ( ! WC_Subscriptions::is_woocommerce_pre( '2.5' ) ) {
wcs_set_coupon_property( $coupon, 'product_ids', $this->get_products( $subscription ) );
wcs_set_coupon_property( $coupon, 'product_ids', $this->get_products( $order ) );
}
// Store the coupon info for later
$this->store_coupon( $subscription->get_id(), $coupon );
$this->store_coupon( wcs_get_objects_property( $order, 'id' ), $coupon );
// Add the coupon to the cart - the actually coupon values / data are grabbed when needed later
if ( WC()->cart && ! WC()->cart->has_discount( $coupon_code ) ) {
@@ -350,22 +354,21 @@ class WCS_Cart_Renewal {
}
}
// If there are no coupons but there is still a discount (i.e. it might have been manually added), we need to account for that as well
} elseif ( ! empty( $subscription_discount ) ) {
} elseif ( ! empty( $order_discount ) ) {
$coupon = new WC_Coupon( 'discount_renewal' );
// Apply our cart style pseudo coupon and the set the amount
wcs_set_coupon_property( $coupon, 'discount_type', 'renewal_cart' );
wcs_set_coupon_property( $coupon, 'coupon_amount', $subscription_discount );
wcs_set_coupon_property( $coupon, 'coupon_amount', $order_discount );
// Set renewal order products as the product ids on the coupon
if ( ! WC_Subscriptions::is_woocommerce_pre( '2.5' ) ) {
wcs_set_coupon_property( $coupon, 'product_ids', $this->get_products( $subscription ) );
wcs_set_coupon_property( $coupon, 'product_ids', $this->get_products( $order ) );
}
// Store the coupon info for later
$this->store_coupon( $subscription->get_id(), $coupon );
$this->store_coupon( wcs_get_objects_property( $order, 'id' ), $coupon );
// Add the coupon to the cart
if ( WC()->cart && ! WC()->cart->has_discount( 'discount_renewal' ) ) {
@@ -767,7 +770,7 @@ class WCS_Cart_Renewal {
return $data;
}
foreach ( $renewal_coupons as $subscription_id => $coupons ) {
foreach ( $renewal_coupons as $order_id => $coupons ) {
foreach ( $coupons as $coupon_code => $coupon_properties ) {
@@ -795,17 +798,17 @@ class WCS_Cart_Renewal {
/**
* Get original products for a renewal order - so that we can ensure renewal coupons are only applied to those
*
* @param object $subscription subscription
* @return array $product_ids an array of product ids on a subscription renewal order
* @param object WC_Order | WC_Subscription $order
* @return array $product_ids an array of product ids on a subscription/order
* @since 2.0.10
*/
protected function get_products( $subscription ) {
protected function get_products( $order ) {
$product_ids = array();
if ( wcs_is_subscription( $subscription ) ) {
foreach ( $subscription->get_items() as $item ) {
$product_id = ( $item['variation_id'] ) ? $item['variation_id'] : $item['product_id'];
if ( is_a( $order, 'WC_Abstract_Order' ) ) {
foreach ( $order->get_items() as $item ) {
$product_id = wcs_get_canonical_product_id( $item );
if ( ! empty( $product_id ) ) {
$product_ids[] = $product_id;
}
@@ -822,8 +825,8 @@ class WCS_Cart_Renewal {
* @param object $coupon coupon
* @since 2.0.10
*/
protected function store_coupon( $subscription_id, $coupon ) {
if ( ! empty( $subscription_id ) && ! empty( $coupon ) ) {
protected function store_coupon( $order_id, $coupon ) {
if ( ! empty( $order_id ) && ! empty( $coupon ) ) {
$renewal_coupons = WC()->session->get( 'wcs_renewal_coupons', array() );
$use_bools = WC_Subscriptions::is_woocommerce_pre( '3.0' ); // Some coupon properties have changed from accepting 'no' and 'yes' to true and false args.
$coupon_properties = array();
@@ -868,10 +871,10 @@ class WCS_Cart_Renewal {
}
// Subscriptions may have multiple coupons, store coupons in an array
if ( array_key_exists( $subscription_id, $renewal_coupons ) ) {
$renewal_coupons[ $subscription_id ][ wcs_get_coupon_property( $coupon, 'code' ) ] = $coupon_properties;
if ( array_key_exists( $order_id, $renewal_coupons ) ) {
$renewal_coupons[ $order_id ][ wcs_get_coupon_property( $coupon, 'code' ) ] = $coupon_properties;
} else {
$renewal_coupons[ $subscription_id ] = array( wcs_get_coupon_property( $coupon, 'code' ) => $coupon_properties );
$renewal_coupons[ $order_id ] = array( wcs_get_coupon_property( $coupon, 'code' ) => $coupon_properties );
}
WC()->session->set( 'wcs_renewal_coupons', $renewal_coupons );
@@ -889,7 +892,7 @@ class WCS_Cart_Renewal {
// Remove the coupons from the cart
if ( ! empty( $renewal_coupons ) ) {
foreach ( $renewal_coupons as $subscription_id => $coupons ) {
foreach ( $renewal_coupons as $order_id => $coupons ) {
foreach ( $coupons as $coupon_code => $coupon_properties ) {
WC()->cart->remove_coupons( $coupon_code );
}
@@ -912,6 +915,16 @@ class WCS_Cart_Renewal {
$order = $this->get_order( $cart_item );
/**
* Allow other plugins to remove/add fees of an existing order prior to building the cart without changing the saved order values
* (e.g. payment gateway based fees can remove fees and later can add new fees depending on the actual selected payment gateway)
*
* @param WC_Order $order is renderd by reference - change meta data of this object
* @param WC_Cart $cart
* @since 2.2.9
*/
do_action( 'woocommerce_adjust_order_fees_for_setup_cart_for_' . $this->cart_item_key, $order, $cart );
if ( $order instanceof WC_Order ) {
foreach ( $order->get_fees() as $fee ) {
$cart->add_fee( $fee['name'], $fee['line_total'], abs( $fee['line_tax'] ) > 0, $fee['tax_class'] );

View File

@@ -17,7 +17,7 @@ class WCS_Limiter {
public static function init() {
//Add limiting subscriptions options on edit product page
add_action( 'woocommerce_product_options_reviews', __CLASS__ . '::admin_edit_product_fields' );
add_action( 'woocommerce_product_options_advanced', __CLASS__ . '::admin_edit_product_fields' );
add_filter( 'woocommerce_subscription_is_purchasable', __CLASS__ . '::is_purchasable_switch', 12, 2 );
@@ -37,7 +37,6 @@ class WCS_Limiter {
public static function admin_edit_product_fields() {
global $post;
echo '</div>';
echo '<div class="options_group limit_subscription show_if_subscription show_if_variable-subscription">';
// Only one Subscription per customer
@@ -52,6 +51,7 @@ class WCS_Limiter {
'any' => __( 'Limit to one of any status', 'woocommerce-subscriptions' ),
),
) );
echo '</div>';
do_action( 'woocommerce_subscriptions_product_options_advanced' );
}

View File

@@ -55,6 +55,8 @@ class WCS_Retry_Manager {
add_action( 'woocommerce_subscription_renewal_payment_failed', __CLASS__ . '::maybe_apply_retry_rule', 10, 2 );
add_action( 'woocommerce_scheduled_subscription_payment_retry', __CLASS__ . '::maybe_retry_payment' );
add_filter( 'woocommerce_subscriptions_is_failed_renewal_order', __CLASS__ . '::compare_order_and_retry_statuses', 10, 3 );
}
}
@@ -324,6 +326,23 @@ class WCS_Retry_Manager {
}
}
/**
* Determines if a renewal order and the last retry statuses are the same (used to determine if a payment method
* change is needed)
*
* @since 2.2.8
*/
public static function compare_order_and_retry_statuses( $is_failed_order, $order_id, $order_status ) {
$last_retry = self::store()->get_last_retry_for_order( $order_id );
if ( null !== $last_retry && $order_status === $last_retry->get_rule()->get_status_to_apply( 'order' ) ) {
$is_failed_order = true;
}
return $is_failed_order;
}
/**
* Access the object used to interface with the database
*

View File

@@ -401,8 +401,11 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
// Admins can suspend subscription at PayPal triggering this IPN
case 'recurring_payment_suspended':
// When a subscriber suspends a PayPal Standard subscription, PayPal will notify WooCommerce by sending an IPN that uses an Express Checkout Recurring Payment payload, instead of an IPN payload for a PayPal Standard Subscription. This means the payload uses the 'recurring_payment_id' key for the subscription ID, not the 'subscr_id' key.
$ipn_profile_id = ( isset( $transaction_details['subscr_id'] ) ) ? $transaction_details['subscr_id'] : $transaction_details['recurring_payment_id'];
// Make sure subscription hasn't been linked to a new payment method
if ( wcs_get_paypal_id( $subscription ) != $transaction_details['subscr_id'] ) {
if ( wcs_get_paypal_id( $subscription ) != $ipn_profile_id ) {
WC_Gateway_Paypal::log( sprintf( 'IPN "recurring_payment_suspended" ignored for subscription %d - PayPal profile ID has changed', $subscription->id ) );
@@ -546,15 +549,8 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
}
}
// Couldn't find the order ID by subscr_id, so it's either not set on the order yet or the $args doesn't have a subscr_id, either way, let's get it from the args
// Couldn't find the order ID by subscr_id, so it's either not set on the order yet or the $args doesn't have a subscr_id (?!), either way, let's get it from the args
if ( empty( $order_id ) && isset( $args['custom'] ) ) {
// WC < 1.6.5
if ( is_numeric( $args['custom'] ) && 'shop_order' == $order_type ) {
$order_id = $args['custom'];
$order_key = $args['invoice'];
} else {
$order_details = json_decode( $args['custom'] );
@@ -569,7 +565,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
$order_key = $order_details->subscription_key;
} else {
// Subscription created with Subscriptions < 2.0
$subscriptions = wcs_get_subscriptions_for_order( $order_details->order_id, array( 'order_type' => array( 'parent' ) ) );
$subscriptions = wcs_get_subscriptions_for_order( absint( $order_details->order_id ), array( 'order_type' => array( 'parent' ) ) );
if ( ! empty( $subscriptions ) ) {
$subscription = array_pop( $subscriptions );
@@ -577,28 +573,13 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
$order_key = $subscription->get_order_key();
}
}
} elseif ( preg_match( '/^a:2:{/', $args['custom'] ) && ! preg_match( '/[CO]:\+?[0-9]+:"/', $args['custom'] ) && ( $order_details = maybe_unserialize( $args['custom'] ) ) ) { // WC 2.0 - WC 2.3.11, only allow serialized data in the expected format, do not allow objects or anything nasty to sneak in
} 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
if ( 'shop_order' == $order_type ) {
$order_id = $order_details[0];
$order_key = $order_details[1];
} else {
$message = __( 'Invalid PayPal IPN Payload: unable to find matching subscription.', 'woocommerce-subscriptions' );
// Subscription, but we didn't have the subscription data in old, serialized value, so we need to pull it based on the order
$subscriptions = wcs_get_subscriptions_for_order( $order_details[0], array( 'order_type' => array( 'parent' ) ) );
WC_Gateway_Paypal::log( $message );
if ( ! empty( $subscriptions ) ) {
$subscription = array_pop( $subscriptions );
$order_id = $subscription->get_id();
$order_key = $subscription->get_order_key();
}
}
} else { // WC 1.6.5 - WC 2.0 or invalid data
$order_id = str_replace( WCS_PayPal::get_option( 'invoice_prefix' ), '', $args['invoice'] );
$order_key = $args['custom'];
}
throw new Exception( $message );
}
}

View File

@@ -90,6 +90,8 @@ class WC_Subscriptions_Upgrader {
add_action( 'woocommerce_subscriptions_upgraded', __CLASS__ . '::maybe_redirect_after_upgrade_complete', 100, 2 );
add_action( 'wcs_repair_end_of_prepaid_term_actions', __CLASS__ . '::repair_end_of_prepaid_term_actions' );
add_action( 'wcs_repair_subscriptions_containing_synced_variations', __CLASS__ . '::repair_subscription_contains_sync_meta' );
}
/**
@@ -192,6 +194,12 @@ class WC_Subscriptions_Upgrader {
WCS_Upgrade_2_2_7::schedule_end_of_prepaid_term_repair();
}
// Repair missing _contains_synced_subscription post meta
if ( version_compare( get_option( 'woocommerce_db_version' ), '3.0', '>=' ) && version_compare( self::$active_version, '2.2.0', '>=' ) && version_compare( self::$active_version, '2.2.9', '<' ) ) {
include_once( 'class-wcs-upgrade-2-2-9.php' );
WCS_Upgrade_2_2_9::schedule_repair();
}
self::upgrade_complete();
}
@@ -748,6 +756,16 @@ class WC_Subscriptions_Upgrader {
WCS_Upgrade_2_2_7::repair_pending_cancelled_subscriptions();
}
/**
* Repair subscriptions with missing contains_synced_subscription post meta.
*
* @since 2.2.9
*/
public static function repair_subscription_contains_sync_meta() {
include_once( 'class-wcs-upgrade-2-2-9.php' );
WCS_Upgrade_2_2_9::repair_subscriptions_containing_synced_variations();
}
/**
* Used to check if a user ID is greater than the last user upgraded to version 1.4.
*

View File

@@ -0,0 +1,123 @@
<?php
/**
* Repair missing _contains_synced_subscription post meta caused by an error in determining if a variation product was synced at subscription signup.
* The error only affects subscriptions containing a synced variation product which were created with WC 3.0 and a Subscriptions version between 2.2.0 and 2.2.8
*
* @author Prospress
* @category Admin
* @package WooCommerce Subscriptions/Admin/Upgrades
* @version 2.2.9
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class WCS_Upgrade_2_2_9 {
private static $cron_hook = 'wcs_repair_subscriptions_containing_synced_variations';
private static $repaired_subscriptions_option = 'wcs_2_2_9_repaired_subscriptions';
private static $batch_size = 30;
/**
* Schedule an WP-Cron event to run in 3 minutes to repair subscription synced post meta.
*
* @since 2.2.9
*/
public static function schedule_repair() {
wp_schedule_single_event( gmdate( 'U' ) + ( MINUTE_IN_SECONDS * 3 ), self::$cron_hook );
}
/**
* Repair a batch of subscriptions.
*
* Subscriptions 2.2.0 included a bug which caused subscriptions which contain a synced variation product created while
* WC 3.0 was active, to have missing _contains_synced_subscription post meta. This was fixed to prevent new subscriptions
* falling victim to that bug in WCS 2.2.8 however existing subscriptions need to be repaired.
*
* @since 2.2.9
*/
public static function repair_subscriptions_containing_synced_variations() {
$repaired_subscriptions = get_option( self::$repaired_subscriptions_option, array() );
$subscriptions_to_repair = self::get_subscriptions_to_repair( $repaired_subscriptions );
foreach ( $subscriptions_to_repair as $subscription_id ) {
try {
$subscription = wcs_get_subscription( $subscription_id );
$subscription_updated = false;
if ( false === $subscription ) {
throw new Exception( 'Failed to instantiate subscription object' );
}
foreach ( $subscription->get_items() as $item ) {
$product_id = wcs_get_canonical_product_id( $item );
if ( WC_Subscriptions_Synchroniser::is_product_synced( $product_id ) ) {
update_post_meta( $subscription->get_id(), '_contains_synced_subscription', 'true' );
self::log( sprintf( 'Subscription %d repaired for synced product ID: %d', $subscription_id, $product_id ) );
$subscription_updated = true;
break;
}
}
if ( false === $subscription_updated ) {
self::log( sprintf( 'Subscription %d wasn\'t repaired - no synced product found', $subscription_id ) );
}
} catch ( Exception $e ) {
self::log( sprintf( '--- Exception caught repairing subscription %d - exception message: %s ---', $subscription_id, $e->getMessage() ) );
}
// Flag this subscription as repaired so we don't pull it into a following batch
$repaired_subscriptions[] = $subscription_id;
update_option( self::$repaired_subscriptions_option, $repaired_subscriptions, 'no' );
}
// If we've processed a full batch, schedule the next batch to be repaired
if ( count( $subscriptions_to_repair ) === self::$batch_size ) {
self::schedule_repair();
} else {
self::log( '2.2.9 repair missing _contains_synced_subscription post meta complete' );
}
}
/**
* Get a batch of subscriptions to repair.
*
* @since 2.2.9
* @param array $repaired_subscriptions A list of subscription post IDs to ignore.
* @return array A list of subscription ids which may need to be repaired.
*/
public static function get_subscriptions_to_repair( $repaired_subscriptions ) {
$subscriptions_to_repair = get_posts( array(
'post_type' => 'shop_subscription',
'posts_per_page' => self::$batch_size,
'post_status' => 'any',
'fields' => 'ids',
'post__not_in' => $repaired_subscriptions,
'meta_query' => array(
array(
'key' => '_contains_synced_subscription',
'compare' => 'NOT EXISTS',
),
array(
'key' => '_order_version', // Try to narrow the focus to subscriptions created after 3.0.0 as they are the only ones affected and needing repair (tough all subscriptions instantiated after 3.0 will also have their _order_version updated)
'value' => '3.0.0',
'compare' => '>=',
),
),
) );
return $subscriptions_to_repair;
}
/**
* Add a message to the wcs-upgrade-subscriptions-containing-synced-variations log
*
* @param string The message to be logged
* @since 2.2.9
*/
protected static function log( $message ) {
WCS_Upgrade_Logger::add( $message, 'wcs-upgrade-subscriptions-containing-synced-variations' );
}
}

View File

@@ -25,7 +25,7 @@ class WCS_Upgrade_Logger {
public static function init() {
add_action( 'woocommerce_subscriptions_upgraded', __CLASS__ . '::schedule_cleanup' );
add_action( 'woocommerce_subscriptions_upgraded', __CLASS__ . '::schedule_cleanup', 10, 2 );
}
/**
@@ -66,8 +66,9 @@ class WCS_Upgrade_Logger {
/**
* Schedule a hook to automatically clear the log after 8 weeks
*/
public static function schedule_cleanup() {
self::add( sprintf( '%s upgrade complete.', WC_Subscriptions::$version ) );
public static function schedule_cleanup( $current_version, $old_version ) {
$wc_version = defined( 'WC_VERSION' ) ? WC_VERSION : 'undefined';
self::add( sprintf( '%s upgrade complete from Subscriptions v%s while WooCommerce WC_VERSION %s and database version %s was active.', $current_version, $old_version, $wc_version, get_option( 'woocommerce_db_version' ) ) );
}
}
WCS_Upgrade_Logger::init();

View File

@@ -64,7 +64,14 @@ function wcs_cart_totals_shipping_html() {
}
$chosen_initial_method = isset( WC()->session->chosen_shipping_methods[ $i ] ) ? WC()->session->chosen_shipping_methods[ $i ] : '';
$chosen_recurring_method = isset( WC()->session->chosen_shipping_methods[ $recurring_cart_key . '_' . $i ] ) ? WC()->session->chosen_shipping_methods[ $recurring_cart_key . '_' . $i ] : $chosen_initial_method;
if ( isset( WC()->session->chosen_shipping_methods[ $recurring_cart_key . '_' . $i ] ) ) {
$chosen_recurring_method = WC()->session->chosen_shipping_methods[ $recurring_cart_key . '_' . $i ];
} elseif ( in_array( $chosen_initial_method, $package['rates'] ) ) {
$chosen_recurring_method = $chosen_initial_method;
} else {
$chosen_recurring_method = current( $package['rates'] )->id;
}
$shipping_selection_displayed = false;

View File

@@ -219,11 +219,11 @@ function wcs_get_objects_property( $object, $property, $single = 'single', $defa
* @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 bool|string $prefix An optional prefix to add to the $key. Default '_'. Set to boolean false to have no prefix added.
* @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
*/
function wcs_set_objects_property( &$object, $key, $value, $save = 'save', $meta_id = '' ) {
function wcs_set_objects_property( &$object, $key, $value, $save = 'save', $meta_id = '', $prefix_meta_key = 'prefix_meta_key' ) {
$prefixed_key = wcs_maybe_prefix_key( $key );
@@ -265,7 +265,8 @@ function wcs_set_objects_property( &$object, $key, $value, $save = 'save', $meta
// If there is no setter, treat as meta within the 3.0.x object.
} elseif ( is_callable( array( $object, 'update_meta_data' ) ) ) {
$object->update_meta_data( $prefixed_key, $value, $meta_id );
$meta_key = ( 'prefix_meta_key' === $prefix_meta_key ) ? $prefixed_key : $key;
$object->update_meta_data( $meta_key, $value, $meta_id );
// 2.6.x handling for name which is not meta.
} elseif ( 'name' === $key ) {
@@ -285,11 +286,12 @@ function wcs_set_objects_property( &$object, $key, $value, $save = 'save', $meta
} elseif ( 'name' === $key ) { // the replacement for post_title added in 3.0, need to update post_title not post meta
wp_update_post( array( 'ID' => wcs_get_objects_property( $object, 'id' ), 'post_title' => $value ) );
} else {
$meta_key = ( 'prefix_meta_key' === $prefix_meta_key ) ? $prefixed_key : $key;
if ( ! empty( $meta_id ) ) {
update_metadata_by_mid( 'post', $meta_id, $value, $prefixed_key );
update_metadata_by_mid( 'post', $meta_id, $value, $meta_key );
} else {
update_post_meta( wcs_get_objects_property( $object, 'id' ), $prefixed_key, $value );
update_post_meta( wcs_get_objects_property( $object, 'id' ), $meta_key, $value );
}
}
}

View File

@@ -24,7 +24,7 @@ function wcs_get_product_limitation( $product ) {
$product = wc_get_product( $product );
}
return apply_filters( 'woocommerce_subscriptions_product_limitation', WC_Subscriptions_Product::get_meta_data( $product, 'subscription_limit', 0 ), $product );
return apply_filters( 'woocommerce_subscriptions_product_limitation', WC_Subscriptions_Product::get_meta_data( $product, 'subscription_limit', 'no', 'use_default_value' ), $product );
}
/**

View File

@@ -178,7 +178,7 @@ function wcs_copy_order_meta( $from_order, $to_order, $type = 'subscription' ) {
$meta = apply_filters( 'wcs_' . $type . '_meta', $meta, $to_order, $from_order );
foreach ( $meta as $meta_item ) {
wcs_set_objects_property( $to_order, $meta_item['meta_key'], maybe_unserialize( $meta_item['meta_value'] ) );
wcs_set_objects_property( $to_order, $meta_item['meta_key'], maybe_unserialize( $meta_item['meta_value'] ), 'save', '', 'omit_key_prefix' );
}
}
@@ -554,6 +554,9 @@ function wcs_get_order_item( $item_id, $order ) {
* @since 2.0
*/
function wcs_get_order_item_meta( $item, $product = null ) {
if ( false === WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) {
wcs_deprecated_function( __FUNCTION__, '3.1 of WooCommerce and 2.2.9 of Subscriptions', 'WC_Order_Item_Product->get_formatted_meta_data() or wc_display_item_meta()' );
}
return new WC_Order_Item_Meta( $item, $product );
}

View File

@@ -161,6 +161,14 @@ function wcs_calculate_min_max_variations( $variations_data ) {
$variable_subscription_sign_up_fee = $variable_subscription_trial_period = $variable_subscription_trial_length = $variable_subscription_length = $variable_subscription_sign_up_fee = $variable_subscription_trial_period = $variable_subscription_trial_length = $variable_subscription_length = '';
$min_variation_id = $max_variation_id = null;
$variations_data_prices_list = array();
$variations_data_sign_up_fees_list = array();
$variations_data_periods_list = array();
$variations_data_intervals_list = array();
$variations_data_trial_lengths_list = array();
$variations_data_trial_periods_list = array();
$variations_data_lengths_list = array();
foreach ( $variations_data as $variation_id => $variation_data ) {
$is_max = $is_min = false;
@@ -169,6 +177,14 @@ function wcs_calculate_min_max_variations( $variations_data ) {
continue;
}
$variations_data_prices_list = array_unique( array_merge( $variations_data_prices_list, array( $variation_data['price'] ) ) );
$variations_data_sign_up_fees_list = array_unique( array_merge( $variations_data_sign_up_fees_list, array( empty( $variation_data['subscription']['sign_up_fee'] ) ? 0 : $variation_data['subscription']['sign_up_fee'] ) ) );
$variations_data_periods_list = array_unique( array_merge( $variations_data_periods_list, array( $variation_data['subscription']['period'] ) ) );
$variations_data_intervals_list = array_unique( array_merge( $variations_data_intervals_list, array( $variation_data['subscription']['interval'] ) ) );
$variations_data_trial_lengths_list = array_unique( array_merge( $variations_data_trial_lengths_list, array( empty( $variation_data['subscription']['trial_length'] ) ? 0 : $variation_data['subscription']['trial_length'] ) ) );
$variations_data_trial_periods_list = array_unique( array_merge( $variations_data_trial_periods_list, array( $variation_data['subscription']['trial_period'] ) ) );
$variations_data_lengths_list = array_unique( array_merge( $variations_data_lengths_list, array( $variation_data['subscription']['length'] ) ) );
$has_free_trial = ( '' !== $variation_data['subscription']['trial_length'] && $variation_data['subscription']['trial_length'] > 0 ) ? true : false;
// Determine some recurring price flags
@@ -381,6 +397,24 @@ function wcs_calculate_min_max_variations( $variations_data ) {
}
}
if ( sizeof( array_unique( $variations_data_prices_list ) ) > 1 ) {
$subscription_details_identical = false;
} elseif ( sizeof( array_unique( $variations_data_sign_up_fees_list ) ) > 1 ) {
$subscription_details_identical = false;
} elseif ( sizeof( array_unique( $variations_data_periods_list ) ) > 1 ) {
$subscription_details_identical = false;
} elseif ( sizeof( array_unique( $variations_data_intervals_list ) ) > 1 ) {
$subscription_details_identical = false;
} elseif ( sizeof( array_unique( $variations_data_trial_lengths_list ) ) > 1 ) {
$subscription_details_identical = false;
} elseif ( sizeof( array_unique( $variations_data_trial_periods_list ) ) > 1 ) {
$subscription_details_identical = false;
} elseif ( sizeof( array_unique( $variations_data_lengths_list ) ) > 1 ) {
$subscription_details_identical = false;
} else {
$subscription_details_identical = true;
}
return array(
'min' => array(
'variation_id' => $min_variation_id,
@@ -404,5 +438,6 @@ function wcs_calculate_min_max_variations( $variations_data ) {
'trial_length' => $variable_subscription_trial_length,
'length' => $variable_subscription_length,
),
'identical' => $subscription_details_identical,
);
}

View File

@@ -21,7 +21,7 @@ if ( ! defined( 'ABSPATH' ) ) {
* passed to it.
*
* @param int | WC_Subscription $subscription Post ID of a 'shop_subscription' post, or instance of a WC_Subscription object
* @return WC_Subscription
* @return WC_Order | WP_Error
* @since 2.0
*/
function wcs_create_renewal_order( $subscription ) {
@@ -95,7 +95,9 @@ function wcs_cart_contains_failed_renewal_order_payment() {
if ( false !== $cart_item && isset( $cart_item['subscription_renewal']['renewal_order_id'] ) ) {
$renewal_order = wc_get_order( $cart_item['subscription_renewal']['renewal_order_id'] );
if ( $renewal_order->has_status( 'failed' ) ) {
$is_failed_renewal_order = apply_filters( 'woocommerce_subscriptions_is_failed_renewal_order', $renewal_order->has_status( 'failed' ), $cart_item['subscription_renewal']['renewal_order_id'], $renewal_order->get_status() );
if ( $is_failed_renewal_order ) {
$contains_renewal = $cart_item;
}
}

View File

@@ -41,6 +41,22 @@ function wcs_maybe_make_user_inactive( $user_id ) {
}
}
/**
* Wrapper for wcs_maybe_make_user_inactive() that accepts a subscription instead of a user ID.
* Handy for hooks that pass a subscription object.
*
* @since 2.2.9
* @param WC_Subscription|WC_Order
*/
function wcs_maybe_make_user_inactive_for( $subscription ) {
wcs_maybe_make_user_inactive( $subscription->get_user_id() );
}
add_action( 'woocommerce_subscription_status_failed', 'wcs_maybe_make_user_inactive_for', 10, 1 );
add_action( 'woocommerce_subscription_status_on-hold', 'wcs_maybe_make_user_inactive_for', 10, 1 );
add_action( 'woocommerce_subscription_status_cancelled', 'wcs_maybe_make_user_inactive_for', 10, 1 );
add_action( 'woocommerce_subscription_status_switched', 'wcs_maybe_make_user_inactive_for', 10, 1 );
add_action( 'woocommerce_subscription_status_expired', 'wcs_maybe_make_user_inactive_for', 10, 1 );
/**
* Update a user's role to a special subscription's role
*

View File

@@ -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.7\n"
"Project-Id-Version: WooCommerce Subscriptions 2.2.10\n"
"Report-Msgid-Bugs-To: "
"https://github.com/Prospress/woocommerce-subscriptions/issues\n"
"POT-Creation-Date: 2017-05-27 00:30:00+00:00\n"
"POT-Creation-Date: 2017-07-20 05:32:36+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -215,7 +215,7 @@ msgstr ""
#: 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:480
#: woocommerce-subscriptions.php:483
msgid "Sign Up Now"
msgstr ""
@@ -350,7 +350,7 @@ msgstr ""
#: includes/admin/class-wc-subscriptions-admin.php:1195
#: includes/upgrades/templates/wcs-about-2-0.php:35
#: includes/upgrades/templates/wcs-about.php:34
#: woocommerce-subscriptions.php:991
#: woocommerce-subscriptions.php:1022
msgid "Settings"
msgstr ""
@@ -575,12 +575,12 @@ msgid "End Date"
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:457
#: includes/wcs-user-functions.php:276
#: includes/wcs-user-functions.php:292
msgid "Reactivate"
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:458
#: includes/wcs-user-functions.php:271
#: includes/wcs-user-functions.php:287
msgid "Suspend"
msgstr ""
@@ -595,12 +595,12 @@ msgid "Delete Permanently"
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:473
#: includes/class-wc-subscriptions-product.php:722
#: includes/class-wc-subscriptions-product.php:733
msgid "Restore this item from the Trash"
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:473
#: includes/class-wc-subscriptions-product.php:723
#: includes/class-wc-subscriptions-product.php:734
msgid "Restore"
msgstr ""
@@ -630,65 +630,65 @@ msgstr ""
msgid "Show more details"
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:598
#: includes/admin/class-wcs-admin-post-types.php:571
msgid "%d item"
msgid_plural "%d items"
msgstr[0] ""
msgstr[1] ""
#: includes/admin/class-wcs-admin-post-types.php:642
#: includes/admin/class-wcs-admin-post-types.php:587
#: templates/myaccount/my-subscriptions.php:48
#. translators: placeholder is the display name of a payment gateway a
#. subscription was paid by
msgid "Via %s"
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:656
#: includes/admin/class-wcs-admin-post-types.php:601
msgid "Y/m/d g:i:s A"
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:659
#: includes/admin/class-wcs-admin-post-types.php:604
msgid ""
"This date should be treated as an estimate only. The payment gateway for "
"this subscription controls when payments are processed."
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:932
#: includes/admin/class-wcs-admin-post-types.php:935
#: includes/admin/class-wcs-admin-post-types.php:938
#: includes/admin/class-wcs-admin-post-types.php:877
#: includes/admin/class-wcs-admin-post-types.php:880
#: includes/admin/class-wcs-admin-post-types.php:883
msgid "Subscription updated."
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:933
#: includes/admin/class-wcs-admin-post-types.php:878
msgid "Custom field updated."
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:934
#: includes/admin/class-wcs-admin-post-types.php:879
msgid "Custom field deleted."
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:939
#: includes/admin/class-wcs-admin-post-types.php:884
msgid "Subscription saved."
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:940
#: includes/admin/class-wcs-admin-post-types.php:885
msgid "Subscription submitted."
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:942
#: includes/admin/class-wcs-admin-post-types.php:887
#. translators: php date string
msgid "Subscription scheduled for: %1$s."
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:943
#: includes/admin/class-wcs-admin-post-types.php:888
msgid "Subscription draft updated."
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:979
#: includes/admin/class-wcs-admin-post-types.php:924
msgid "Any Payment Method"
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:980
#: includes/admin/class-wcs-admin-post-types.php:925
msgid "None"
msgstr ""
@@ -1403,109 +1403,109 @@ msgstr ""
msgid "Unable to change subscription status to \"%s\"."
msgstr ""
#: includes/class-wc-subscription.php:522
#: includes/class-wc-subscription.php:520
msgid "Unable to change subscription status to \"%s\". Exception: %s"
msgstr ""
#: includes/class-wc-subscription.php:544
#: includes/class-wc-subscription.php:542
#. translators: 1: old subscription status 2: new subscription status
msgid "Status changed from %1$s to %2$s."
msgstr ""
#: includes/class-wc-subscription.php:556
#: includes/class-wc-subscription.php:554
#. translators: %s: new order status
msgid "Status set to %s."
msgstr ""
#: includes/class-wc-subscription.php:1150
#: includes/class-wc-subscription.php:1148
#: includes/class-wc-subscriptions-manager.php:2221
#: includes/wcs-formatting-functions.php:228
#. translators: placeholder is human time diff (e.g. "3 weeks")
msgid "In %s"
msgstr ""
#: includes/class-wc-subscription.php:1153
#: includes/class-wc-subscription.php:1151
#: includes/wcs-formatting-functions.php:231
#. translators: placeholder is human time diff (e.g. "3 weeks")
msgid "%s ago"
msgstr ""
#: includes/class-wc-subscription.php:1160
#: includes/class-wc-subscription.php:1158
msgid "Not yet ended"
msgstr ""
#: includes/class-wc-subscription.php:1163
#: includes/class-wc-subscription.php:1161
msgid "Not cancelled"
msgstr ""
#: includes/class-wc-subscription.php:1278
#: includes/class-wc-subscription.php:1276
msgid "The start date of a subscription can not be deleted, only updated."
msgstr ""
#: includes/class-wc-subscription.php:1282
#: includes/class-wc-subscription.php:1280
msgid "The %s date of a subscription can not be deleted. You must delete the order."
msgstr ""
#: includes/class-wc-subscription.php:1683
#: includes/class-wc-subscription.php:1681
msgid "Sign-up complete."
msgstr ""
#: includes/class-wc-subscription.php:1685
#: includes/class-wc-subscription.php:1683
msgid "Payment received."
msgstr ""
#: includes/class-wc-subscription.php:1716
#: includes/class-wc-subscription.php:1714
msgid "Payment failed."
msgstr ""
#: includes/class-wc-subscription.php:1721
#: includes/class-wc-subscription.php:1719
msgid "Subscription Cancelled: maximum number of failed payments reached."
msgstr ""
#: includes/class-wc-subscription.php:1923
#: includes/class-wc-subscription.php:1921
#: includes/class-wcs-change-payment-method-admin.php:156
msgid "Manual Renewal"
msgstr ""
#: includes/class-wc-subscription.php:2002
#: includes/class-wc-subscription.php:2000
msgid "Payment method meta must be an array."
msgstr ""
#: includes/class-wc-subscription.php:2229
#: includes/class-wc-subscription.php:2235
msgid "Invalid format. First parameter needs to be an array."
msgstr ""
#: includes/class-wc-subscription.php:2233
#: includes/class-wc-subscription.php:2239
msgid "Invalid data. First parameter was empty when passed to update_dates()."
msgstr ""
#: includes/class-wc-subscription.php:2240
#: includes/class-wc-subscription.php:2246
msgid ""
"Invalid data. First parameter has a date that is not in the registered date "
"types."
msgstr ""
#: includes/class-wc-subscription.php:2304
#: includes/class-wc-subscription.php:2310
msgid "The %s date must occur after the cancellation date."
msgstr ""
#: includes/class-wc-subscription.php:2309
#: includes/class-wc-subscription.php:2315
msgid "The %s date must occur after the last payment date."
msgstr ""
#: includes/class-wc-subscription.php:2313
#: includes/class-wc-subscription.php:2319
msgid "The %s date must occur after the next payment date."
msgstr ""
#: includes/class-wc-subscription.php:2318
#: includes/class-wc-subscription.php:2324
msgid "The %s date must occur after the trial end date."
msgstr ""
#: includes/class-wc-subscription.php:2322
#: includes/class-wc-subscription.php:2328
msgid "The %s date must occur after the start date."
msgstr ""
#: includes/class-wc-subscription.php:2351
#: includes/class-wc-subscription.php:2357
#: includes/class-wc-subscriptions-checkout.php:313
#: includes/wcs-order-functions.php:279
msgid "Backordered"
@@ -1629,59 +1629,63 @@ msgstr ""
msgid "Error %d: Unable to create order. Please try again."
msgstr ""
#: includes/class-wc-subscriptions-coupon.php:63
#: includes/class-wc-subscriptions-coupon.php:65
msgid "Sign Up Fee Discount"
msgstr ""
#: includes/class-wc-subscriptions-coupon.php:64
#: includes/class-wc-subscriptions-coupon.php:66
msgid "Sign Up Fee % Discount"
msgstr ""
#: includes/class-wc-subscriptions-coupon.php:65
#: includes/class-wc-subscriptions-coupon.php:67
msgid "Recurring Product Discount"
msgstr ""
#: includes/class-wc-subscriptions-coupon.php:66
#: includes/class-wc-subscriptions-coupon.php:68
msgid "Recurring Product % Discount"
msgstr ""
#: includes/class-wc-subscriptions-coupon.php:256
#: includes/class-wc-subscriptions-coupon.php:258
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:262
#: includes/class-wc-subscriptions-coupon.php:264
msgid "Sorry, this coupon is only valid for new subscriptions."
msgstr ""
#: includes/class-wc-subscriptions-coupon.php:267
#: includes/class-wc-subscriptions-coupon.php:269
msgid "Sorry, this coupon is only valid for subscription products."
msgstr ""
#: includes/class-wc-subscriptions-coupon.php:273
#: includes/class-wc-subscriptions-coupon.php:275
#. 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:278
#: includes/class-wc-subscriptions-coupon.php:280
msgid ""
"Sorry, this coupon is only valid for subscription products with a sign-up "
"fee."
msgstr ""
#: includes/class-wc-subscriptions-coupon.php:503
#: includes/class-wc-subscriptions-coupon.php:505
msgid "Renewal % discount"
msgstr ""
#: includes/class-wc-subscriptions-coupon.php:504
#: includes/class-wc-subscriptions-coupon.php:506
msgid "Renewal product discount"
msgstr ""
#: includes/class-wc-subscriptions-coupon.php:505
#: includes/class-wc-subscriptions-coupon.php:507
msgid "Renewal cart discount"
msgstr ""
#: includes/class-wc-subscriptions-coupon.php:524
msgid "Renewal Discount"
msgstr ""
#: includes/class-wc-subscriptions-manager.php:104
msgid ""
"Error: Unable to create renewal order from scheduled payment. Please try "
@@ -1772,40 +1776,40 @@ msgstr ""
msgid "Date Changed"
msgstr ""
#: includes/class-wc-subscriptions-order.php:369
#: includes/class-wc-subscriptions-order.php:371
msgid "Your subscription will be activated when payment clears."
msgid_plural "Your subscriptions will be activated when payment clears."
msgstr[0] ""
msgstr[1] ""
#: includes/class-wc-subscriptions-order.php:378
#: includes/class-wc-subscriptions-order.php:380
#. translators: placeholders are opening and closing link tags
msgid "View the status of your subscription in %syour account%s."
msgid_plural "View the status of your subscriptions in %syour account%s."
msgstr[0] ""
msgstr[1] ""
#: includes/class-wc-subscriptions-order.php:426
#: includes/class-wc-subscriptions-order.php:428
msgid "Subscription Relationship"
msgstr ""
#: includes/class-wc-subscriptions-order.php:446
#: includes/class-wc-subscriptions-order.php:448
msgid "Renewal Order"
msgstr ""
#: includes/class-wc-subscriptions-order.php:448
#: includes/class-wc-subscriptions-order.php:450
msgid "Resubscribe Order"
msgstr ""
#: includes/class-wc-subscriptions-order.php:450
#: includes/class-wc-subscriptions-order.php:452
msgid "Parent Order"
msgstr ""
#: includes/class-wc-subscriptions-order.php:673
#: includes/class-wc-subscriptions-order.php:675
msgid "All orders types"
msgstr ""
#: includes/class-wc-subscriptions-order.php:940
#: includes/class-wc-subscriptions-order.php:963
#. translators: $1: opening link tag, $2: order number, $3: closing link tag
msgid "Subscription cancelled for refunded order %1$s#%2$s%3$s."
msgstr ""
@@ -1904,12 +1908,12 @@ msgstr ""
msgid "%1$s and a %2$s sign-up fee"
msgstr ""
#: includes/class-wc-subscriptions-renewal-order.php:148
#: includes/class-wc-subscriptions-renewal-order.php:152
#. translators: placeholder is order ID
msgid "Order %s created to record renewal."
msgstr ""
#: includes/class-wc-subscriptions-renewal-order.php:168
#: includes/class-wc-subscriptions-renewal-order.php:172
msgid "Subscription renewal orders cannot be cancelled."
msgstr ""
@@ -2016,7 +2020,7 @@ msgstr ""
#: includes/class-wc-subscriptions-switcher.php:404
#: includes/class-wc-subscriptions-switcher.php:430
#: includes/class-wc-subscriptions-switcher.php:2311
#: includes/class-wc-subscriptions-switcher.php:2323
msgid "Upgrade or Downgrade"
msgstr ""
@@ -2054,16 +2058,16 @@ msgstr ""
msgid "There was an error locating the switch details."
msgstr ""
#: includes/class-wc-subscriptions-switcher.php:1902
#: includes/class-wc-subscriptions-switcher.php:2217
#: includes/class-wc-subscriptions-switcher.php:1914
#: includes/class-wc-subscriptions-switcher.php:2229
msgid "The original subscription item being switched cannot be found."
msgstr ""
#: includes/class-wc-subscriptions-switcher.php:1904
#: includes/class-wc-subscriptions-switcher.php:1916
msgid "The item on the switch order cannot be found."
msgstr ""
#: includes/class-wc-subscriptions-switcher.php:2255
#: includes/class-wc-subscriptions-switcher.php:2267
msgid "Failed to update the subscription shipping method."
msgstr ""
@@ -2144,6 +2148,10 @@ msgstr ""
msgid "View and manage subscriptions"
msgstr ""
#: includes/class-wcs-cached-data-manager.php:198
msgid "Weekly"
msgstr ""
#: includes/class-wcs-cart-initial-payment.php:56
#: includes/class-wcs-cart-renewal.php:156
msgid "That doesn't appear to be your order."
@@ -2165,7 +2173,7 @@ msgstr ""
msgid "Subscription #%s has not been added to the cart."
msgstr ""
#: includes/class-wcs-cart-renewal.php:406
#: includes/class-wcs-cart-renewal.php:409
msgid ""
"We couldn't find the original subscription for an item in your cart. The "
"item was removed."
@@ -2175,7 +2183,7 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
#: includes/class-wcs-cart-renewal.php:413
#: includes/class-wcs-cart-renewal.php:416
msgid ""
"We couldn't find the original renewal order for an item in your cart. The "
"item was removed."
@@ -2185,7 +2193,7 @@ msgid_plural ""
msgstr[0] ""
msgstr[1] ""
#: includes/class-wcs-cart-renewal.php:688
#: includes/class-wcs-cart-renewal.php:691
msgid "All linked subscription items have been removed from the cart."
msgstr ""
@@ -2216,26 +2224,26 @@ msgstr ""
msgid "Please choose a valid payment gateway to change to."
msgstr ""
#: includes/class-wcs-limiter.php:46
#: includes/class-wcs-limiter.php:45
msgid "Limit subscription"
msgstr ""
#: includes/class-wcs-limiter.php:48
#: includes/class-wcs-limiter.php:47
#. translators: placeholders are opening and closing link tags
msgid ""
"Only allow a customer to have one subscription to this product. %sLearn "
"more%s."
msgstr ""
#: includes/class-wcs-limiter.php:50
#: includes/class-wcs-limiter.php:49
msgid "Do not limit"
msgstr ""
#: includes/class-wcs-limiter.php:51
#: includes/class-wcs-limiter.php:50
msgid "Limit to one active subscription"
msgstr ""
#: includes/class-wcs-limiter.php:52
#: includes/class-wcs-limiter.php:51
msgid "Limit to one of any status"
msgstr ""
@@ -2713,18 +2721,22 @@ msgstr ""
msgid "IPN subscription failing payment method changed."
msgstr ""
#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:414
#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:417
msgid "IPN subscription suspended."
msgstr ""
#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:437
#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:440
msgid "IPN subscription cancelled."
msgstr ""
#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:453
#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:456
msgid "IPN subscription payment failure."
msgstr ""
#: includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php:578
msgid "Invalid PayPal IPN Payload: unable to find matching subscription."
msgstr ""
#: includes/gateways/paypal/includes/class-wcs-paypal-status-manager.php:42
msgid "Subscription cancelled with PayPal"
msgstr ""
@@ -2836,13 +2848,13 @@ msgstr ""
msgid "No retries found in trash"
msgstr ""
#: includes/upgrades/class-wc-subscriptions-upgrader.php:284
#: includes/upgrades/class-wc-subscriptions-upgrader.php:292
#. translators: placeholder is a list of version numbers (e.g. "1.3 & 1.4 &
#. 1.5")
msgid "Database updated to version %s"
msgstr ""
#: includes/upgrades/class-wc-subscriptions-upgrader.php:307
#: includes/upgrades/class-wc-subscriptions-upgrader.php:315
#. translators: 1$: number of action scheduler hooks upgraded, 2$:
#. "{execution_time}", will be replaced on front end with actual time
msgid ""
@@ -2850,24 +2862,24 @@ msgid ""
"seconds)."
msgstr ""
#: includes/upgrades/class-wc-subscriptions-upgrader.php:323
#: includes/upgrades/class-wc-subscriptions-upgrader.php:331
#. translators: 1$: number of subscriptions upgraded, 2$: "{execution_time}",
#. will be replaced on front end with actual time it took
msgid "Migrated %1$s subscriptions to the new structure (in %2$s seconds)."
msgstr ""
#: includes/upgrades/class-wc-subscriptions-upgrader.php:336
#: includes/upgrades/class-wc-subscriptions-upgrader.php:344
#. translators: 1$: error message, 2$: opening link tag, 3$: closing link tag
msgid ""
"Unable to upgrade subscriptions.<br/>Error: %1$s<br/>Please refresh the "
"page and try again. If problem persists, %2$scontact support%3$s."
msgstr ""
#: includes/upgrades/class-wc-subscriptions-upgrader.php:591
#: includes/upgrades/class-wc-subscriptions-upgrader.php:599
msgid "Welcome to WooCommerce Subscriptions 2.1"
msgstr ""
#: includes/upgrades/class-wc-subscriptions-upgrader.php:591
#: includes/upgrades/class-wc-subscriptions-upgrader.php:599
msgid "About WooCommerce Subscriptions"
msgstr ""
@@ -3498,21 +3510,21 @@ msgstr ""
msgid "There was an error with the update. Please refresh the page and try again."
msgstr ""
#: includes/wcs-cart-functions.php:76 includes/wcs-cart-functions.php:77
#: includes/wcs-cart-functions.php:83 includes/wcs-cart-functions.php:84
msgid "Shipping via %s"
msgstr ""
#: includes/wcs-cart-functions.php:96
#: includes/wcs-cart-functions.php:103
msgid "Shipping"
msgid_plural "Shipping %d"
msgstr[0] ""
msgstr[1] ""
#: includes/wcs-cart-functions.php:225
#: includes/wcs-cart-functions.php:232
msgid "Free shipping coupon"
msgstr ""
#: includes/wcs-cart-functions.php:329
#: includes/wcs-cart-functions.php:336
#. translators: placeholder is a date
msgid "First renewal: %s"
msgstr ""
@@ -3670,8 +3682,8 @@ msgid_plural "a %s-year"
msgstr[0] ""
msgstr[1] ""
#: includes/wcs-user-functions.php:283
#: templates/single-product/add-to-cart/subscription.php:41
#: includes/wcs-user-functions.php:299
#: templates/single-product/add-to-cart/subscription.php:43
#: templates/single-product/add-to-cart/variable-subscription.php:29
msgid "Resubscribe"
msgstr ""
@@ -3949,7 +3961,7 @@ msgstr ""
msgid "Are you sure you want remove this item from your subscription?"
msgstr ""
#: templates/single-product/add-to-cart/subscription.php:43
#: templates/single-product/add-to-cart/subscription.php:45
#: templates/single-product/add-to-cart/variable-subscription.php:31
msgid "You have an active subscription to this product already."
msgstr ""
@@ -4029,28 +4041,28 @@ msgid ""
"can not be purchased at the same time."
msgstr ""
#: woocommerce-subscriptions.php:549 woocommerce-subscriptions.php:566
#: woocommerce-subscriptions.php:552 woocommerce-subscriptions.php:569
#. 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:554
#: woocommerce-subscriptions.php:557
#. translators: placeholder is a number, numbers ending in 1
msgid "%sst"
msgstr ""
#: woocommerce-subscriptions.php:558
#: woocommerce-subscriptions.php:561
#. translators: placeholder is a number, numbers ending in 2
msgid "%snd"
msgstr ""
#: woocommerce-subscriptions.php:562
#: woocommerce-subscriptions.php:565
#. translators: placeholder is a number, numbers ending in 3
msgid "%srd"
msgstr ""
#: woocommerce-subscriptions.php:592
#: woocommerce-subscriptions.php:595
#. translators: 1$-2$: opening and closing <strong> 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
@@ -4060,7 +4072,7 @@ msgid ""
"%5$sinstall & activate WooCommerce &raquo;%6$s"
msgstr ""
#: woocommerce-subscriptions.php:599
#: woocommerce-subscriptions.php:602
#. translators: 1$-2$: opening and closing <strong> tags, 3$-4$: opening and
#. closing link tags, leads to plugin admin
msgid ""
@@ -4069,11 +4081,11 @@ msgid ""
"WooCommerce to version 2.4 or newer &raquo;%4$s"
msgstr ""
#: woocommerce-subscriptions.php:625
#: woocommerce-subscriptions.php:628
msgid "Variable Subscription"
msgstr ""
#: woocommerce-subscriptions.php:812
#: woocommerce-subscriptions.php:815
#. translators: 1$-2$: opening and closing <strong> tags, 3$-4$: opening and
#. closing link tags. Leads to duplicate site article on docs
msgid ""
@@ -4083,19 +4095,19 @@ msgid ""
"environment. %3$sLearn more &raquo;%4$s."
msgstr ""
#: woocommerce-subscriptions.php:814
#: woocommerce-subscriptions.php:817
msgid "Quit nagging me (but don't enable automatic payments)"
msgstr ""
#: woocommerce-subscriptions.php:815
#: woocommerce-subscriptions.php:818
msgid "Enable automatic payments"
msgstr ""
#: woocommerce-subscriptions.php:993
#: woocommerce-subscriptions.php:1024
msgid "Support"
msgstr ""
#: woocommerce-subscriptions.php:1098
#: woocommerce-subscriptions.php:1129
#. translators: placeholders are opening and closing tags. Leads to docs on
#. version 2
msgid ""
@@ -4106,14 +4118,14 @@ msgid ""
"2.0 &raquo;%s"
msgstr ""
#: woocommerce-subscriptions.php:1113
#: woocommerce-subscriptions.php:1144
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:1114
#: woocommerce-subscriptions.php:1145
msgid ""
"Please upgrade the WooCommerce Subscriptions plugin to version 2.0 or newer "
"immediately. If you need assistance, after upgrading to Subscriptions v2.0, "
@@ -4260,7 +4272,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/wcs-user-functions.php:292
#: includes/wcs-user-functions.php:308
#: templates/myaccount/related-orders.php:67
msgctxt "an action on a subscription"
msgid "Cancel"
@@ -4288,13 +4300,13 @@ msgctxt "Subscription title on admin table. (e.g.: #211 for John Doe)"
msgid "%1$s#%2$s%3$s for %4$s"
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:937
#: includes/admin/class-wcs-admin-post-types.php:882
#. translators: placeholder is previous post title
msgctxt "used in post updated messages"
msgid "Subscription restored to revision from %s"
msgstr ""
#: includes/admin/class-wcs-admin-post-types.php:942
#: includes/admin/class-wcs-admin-post-types.php:887
msgctxt "used in \"Subscription scheduled for <date>\""
msgid "M j, Y @ G:i"
msgstr ""
@@ -4334,7 +4346,7 @@ msgid "Gateway ID: [%s]"
msgstr ""
#: includes/admin/meta-boxes/views/html-related-orders-row.php:19
#: includes/class-wc-subscriptions-renewal-order.php:145
#: includes/class-wc-subscriptions-renewal-order.php:149
#: templates/myaccount/my-subscriptions.php:37
#: templates/myaccount/related-orders.php:39
#: templates/myaccount/related-subscriptions.php:32
@@ -4363,7 +4375,7 @@ msgctxt "table heading"
msgid "Total"
msgstr ""
#: includes/class-wcs-retry-manager.php:120
#: includes/class-wcs-retry-manager.php:122
msgctxt "table heading"
msgid "Renewal Payment Retry"
msgstr ""
@@ -4436,12 +4448,12 @@ msgctxt "API response confirming order note deleted from a subscription"
msgid "Permanently deleted subscription note"
msgstr ""
#: includes/class-wc-subscription.php:1168
#: includes/class-wc-subscription.php:1166
msgctxt "original denotes there is no date to display"
msgid "-"
msgstr ""
#: includes/class-wc-subscription.php:2267
#: includes/class-wc-subscription.php:2273
#. 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\"."
@@ -4471,7 +4483,7 @@ msgctxt "used in order note as reason for why subscription status changed"
msgid "Subscription renewal payment due:"
msgstr ""
#: includes/class-wcs-retry-manager.php:300
#: includes/class-wcs-retry-manager.php:302
msgctxt "used in order note as reason for why subscription status changed"
msgid "Subscription renewal payment retry:"
msgstr ""
@@ -4506,7 +4518,7 @@ msgctxt "Subscription status"
msgid "On-hold"
msgstr ""
#: includes/class-wc-subscriptions-switcher.php:2452 wcs-functions.php:212
#: includes/class-wc-subscriptions-switcher.php:2464 wcs-functions.php:212
msgctxt "Subscription status"
msgid "Switched"
msgstr ""
@@ -4528,32 +4540,32 @@ msgctxt "used in a select box"
msgid "%1$s-%2$s"
msgstr ""
#: includes/class-wc-subscriptions-order.php:676
#: includes/class-wc-subscriptions-order.php:678
msgctxt "An order type"
msgid "Original"
msgstr ""
#: includes/class-wc-subscriptions-order.php:677
#: includes/class-wc-subscriptions-order.php:679
msgctxt "An order type"
msgid "Subscription Parent"
msgstr ""
#: includes/class-wc-subscriptions-order.php:678
#: includes/class-wc-subscriptions-order.php:680
msgctxt "An order type"
msgid "Subscription Renewal"
msgstr ""
#: includes/class-wc-subscriptions-order.php:679
#: includes/class-wc-subscriptions-order.php:681
msgctxt "An order type"
msgid "Subscription Resubscribe"
msgstr ""
#: includes/class-wc-subscriptions-order.php:680
#: includes/class-wc-subscriptions-order.php:682
msgctxt "An order type"
msgid "Subscription Switch"
msgstr ""
#: includes/class-wc-subscriptions-order.php:681
#: includes/class-wc-subscriptions-order.php:683
msgctxt "An order type"
msgid "Non-subscription"
msgstr ""
@@ -4628,30 +4640,30 @@ msgctxt "when to prorate first payment / subscription length"
msgid "For All Subscription Products"
msgstr ""
#: includes/class-wc-subscriptions-switcher.php:1788
#: includes/class-wc-subscriptions-switcher.php:1800
msgctxt "a switch order"
msgid "Downgrade"
msgstr ""
#: includes/class-wc-subscriptions-switcher.php:1791
#: includes/class-wc-subscriptions-switcher.php:1803
msgctxt "a switch order"
msgid "Upgrade"
msgstr ""
#: includes/class-wc-subscriptions-switcher.php:1794
#: includes/class-wc-subscriptions-switcher.php:1806
msgctxt "a switch order"
msgid "Crossgrade"
msgstr ""
#: includes/class-wc-subscriptions-switcher.php:1799
#: includes/class-wc-subscriptions-switcher.php:1811
#. 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:1915
#: includes/class-wc-subscriptions-switcher.php:2228
#: includes/class-wc-subscriptions-switcher.php:1927
#: includes/class-wc-subscriptions-switcher.php:2240
#. translators: 1$: old item, 2$: new item when switching
msgctxt "used in order notes"
msgid "Customer switched from: %1$s to %2$s."
@@ -4682,7 +4694,7 @@ msgctxt "input field placeholder for day field for annual subscriptions"
msgid "Day"
msgstr ""
#: includes/class-wcs-cart-renewal.php:717
#: includes/class-wcs-cart-renewal.php:720
msgctxt ""
"Used in WooCommerce by removed item notification: \"_All linked "
"subscription items were_ removed. Undo?\" Filter for item title."
@@ -4726,12 +4738,12 @@ msgctxt "used in order note"
msgid "IPN subscription payment %s for reason: %s."
msgstr ""
#: includes/class-wcs-retry-manager.php:230
#: includes/class-wcs-retry-manager.php:232
msgctxt "used in order note as reason for why status changed"
msgid "Retry rule applied:"
msgstr ""
#: includes/class-wcs-retry-manager.php:296
#: includes/class-wcs-retry-manager.php:298
msgctxt "used in order note as reason for why order status changed"
msgid "Subscription renewal payment retry:"
msgstr ""
@@ -4954,21 +4966,21 @@ msgctxt "Admin menu name"
msgid "Renewal Payment Retries"
msgstr ""
#: includes/upgrades/class-wc-subscriptions-upgrader.php:295
#: includes/upgrades/class-wc-subscriptions-upgrader.php:303
#. translators: placeholder is number of upgraded subscriptions
msgctxt "used in the subscriptions upgrader"
msgid "Marked %s subscription products as \"sold individually\"."
msgstr ""
#: includes/upgrades/class-wc-subscriptions-upgrader.php:326
#: includes/upgrades/class-wc-subscriptions-upgrader.php:376
#: includes/upgrades/class-wc-subscriptions-upgrader.php:334
#: includes/upgrades/class-wc-subscriptions-upgrader.php:384
#. translators: placeholder is "{time_left}", will be replaced on front end
#. with actual time
msgctxt "Message that gets sent to front end."
msgid "Estimated time left (minutes:seconds): %s"
msgstr ""
#: includes/upgrades/class-wc-subscriptions-upgrader.php:355
#: includes/upgrades/class-wc-subscriptions-upgrader.php:363
#. translators: placeholder is the number of subscriptions repaired
msgctxt "Repair message that gets sent to front end."
msgid ""
@@ -4976,7 +4988,7 @@ msgid ""
"customer notes."
msgstr ""
#: includes/upgrades/class-wc-subscriptions-upgrader.php:361
#: includes/upgrades/class-wc-subscriptions-upgrader.php:369
#. translators: placeholder is number of subscriptions that were checked and
#. did not need repairs. There's a space at the beginning!
msgctxt "Repair message that gets sent to front end."
@@ -4985,14 +4997,14 @@ msgid_plural "%d other subscriptions were checked and did not need any repairs."
msgstr[0] ""
msgstr[1] ""
#: includes/upgrades/class-wc-subscriptions-upgrader.php:365
#: includes/upgrades/class-wc-subscriptions-upgrader.php:373
#. translators: placeholder is "{execution_time}", which will be replaced on
#. front end with actual time
msgctxt "Repair message that gets sent to front end."
msgid "(in %s seconds)"
msgstr ""
#: includes/upgrades/class-wc-subscriptions-upgrader.php:368
#: includes/upgrades/class-wc-subscriptions-upgrader.php:376
#. translators: $1: "Repaired x subs with incorrect dates...", $2: "X others
#. were checked and no repair needed", $3: "(in X seconds)". Ordering for RTL
#. languages.
@@ -5000,7 +5012,7 @@ msgctxt "The assembled repair message that gets sent to front end."
msgid "%1$s%2$s %3$s"
msgstr ""
#: includes/upgrades/class-wc-subscriptions-upgrader.php:387
#: includes/upgrades/class-wc-subscriptions-upgrader.php:395
#. translators: 1$: error message, 2$: opening link tag, 3$: closing link tag
msgctxt "Error message that gets sent to front end when upgrading Subscriptions"
msgid ""
@@ -5009,7 +5021,7 @@ msgid ""
msgstr ""
#: includes/upgrades/templates/wcs-about-2-0.php:36
#: woocommerce-subscriptions.php:992
#: woocommerce-subscriptions.php:1023
msgctxt "short for documents"
msgid "Docs"
msgstr ""
@@ -5049,12 +5061,12 @@ msgctxt "text on submit button"
msgid "Update Database"
msgstr ""
#: includes/wcs-cart-functions.php:185
#: includes/wcs-cart-functions.php:192
msgctxt "shipping method price"
msgid "Free"
msgstr ""
#: includes/wcs-cart-functions.php:260
#: includes/wcs-cart-functions.php:267
#. translators: placeholder is price string, denotes tax included in cart/order
#. total
msgctxt "includes tax"

View File

@@ -54,7 +54,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<td class="order-actions">
<?php $actions = array();
if ( in_array( $order->get_status(), apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $order ) ) ) {
if ( in_array( $order->get_status(), apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $order ) ) && wcs_get_objects_property( $order, 'id' ) == $subscription->get_last_order() ) {
$actions['pay'] = array(
'url' => $order->get_checkout_payment_url(),
'name' => esc_html_x( 'Pay', 'pay for a subscription', 'woocommerce-subscriptions' ),

View File

@@ -111,9 +111,9 @@ wc_print_notices();
<td class="product-name">
<?php
if ( $_product && ! $_product->is_visible() ) {
echo esc_html( apply_filters( 'woocommerce_order_item_name', $item['name'], $item ) );
echo esc_html( apply_filters( 'woocommerce_order_item_name', $item['name'], $item, false ) );
} else {
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', sprintf( '<a href="%s">%s</a>', get_permalink( $item['product_id'] ), $item['name'] ), $item ) );
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', sprintf( '<a href="%s">%s</a>', get_permalink( $item['product_id'] ), $item['name'] ), $item, false ) );
}
echo wp_kses_post( apply_filters( 'woocommerce_order_item_quantity_html', ' <strong class="product-quantity">' . sprintf( '&times; %s', $item['qty'] ) . '</strong>', $item ) );

View File

@@ -20,12 +20,14 @@ if ( ! $product->is_purchasable() && ( ! is_user_logged_in() || 'no' == wcs_get_
$user_id = get_current_user_id();
// Availability
if ( WC_Subscriptions::is_woocommerce_pre( '3.0' ) ) :
$availability = $product->get_availability();
if ( $availability['availability'] ) :
echo wp_kses_post( apply_filters( 'woocommerce_stock_html', '<p class="stock '.$availability['class'].'">'.$availability['availability'].'</p>', $availability['availability'] ) );
endif;
else :
echo wp_kses_post( wc_get_stock_html( $product ) );
endif;
if ( ! $product->is_in_stock() ) : ?>
<link itemprop="availability" href="http://schema.org/OutOfStock">

View File

@@ -5,9 +5,9 @@
* Description: Sell products and services with recurring payments in your WooCommerce Store.
* Author: Prospress Inc.
* Author URI: http://prospress.com/
* Version: 2.2.7
* Version: 2.2.10
*
* Copyright 2016 Prospress, Inc. (email : freedoms@prospress.com)
* Copyright 2017 Prospress, Inc. (email : freedoms@prospress.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -126,7 +126,7 @@ class WC_Subscriptions {
public static $plugin_file = __FILE__;
public static $version = '2.2.7';
public static $version = '2.2.10';
private static $total_subscription_count = null;
@@ -414,9 +414,12 @@ class WC_Subscriptions {
self::add_notice( __( 'A subscription has been removed from your cart. Products and subscriptions can not be purchased at the same time.', 'woocommerce-subscriptions' ), 'notice' );
if ( WC_Subscriptions::is_woocommerce_pre( '3.0.8' ) ) {
// Redirect to cart page to remove subscription & notify shopper
add_filter( 'add_to_cart_fragments', __CLASS__ . '::redirect_ajax_add_to_cart' );
} else {
add_filter( 'woocommerce_add_to_cart_fragments', __CLASS__ . '::redirect_ajax_add_to_cart' );
}
}
return $valid;
@@ -973,7 +976,35 @@ class WC_Subscriptions {
*/
public static function is_duplicate_site() {
$is_duplicate = ( get_site_url() !== self::get_site_url() ) ? true : false;
if ( defined( 'WP_SITEURL' ) ) {
$site_url = WP_SITEURL;
} else {
$site_url = get_site_url();
}
$wp_site_url_parts = wp_parse_url( $site_url );
$wcs_site_url_parts = wp_parse_url( self::get_site_url() );
if ( ! isset( $wp_site_url_parts['path'] ) && ! isset( $wcs_site_url_parts['path'] ) ) {
$paths_match = true;
} elseif ( isset( $wp_site_url_parts['path'] ) && isset( $wcs_site_url_parts['path'] ) && $wp_site_url_parts['path'] == $wcs_site_url_parts['path'] ) {
$paths_match = true;
} else {
$paths_match = false;
}
if ( isset( $wp_site_url_parts['host'] ) && isset( $wcs_site_url_parts['host'] ) && $wp_site_url_parts['host'] == $wcs_site_url_parts['host'] ) {
$hosts_match = true;
} else {
$hosts_match = false;
}
// Check the host and path, do not check the protocol/scheme to avoid issues with WP Engine and other occasions where the WP_SITEURL constant may be set, but being overridden (e.g. by FORCE_SSL_ADMIN)
if ( $paths_match && $hosts_match ) {
$is_duplicate = false;
} else {
$is_duplicate = true;
}
return apply_filters( 'woocommerce_subscriptions_is_duplicate_site', $is_duplicate );
}