diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md
deleted file mode 100755
index b25b4ce..0000000
--- a/.github/ISSUE_TEMPLATE/Bug_report.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-name: "Bug report"
-about: Report a bug if something isn't working as expected in Subscriptions
-
----
-
-### Describe the bug
-
-
-### To reproduce
-
-1.
-1.
-1.
-
-**Screenshots**
-
-
-### Expected behavior
-
-
-### Additional details
-
-
-System status
-
- ```
-
- ```
-
diff --git a/.github/ISSUE_TEMPLATE/Enhancement.md b/.github/ISSUE_TEMPLATE/Enhancement.md
deleted file mode 100755
index 9534e7d..0000000
--- a/.github/ISSUE_TEMPLATE/Enhancement.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-name: "New Enhancement"
-about: ""
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Proposed approach**
-Describe the proposed approach for the enhancement.
diff --git a/.github/config.yml b/.github/config.yml
deleted file mode 100755
index a80ba44..0000000
--- a/.github/config.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-# helPR bot config. https://probot.github.io/apps/helpr/
-helpr:
- opened: 'hasPR'
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
deleted file mode 100755
index 74151a7..0000000
--- a/.github/pull_request_template.md
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-**Issue**: #
-
-**Ticket**:
-
-**Slack thread**:
-
----
-
-### Description
-
-
-### Steps to test:
-
-
-
-1.
-1.
-1.
-
-### Documentation
-
-
-- [ ] This PR needs documentation (has the "status:needs-docs" label).
-
-
-Closes # .
diff --git a/assets/css/admin.css b/assets/css/admin.css
index 9e4ac60..7b9e806 100755
--- a/assets/css/admin.css
+++ b/assets/css/admin.css
@@ -274,10 +274,10 @@ a.close-subscriptions-search {
}
.variable_subscription_pricing_2_3 .wc_input_subscription_payment_sync_day {
max-width: 13%;
+ float: right;
}
.variable_subscription_pricing_2_3 .wc_input_subscription_payment_sync_month {
max-width: 86%;
- float: right;
}
@media screen and (max-width: 1190px) {
.variable_subscription_pricing_2_3 p._subscription_price_field,
@@ -290,10 +290,10 @@ a.close-subscriptions-search {
}
.variable_subscription_pricing_2_3 .wc_input_subscription_payment_sync_day {
max-width: 20%;
+ float: right;
}
.variable_subscription_pricing_2_3 .wc_input_subscription_payment_sync_month {
max-width: 78%;
- float: right;
}
}
._subscription_limit_field .description {
diff --git a/assets/js/admin/admin.js b/assets/js/admin/admin.js
index a670a15..f79ceb0 100755
--- a/assets/js/admin/admin.js
+++ b/assets/js/admin/admin.js
@@ -12,6 +12,10 @@ jQuery(document).ready(function($){
return decodeURIComponent(results[1].replace(/\+/g, ' '));
}
},
+ daysInMonth: function( month ) {
+ // Intentionally choose a non-leap year because we want february to have only 28 days.
+ return new Date(Date.UTC(2001, month, 0)).getUTCDate();
+ },
showHideSubscriptionMeta: function(){
if ($('select#product-type').val()==WCSubscriptions.productType) {
$('.show_if_simple').show();
@@ -150,7 +154,7 @@ jQuery(document).ready(function($){
if ($('select#product-type').val()=='variable-subscription') {
var $container = periodField.closest('.woocommerce_variable_attributes').find('.variable_subscription_sync');
} else {
- $container = periodField.closest('#general_product_data').find('.subscription_sync')
+ $container = periodField.closest('#general_product_data').find('.subscription_sync');
}
var $syncWeekMonthContainer = $container.find('.subscription_sync_week_month'),
@@ -170,16 +174,17 @@ jQuery(document).ready(function($){
if('day'==billingPeriod) {
$syncWeekMonthSelect.val(0);
- $syncAnnualContainer.find('input[type="number"]').val(0);
+ $syncAnnualContainer.find('input[type="number"]').val(0).trigger('change');
} else {
if('year'==billingPeriod) {
// Make sure the year sync fields are reset
- $syncAnnualContainer.find('input[type="number"]').val(0);
+ $syncAnnualContainer.find('input[type="number"]').val(0).trigger('change');
// And the week/month field has no option selected
$syncWeekMonthSelect.val(0);
} else {
// Make sure the year sync value is 0
- $syncAnnualContainer.find('input[type="number"]').val(0);
+ $syncAnnualContainer.find('input[type="number"]').val(0).trigger('change');
+
// And the week/month field has the appropriate options
$syncWeekMonthSelect.empty();
$.each(WCSubscriptions.syncOptions[billingPeriod], function(key,description) {
@@ -202,6 +207,7 @@ jQuery(document).ready(function($){
if ($varSubField.length > 0) { // Variation
var matches = $varSubField.attr('name').match(/\[(.*?)\]/);
$subscriptionPeriodElement = $('[name="variable_subscription_period['+matches[1]+']"]');
+
if ($('select#product-type').val()=='variable-subscription') {
$slideSwitch = true;
}
@@ -433,6 +439,22 @@ jQuery(document).ready(function($){
$.setTrialPeriods();
});
+ // Handles changes to sync date select/input for yearly subscription products.
+ $('#woocommerce-product-data').on('change', '[name^="_subscription_payment_sync_date_day"], [name^="variable_subscription_payment_sync_date_day"]', function() {
+ if ( 0 == $(this).val() ) {
+ $(this).siblings('[name^="_subscription_payment_sync_date_month"], [name^="variable_subscription_payment_sync_date_month"]').val(0);
+ $(this).prop('disabled', true);
+ }
+ }).on('change', '[name^="_subscription_payment_sync_date_month"], [name^="variable_subscription_payment_sync_date_month"]', function() {
+ var $syncDayOfMonthInput = $(this).siblings('[name^="_subscription_payment_sync_date_day"], [name^="variable_subscription_payment_sync_date_day"]');
+
+ if ( 0 < $(this).val() ) {
+ $syncDayOfMonthInput.val(1).attr({step: "1", min: "1", max: $.daysInMonth($(this).val())}).prop('disabled', false);
+ } else {
+ $syncDayOfMonthInput.val(0).trigger('change');
+ }
+ });
+
$('body').bind('woocommerce-product-type-change',function(){
$.showHideSubscriptionMeta();
$.showHideVariableSubscriptionMeta();
diff --git a/changelog.txt b/changelog.txt
index e777146..3cc3830 100755
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,9 +1,57 @@
*** WooCommerce Subscriptions Changelog ***
+2019.11.14 - version 2.6.5
+* Fix: Account for prorated switch sign up fees in multi-switches. PR#3519
+* Fix: Tooltip content displayed on WooCommerce > Subscriptions administration screen.
+* Dev: Add additional hooks in My Account Subscription Details table template. PR#3523
+
+2019.11.12 - version 2.6.4
+* Tweak: Update the My Account customer has no subscriptions notice to match WC core. PR#3516
+* Fix: Add hidden class to subscription_pricing and subscription_sync edit product fields. Fixes a bug when the subscription product types are removed from the edit product type drop-down. PR#3514
+* Fix: error on My Account > Payment Methods for non credit card tokens and allow deleting tokens with clear alternative. PR#3482
+* Fix: Allow only number of days in specific month for synchronize renewals. PR#3470
+* Fix: Save subscription meta box data via set_props(). Fixes fatal error when saving invalid data. PR#3524
+* Fix: Use update_option() rather than add_option() to record WC Subscriptions activation. Fixes infinitely running activation hook under some circumstances. PR#3525
+* Dev - Opt-in tracking data for Subscriptions PR#3504
+ Data sent to WooCommerce:
+ Staging or live site
+ Live URL
+ WooCommerce Subscriptions Settings
+ Dates of the first and last created subscriptions
+ Number of subscriptions
+ Number of subscriptions with each status
+ Gross totals for switch, renewal, resubscribe, and initial totals
+ Order counts for for switch, renewal, resubscribe, and initial orders
+ To disable this tracking, opt out of WooCommerce tracking, see https://woocommerce.com/usage-tracking/
+
+2019.10.29 - version 2.6.3
+* Fix: use dashicon over fa icon. PR#3497
+* Fix: remove button type from close modal link. PR#3497
+* Fix: Remove double filtering of the meta label through the woocommerce_attribute_label filter. PR#3476
+* Fix: Restore the subscription's end date after reactivation. PR#3399
+* Fix: Tooltip content displayed on WooCommerce > Subscriptions administration screen.
+* Tweak: Allow modals to be displayed on admin screens. PR#3497
+* Tweak: Redirect the customer to checkout after failed early renewal attempt. PR#3494
+* Dev: Allow third parties to filter the switch cart item object properties. PR#3484
+
+2019.10.10 - version 2.6.2
+* Tweak: Add the switch direction the switch data stored in _subscription_switch_data order meta. PR#3440
+* Tweak: Add an order note to manual renewal order to note the order is awaiting customer payment. PR#3456
+* Tweak: Add note on the renewal order when a manual payment retry is ran. PR#3477
+* Fix: Hide sync meta data on the edit order and subscription screen. PR#3454
+* Fix: Fix an issue that led to missing _switched_subscription_item_id line item meta which caused incorrect multi-switch upgrade costs among other issues. PR#3461
+* Fix: Store the full set of current subscription counts not just the last element. Fixes issues when exporting subscription report data. PR#3455
+* Fix: Add the manually admin requested renewal order notes in the correct order. PR#3462
+* Fix: Display the customer facing subscription dates in site time. Fixing display inconsistencies. PR#3469
+* Fix: Updated the link in the staging site admin notice. PR#3473
+* Fix: Only get return retries from the post store which are retry posts. Fixes an issue where it would return a retry object for other post types. PR#3481
+* Fix: Load renewal order fee items to manual renewal carts. PR#3480
+* Dev: Fixed WC_Subscription::get_date() returning dates in the site time if the site was using GMT offsets in their site settings. PR#3469
+
2019.09.04 - version 2.6.1
* Fix a bug that would lead to switch log entries not including all information. PR#3441
* Fix fatal errors that would occur on the admin edit order screen on staging sites. PR#3443
-* Performance: Sort subscription related order IDs on the application layer with rsort() instead of MySQL orderby clause. PR#3442
+* Performance: Sort using subscription related order IDs on the application layer with rsort() instead of MySQL orderby clause. PR#3442
2019.09.02 - version 2.6.0
* New: New option to allow customers with automatically renewing subscriptions to renew early via a modal rather than going through the checkout. PR#3293
diff --git a/includes/admin/class-wc-subscriptions-admin.php b/includes/admin/class-wc-subscriptions-admin.php
index 693ba0c..bc56e83 100755
--- a/includes/admin/class-wc-subscriptions-admin.php
+++ b/includes/admin/class-wc-subscriptions-admin.php
@@ -110,9 +110,7 @@ class WC_Subscriptions_Admin {
add_filter( 'posts_where', array( __CLASS__, 'filter_orders' ) );
- add_filter( 'posts_where', array( __CLASS__, 'filter_orders_from_list' ) );
-
- add_filter( 'posts_where', array( __CLASS__, 'filter_subscriptions_from_list' ) );
+ add_filter( 'posts_where', array( __CLASS__, 'filter_orders_and_subscriptions_from_list' ) );
add_filter( 'posts_where', array( __CLASS__, 'filter_paid_subscription_orders_for_user' ) );
@@ -288,7 +286,7 @@ class WC_Subscriptions_Admin {
$chosen_period = 'month';
}
- echo '
';
+ echo '
';
// Subscription Price, Interval and Period
?>
@@ -372,7 +370,7 @@ class WC_Subscriptions_Admin {
global $post;
echo '
';
- echo '
';
+ echo '
';
// Only one Subscription per customer
woocommerce_wp_checkbox( array(
@@ -1455,62 +1453,60 @@ class WC_Subscriptions_Admin {
}
/**
- * Filters the Admin orders table results based on a list of IDs returned by a report query.
+ * Filters the Admin orders and subscriptions table results based on a list of IDs returned by a report query.
+ *
+ * @since 2.6.2
*
* @param string $where The query WHERE clause.
* @return string $where
- * @since 2.6.0
*/
- public static function filter_orders_from_list( $where ) {
+ public static function filter_orders_and_subscriptions_from_list( $where ) {
global $typenow, $wpdb;
- if ( ! is_admin() || 'shop_order' !== $typenow || ! isset( $_GET['_orders_list_key'], $_GET['_report'] ) ) {
+ if ( ! is_admin() || ! in_array( $typenow, array( 'shop_subscription', 'shop_order' ) ) || ! isset( $_GET['_report'] ) ) {
return $where;
}
- if ( ! empty( $_GET['_orders_list_key'] ) && ! empty( $_GET['_report'] ) ) {
- $cache = get_transient( $_GET['_report'] );
- $results = $cache[ $_GET['_orders_list_key'] ];
- $order_ids = explode( ',', implode( ',', wp_list_pluck( $results, 'order_ids', true ) ) );
+ // Map the order or subscription type to their respective keys and type key.
+ $object_type = 'shop_order' === $typenow ? 'order' : 'subscription';
+ $cache_report_key = isset( $_GET[ "_{$object_type}s_list_key" ] ) ? $_GET[ "_{$object_type}s_list_key" ] : '';
- // $format = '%d, %d, %d, %d, %d, [...]'
- $format = implode( ', ', array_fill( 0, count( $order_ids ), '%d' ) );
- $where .= $wpdb->prepare( " AND {$wpdb->posts}.ID IN ($format)", $order_ids );
- } else {
- // No orders in list. So, give invalid 'where' clause so as to make the query return 0 items.
+ // If the report key or report arg is empty exit early.
+ if ( empty( $cache_report_key ) || empty( $_GET['_report'] ) ) {
$where .= " AND {$wpdb->posts}.ID = 0";
- }
-
- return $where;
- }
-
- /**
- * Filters the Admin subscriptions table results based on a list of IDs returned by a report query.
- *
- * @param string $where The query WHERE clause.
- * @return string
- * @since 2.6.0
- */
- public static function filter_subscriptions_from_list( $where ) {
- global $typenow, $wpdb;
-
- if ( ! is_admin() || 'shop_subscription' !== $typenow || ! isset( $_GET['_subscriptions_list_key'], $_GET['_report'] ) ) {
return $where;
}
- if ( ! empty( $_GET['_subscriptions_list_key'] ) && ! empty( $_GET['_report'] ) ) {
- $cache = get_transient( $_GET['_report'] );
- $results = $cache[ $_GET['_subscriptions_list_key'] ];
- $subscription_ids = explode( ',', implode( ',', wp_list_pluck( $results, 'subscription_ids', true ) ) );
+ $cache = get_transient( $_GET['_report'] );
+
+ // Display an admin notice if we cannot find the report data requested.
+ if ( ! isset( $cache[ $cache_report_key ] ) ) {
+ $admin_notice = new WCS_Admin_Notice( 'error' );
+ $admin_notice->set_simple_content( sprintf(
+ /* translators: Placeholders are opening and closing link tags. */
+ __( "We weren't able to locate the set of report results you requested. Please regenerate the link from the %sSubscription Reports screen%s.", 'woocommerce-subscriptions' ),
+ '',
+ ''
+ ) );
+ $admin_notice->display();
- // $format = '%d, %d, %d, %d, %d, [...]'
- $format = implode( ', ', array_fill( 0, count( $subscription_ids ), '%d' ) );
- $where .= $wpdb->prepare( " AND {$wpdb->posts}.ID IN ($format)", $subscription_ids );
- } else {
- // No subscriptions in list. So, give invalid 'where' clause so as to make the query return 0 items.
$where .= " AND {$wpdb->posts}.ID = 0";
+ return $where;
}
+ $results = $cache[ $cache_report_key ];
+
+ // The current subscriptions count report will include the specific result (the subscriptions active on the last day) that should be used to generate the subscription list.
+ if ( ! empty( $_GET['_data_key'] ) && isset( $results[ (int) $_GET['_data_key'] ] ) ) {
+ $results = array( $results[ (int) $_GET['_data_key'] ] );
+ }
+
+ $ids = explode( ',', implode( ',', wp_list_pluck( $results, "{$object_type}_ids", true ) ) );
+
+ // $format = '%d, %d, %d, %d, %d, [...]'
+ $format = implode( ', ', array_fill( 0, count( $ids ), '%d' ) );
+ $where .= $wpdb->prepare( " AND {$wpdb->posts}.ID IN ($format)", $ids );
+
return $where;
}
@@ -2055,4 +2051,34 @@ class WC_Subscriptions_Admin {
public static function recurring_totals_meta_box( $post ) {
_deprecated_function( __METHOD__, '2.0' );
}
+
+ /**
+ * Filters the Admin orders table results based on a list of IDs returned by a report query.
+ *
+ * @deprecated 2.6.2
+ *
+ * @param string $where The query WHERE clause.
+ * @return string $where
+ * @since 2.6.0
+ */
+ public static function filter_orders_from_list( $where ) {
+ wcs_deprecated_function( __METHOD__, '2.6.2', 'WC_Subscriptions_Admin::filter_orders_and_subscriptions_from_list( $where )' );
+
+ return WC_Subscriptions_Admin::filter_orders_and_subscriptions_from_list( $where );
+ }
+
+ /**
+ * Filters the Admin subscriptions table results based on a list of IDs returned by a report query.
+ *
+ * @deprecated 2.6.2
+ *
+ * @param string $where The query WHERE clause.
+ * @return string
+ * @since 2.6.0
+ */
+ public static function filter_subscriptions_from_list( $where ) {
+ wcs_deprecated_function( __METHOD__, '2.6.2', 'WC_Subscriptions_Admin::filter_orders_and_subscriptions_from_list( $where )' );
+
+ return WC_Subscriptions_Admin::filter_orders_and_subscriptions_from_list( $where );
+ }
}
diff --git a/includes/admin/class-wcs-admin-meta-boxes.php b/includes/admin/class-wcs-admin-meta-boxes.php
index b21035b..a488ab4 100755
--- a/includes/admin/class-wcs-admin-meta-boxes.php
+++ b/includes/admin/class-wcs-admin-meta-boxes.php
@@ -179,8 +179,8 @@ class WCS_Admin_Meta_Boxes {
* @since 2.0
*/
public static function process_renewal_action_request( $subscription ) {
- do_action( 'woocommerce_scheduled_subscription_payment', $subscription->get_id() );
$subscription->add_order_note( __( 'Process renewal order action requested by admin.', 'woocommerce-subscriptions' ), false, true );
+ do_action( 'woocommerce_scheduled_subscription_payment', $subscription->get_id() );
}
/**
@@ -190,7 +190,7 @@ class WCS_Admin_Meta_Boxes {
* @since 2.0
*/
public static function create_pending_renewal_action_request( $subscription ) {
-
+ $subscription->add_order_note( __( 'Create pending renewal order requested by admin action.', 'woocommerce-subscriptions' ), false, true );
$subscription->update_status( 'on-hold' );
$renewal_order = wcs_create_renewal_order( $subscription );
@@ -203,8 +203,6 @@ class WCS_Admin_Meta_Boxes {
$renewal_order->save();
}
}
-
- $subscription->add_order_note( __( 'Create pending renewal order requested by admin action.', 'woocommerce-subscriptions' ), false, true );
}
/**
@@ -264,6 +262,7 @@ class WCS_Admin_Meta_Boxes {
// init payment gateways
WC()->payment_gateways();
+ $order->add_order_note( __( 'Retry renewal payment action requested by admin.', 'woocommerce-subscriptions' ), false, true );
do_action( 'woocommerce_scheduled_subscription_payment_' . wcs_get_objects_property( $order, 'payment_method' ), $order->get_total(), $order );
}
}
diff --git a/includes/admin/class-wcs-admin-post-types.php b/includes/admin/class-wcs-admin-post-types.php
index f15bd7d..5a8f404 100755
--- a/includes/admin/class-wcs-admin-post-types.php
+++ b/includes/admin/class-wcs-admin-post-types.php
@@ -538,7 +538,7 @@ class WCS_Admin_Post_Types {
}
if ( ! empty( $customer_tip ) ) {
- echo '
';
+ echo '
'; // XSS ok.
}
// This is to stop PHP from complaining
@@ -1078,7 +1078,7 @@ class WCS_Admin_Post_Types {
$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 .= wcs_help_tip( $item_meta_html, true );
}
$item_html .= '
diff --git a/wcs-functions.php b/wcs-functions.php
index ef13956..0b01f50 100755
--- a/wcs-functions.php
+++ b/wcs-functions.php
@@ -73,7 +73,7 @@ function wcs_do_subscriptions_exist() {
*
* @since 2.0
* @param mixed $the_subscription Post object or post ID of the order.
- * @return WC_Subscription
+ * @return WC_Subscription|false The subscription object, or false if it cannot be found.
*/
function wcs_get_subscription( $the_subscription ) {
diff --git a/woocommerce-subscriptions.php b/woocommerce-subscriptions.php
index d50fcee..ba7700c 100755
--- a/woocommerce-subscriptions.php
+++ b/woocommerce-subscriptions.php
@@ -5,10 +5,10 @@
* Description: Sell products and services with recurring payments in your WooCommerce Store.
* Author: Automattic
* Author URI: https://woocommerce.com/
- * Version: 2.6.1
+ * Version: 2.6.5
*
- * WC requires at least: 3.0
- * WC tested up to: 3.6
+ * WC requires at least: 3.0.9
+ * WC tested up to: 3.8
* Woo: 27147:6115e6d7e297b623a169fdcf5728b224
*
* Copyright 2019 WooCommerce
@@ -83,6 +83,7 @@ WC_Subscriptions_Change_Payment_Gateway::init();
WC_Subscriptions_Payment_Gateways::init();
WCS_PayPal_Standard_Change_Payment_Method::init();
WC_Subscriptions_Switcher::init();
+WC_Subscriptions_Tracker::init();
WCS_Upgrade_Logger::init();
new WCS_Cart_Renewal();
new WCS_Cart_Resubscribe();
@@ -117,7 +118,7 @@ class WC_Subscriptions {
public static $plugin_file = __FILE__;
- public static $version = '2.6.1';
+ public static $version = '2.6.5';
public static $wc_minimum_supported_version = '3.0';
@@ -740,7 +741,7 @@ class WC_Subscriptions {
update_option( WC_Subscriptions_admin::$option_prefix . '_paypal_debugging_default_set', 'true' );
}
- add_option( WC_Subscriptions_Admin::$option_prefix . '_is_active', true );
+ update_option( WC_Subscriptions_Admin::$option_prefix . '_is_active', true );
set_transient( self::$activation_transient, true, 60 * 60 );
@@ -894,7 +895,7 @@ class WC_Subscriptions {
// translators: 1$-2$: opening and closing tags. 3$-4$: opening and closing link tags for learn more. Leads to duplicate site article on docs. 5$-6$: Opening and closing link to production URL. 7$: Production URL .
esc_html__( 'It looks like this site has moved or is a duplicate site. %1$sWooCommerce Subscriptions%2$s has disabled automatic payments and subscription related emails on this site to prevent duplicate payments from a staging or test environment. %1$sWooCommerce Subscriptions%2$s considers %5$s%7$s%6$s to be the site\'s URL. %3$sLearn more »%4$s.', 'woocommerce-subscriptions' ),
'', '',
- '', '',
+ '', '',
'', '',
esc_url( self::get_site_url_from_source( 'subscriptions_install' ) )
)