mirror of
https://github.com/pronamic/woocommerce-subscriptions.git
synced 2025-10-16 14:22:56 +00:00
2.0.18
This commit is contained in:
@@ -248,7 +248,7 @@ p._subscription_trial_length_field input,
|
||||
}
|
||||
.variable_subscription_pricing_2_3 .wc_input_subscription_period_interval {
|
||||
max-width: 41%;
|
||||
float: right;
|
||||
float: left;
|
||||
}
|
||||
.variable_subscription_pricing_2_3 .wc_input_subscription_period {
|
||||
max-width: 32%;
|
||||
@@ -486,11 +486,30 @@ body.post-type-shop_subscription .add-items .description.tips,
|
||||
body.post-type-shop_subscription .add-items .button.refund-items {
|
||||
display: none;
|
||||
}
|
||||
@media screen and (max-width: 782px) {
|
||||
@media only screen and (max-width: 782px) {
|
||||
#woocommerce-subscription-schedule .wcs-date-input input[type="text"]:first-of-type {
|
||||
width: 45%;
|
||||
}
|
||||
#woocommerce-subscription-schedule .wcs-date-input input[type="text"]:not(:first-of-type) {
|
||||
width: 19%;
|
||||
}
|
||||
|
||||
.post-type-shop_subscription .wp-list-table .column-status {
|
||||
display: none;
|
||||
text-align: left;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.post-type-shop_subscription .wp-list-table .column-status mark {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.post-type-shop_subscription .wp-list-table .column-status:before {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.post-type-shop_subscription .wp-list-table .column-orders {
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,32 @@
|
||||
*** WooCommerce Subscriptions Changelog ***
|
||||
|
||||
2016.07.22 - version 2.0.18
|
||||
* Tweak: cache shipping package rates to prevent multiple re-calculations per request. (PR#1485)
|
||||
* Tweak: remove multiple, redundant calls to $subscription->get_items() and WP_Posts_List->__construct() on admin subscriptions screen. (PR#1524)
|
||||
* Tweak: support translation for subscription shortcode. (PR#1504)
|
||||
* Tweak: add new 'woocommerce_subscriptions_after_recurring_shipping_rates' hook after displaying recurring shipping rates. (PR#1517)
|
||||
* Tweak: use default nonce action for change payment URL so 3rd party code can use custom URLs is needed. (PR#1529)
|
||||
* Tweak: remove duplicate PayPal log calls. (PR#1527)
|
||||
* Tweak: slightly improve efficiency of wcs_can_user_resubscribe_to(). (PR#1501)
|
||||
* Tweak: refactor wcs_user_has_subscription() to accept an array for statuses. (PR#1496)
|
||||
* Tweak: update _paid_date post meta flag for manual / failed payment original / renewal orders. (PR#1488)
|
||||
* Tweak: use WooCommerce's decimal place setting for rounding switch prorations. (PR#1483)
|
||||
* Fix: recurring coupons with WooCommerce 2.6.3 (issue does not exist with WC 2.6.2 or 2.6.4+). (PR#1546)
|
||||
* Fix: grant new product download file permissions to existing subscriptions for product which were not marked as downloadable or did not have downloadable files associated with them at the time the subscription was created. (PR#1533)
|
||||
* Fix: show cancel button for on-hold subscriptions with empty next payment. (PR#1515)
|
||||
* Fix: select the correct way to apply tax rates based on the 'woocommerce_adjust_non_base_location_prices' filter. (PR#1500)
|
||||
* Fix: display price string for one payment subscriptions consistently between cart/checkout and my account. e.g. display "$100 for 1 year" everywhere, instead of "$100 for 1 year" on cart/checkout and "$100 / year" on My Account. (PR#1451)
|
||||
* Fix: do not allow a customer with an active and cancelled subscription to a product limited to active status to resubscribe to the inactive subscription. (PR#1482)
|
||||
* Fix: updates resubscribe button displayed on the limited simple subscriptoin product pages text from the old "Renew" terminology. (PR#1487)
|
||||
* Fix: calculate correct renewal/resubscribe cart item taxes rates. (PR#1476)
|
||||
* Fix: honour chosen shipping method as default method. (PR#1480)
|
||||
* Fix: remove the mock trial added to switches with no prorated inital switch costs when creating the grouping key dates to fix incorrect "the next_payment date must occur after the trial end date" error in the rare case where the first renewal payment for the new subscription is scheduled less than 1 billing period in the future. (PR#1519)
|
||||
* Fix: always allow subscription status updates while processing PayPal IPNs to avoid issues when processing renewals for PayPal accounts issuing out-of-odate subscription IDs that begin with S-. (PR#1526)
|
||||
* Fix: responsiveness of Subscriptions administration screen list table to improve display on small screens. (PR#1502)
|
||||
* Fix: do not use variable references ot fix 'nested by-reference foreach loop' notice with PHP7. (PR#1522)
|
||||
* Fix: tab order of billing period and interval on Edit Product screen for subscription variations. (PR#1543)
|
||||
* Fix: deviation calculations in wcs_estimate_period_between(). (PR#1455)
|
||||
|
||||
2016.06.24 - version 2.0.17
|
||||
* Tweak: add support for bulk editing subscription variation prices using relative increase or decrease from existing price (either fixed amount or per cent). (PR#1425)
|
||||
* Tweak: use filterable helper function when validating switch request to improve compatibilty with Name Your Price and other plugins. (PR#1453)
|
||||
|
@@ -1352,7 +1352,7 @@ class WC_Subscriptions_Admin {
|
||||
|
||||
if ( empty( $subscriptions ) ) {
|
||||
return '<ul class="user-subscriptions no-user-subscriptions">
|
||||
<li>No subscriptions found.</li>
|
||||
<li>' . esc_html_x( 'No subscriptions found.', 'in [subscriptions] shortcode', 'woocommerce-subscriptions' ) . '</li>
|
||||
</ul>';
|
||||
}
|
||||
|
||||
@@ -1360,7 +1360,9 @@ class WC_Subscriptions_Admin {
|
||||
|
||||
foreach ( $subscriptions as $subscription ) {
|
||||
if ( 'all' == $attributes['status'] || $subscription->has_status( $attributes['status'] ) ) {
|
||||
$list .= sprintf( '<li><a href="%s">Subscription %s</a></li>', $subscription->get_view_order_url(), $subscription->get_order_number() );
|
||||
// translators: order number
|
||||
$shortcode_translate = sprintf( esc_html_x( 'Subscription %s', 'in [subscriptions] shortcode', 'woocommerce-subscriptions' ), $subscription->get_order_number() );
|
||||
$list .= sprintf( '<li><a href="%s">%s</a></li>', $subscription->get_view_order_url(), $shortcode_translate );
|
||||
}
|
||||
}
|
||||
$list .= '</ul>';
|
||||
|
@@ -51,6 +51,9 @@ class WCS_Admin_Post_Types {
|
||||
|
||||
add_action( 'restrict_manage_posts', array( $this, 'restrict_by_product' ) );
|
||||
add_action( 'restrict_manage_posts', array( $this, 'restrict_by_payment_method' ) );
|
||||
|
||||
add_action( 'list_table_primary_column', array( $this, 'list_table_primary_column' ), 10, 2 );
|
||||
add_filter( 'post_row_actions', array( $this, 'shop_subscription_row_actions' ), 10, 2 );
|
||||
}
|
||||
|
||||
|
||||
@@ -330,7 +333,7 @@ class WCS_Admin_Post_Types {
|
||||
* @param string $column
|
||||
*/
|
||||
public function render_shop_subscription_columns( $column ) {
|
||||
global $post, $the_subscription;
|
||||
global $post, $the_subscription, $wp_list_table;
|
||||
|
||||
if ( empty( $the_subscription ) || $the_subscription->id != $post->ID ) {
|
||||
$the_subscription = wcs_get_subscription( $post->ID );
|
||||
@@ -343,8 +346,6 @@ class WCS_Admin_Post_Types {
|
||||
// The status label
|
||||
$column_content = sprintf( '<mark class="%s tips" data-tip="%s">%s</mark>', sanitize_title( $the_subscription->get_status() ), wcs_get_subscription_status_name( $the_subscription->get_status() ), wcs_get_subscription_status_name( $the_subscription->get_status() ) );
|
||||
|
||||
// Inline actions
|
||||
$wp_list_table = _get_list_table( 'WP_Posts_List_Table' );
|
||||
$post_type_object = get_post_type_object( $post->post_type );
|
||||
|
||||
$actions = array();
|
||||
@@ -459,6 +460,8 @@ class WCS_Admin_Post_Types {
|
||||
|
||||
$column_content .= '</div>';
|
||||
|
||||
$column_content .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details', 'woocommerce-subscriptions' ) . '</span></button>';
|
||||
|
||||
break;
|
||||
case 'order_items' :
|
||||
// Display either the item name or item count with a collapsed list of items
|
||||
@@ -468,7 +471,7 @@ class WCS_Admin_Post_Types {
|
||||
$column_content .= '–';
|
||||
break;
|
||||
case 1 :
|
||||
foreach ( $the_subscription->get_items() as $item ) {
|
||||
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 );
|
||||
@@ -562,7 +565,7 @@ class WCS_Admin_Post_Types {
|
||||
break;
|
||||
}
|
||||
|
||||
echo wp_kses( apply_filters( 'woocommerce_subscription_list_table_column_content', $column_content, $the_subscription, $column ), array( 'a' => array( 'class' => array(), 'href' => array(), 'data-tip' => array(), 'title' => array() ), 'time' => array( 'class' => array(), 'title' => array() ), 'mark' => array( 'class' => array(), 'data-tip' => array() ), 'small' => array( 'class' => array() ), 'table' => array( 'class' => array(), 'cellspacing' => array(), 'cellpadding' => array() ), 'tr' => array( 'class' => array() ), 'td' => array( 'class' => array() ), 'div' => array( 'class' => array(), 'data-tip' => array() ), 'br' => array(), 'strong' => array(), 'span' => array( 'class' => array() ), 'p' => array( 'class' => array() ) ) );
|
||||
echo wp_kses( apply_filters( 'woocommerce_subscription_list_table_column_content', $column_content, $the_subscription, $column ), array( 'a' => array( 'class' => array(), 'href' => array(), 'data-tip' => array(), 'title' => array() ), 'time' => array( 'class' => array(), 'title' => array() ), 'mark' => array( 'class' => array(), 'data-tip' => array() ), 'small' => array( 'class' => array() ), 'table' => array( 'class' => array(), 'cellspacing' => array(), 'cellpadding' => array() ), 'tr' => array( 'class' => array() ), 'td' => array( 'class' => array() ), 'div' => array( 'class' => array(), 'data-tip' => array() ), 'br' => array(), 'strong' => array(), 'span' => array( 'class' => array() ), 'p' => array( 'class' => array() ), 'button' => array( 'type' => array(), 'class' => array() ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -881,6 +884,39 @@ class WCS_Admin_Post_Types {
|
||||
}?>
|
||||
</select> <?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets post table primary column subscriptions.
|
||||
*
|
||||
* @param string $default
|
||||
* @param string $screen_id
|
||||
* @return string
|
||||
*/
|
||||
public function list_table_primary_column( $default, $screen_id ) {
|
||||
|
||||
if ( 'edit-shop_subscription' == $screen_id ) {
|
||||
$default = 'order_title';
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't display default Post actions on Subscription post types (we display our own set of
|
||||
* actions when rendering the column content).
|
||||
*
|
||||
* @param array $actions
|
||||
* @param object $post
|
||||
* @return array
|
||||
*/
|
||||
public function shop_subscription_row_actions( $actions, $post ) {
|
||||
|
||||
if ( 'shop_subscription' == $post->post_type ) {
|
||||
$actions = array();
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
}
|
||||
|
||||
new WCS_Admin_Post_Types();
|
||||
|
@@ -311,16 +311,16 @@ class WC_API_Subscriptions extends WC_API_Orders {
|
||||
|
||||
if ( ! empty( $payment_method_meta ) ) {
|
||||
|
||||
foreach ( $payment_method_meta as $meta_table => &$meta ) {
|
||||
foreach ( $payment_method_meta as $meta_table => $meta ) {
|
||||
|
||||
if ( ! is_array( $meta ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $meta as $meta_key => &$meta_data ) {
|
||||
foreach ( $meta as $meta_key => $meta_data ) {
|
||||
|
||||
if ( isset( $payment_details[ $meta_table ][ $meta_key ] ) ) {
|
||||
$meta_data['value'] = $payment_details[ $meta_table ][ $meta_key ];
|
||||
$payment_method_meta[ $meta_table ][ $meta_key ]['value'] = $payment_details[ $meta_table ][ $meta_key ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1072,7 +1072,9 @@ class WC_Subscription extends WC_Order {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( 'excl' == $tax_display ) {
|
||||
if ( $this->is_one_payment() ) {
|
||||
$subtotal = parent::get_formatted_line_subtotal( $item, $tax_display );
|
||||
} else if ( 'excl' == $tax_display ) {
|
||||
$display_ex_tax_label = $this->prices_include_tax ? 1 : 0;
|
||||
$subtotal = wcs_price_string( $this->get_price_string_details( $this->get_line_subtotal( $item ) ), $display_ex_tax_label );
|
||||
} else {
|
||||
@@ -1090,7 +1092,7 @@ class WC_Subscription extends WC_Order {
|
||||
* @return string
|
||||
*/
|
||||
public function get_formatted_order_total( $tax_display = '', $display_refunded = true ) {
|
||||
if ( $this->get_total() > 0 && ! empty( $this->billing_period ) ) {
|
||||
if ( $this->get_total() > 0 && ! empty( $this->billing_period ) && ! $this->is_one_payment() ) {
|
||||
$formatted_order_total = wcs_price_string( $this->get_price_string_details( $this->get_total() ) );
|
||||
} else {
|
||||
$formatted_order_total = parent::get_formatted_order_total();
|
||||
@@ -1729,4 +1731,42 @@ class WC_Subscription extends WC_Order {
|
||||
|
||||
return apply_filters( 'woocommerce_get_item_downloads', $files, $item, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the subscription is for one payment only.
|
||||
*
|
||||
* @return bool whether the subscription is for only one payment
|
||||
* @since 2.0.17
|
||||
*/
|
||||
public function is_one_payment() {
|
||||
|
||||
$is_one_payment = false;
|
||||
|
||||
if ( 0 != ( $end_time = $this->get_time( 'end' ) ) ) {
|
||||
|
||||
$from_timestamp = $this->get_time( 'start' );
|
||||
|
||||
if ( 0 != $this->get_time( 'trial_end' ) || WC_Subscriptions_Synchroniser::subscription_contains_synced_product( $this ) ) {
|
||||
|
||||
$subscription_order_count = count( $this->get_related_orders() );
|
||||
|
||||
// when we have a sync'd subscription before its 1st payment, we need to base the calculations for the next payment on the first/next payment timestamp.
|
||||
if ( $subscription_order_count < 2 && 0 != ( $next_payment_timestamp = $this->get_time( 'next_payment' ) ) ) {
|
||||
$from_timestamp = $next_payment_timestamp;
|
||||
|
||||
// when we have a sync'd subscription after its 1st payment, we need to base the calculations for the next payment on the last payment timestamp.
|
||||
} else if ( ! ( $subscription_order_count > 2 ) && 0 != ( $last_payment_timestamp = $this->get_time( 'last_payment' ) ) ) {
|
||||
$from_timestamp = $last_payment_timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
$next_payment_timestamp = wcs_add_time( $this->billing_interval, $this->billing_period, $from_timestamp );
|
||||
|
||||
if ( ( $next_payment_timestamp + DAY_IN_SECONDS - 1 ) > $end_time ) {
|
||||
$is_one_payment = true;
|
||||
}
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_subscription_is_one_payment', $is_one_payment, $this );
|
||||
}
|
||||
}
|
||||
|
@@ -40,6 +40,13 @@ class WC_Subscriptions_Cart {
|
||||
*/
|
||||
private static $recurring_shipping_packages = array();
|
||||
|
||||
/**
|
||||
* A cache of the calculated shipping package rates
|
||||
*
|
||||
* @since 2.0.18
|
||||
*/
|
||||
private static $shipping_rates = array();
|
||||
|
||||
/**
|
||||
* Bootstraps the class and hooks required actions & filters.
|
||||
*
|
||||
@@ -91,6 +98,9 @@ class WC_Subscriptions_Cart {
|
||||
// Make sure we use our recurring shipping method for recurring shipping calculations not the default method
|
||||
add_filter( 'woocommerce_shipping_chosen_method', array( __CLASS__, 'set_chosen_shipping_method' ), 10, 2 );
|
||||
|
||||
// Cache package rates. Hook in early to ensure we get a full set of rates.
|
||||
add_filter( 'woocommerce_package_rates', __CLASS__ . '::cache_package_rates', 1, 2 );
|
||||
|
||||
// When WooCommerce calculates rates for a recurring shipping package, only return the recurring shipping package rates
|
||||
add_filter( 'woocommerce_package_rates', __CLASS__ . '::filter_package_rates', 10, 2 );
|
||||
|
||||
@@ -472,8 +482,8 @@ class WC_Subscriptions_Cart {
|
||||
|
||||
$default_method = current( array_keys( $prioritized_methods ) );
|
||||
|
||||
// Set the chosen shipping method (if available) to workaround a bug with WC_Shipping::get_default_method() in WC < 2.6 which leads to the default shipping method always being used instead of a valid chosen shipping method
|
||||
} elseif ( isset( $chosen_methods[ $package_index ] ) && $default_method !== $chosen_methods[ $package_index ] && WC_Subscriptions::is_woocommerce_pre( '2.6' ) ) {
|
||||
// Set the chosen shipping method (if available) to workaround WC_Shipping::get_default_method() setting the default shipping method whenever method count changes
|
||||
} elseif ( isset( $chosen_methods[ $package_index ] ) && $default_method !== $chosen_methods[ $package_index ] ) {
|
||||
$default_method = $chosen_methods[ $package_index ];
|
||||
}
|
||||
|
||||
@@ -1100,7 +1110,7 @@ class WC_Subscriptions_Cart {
|
||||
$packages = $recurring_cart->get_shipping_packages();
|
||||
|
||||
foreach ( $packages as $package_index => $base_package ) {
|
||||
$package = WC()->shipping->calculate_shipping_for_package( $base_package );
|
||||
$package = self::get_calculated_shipping_for_package( $base_package );
|
||||
|
||||
if ( ( isset( $standard_packages[ $package_index ] ) && $package['rates'] == $standard_packages[ $package_index ]['rates'] ) && apply_filters( 'wcs_cart_totals_shipping_html_price_only', true, $package, WC()->cart->recurring_carts[ $recurring_cart_key ] ) ) {
|
||||
// the recurring package rates match the initial package rates, there won't be a selected shipping method for this recurring cart package
|
||||
@@ -1146,6 +1156,53 @@ class WC_Subscriptions_Cart {
|
||||
return $cart_contains_product;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache the package rates calculated by @see WC_Shipping::calculate_shipping_for_package() to avoid multiple calls of calculate_shipping_for_package() per request.
|
||||
*
|
||||
* @param array $rates A set of WC_Shipping_Rate objects.
|
||||
* @param array $package A shipping package in the form returned by @see WC_Cart->get_shipping_packages()
|
||||
* @return array $rates An unaltered set of WC_Shipping_Rate objects passed to the function
|
||||
* @since 2.0.18
|
||||
*/
|
||||
public static function cache_package_rates( $rates, $package ) {
|
||||
self::$shipping_rates[ self::get_package_shipping_rates_cache_key( $package ) ] = $rates;
|
||||
|
||||
return $rates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the shipping rates for a package.
|
||||
*
|
||||
* This function will check cached rates based on a hash of the package contents to avoid re-calculation per page load.
|
||||
* If there are no rates stored in the cache for this package, it will fall back to @see WC_Shipping::calculate_shipping_for_package()
|
||||
*
|
||||
* @param array $package A shipping package in the form returned by @see WC_Cart->get_shipping_packages()
|
||||
* @return array $package
|
||||
* @since 2.0.18
|
||||
*/
|
||||
public static function get_calculated_shipping_for_package( $package ) {
|
||||
$key = self::get_package_shipping_rates_cache_key( $package );
|
||||
|
||||
if ( isset( self::$shipping_rates[ $key ] ) ) {
|
||||
$package['rates'] = apply_filters( 'woocommerce_package_rates', self::$shipping_rates[ $key ], $package );
|
||||
} else {
|
||||
$package = WC()->shipping->calculate_shipping_for_package( $package );
|
||||
}
|
||||
|
||||
return $package;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unqiue package key for a given shipping package to be used for caching package rates.
|
||||
*
|
||||
* @param array $package A shipping package in the form returned by WC_Cart->get_shipping_packages().
|
||||
* @return string key hash
|
||||
* @since 2.0.18
|
||||
*/
|
||||
private static function get_package_shipping_rates_cache_key( $package ) {
|
||||
return md5( implode( array_keys( $package['contents'] ) ) );
|
||||
}
|
||||
|
||||
/* Deprecated */
|
||||
|
||||
/**
|
||||
|
@@ -184,7 +184,7 @@ class WC_Subscriptions_Change_Payment_Gateway {
|
||||
|
||||
$subscription = wcs_get_subscription( absint( $_GET['change_payment_method'] ) );
|
||||
|
||||
if ( wp_verify_nonce( $_GET['_wpnonce'], __FILE__ ) === false ) {
|
||||
if ( wp_verify_nonce( $_GET['_wpnonce'] ) === false ) {
|
||||
|
||||
WC_Subscriptions::add_notice( __( 'There was an error with your request. Please try again.', 'woocommerce-subscriptions' ), 'error' );
|
||||
|
||||
@@ -255,7 +255,7 @@ class WC_Subscriptions_Change_Payment_Gateway {
|
||||
if ( $subscription->can_be_updated_to( 'new-payment-method' ) ) {
|
||||
|
||||
$actions['change_payment_method'] = array(
|
||||
'url' => wp_nonce_url( add_query_arg( array( 'change_payment_method' => $subscription->id ), $subscription->get_checkout_payment_url() ), __FILE__ ),
|
||||
'url' => wp_nonce_url( add_query_arg( array( 'change_payment_method' => $subscription->id ), $subscription->get_checkout_payment_url() ) ),
|
||||
'name' => _x( 'Change Payment', 'label on button, imperative', 'woocommerce-subscriptions' ),
|
||||
);
|
||||
|
||||
|
@@ -223,7 +223,7 @@ class WC_Subscriptions_Checkout {
|
||||
|
||||
foreach ( $cart->get_shipping_packages() as $package_index => $base_package ) {
|
||||
|
||||
$package = WC()->shipping->calculate_shipping_for_package( $base_package );
|
||||
$package = WC_Subscriptions_Cart::get_calculated_shipping_for_package( $base_package );
|
||||
|
||||
$recurring_shipping_package_key = WC_Subscriptions_Cart::get_recurring_shipping_package_key( $cart->recurring_cart_key, $package_index );
|
||||
|
||||
|
@@ -188,7 +188,7 @@ class WC_Subscriptions_Coupon {
|
||||
}
|
||||
|
||||
// Round - consistent with WC approach
|
||||
$discount_amount = round( $discount_amount, WC_ROUNDING_PRECISION );
|
||||
$discount_amount = round( $discount_amount, wcs_get_rounding_precision() );
|
||||
|
||||
return $discount_amount;
|
||||
}
|
||||
|
@@ -90,6 +90,7 @@ class WC_Subscriptions_Renewal_Order {
|
||||
);
|
||||
|
||||
wp_update_post( $update_post_data );
|
||||
update_post_meta( $order_id, '_paid_date', current_time( 'mysql', true ) );
|
||||
}
|
||||
|
||||
foreach ( $subscriptions as $subscription ) {
|
||||
|
@@ -115,6 +115,18 @@ class WC_Subscriptions_Switcher {
|
||||
|
||||
// Require payment when switching from a $0 / period subscription to a non-zero subscription to process automatic payments
|
||||
add_filter( 'woocommerce_payment_successful_result', __CLASS__ . '::maybe_set_payment_method' , 10, 2 );
|
||||
|
||||
// Mock a free trial on the cart item to make sure the switch total doesn't include any recurring amount
|
||||
add_filter( 'woocommerce_before_calculate_totals', __CLASS__ . '::maybe_set_free_trial', 100, 1 );
|
||||
add_action( 'woocommerce_subscription_cart_before_grouping', __CLASS__ . '::maybe_unset_free_trial' );
|
||||
add_action( 'woocommerce_subscription_cart_after_grouping', __CLASS__ . '::maybe_set_free_trial' );
|
||||
add_action( 'wcs_recurring_cart_start_date', __CLASS__ . '::maybe_unset_free_trial', 0, 1 );
|
||||
add_action( 'wcs_recurring_cart_end_date', __CLASS__ . '::maybe_set_free_trial', 100, 1 );
|
||||
add_filter( 'woocommerce_subscriptions_calculated_total', __CLASS__ . '::maybe_unset_free_trial', 10000, 1 );
|
||||
add_action( 'woocommerce_cart_totals_before_shipping', __CLASS__ . '::maybe_set_free_trial' );
|
||||
add_action( 'woocommerce_cart_totals_after_shipping', __CLASS__ . '::maybe_unset_free_trial' );
|
||||
add_action( 'woocommerce_review_order_before_shipping', __CLASS__ . '::maybe_set_free_trial' );
|
||||
add_action( 'woocommerce_review_order_after_shipping', __CLASS__ . '::maybe_unset_free_trial' );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1228,8 +1240,8 @@ class WC_Subscriptions_Switcher {
|
||||
|
||||
// Keep a record of the two separate amounts so we store these and calculate future switch amounts correctly
|
||||
WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_sign_up_fee_prorated = WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_sign_up_fee;
|
||||
WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_price_prorated = round( $extra_to_pay, 2 );
|
||||
WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_sign_up_fee += round( $extra_to_pay, 2 );
|
||||
WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_price_prorated = round( $extra_to_pay, wc_get_price_decimals() );
|
||||
WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_sign_up_fee += round( $extra_to_pay, wc_get_price_decimals() );
|
||||
|
||||
}
|
||||
|
||||
@@ -1261,11 +1273,6 @@ class WC_Subscriptions_Switcher {
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, if we need to make sure the initial total doesn't include any recurring amount, we can by spoofing a free trial
|
||||
if ( 0 != WC()->cart->cart_contents[ $cart_item_key ]['subscription_switch']['first_payment_timestamp'] ) {
|
||||
WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_trial_length = 1;
|
||||
}
|
||||
|
||||
if ( 'yes' == $apportion_length || ( 'virtual' == $apportion_length && $is_virtual_product ) ) {
|
||||
|
||||
$base_length = WC_Subscriptions_Product::get_length( $product_id );
|
||||
@@ -1775,6 +1782,37 @@ class WC_Subscriptions_Switcher {
|
||||
return $payment_processing_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure switch cart item price doesn't include any recurring amount by setting a free trial.
|
||||
*
|
||||
* @since 2.0.18
|
||||
*/
|
||||
public static function maybe_set_free_trial( $total = '' ) {
|
||||
|
||||
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
|
||||
if ( isset( $cart_item['subscription_switch']['first_payment_timestamp'] ) && 0 != $cart_item['subscription_switch']['first_payment_timestamp'] ) {
|
||||
WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_trial_length = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove mock free trials from switch cart items.
|
||||
*
|
||||
* @since 2.0.18
|
||||
*/
|
||||
public static function maybe_unset_free_trial( $total = '' ) {
|
||||
|
||||
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
|
||||
if ( isset( $cart_item['subscription_switch']['first_payment_timestamp'] ) && 0 != $cart_item['subscription_switch']['first_payment_timestamp'] ) {
|
||||
WC()->cart->cart_contents[ $cart_item_key ]['data']->subscription_trial_length = 0;
|
||||
}
|
||||
}
|
||||
return $total;
|
||||
}
|
||||
|
||||
/** Deprecated Methods **/
|
||||
|
||||
/**
|
||||
|
@@ -350,7 +350,13 @@ class WCS_Cart_Renewal {
|
||||
$price = $item_to_renew['line_subtotal'];
|
||||
|
||||
if ( wc_prices_include_tax() ) {
|
||||
|
||||
if ( apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) ) {
|
||||
$base_tax_rates = WC_Tax::get_base_tax_rates( $_product->tax_class );
|
||||
} else {
|
||||
$base_tax_rates = WC_Tax::get_rates( $_product->tax_class );
|
||||
}
|
||||
|
||||
$base_taxes_on_item = WC_Tax::calc_tax( $price, $base_tax_rates, false, false );
|
||||
$price += array_sum( $base_taxes_on_item );
|
||||
}
|
||||
|
@@ -115,14 +115,14 @@ class WCS_Change_Payment_Method_Admin {
|
||||
|
||||
if ( ! empty( $payment_method_meta ) ) {
|
||||
|
||||
foreach ( $payment_method_meta as $meta_table => &$meta ) {
|
||||
foreach ( $payment_method_meta as $meta_table => $meta ) {
|
||||
|
||||
if ( ! is_array( $meta ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $meta as $meta_key => &$meta_data ) {
|
||||
$meta_data['value'] = isset( $_POST['_payment_method_meta'][ $meta_table ][ $meta_key ] ) ? $_POST['_payment_method_meta'][ $meta_table ][ $meta_key ] : '';
|
||||
foreach ( $meta as $meta_key => $meta_data ) {
|
||||
$payment_method_meta[ $meta_table ][ $meta_key ]['value'] = isset( $_POST['_payment_method_meta'][ $meta_table ][ $meta_key ] ) ? $_POST['_payment_method_meta'][ $meta_table ][ $meta_key ] : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -33,6 +33,8 @@ class WCS_Download_Handler {
|
||||
add_action( 'woocommerce_process_shop_order_meta', __CLASS__ . '::repair_permission_data', 60, 1 );
|
||||
|
||||
add_action( 'deleted_post', __CLASS__ . '::delete_subscription_permissions' );
|
||||
|
||||
add_action( 'woocommerce_process_product_file_download_paths', __CLASS__ . '::grant_new_file_product_permissions', 11, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,5 +192,44 @@ class WCS_Download_Handler {
|
||||
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE order_id = %d", $post_id ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Grant downloadable file access to any newly added files on any existing subscriptions
|
||||
* which don't have existing permissions.
|
||||
*
|
||||
* @param int $product_id
|
||||
* @param int $variation_id
|
||||
* @param array $downloadable_files product downloadable files
|
||||
* @since 2.0.18
|
||||
*/
|
||||
public static function grant_new_file_product_permissions( $product_id, $variation_id, $downloadable_files ) {
|
||||
global $wpdb;
|
||||
|
||||
$product_id = ( $variation_id ) ? $variation_id : $product_id;
|
||||
$product = wc_get_product( $product_id );
|
||||
$existing_download_ids = array_keys( (array) $product->get_files() );
|
||||
$downloadable_ids = array_keys( (array) $downloadable_files );
|
||||
$new_download_ids = array_filter( array_diff( $downloadable_ids, $existing_download_ids ) );
|
||||
|
||||
if ( ! empty( $new_download_ids ) ) {
|
||||
|
||||
$existing_permissions = $wpdb->get_col( $wpdb->prepare( "SELECT order_id from {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE product_id = %d GROUP BY order_id", $product_id ) );
|
||||
$subscriptions = wcs_get_subscriptions_for_product( $product_id );
|
||||
|
||||
foreach ( $subscriptions as $subscription_id ) {
|
||||
|
||||
// only grant permissions to subscriptions which have no permissions for this product
|
||||
if ( ! in_array( $subscription_id, $existing_permissions ) ) {
|
||||
$subscription = wcs_get_subscription( $subscription_id );
|
||||
|
||||
foreach ( $new_download_ids as $download_id ) {
|
||||
if ( $subscription && apply_filters( 'woocommerce_process_product_file_download_paths_grant_access_to_new_file', true, $download_id, $product_id, $subscription ) ) {
|
||||
wc_downloadable_file_permission( $download_id, $product_id, $subscription );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
WCS_Download_Handler::init();
|
||||
|
@@ -80,6 +80,9 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
|
||||
$subscription = wcs_get_subscription( $subscription_id_and_key['order_id'] );
|
||||
$subscription_key = $subscription_id_and_key['order_key'];
|
||||
|
||||
// For the purposes of processing the IPN, we need to force the ability to update subscription statuses by unhooking the function enforcing strict PayPal support on S- prefixed subscription ids
|
||||
remove_filter( 'woocommerce_subscription_payment_gateway_supports', 'WCS_PayPal_Supports::add_feature_support_for_subscription', 10 );
|
||||
|
||||
// We have an invalid $subscription, probably because invoice_prefix has changed since the subscription was first created, so get the subscription by order key
|
||||
if ( ! isset( $subscription->id ) ) {
|
||||
$subscription = wcs_get_subscription( wc_get_order_id_by_order_key( $subscription_key ) );
|
||||
@@ -160,9 +163,6 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler {
|
||||
}
|
||||
}
|
||||
|
||||
WC_Gateway_Paypal::log( 'Subscription transaction details: ' . print_r( $transaction_details, true ) );
|
||||
WC_Gateway_Paypal::log( 'Subscription Transaction Type: ' . $transaction_details['txn_type'] );
|
||||
|
||||
$is_renewal_sign_up_after_failure = false;
|
||||
|
||||
// If the invoice ID doesn't match the default invoice ID and contains the string '-wcsfrp-', the IPN is for a subscription payment to fix up a failed payment
|
||||
|
@@ -50,7 +50,8 @@ function wcs_cart_totals_shipping_html() {
|
||||
|
||||
$product_names = array();
|
||||
|
||||
$package = WC()->shipping->calculate_shipping_for_package( $base_package );
|
||||
$package = WC_Subscriptions_Cart::get_calculated_shipping_for_package( $base_package );
|
||||
$index = sprintf( '%1$s_%2$d', $recurring_cart_key, $i );
|
||||
|
||||
if ( $show_package_details ) {
|
||||
foreach ( $package['contents'] as $item_id => $values ) {
|
||||
@@ -73,7 +74,6 @@ function wcs_cart_totals_shipping_html() {
|
||||
<td>
|
||||
<?php echo wp_kses_post( wcs_cart_totals_shipping_method_price_label( $shipping_method, $recurring_cart ) ); ?>
|
||||
<?php if ( 1 === count( $package['rates'] ) ) : ?>
|
||||
<?php $index = sprintf( '%1$s_%2$d', $recurring_cart_key, $i ); ?>
|
||||
<?php wcs_cart_print_shipping_input( $index, $shipping_method ); ?>
|
||||
<?php do_action( 'woocommerce_after_shipping_rate', $shipping_method, $index ); ?>
|
||||
<?php endif; ?>
|
||||
@@ -99,7 +99,7 @@ function wcs_cart_totals_shipping_html() {
|
||||
'show_package_details' => $show_package_details,
|
||||
'package_details' => $package_details,
|
||||
'package_name' => $package_name,
|
||||
'index' => sprintf( '%1$s_%2$d', $recurring_cart_key, $i ),
|
||||
'index' => $index,
|
||||
'chosen_method' => $chosen_recurring_method,
|
||||
'recurring_cart_key' => $recurring_cart_key,
|
||||
'recurring_cart' => $recurring_cart,
|
||||
@@ -109,6 +109,7 @@ function wcs_cart_totals_shipping_html() {
|
||||
);
|
||||
$show_package_name = false;
|
||||
}
|
||||
do_action( 'woocommerce_subscriptions_after_recurring_shipping_rates', $index, $base_package, $recurring_cart );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -136,3 +136,25 @@ function wcs_array_insert_after( $needle, $haystack, $new_key, $new_value) {
|
||||
|
||||
return $haystack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get around WooCommerce version 2.6.3 which removed the constant WC_ROUNDING_PRECISION and
|
||||
* introduced the function wc_get_rounding_precision. Every version 2.6.2 and earlier has the constant. Every version
|
||||
* 2.6.4 and later (hopefully) will also have the constant AND the wc_get_rounding_precision function. 2.6.3 only has
|
||||
* the function however.
|
||||
*
|
||||
* @see https://github.com/Prospress/woocommerce-subscriptions/issues/1545
|
||||
*
|
||||
* @return int rounding precision
|
||||
*/
|
||||
function wcs_get_rounding_precision() {
|
||||
if ( function_exists( 'wc_get_rounding_precision' ) ) {
|
||||
$precision = wc_get_rounding_precision();
|
||||
} elseif ( defined( 'WC_ROUNDING_PRECISION' ) ) {
|
||||
$precision = WC_ROUNDING_PRECISION;
|
||||
} else {
|
||||
$precision = wc_get_price_decimals() + 2;
|
||||
}
|
||||
|
||||
return $precision;
|
||||
}
|
||||
|
@@ -165,6 +165,8 @@ function wcs_get_subscriptions_for_resubscribe_order( $order ) {
|
||||
* 3. its parent order must not have already been superseded by a new order (to prevent
|
||||
* displaying "Resubscribe" links on subscriptions that have already been renewed)
|
||||
* 4. the products to which the subscription relates must not have been deleted
|
||||
* 5. have a recurring amount greater than $0, to avoid allowing resubscribes to subscriptions
|
||||
* where the entire cost is charged in a sign-up fee
|
||||
*
|
||||
* @param int | WC_Subscription $subscription Post ID of a 'shop_subscription' post, or instance of a WC_Subscription object
|
||||
* @param int The ID of a user
|
||||
@@ -189,6 +191,14 @@ function wcs_can_user_resubscribe_to( $subscription, $user_id = '' ) {
|
||||
|
||||
$can_user_resubscribe = false;
|
||||
|
||||
} elseif ( ! $subscription->has_status( array( 'cancelled', 'expired', 'trash' ) ) ) {
|
||||
|
||||
$can_user_resubscribe = false;
|
||||
|
||||
} elseif ( $subscription->get_total() <= 0 ) {
|
||||
|
||||
$can_user_resubscribe = false;
|
||||
|
||||
} else {
|
||||
|
||||
$resubscribe_orders = get_posts( array(
|
||||
@@ -207,6 +217,9 @@ function wcs_can_user_resubscribe_to( $subscription, $user_id = '' ) {
|
||||
// Make sure all line items still exist
|
||||
$all_line_items_exist = true;
|
||||
|
||||
// Check if product in subscription is limited
|
||||
$has_active_limited_subscription = false;
|
||||
|
||||
foreach ( $subscription->get_items() as $line_item ) {
|
||||
|
||||
$product = ( ! empty( $line_item['variation_id'] ) ) ? wc_get_product( $line_item['variation_id'] ) : wc_get_product( $line_item['product_id'] );
|
||||
@@ -215,9 +228,14 @@ function wcs_can_user_resubscribe_to( $subscription, $user_id = '' ) {
|
||||
$all_line_items_exist = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( 'active' == $product->limit_subscriptions && ( wcs_user_has_subscription( $user_id, $product->id, 'on-hold' ) || wcs_user_has_subscription( $user_id, $product->id, 'active' ) ) ) {
|
||||
$has_active_limited_subscription = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $resubscribe_orders ) && $subscription->get_completed_payment_count() > 0 && $subscription->get_total() > 0 && true === $all_line_items_exist && $subscription->has_status( array( 'cancelled', 'expired', 'trash' ) ) ) {
|
||||
if ( empty( $resubscribe_orders ) && $subscription->get_completed_payment_count() > 0 && true === $all_line_items_exist && false === $has_active_limited_subscription ) {
|
||||
$can_user_resubscribe = true;
|
||||
} else {
|
||||
$can_user_resubscribe = false;
|
||||
|
@@ -401,12 +401,12 @@ function wcs_estimate_period_between( $last_date, $second_date, $interval = 1 )
|
||||
$possible_periods = array();
|
||||
|
||||
// check for months
|
||||
$full_months = wcs_find_full_months_between( $earlier_timestamp, $later_timestamp );
|
||||
$full_months = wcs_find_full_months_between( $earlier_timestamp, $later_timestamp, $interval );
|
||||
|
||||
$possible_periods['month'] = array(
|
||||
'intervals' => $full_months['months'],
|
||||
'remainder' => $remainder = $full_months['remainder'],
|
||||
'fraction' => $remainder / ( 30 * DAY_IN_SECONDS ),
|
||||
'intervals' => floor( $full_months['months'] / $interval ),
|
||||
'remainder' => $full_months['remainder'],
|
||||
'fraction' => $full_months['remainder'] / ( 30 * DAY_IN_SECONDS ),
|
||||
'period' => 'month',
|
||||
'days_in_month' => $days_in_month,
|
||||
'original_interval' => $interval,
|
||||
@@ -416,8 +416,8 @@ function wcs_estimate_period_between( $last_date, $second_date, $interval = 1 )
|
||||
foreach ( array( 'year' => YEAR_IN_SECONDS, 'week' => WEEK_IN_SECONDS, 'day' => DAY_IN_SECONDS ) as $time => $seconds ) {
|
||||
$possible_periods[ $time ] = array(
|
||||
'intervals' => floor( $period_in_seconds / $seconds ),
|
||||
'remainder' => $remainder = $period_in_seconds % $seconds,
|
||||
'fraction' => $remainder / $seconds,
|
||||
'remainder' => $period_in_seconds % $seconds,
|
||||
'fraction' => ($period_in_seconds % $seconds) / $seconds,
|
||||
'period' => $time,
|
||||
'days_in_month' => $days_in_month,
|
||||
'original_interval' => $interval,
|
||||
@@ -473,27 +473,38 @@ function wcs_estimate_period_between( $last_date, $second_date, $interval = 1 )
|
||||
* @param numeric $end_timestamp unix timestamp of an end date
|
||||
* @return array with keys 'months' (integer) and 'remainder' (seconds, integer)
|
||||
*/
|
||||
function wcs_find_full_months_between( $start_timestamp, $end_timestamp ) {
|
||||
function wcs_find_full_months_between( $start_timestamp, $end_timestamp, $interval = 1 ) {
|
||||
$number_of_months = 0;
|
||||
$remainder = null;
|
||||
$previous_remainder = null;
|
||||
$remainder = 0;
|
||||
$previous_remainder = 0;
|
||||
$months_in_period = 0;
|
||||
$remainder_in_period = 0;
|
||||
|
||||
while ( 0 <= $remainder ) {
|
||||
$previous_timestamp = $start_timestamp;
|
||||
$start_timestamp = wcs_add_months( $start_timestamp, 1 );
|
||||
$previous_remainder = $remainder;
|
||||
$remainder = $end_timestamp - $start_timestamp;
|
||||
$remainder_in_period += $start_timestamp - $previous_timestamp;
|
||||
|
||||
if ( $remainder >= 0 ) {
|
||||
$number_of_months++;
|
||||
} elseif ( null === $previous_remainder ) {
|
||||
$months_in_period++;
|
||||
} elseif ( 0 === $previous_remainder ) {
|
||||
$previous_remainder = $end_timestamp - $previous_timestamp;
|
||||
}
|
||||
|
||||
if ( $months_in_period >= $interval ) {
|
||||
$months_in_period = 0;
|
||||
$remainder_in_period = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$remainder_in_period += $remainder;
|
||||
|
||||
$time_difference = array(
|
||||
'months' => $number_of_months,
|
||||
'remainder' => $previous_remainder,
|
||||
'remainder' => $remainder_in_period,
|
||||
);
|
||||
|
||||
return $time_difference;
|
||||
@@ -511,10 +522,10 @@ function wcs_discard_zero_intervals( $array ) {
|
||||
|
||||
/**
|
||||
* Used in an array_filter, discards high deviation elements.
|
||||
* - for days it's 1/24th
|
||||
* - for week it's 1/7th
|
||||
* - for year it's 1/300th
|
||||
* - for month it's 1/($days_in_months-2)
|
||||
* - 10 days for a year (10/365th)
|
||||
* - 4 days for a month (4/(days_in_month))
|
||||
* - 1 day for week (i.e. 1/7th)
|
||||
* - 1 hour for days (i.e. 1/24th)
|
||||
*
|
||||
* @param array $array elements of the filtered array
|
||||
* @return bool true if value is within deviation limit
|
||||
@@ -522,10 +533,10 @@ function wcs_discard_zero_intervals( $array ) {
|
||||
function wcs_discard_high_deviations( $array ) {
|
||||
switch ( $array['period'] ) {
|
||||
case 'year':
|
||||
return $array['fraction'] < ( 1 / 300 );
|
||||
return $array['fraction'] < ( 10 / 365 );
|
||||
break;
|
||||
case 'month':
|
||||
return $array['fraction'] < ( 1 / ( $array['days_in_month'] - 2 ) );
|
||||
return $array['fraction'] < ( 4 / $array['days_in_month'] );
|
||||
break;
|
||||
case 'week':
|
||||
return $array['fraction'] < ( 1 / 7 );
|
||||
@@ -556,8 +567,12 @@ function wcs_match_intervals( $array ) {
|
||||
*/
|
||||
function wcs_sort_by_intervals( $a, $b ) {
|
||||
if ( $a['intervals'] == $b['intervals'] ) {
|
||||
if ( $a['fraction'] == $b['fraction'] ) {
|
||||
return 0;
|
||||
}
|
||||
return ( $a['fraction'] < $b['fraction'] ) ? -1 : 1;
|
||||
|
||||
}
|
||||
return ( $a['intervals'] < $b['intervals'] ) ? -1 : 1;
|
||||
}
|
||||
|
||||
|
@@ -109,7 +109,7 @@ function wcs_get_new_user_role_names( $role_new ) {
|
||||
*
|
||||
* @param int (optional) The ID of a user in the store. If left empty, the current user's ID will be used.
|
||||
* @param int (optional) The ID of a product in the store. If left empty, the function will see if the user has any subscription.
|
||||
* @param string (optional) A valid subscription status. If left empty, the function will see if the user has a subscription of any status.
|
||||
* @param mixed (optional) A valid subscription status string or array. If left empty, the function will see if the user has a subscription of any status.
|
||||
* @since 2.0
|
||||
*/
|
||||
function wcs_user_has_subscription( $user_id = 0, $product_id = '', $status = 'any' ) {
|
||||
@@ -122,7 +122,7 @@ function wcs_user_has_subscription( $user_id = 0, $product_id = '', $status = 'a
|
||||
|
||||
if ( ! empty( $status ) && 'any' != $status ) { // We need to check for a specific status
|
||||
foreach ( $subscriptions as $subscription ) {
|
||||
if ( $subscription->get_status() == $status ) {
|
||||
if ( $subscription->has_status( $status ) ) {
|
||||
$has_subscription = true;
|
||||
break;
|
||||
}
|
||||
@@ -133,7 +133,7 @@ function wcs_user_has_subscription( $user_id = 0, $product_id = '', $status = 'a
|
||||
} else {
|
||||
|
||||
foreach ( $subscriptions as $subscription ) {
|
||||
if ( $subscription->has_product( $product_id ) && ( empty( $status ) || 'any' == $status || $subscription->get_status() == $status ) ) {
|
||||
if ( $subscription->has_product( $product_id ) && ( empty( $status ) || 'any' == $status || $subscription->has_status( $status ) ) ) {
|
||||
$has_subscription = true;
|
||||
break;
|
||||
}
|
||||
@@ -281,7 +281,8 @@ function wcs_get_all_user_actions_for_subscription( $subscription, $user_id ) {
|
||||
}
|
||||
|
||||
// Show button for subscriptions which can be cancelled and which may actually require cancellation (i.e. has a future payment)
|
||||
if ( $subscription->can_be_updated_to( 'cancelled' ) && $subscription->get_time( 'next_payment' ) > 0 ) {
|
||||
$next_payment = $subscription->get_time( 'next_payment' );
|
||||
if ( $subscription->can_be_updated_to( 'cancelled' ) && ! $subscription->is_one_payment() && ( $next_payment > 0 || ( $subscription->has_status( 'on-hold' ) && empty( $next_payment ) ) ) ) {
|
||||
$actions['cancel'] = array(
|
||||
'url' => wcs_get_users_change_status_link( $subscription->id, 'cancelled', $current_status ),
|
||||
'name' => _x( 'Cancel', 'an action on a subscription', 'woocommerce-subscriptions' ),
|
||||
|
@@ -46,12 +46,6 @@ $chosen_trial_period = WC_Subscriptions_Product::get_trial_period( $variation->I
|
||||
?>
|
||||
</label>
|
||||
<input type="text" class="wc_input_subscription_price" name="variable_subscription_price[<?php echo esc_attr( $loop ); ?>]" value="<?php echo esc_attr( get_post_meta( $variation->ID, '_subscription_price', true ) ); ?>" placeholder="<?php echo esc_attr_x( 'e.g. 9.90', 'example price', 'woocommerce-subscriptions' ); ?>">
|
||||
<label for="variable_subscription_period[<?php echo esc_attr( $loop ); ?>]" class="wcs_hidden_label"><?php esc_html_e( 'Billing Period:', 'woocommerce-subscriptions' ); ?></label>
|
||||
<select name="variable_subscription_period[<?php echo esc_attr( $loop ); ?>]" class="wc_input_subscription_period">
|
||||
<?php foreach ( wcs_get_subscription_period_strings() as $key => $value ) : ?>
|
||||
<option value="<?php echo esc_attr( $key ); ?>" <?php selected( $key, $subscription_period ); ?>><?php echo esc_html( $value ); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
|
||||
<label for="variable_subscription_period_interval[<?php echo esc_attr( $loop ); ?>]" class="wcs_hidden_label"><?php esc_html_e( 'Billing Interval:', 'woocommerce-subscriptions' ); ?></label>
|
||||
<select name="variable_subscription_period_interval[<?php echo esc_attr( $loop ); ?>]" class="wc_input_subscription_period_interval">
|
||||
@@ -59,6 +53,14 @@ $chosen_trial_period = WC_Subscriptions_Product::get_trial_period( $variation->I
|
||||
<option value="<?php echo esc_attr( $key ); ?>" <?php selected( $key, $chosen_interval ); ?>><?php echo esc_html( $value ); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
|
||||
<label for="variable_subscription_period[<?php echo esc_attr( $loop ); ?>]" class="wcs_hidden_label"><?php esc_html_e( 'Billing Period:', 'woocommerce-subscriptions' ); ?></label>
|
||||
<select name="variable_subscription_period[<?php echo esc_attr( $loop ); ?>]" class="wc_input_subscription_period">
|
||||
<?php foreach ( wcs_get_subscription_period_strings() as $key => $value ) : ?>
|
||||
<option value="<?php echo esc_attr( $key ); ?>" <?php selected( $key, $subscription_period ); ?>><?php echo esc_html( $value ); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
|
||||
</p>
|
||||
<p class="form-row form-row-last show_if_variable-subscription _subscription_length_field">
|
||||
<label for="variable_subscription_length[<?php echo esc_attr( $loop ); ?>]"><?php esc_html_e( 'Subscription Length:', 'woocommerce-subscriptions' ); ?></label>
|
||||
|
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* @author WooThemes
|
||||
* @package WooCommerce-Subscriptions/Templates
|
||||
* @version 1.5.4
|
||||
* @version 2.0.18
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
@@ -37,9 +37,9 @@ if ( ! $product->is_in_stock() ) : ?>
|
||||
|
||||
<?php if ( ! $product->is_purchasable() && 0 != $user_id && 'no' != $product->limit_subscriptions && ( ( 'active' == $product->limit_subscriptions && wcs_user_has_subscription( $user_id, $product->id, 'on-hold' ) ) || $user_has_subscription = wcs_user_has_subscription( $user_id, $product->id, $product->limit_subscriptions ) ) ) : ?>
|
||||
<?php if ( 'any' == $product->limit_subscriptions && $user_has_subscription && ! wcs_user_has_subscription( $user_id, $product->id, 'active' ) && ! wcs_user_has_subscription( $user_id, $product->id, 'on-hold' ) ) : // customer has an inactive subscription, maybe offer the renewal button ?>
|
||||
<?php $renewal_link = wcs_get_users_resubscribe_link_for_product( $product->id ); ?>
|
||||
<?php if ( ! empty( $renewal_link ) ) : ?>
|
||||
<a href="<?php echo esc_url( $renewal_link ); ?>" class="button product-renewal-link"><?php esc_html_e( 'Renew', 'woocommerce-subscriptions' ); ?></a>
|
||||
<?php $resubscribe_link = wcs_get_users_resubscribe_link_for_product( $product->id ); ?>
|
||||
<?php if ( ! empty( $resubscribe_link ) ) : ?>
|
||||
<a href="<?php echo esc_url( $resubscribe_link ); ?>" class="button product-resubscribe-link"><?php esc_html_e( 'Resubscribe', 'woocommerce-subscriptions' ); ?></a>
|
||||
<?php endif; ?>
|
||||
<?php else : ?>
|
||||
<p class="limited-subscription-notice notice"><?php esc_html_e( 'You have an active subscription to this product already.', 'woocommerce-subscriptions' ); ?></p>
|
||||
|
@@ -5,7 +5,7 @@
|
||||
* Description: Sell products and services with recurring payments in your WooCommerce Store.
|
||||
* Author: Prospress Inc.
|
||||
* Author URI: http://prospress.com/
|
||||
* Version: 2.0.17
|
||||
* Version: 2.0.18
|
||||
*
|
||||
* Copyright 2016 Prospress, Inc. (email : freedoms@prospress.com)
|
||||
*
|
||||
@@ -118,7 +118,7 @@ class WC_Subscriptions {
|
||||
|
||||
public static $plugin_file = __FILE__;
|
||||
|
||||
public static $version = '2.0.17';
|
||||
public static $version = '2.0.18';
|
||||
|
||||
private static $total_subscription_count = null;
|
||||
|
||||
|
Reference in New Issue
Block a user