mirror of
https://github.com/pronamic/woocommerce-subscriptions.git
synced 2025-10-18 15:22:57 +00:00
2.6.5
This commit is contained in:

committed by
Remco Tolsma

parent
091a1c9089
commit
92239cc451
30
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
30
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
@@ -1,30 +0,0 @@
|
||||
---
|
||||
name: "Bug report"
|
||||
about: Report a bug if something isn't working as expected in Subscriptions
|
||||
|
||||
---
|
||||
|
||||
### Describe the bug
|
||||
<!-- A clear and concise description of what the bug is. Please be as descriptive as possible; issues lacking detail, or for any other reason than to report a bug, may be closed without action.-->
|
||||
|
||||
### To reproduce
|
||||
<!-- Describe the steps to reproduce the behavior -->
|
||||
1.
|
||||
1.
|
||||
1.
|
||||
|
||||
**Screenshots**
|
||||
<!-- If applicable, add screenshots to help explain your problem.-->
|
||||
|
||||
### Expected behavior
|
||||
<!-- A clear and concise description of what you expected to happen.-->
|
||||
|
||||
### Additional details
|
||||
<!--Here you can include any additional details you think might be helpful.-->
|
||||
<!--Ticket numbers/links, plugin versions, system statuses etc.-->
|
||||
<details><summary>System status</summary>
|
||||
|
||||
```
|
||||
<!--If applicable, paste the system status here. Please ensure you redact or remove any identifying information. -->
|
||||
```
|
||||
</details>
|
17
.github/ISSUE_TEMPLATE/Enhancement.md
vendored
17
.github/ISSUE_TEMPLATE/Enhancement.md
vendored
@@ -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.
|
3
.github/config.yml
vendored
3
.github/config.yml
vendored
@@ -1,3 +0,0 @@
|
||||
# helPR bot config. https://probot.github.io/apps/helpr/
|
||||
helpr:
|
||||
opened: 'hasPR'
|
28
.github/pull_request_template.md
vendored
28
.github/pull_request_template.md
vendored
@@ -1,28 +0,0 @@
|
||||
<!-- Reference the source of this Pull Request. -->
|
||||
<!-- Remove any which are not applicable. -->
|
||||
**Issue**: #
|
||||
|
||||
**Ticket**:
|
||||
|
||||
**Slack thread**:
|
||||
|
||||
---
|
||||
|
||||
### Description
|
||||
<!-- Describe the changes made in this Pull Request and the reason for these changes. -->
|
||||
|
||||
### Steps to test:
|
||||
<!-- Describe the steps to replicate the issue and confirm the fix -->
|
||||
<!-- Try to include as many details as possible. -->
|
||||
<!-- Please include screenshots. If you work with Prospress, sign-up for CloudApp via https://prospress.cl.ly -->
|
||||
1.
|
||||
1.
|
||||
1.
|
||||
|
||||
### Documentation
|
||||
<!-- Will this change require new documentation or changes to existing documentation? -->
|
||||
<!-- A good way to answer it is to ask: will more than one customer ever need to know about this? -->
|
||||
- [ ] This PR needs documentation (has the "status:needs-docs" label).
|
||||
<!-- For an extra 💯 include further details about which change requires documentation -->
|
||||
|
||||
Closes # .
|
@@ -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 {
|
||||
|
@@ -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();
|
||||
|
@@ -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
|
||||
|
@@ -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 '<div class="options_group subscription_pricing show_if_subscription">';
|
||||
echo '<div class="options_group subscription_pricing show_if_subscription hidden">';
|
||||
|
||||
// Subscription Price, Interval and Period
|
||||
?><p class="form-field _subscription_price_fields _subscription_price_field">
|
||||
@@ -372,7 +370,7 @@ class WC_Subscriptions_Admin {
|
||||
global $post;
|
||||
|
||||
echo '</div>';
|
||||
echo '<div class="options_group subscription_one_time_shipping show_if_subscription show_if_variable-subscription">';
|
||||
echo '<div class="options_group subscription_one_time_shipping show_if_subscription show_if_variable-subscription hidden">';
|
||||
|
||||
// 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' ),
|
||||
'<a href="' . esc_url( admin_url( 'admin.php?page=wc-reports&tab=subscriptions&report=subscription_events_by_date' ) ) . '">',
|
||||
'</a>'
|
||||
) );
|
||||
$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 );
|
||||
}
|
||||
}
|
||||
|
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
@@ -538,7 +538,7 @@ class WCS_Admin_Post_Types {
|
||||
}
|
||||
|
||||
if ( ! empty( $customer_tip ) ) {
|
||||
echo '<div class="tips" data-tip="' . esc_attr( $customer_tip ) . '">';
|
||||
echo '<div class="tips" data-tip="' . wc_sanitize_tooltip( $customer_tip ) . '">'; // 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 .= '</div>';
|
||||
@@ -1106,7 +1106,7 @@ class WCS_Admin_Post_Types {
|
||||
echo wp_kses( $item_name, array( 'a' => array( 'href' => array() ) ) );
|
||||
|
||||
if ( $item_meta_html ) {
|
||||
echo wcs_help_tip( $item_meta_html );
|
||||
echo wcs_help_tip( $item_meta_html, true );
|
||||
} ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
@@ -315,38 +315,56 @@ class WCS_Meta_Box_Subscription_Data extends WC_Meta_Box_Order_Data {
|
||||
|
||||
// Get subscription object.
|
||||
$subscription = wcs_get_subscription( $post_id );
|
||||
$props = array();
|
||||
|
||||
// Ensure there is an order key.
|
||||
if ( ! $subscription->get_order_key() ) {
|
||||
wcs_set_objects_property( $subscription, 'order_key', wcs_generate_order_key() );
|
||||
$props['order_key'] = wcs_generate_order_key();
|
||||
}
|
||||
|
||||
// Update meta
|
||||
$customer_id = isset( $_POST['customer_user'] ) ? absint( $_POST['customer_user'] ) : 0;
|
||||
if ( $customer_id !== $subscription->get_customer_id() ) {
|
||||
wcs_set_objects_property( $subscription, '_customer_user', $customer_id );
|
||||
$props['customer_id'] = $customer_id;
|
||||
}
|
||||
|
||||
// Handle the billing fields.
|
||||
// Update billing fields.
|
||||
foreach ( self::$billing_fields as $key => $field ) {
|
||||
$field['id'] = isset( $field['id'] ) ? $field['id'] : "_billing_{$key}";
|
||||
|
||||
if ( ! isset( $_POST[ $field['id'] ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
wcs_set_objects_property( $subscription, $field['id'], wc_clean( $_POST[ $field['id'] ] ) );
|
||||
$value = wc_clean( wp_unslash( $_POST[ $field['id'] ] ) );
|
||||
|
||||
if ( is_callable( array( $subscription, 'set_billing_' . $key ) ) ) {
|
||||
$props[ "billing_{$key}" ] = $value;
|
||||
} else {
|
||||
$subscription->update_meta_data( $field['id'], $value );
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the shipping fields.
|
||||
foreach ( self::$shipping_fields as $key => $field ) {
|
||||
// Update shipping fields.
|
||||
foreach ( self::$billing_fields as $key => $field ) {
|
||||
$field['id'] = isset( $field['id'] ) ? $field['id'] : "_shipping_{$key}";
|
||||
|
||||
if ( ! isset( $_POST[ $field['id'] ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
wcs_set_objects_property( $subscription, $field['id'], wc_clean( $_POST[ $field['id'] ] ) );
|
||||
$value = wc_clean( wp_unslash( $_POST[ $field['id'] ] ) );
|
||||
|
||||
if ( is_callable( array( $subscription, 'set_billing_' . $key ) ) ) {
|
||||
$props[ "shipping_{$key}" ] = $value;
|
||||
} else {
|
||||
$subscription->update_meta_data( $field['id'], $value );
|
||||
}
|
||||
}
|
||||
|
||||
$subscription->set_props( $props );
|
||||
$subscription->save();
|
||||
|
||||
// Save the linked parent order id
|
||||
if ( ! empty( $_POST['parent-order-id'] ) ) {
|
||||
// if the parent order to be set is a renewal order
|
||||
|
@@ -53,6 +53,7 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report {
|
||||
public function get_data( $args = array() ) {
|
||||
global $wpdb;
|
||||
|
||||
$update_cache = false;
|
||||
$default_args = array(
|
||||
'no_cache' => false,
|
||||
'order_status' => apply_filters( 'woocommerce_reports_order_statuses', array( 'completed', 'processing', 'on-hold' ) ),
|
||||
@@ -62,17 +63,17 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report {
|
||||
$args = wp_parse_args( $args, $default_args );
|
||||
|
||||
$query_end_date = date( 'Y-m-d', strtotime( '+1 DAY', $this->end_date ) );
|
||||
$offset = get_option( 'gmt_offset' );
|
||||
$offset = get_option( 'gmt_offset' );
|
||||
|
||||
// Convert from Decimal format(eg. 11.5) to a suitable format(eg. +11:30) for CONVERT_TZ() of SQL query.
|
||||
$site_timezone = sprintf( '%+02d:%02d', (int) $offset, ( $offset - floor( $offset ) ) * 60 );
|
||||
|
||||
$this->report_data = new stdClass;
|
||||
|
||||
// While generating report data via get_order_report_data(), hook in to set the query hash so we can cache the results.
|
||||
add_filter( 'woocommerce_reports_get_order_report_query', array( $this, 'set_query_hash' ) );
|
||||
|
||||
$this->generating_report = 'new_subscriptions';
|
||||
|
||||
$this->generating_report = 'new_subscriptions';
|
||||
$this->report_data->new_subscriptions_data = (array) $this->get_order_report_data(
|
||||
array(
|
||||
'data' => array(
|
||||
@@ -111,8 +112,7 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report {
|
||||
)
|
||||
);
|
||||
|
||||
$this->generating_report = 'renewals';
|
||||
|
||||
$this->generating_report = 'renewals';
|
||||
$this->report_data->renewal_data = (array) $this->get_order_report_data(
|
||||
array(
|
||||
'data' => array(
|
||||
@@ -162,8 +162,7 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report {
|
||||
)
|
||||
);
|
||||
|
||||
$this->generating_report = 'resubscribes';
|
||||
|
||||
$this->generating_report = 'resubscribes';
|
||||
$this->report_data->resubscribe_data = (array) $this->get_order_report_data(
|
||||
array(
|
||||
'data' => array(
|
||||
@@ -213,8 +212,7 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report {
|
||||
)
|
||||
);
|
||||
|
||||
$this->generating_report = 'switches';
|
||||
|
||||
$this->generating_report = 'switches';
|
||||
$this->report_data->switch_data = (array) $this->get_order_report_data(
|
||||
array(
|
||||
'data' => array(
|
||||
@@ -264,15 +262,24 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report {
|
||||
)
|
||||
);
|
||||
|
||||
// We've finished generating report data via get_order_report_data() so unhook our query hash flagging function.
|
||||
unset( $this->generating_report );
|
||||
|
||||
remove_filter( 'woocommerce_reports_get_order_report_query', array( $this, 'set_query_hash' ) );
|
||||
|
||||
$cached_results = get_transient( strtolower( get_class( $this ) ) );
|
||||
|
||||
// Check if we need to update the cache with the query results from the figures generated by get_order_report_data().
|
||||
foreach ( array( 'new_subscriptions' => 'new_subscriptions', 'renewals' => 'renewal', 'resubscribes' => 'resubscribe', 'switches' => 'switch' ) as $report => $property_key ) {
|
||||
$query_hash = $this->report_data->{"{$report}_query_hash"};
|
||||
if ( ! isset( $cached_results[ $query_hash ] ) ) {
|
||||
$cached_results[ $query_hash ] = $this->report_data->{"{$property_key}_data"};
|
||||
$update_cache = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* New subscription orders
|
||||
*/
|
||||
* New subscription orders
|
||||
*/
|
||||
$query = $wpdb->prepare(
|
||||
"SELECT SUM(subscriptions.count) as count,
|
||||
order_posts.post_date as post_date,
|
||||
@@ -310,7 +317,7 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report {
|
||||
if ( $args['no_cache'] || false === $cached_results || ! isset( $cached_results[ $query_hash ] ) ) {
|
||||
$wpdb->query( 'SET SESSION SQL_BIG_SELECTS=1' );
|
||||
$cached_results[ $query_hash ] = apply_filters( 'wcs_reports_subscription_events_sign_up_data', (array) $wpdb->get_results( $query ), $args );
|
||||
set_transient( strtolower( get_class( $this ) ), $cached_results, WEEK_IN_SECONDS );
|
||||
$update_cache = true;
|
||||
}
|
||||
|
||||
$this->report_data->signup_data = $cached_results[ $query_hash ];
|
||||
@@ -375,12 +382,10 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report {
|
||||
if ( $args['no_cache'] || false === $cached_results || ! isset( $cached_results[ $query_hash ] ) ) {
|
||||
$wpdb->query( 'SET SESSION SQL_BIG_SELECTS=1' );
|
||||
$cached_results[ $query_hash ] = apply_filters( 'wcs_reports_subscription_events_subscriber_count_data', (array) $wpdb->get_results( $query ), $args );
|
||||
set_transient( strtolower( get_class( $this ) ), $cached_results, WEEK_IN_SECONDS );
|
||||
$update_cache = true;
|
||||
}
|
||||
|
||||
$this->report_data->subscriber_counts = $cached_results[ $query_hash ];
|
||||
|
||||
$cached_results[ $query_hash ] = array_slice( $this->report_data->subscriber_counts, -1 );
|
||||
$this->report_data->current_subscriptions_query_hash = $query_hash;
|
||||
|
||||
/*
|
||||
@@ -406,7 +411,7 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report {
|
||||
if ( $args['no_cache'] || false === $cached_results || ! isset( $cached_results[ $query_hash ] ) ) {
|
||||
$wpdb->query( 'SET SESSION SQL_BIG_SELECTS=1' );
|
||||
$cached_results[ $query_hash ] = apply_filters( 'wcs_reports_subscription_events_cancel_count_data', (array) $wpdb->get_results( $query ), $args );
|
||||
set_transient( strtolower( get_class( $this ) ), $cached_results, WEEK_IN_SECONDS );
|
||||
$update_cache = true;
|
||||
}
|
||||
|
||||
$this->report_data->cancel_counts = $cached_results[ $query_hash ];
|
||||
@@ -436,7 +441,7 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report {
|
||||
if ( $args['no_cache'] || false === $cached_results || ! isset( $cached_results[ $query_hash ] ) ) {
|
||||
$wpdb->query( 'SET SESSION SQL_BIG_SELECTS=1' );
|
||||
$cached_results[ $query_hash ] = apply_filters( 'wcs_reports_subscription_events_ended_count_data', (array) $wpdb->get_results( $query ), $args );
|
||||
set_transient( strtolower( get_class( $this ) ), $cached_results, WEEK_IN_SECONDS );
|
||||
$update_cache = true;
|
||||
}
|
||||
|
||||
$this->report_data->ended_counts = $cached_results[ $query_hash ];
|
||||
@@ -458,6 +463,14 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report {
|
||||
$this->report_data->total_subscriptions_at_period_end = $this->report_data->subscriber_counts ? absint( end( $this->report_data->subscriber_counts )->count ) : 0;
|
||||
$this->report_data->total_subscriptions_at_period_start = isset( $this->report_data->subscriber_counts[0]->count ) ? absint( $this->report_data->subscriber_counts[0]->count ) : 0;
|
||||
|
||||
if ( $update_cache ) {
|
||||
set_transient( strtolower( get_class( $this ) ), $cached_results, WEEK_IN_SECONDS );
|
||||
|
||||
// Remove this class from the list of classes WC updates on shutdown. Introduced in WC 3.7
|
||||
if ( ! WC_Subscriptions::is_woocommerce_pre( '3.7' ) ) {
|
||||
unset( WC_Admin_Report::$transients_to_update[ strtolower( get_class( $this ) ) ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -552,9 +565,12 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report {
|
||||
'highlight_series' => 6,
|
||||
);
|
||||
|
||||
// For the subscriptions count we only need to display the subscriptions included on the last day of the report period so pass the last cache key. The array keys are integers so using max() returns the last array key.
|
||||
$data_key = max( array_keys( $this->report_data->subscriber_counts ) );
|
||||
|
||||
$legend[] = array(
|
||||
'title' => sprintf( __( '%2$s %1$s current subscriptions', 'woocommerce-subscriptions' ), '<strong> <span class="woocommerce-subscriptions-count count">' . $this->report_data->total_subscriptions_at_period_end . '</strong> </a>',
|
||||
'<a href="' . esc_url( add_query_arg( array( 'post_type' => 'shop_subscription', '_subscriptions_list_key' => $this->report_data->current_subscriptions_query_hash, '_report' => strtolower( get_class( $this ) ) ), admin_url( 'edit.php' ) ) ). '">' ),
|
||||
'<a href="' . esc_url( add_query_arg( array( 'post_type' => 'shop_subscription', '_subscriptions_list_key' => $this->report_data->current_subscriptions_query_hash, '_report' => strtolower( get_class( $this ) ), '_data_key' => $data_key ), admin_url( 'edit.php' ) ) ). '">' ),
|
||||
'placeholder' => __( 'The number of subscriptions during this period with an end date in the future and a status other than pending.', 'woocommerce-subscriptions' ),
|
||||
'color' => $this->chart_colours['subscriber_count'],
|
||||
'highlight_series' => 5,
|
||||
|
@@ -434,6 +434,8 @@ class WC_Subscription extends WC_Order {
|
||||
break;
|
||||
|
||||
case 'pending-cancel' :
|
||||
// Store the subscription's end date before overriding it. Used for restoring the dates if the customer reactivates the subscription.
|
||||
$this->update_meta_data( 'end_date_pre_cancellation', $this->get_date( 'end' ) );
|
||||
|
||||
$end_date = $this->calculate_date( 'end_of_prepaid_term' );
|
||||
|
||||
@@ -456,7 +458,7 @@ class WC_Subscription extends WC_Order {
|
||||
if ( 'pending-cancel' === $old_status ) {
|
||||
$this->update_dates( array(
|
||||
'cancelled' => 0,
|
||||
'end' => 0,
|
||||
'end' => $this->meta_exists( 'end_date_pre_cancellation' ) ? $this->get_meta( 'end_date_pre_cancellation' ) : 0,
|
||||
'next_payment' => $this->get_date( 'end' ),
|
||||
) );
|
||||
} else {
|
||||
@@ -1016,7 +1018,7 @@ class WC_Subscription extends WC_Order {
|
||||
$date->setTimezone( new DateTimeZone( 'UTC' ) );
|
||||
}
|
||||
|
||||
$date = $date->format( 'Y-m-d H:i:s' );
|
||||
$date = $date->date( 'Y-m-d H:i:s' );
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_subscription_get_' . $date_type . '_date', $date, $this, $timezone );
|
||||
@@ -1228,8 +1230,6 @@ class WC_Subscription extends WC_Order {
|
||||
* @param string $timezone The timezone of the $datetime param. Default 'gmt'.
|
||||
*/
|
||||
public function update_dates( $dates, $timezone = 'gmt' ) {
|
||||
global $wpdb;
|
||||
|
||||
$dates = $this->validate_date_updates( $dates, $timezone );
|
||||
|
||||
// If an exception hasn't been thrown by this point, we can safely update the dates
|
||||
@@ -2338,7 +2338,7 @@ class WC_Subscription extends WC_Order {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We don't want to validate dates for relates orders when instantiating the subscription
|
||||
// We don't want to validate dates for related orders when instantiating the subscription
|
||||
if ( false === $this->object_read && ( 0 === strpos( $date_type, 'last_order_date_' ) || in_array( $date_type, array( 'date_paid', 'date_completed' ) ) ) ) {
|
||||
continue;
|
||||
}
|
||||
|
@@ -134,6 +134,7 @@ class WC_Subscriptions_Manager {
|
||||
|
||||
if ( $subscription->is_manual() ) {
|
||||
do_action( 'woocommerce_generated_manual_renewal_order', wcs_get_objects_property( $renewal_order, 'id' ), $subscription );
|
||||
$renewal_order->add_order_note( __( 'Manual renewal order awaiting customer payment.', 'woocommerce-subscriptions' ) );
|
||||
} else {
|
||||
$renewal_order->set_payment_method( wc_get_payment_gateway_by_order( $subscription ) ); // We need to pass the payment gateway instance to be compatible with WC < 3.0, only WC 3.0+ supports passing the string name
|
||||
|
||||
|
@@ -668,13 +668,16 @@ class WC_Subscriptions_Product {
|
||||
public static function set_subscription_variation_class( $classname, $product_type, $post_type, $product_id ) {
|
||||
|
||||
if ( 'product_variation' === $post_type && 'variation' === $product_type ) {
|
||||
$post = get_post( $product_id );
|
||||
|
||||
$terms = get_the_terms( get_post( $product_id )->post_parent, 'product_type' );
|
||||
if ( $post ) {
|
||||
$terms = get_the_terms( $post->post_parent, 'product_type' );
|
||||
|
||||
$parent_product_type = ! empty( $terms ) && isset( current( $terms )->slug ) ? current( $terms )->slug : '';
|
||||
$parent_product_type = ! empty( $terms ) && isset( current( $terms )->slug ) ? current( $terms )->slug : '';
|
||||
|
||||
if ( 'variable-subscription' === $parent_product_type ) {
|
||||
$classname = 'WC_Product_Subscription_Variation';
|
||||
if ( 'variable-subscription' === $parent_product_type ) {
|
||||
$classname = 'WC_Product_Subscription_Variation';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -820,8 +820,9 @@ class WC_Subscriptions_Switcher {
|
||||
*/
|
||||
public static function add_line_item_meta( $order_item, $cart_item_key, $cart_item, $order ) {
|
||||
if ( isset( $cart_item['subscription_switch'] ) ) {
|
||||
if ( $switches = self::cart_contains_switches( 'any' ) && isset( $switches[ $cart_item_key ] ) ) {
|
||||
$switches = self::cart_contains_switches( 'any' );
|
||||
|
||||
if ( isset( $switches[ $cart_item_key ] ) ) {
|
||||
$switch_details = $switches[ $cart_item_key ];
|
||||
|
||||
if ( wcs_is_subscription( $order ) ) {
|
||||
@@ -829,8 +830,8 @@ class WC_Subscriptions_Switcher {
|
||||
$order_item->add_meta_data( '_switched_subscription_item_id', $switch_details['item_id'] );
|
||||
}
|
||||
} else {
|
||||
$sign_up_fee_prorated = WC()->cart->cart_contents[ $cart_item_key ]['data']->get_meta( 'subscription_sign_up_fee_prorated', true );
|
||||
$price_prorated = WC()->cart->cart_contents[ $cart_item_key ]['data']->get_meta( 'subscription_price_prorated', true );
|
||||
$sign_up_fee_prorated = WC()->cart->cart_contents[ $cart_item_key ]['data']->get_meta( '_subscription_sign_up_fee_prorated', true );
|
||||
$price_prorated = WC()->cart->cart_contents[ $cart_item_key ]['data']->get_meta( '_subscription_price_prorated', true );
|
||||
$order_item->add_meta_data( '_switched_subscription_sign_up_fee_prorated', empty( $sign_up_fee_prorated ) ? 0 : $sign_up_fee_prorated );
|
||||
$order_item->add_meta_data( '_switched_subscription_price_prorated', empty( $price_prorated ) ? 0 : $price_prorated );
|
||||
}
|
||||
@@ -912,10 +913,11 @@ class WC_Subscriptions_Switcher {
|
||||
$switched_item_data = array();
|
||||
|
||||
if ( ! empty( $cart_item['subscription_switch']['item_id'] ) ) {
|
||||
$switched_item_data['remove_line_item'] = $cart_item['subscription_switch']['item_id'];
|
||||
$existing_item = wcs_get_order_item( $cart_item['subscription_switch']['item_id'], $subscription );
|
||||
$switch_item = new WCS_Switch_Cart_Item( $cart_item, $subscription, $existing_item );
|
||||
$is_switch_with_matching_trials = $switch_item->is_switch_during_trial() && $switch_item->trial_periods_match();
|
||||
$switched_item_data['remove_line_item'] = $cart_item['subscription_switch']['item_id'];
|
||||
$switched_item_data['switch_direction'] = $switch_item->get_switch_type();
|
||||
}
|
||||
|
||||
// If the item is on the same schedule, we can just add it to the new subscription and remove the old item.
|
||||
@@ -2253,16 +2255,21 @@ class WC_Subscriptions_Switcher {
|
||||
}
|
||||
|
||||
// Remove any signup fees if necessary.
|
||||
if ( $order_is_parent && 'include_sign_up_fees' !== $include_sign_up_fees ) {
|
||||
if ( $order_item->meta_exists( '_synced_sign_up_fee' ) ) {
|
||||
$item_total -= $order_item->get_meta( '_synced_sign_up_fee' );
|
||||
} elseif ( $subscription_item->meta_exists( '_has_trial' ) ) {
|
||||
// Where there's a free trial, the sign up fee is the entire item total so the non-sign-up fee portion is 0.
|
||||
$item_total = 0;
|
||||
} else {
|
||||
// For non-free trial subscriptions, the sign up fee portion is the order total minus the recurring total (subscription item total).
|
||||
// Use the subscription item's subtotal (without discounts) to avoid signup fee coupon discrepancies
|
||||
$item_total -= max( $order_item->get_total() - $subscription_item->get_subtotal(), 0 );
|
||||
if ( 'include_sign_up_fees' !== $include_sign_up_fees ) {
|
||||
if ( $order_is_parent ) {
|
||||
if ( $order_item->meta_exists( '_synced_sign_up_fee' ) ) {
|
||||
$item_total -= $order_item->get_meta( '_synced_sign_up_fee' ) * $order_item->get_quantity();
|
||||
} elseif ( $subscription_item->meta_exists( '_has_trial' ) ) {
|
||||
// Where there's a free trial, the sign up fee is the entire item total so the non-sign-up fee portion is 0.
|
||||
$item_total = 0;
|
||||
} else {
|
||||
// For non-free trial subscriptions, the sign up fee portion is the order total minus the recurring total (subscription item total).
|
||||
// Use the subscription item's subtotal (without discounts) to avoid signup fee coupon discrepancies
|
||||
$item_total -= max( $order_item->get_total() - $subscription_item->get_subtotal(), 0 );
|
||||
}
|
||||
// Remove the prorated sign up fees.
|
||||
} elseif ( $order_item->meta_exists( '_switched_subscription_sign_up_fee_prorated' ) ) {
|
||||
$item_total -= $order_item->get_meta( '_switched_subscription_sign_up_fee_prorated' ) * $order_item->get_quantity();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -122,6 +122,9 @@ class WC_Subscriptions_Synchroniser {
|
||||
|
||||
// Ensure options are the proper type.
|
||||
add_filter( 'option_' . self::$setting_id_days_no_fee, 'intval' );
|
||||
|
||||
// Don't display migrated order item meta on the Edit Order screen
|
||||
add_filter( 'woocommerce_hidden_order_itemmeta', array( __CLASS__, 'hide_order_itemmeta' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,13 +276,13 @@ class WC_Subscriptions_Synchroniser {
|
||||
|
||||
// An annual sync date is already set in the form: array( 'day' => 'nn', 'month' => 'nn' ), create a MySQL string from those values (year and time are irrelvent as they are ignored)
|
||||
if ( is_array( $payment_day ) ) {
|
||||
$payment_month = $payment_day['month'];
|
||||
$payment_month = ( 0 === (int) $payment_day['day'] ) ? 0 : $payment_day['month'];
|
||||
$payment_day = $payment_day['day'];
|
||||
} else {
|
||||
$payment_month = gmdate( 'm' );
|
||||
$payment_month = 0;
|
||||
}
|
||||
|
||||
echo '<div class="options_group subscription_pricing subscription_sync show_if_subscription">';
|
||||
echo '<div class="options_group subscription_pricing subscription_sync show_if_subscription hidden">';
|
||||
echo '<div class="subscription_sync_week_month" style="' . esc_attr( $display_week_month_select ) . '">';
|
||||
|
||||
woocommerce_wp_select( array(
|
||||
@@ -300,16 +303,16 @@ class WC_Subscriptions_Synchroniser {
|
||||
?><p class="form-field _subscription_payment_sync_date_day_field">
|
||||
<label for="_subscription_payment_sync_date_day"><?php echo esc_html( self::$sync_field_label ); ?></label>
|
||||
<span class="wrap">
|
||||
<input type="number" id="<?php echo esc_attr( self::$post_meta_key_day ); ?>" name="<?php echo esc_attr( self::$post_meta_key_day ); ?>" class="wc_input_subscription_payment_sync" value="<?php echo esc_attr( $payment_day ); ?>" placeholder="<?php echo esc_attr_x( 'Day', 'input field placeholder for day field for annual subscriptions', 'woocommerce-subscriptions' ); ?>" />
|
||||
|
||||
<label for="<?php echo esc_attr( self::$post_meta_key_month ); ?>" class="wcs_hidden_label"><?php esc_html_e( 'Month for Synchronisation', 'woocommerce-subscriptions' ); ?></label>
|
||||
<select id="<?php echo esc_attr( self::$post_meta_key_month ); ?>" name="<?php echo esc_attr( self::$post_meta_key_month ); ?>" class="wc_input_subscription_payment_sync last" >
|
||||
<?php foreach ( $wp_locale->month as $value => $label ) { ?>
|
||||
<?php foreach ( self::get_year_sync_options() as $value => $label ) { ?>
|
||||
<option value="<?php echo esc_attr( $value ); ?>" <?php selected( $value, $payment_month, true ) ?>><?php echo esc_html( $label ); ?></option>
|
||||
<?php } ?>
|
||||
</select>
|
||||
|
||||
</select>
|
||||
<?php $daysInMonth = $payment_month ? cal_days_in_month( CAL_GREGORIAN, (int) $payment_month, 2001 ) : 0; ?>
|
||||
<input type="number" id="<?php echo esc_attr( self::$post_meta_key_day ); ?>" name="<?php echo esc_attr( self::$post_meta_key_day ); ?>" class="wc_input_subscription_payment_sync" value="<?php echo esc_attr( $payment_day ); ?>" placeholder="<?php echo esc_attr_x( 'Day', 'input field placeholder for day field for annual subscriptions', 'woocommerce-subscriptions' ); ?>" step="1" min="<?php echo esc_attr( min( 1, $daysInMonth ) ); ?>" max="<?php echo esc_attr( $daysInMonth ); ?>" <?php disabled( 0, $payment_month, true ); ?> />
|
||||
</span>
|
||||
<?php echo wcs_help_tip( self::$sync_description_year ); ?>
|
||||
</p><?php
|
||||
@@ -343,10 +346,10 @@ class WC_Subscriptions_Synchroniser {
|
||||
|
||||
// An annual sync date is already set in the form: array( 'day' => 'nn', 'month' => 'nn' ), create a MySQL string from those values (year and time are irrelvent as they are ignored)
|
||||
if ( is_array( $payment_day ) ) {
|
||||
$payment_month = $payment_day['month'];
|
||||
$payment_month = ( 0 === (int) $payment_day['day'] ) ? 0 : $payment_day['month'];
|
||||
$payment_day = $payment_day['day'];
|
||||
} else {
|
||||
$payment_month = gmdate( 'm' );
|
||||
$payment_month = 0;
|
||||
}
|
||||
|
||||
include( plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/admin/html-variation-synchronisation.php' );
|
||||
@@ -446,8 +449,8 @@ class WC_Subscriptions_Synchroniser {
|
||||
$script_parameters['syncOptions'] = array(
|
||||
'week' => $billing_period_strings['week'],
|
||||
'month' => $billing_period_strings['month'],
|
||||
'year' => self::get_year_sync_options(),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return $script_parameters;
|
||||
@@ -711,6 +714,20 @@ class WC_Subscriptions_Synchroniser {
|
||||
return apply_filters( 'woocommerce_subscriptions_synced_first_payment_date', $first_payment, $product, $type, $from_date, $from_date_param );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an i18n'ified associative array of sync options for 'year' as billing period
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function get_year_sync_options() {
|
||||
global $wp_locale;
|
||||
|
||||
$year_sync_options[0] = __( 'Do not synchronise', 'woocommerce-subscriptions' );
|
||||
$year_sync_options += $wp_locale->month;
|
||||
|
||||
return $year_sync_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an i18n'ified associative array of all possible subscription periods.
|
||||
*
|
||||
@@ -721,7 +738,7 @@ class WC_Subscriptions_Synchroniser {
|
||||
|
||||
if ( empty( self::$billing_period_ranges ) ) {
|
||||
|
||||
foreach ( array( 'week', 'month', 'year' ) as $key ) {
|
||||
foreach ( array( 'week', 'month' ) as $key ) {
|
||||
self::$billing_period_ranges[ $key ][0] = __( 'Do not synchronise', 'woocommerce-subscriptions' );
|
||||
}
|
||||
|
||||
@@ -1228,6 +1245,22 @@ class WC_Subscriptions_Synchroniser {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides synced subscription meta on the edit order and subscription screen on non-debug sites.
|
||||
*
|
||||
* @since 2.6.2
|
||||
* @param array $hidden_meta_keys the list of meta keys hidden on the edit order and subscription screen.
|
||||
* @return array $hidden_meta_keys
|
||||
*/
|
||||
public static function hide_order_itemmeta( $hidden_meta_keys ) {
|
||||
if ( apply_filters( 'woocommerce_subscriptions_hide_synchronization_itemmeta', ! defined( 'WCS_DEBUG' ) || true !== WCS_DEBUG ) ) {
|
||||
$hidden_meta_keys[] = '_synced_sign_up_fee';
|
||||
}
|
||||
|
||||
return $hidden_meta_keys;
|
||||
|
||||
}
|
||||
|
||||
/* Deprecated Functions */
|
||||
|
||||
/**
|
||||
|
198
includes/class-wc-subscriptions-tracker.php
Executable file
198
includes/class-wc-subscriptions-tracker.php
Executable file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
/**
|
||||
* Tracker for Subscriptions usage.
|
||||
*
|
||||
* @class WC_Subscriptions_Tracker
|
||||
* @version 2.6.4
|
||||
* @package WooCommerce Subscriptions/Classes
|
||||
* @category Class
|
||||
* @author WooCommerce
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
class WC_Subscriptions_Tracker {
|
||||
|
||||
/**
|
||||
* Initialize the Tracker.
|
||||
*/
|
||||
public static function init() {
|
||||
// Only add data if Tracker enabled
|
||||
if ( 'yes' === get_option( 'woocommerce_allow_tracking', 'no' ) ) {
|
||||
add_filter( 'woocommerce_tracker_data', array( __CLASS__, 'add_subscriptions_tracking_data' ), 10, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds Subscriptions data to the WC tracked data.
|
||||
*
|
||||
* @param array $data
|
||||
* @return array all the tracking data.
|
||||
*/
|
||||
public static function add_subscriptions_tracking_data( $data ) {
|
||||
$data['extensions']['wc_subscriptions']['settings'] = self::get_subscriptions_options();
|
||||
$data['extensions']['wc_subscriptions']['subscriptions'] = self::get_subscriptions();
|
||||
$data['extensions']['wc_subscriptions']['subscription_orders'] = self::get_subscription_orders();
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the tracked Subscriptions options data.
|
||||
*
|
||||
* @return array Subscriptions options data.
|
||||
*/
|
||||
private static function get_subscriptions_options() {
|
||||
return array(
|
||||
// Staging and live site
|
||||
'wc_subscriptions_staging' => WC_Subscriptions::is_duplicate_site() ? 'staging' : 'live',
|
||||
'wc_subscriptions_live_url' => esc_url( WC_Subscriptions::get_site_url_from_source( 'subscriptions_install' ) ),
|
||||
|
||||
// Button text, roles
|
||||
'add_to_cart_button_text' => get_option( WC_Subscriptions_Admin::$option_prefix . '_add_to_cart_button_text' ),
|
||||
'order_button_text' => get_option( WC_Subscriptions_Admin::$option_prefix . '_order_button_text' ),
|
||||
'subscriber_role' => get_option( WC_Subscriptions_Admin::$option_prefix . '_subscriber_role' ),
|
||||
'cancelled_role' => get_option( WC_Subscriptions_Admin::$option_prefix . '_cancelled_role' ),
|
||||
|
||||
// Renewals
|
||||
'accept_manual_renewals' => get_option( WC_Subscriptions_Admin::$option_prefix . '_accept_manual_renewals' ),
|
||||
'turn_off_automatic_payments' => 'no' == get_option( WC_Subscriptions_Admin::$option_prefix . '_accept_manual_renewals' ) ? 'none' : get_option( WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'none' ),
|
||||
'enable_auto_renewal_toggle' => get_option( WC_Subscriptions_Admin::$option_prefix . '_enable_auto_renewal_toggle' ),
|
||||
|
||||
// Early renewal
|
||||
'enable_early_renewal' => get_option( WC_Subscriptions_Admin::$option_prefix . '_enable_early_renewal' ),
|
||||
'enable_early_renewal_via_modal' => 'no' == get_option( WC_Subscriptions_Admin::$option_prefix . '_enable_early_renewal' ) ? 'none' : get_option( WC_Subscriptions_Admin::$option_prefix . '_enable_early_renewal_via_modal', 'none' ),
|
||||
|
||||
// Switching
|
||||
'allow_switching' => get_option( WC_Subscriptions_Admin::$option_prefix . '_allow_switching' ),
|
||||
'apportion_recurring_price' => get_option( WC_Subscriptions_Admin::$option_prefix . '_apportion_recurring_price', 'none' ),
|
||||
'apportion_sign_up_fee' => get_option( WC_Subscriptions_Admin::$option_prefix . '_apportion_sign_up_fee', 'none' ),
|
||||
'apportion_length' => get_option( WC_Subscriptions_Admin::$option_prefix . '_apportion_length', 'none' ),
|
||||
'switch_button_text' => get_option( WC_Subscriptions_Admin::$option_prefix . '_switch_button_text', 'none' ),
|
||||
|
||||
// Synchronization
|
||||
'sync_payments' => get_option( WC_Subscriptions_Admin::$option_prefix . '_sync_payments' ),
|
||||
'prorate_synced_payments' => $prorate_synced_payments = ( 'no' == get_option( WC_Subscriptions_Admin::$option_prefix . '_sync_payments' ) ? 'none' : get_option( WC_Subscriptions_Admin::$option_prefix . '_prorate_synced_payments', 'none' ) ),
|
||||
'days_no_fee' => 'recurring' == $prorate_synced_payments ? get_option( WC_Subscriptions_Admin::$option_prefix . '_days_no_fee', 'none' ) : 'none',
|
||||
|
||||
// Miscellaneous
|
||||
'max_customer_suspensions' => get_option( WC_Subscriptions_Admin::$option_prefix . '_max_customer_suspensions' ),
|
||||
'multiple_purchase' => get_option( WC_Subscriptions_Admin::$option_prefix . '_multiple_purchase' ),
|
||||
'allow_zero_initial_order_without_payment_method' => get_option( WC_Subscriptions_Admin::$option_prefix . '_zero_initial_payment_requires_payment' ),
|
||||
'drip_downloadable_content_on_renewal' => get_option( WC_Subscriptions_Admin::$option_prefix . '_drip_downloadable_content_on_renewal' ),
|
||||
'enable_retry' => get_option( WC_Subscriptions_Admin::$option_prefix . '_enable_retry' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the combined subscription dates, count, and totals data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function get_subscriptions() {
|
||||
$subscription_dates = self::get_subscription_dates();
|
||||
$subscription_counts = self::get_subscription_counts();
|
||||
|
||||
return array_merge( $subscription_dates, $subscription_counts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets subscription counts.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function get_subscription_counts() {
|
||||
$subscription_counts = array();
|
||||
$subscription_counts_data = wp_count_posts( 'shop_subscription' );
|
||||
foreach ( wcs_get_subscription_statuses() as $status_slug => $status_name ) {
|
||||
$subscription_counts[ $status_slug ] = $subscription_counts_data->{ $status_slug };
|
||||
}
|
||||
return $subscription_counts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets subscription order counts and totals.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function get_subscription_orders() {
|
||||
global $wpdb;
|
||||
|
||||
$order_totals = array();
|
||||
$relation_types = array(
|
||||
'switch',
|
||||
'renewal',
|
||||
'resubscribe',
|
||||
);
|
||||
|
||||
foreach ( $relation_types as $relation_type ) {
|
||||
|
||||
$total_and_count = $wpdb->get_row( sprintf(
|
||||
"SELECT
|
||||
SUM( order_total.meta_value ) AS 'gross_total', COUNT( orders.ID ) as 'count'
|
||||
FROM {$wpdb->prefix}posts AS orders
|
||||
LEFT JOIN {$wpdb->prefix}postmeta AS order_relation ON order_relation.post_id = orders.ID
|
||||
LEFT JOIN {$wpdb->prefix}postmeta AS order_total ON order_total.post_id = orders.ID
|
||||
WHERE order_relation.meta_key = '_subscription_%s'
|
||||
AND orders.post_status in ( 'wc-completed', 'wc-processing', 'wc-refunded' )
|
||||
AND order_total.meta_key = '_order_total'
|
||||
GROUP BY order_total.meta_key
|
||||
", $relation_type
|
||||
), ARRAY_A );
|
||||
|
||||
$order_totals[ $relation_type . '_gross' ] = is_null( $total_and_count ) ? 0 : $total_and_count['gross_total'];
|
||||
$order_totals[ $relation_type . '_count' ] = is_null( $total_and_count ) ? 0 : $total_and_count['count'];
|
||||
}
|
||||
|
||||
// Finally get the initial revenue and count
|
||||
$total_and_count = $wpdb->get_row(
|
||||
"SELECT
|
||||
SUM( order_total.meta_value ) AS 'gross_total', COUNT( * ) as 'count'
|
||||
FROM {$wpdb->prefix}posts AS orders
|
||||
LEFT JOIN {$wpdb->prefix}posts AS subscriptions ON subscriptions.post_parent = orders.ID
|
||||
LEFT JOIN {$wpdb->prefix}postmeta AS order_total ON order_total.post_id = orders.ID
|
||||
WHERE orders.post_status in ( 'wc-completed', 'wc-processing', 'wc-refunded' )
|
||||
AND subscriptions.post_type = 'shop_subscription'
|
||||
AND orders.post_type = 'shop_order'
|
||||
AND order_total.meta_key = '_order_total'
|
||||
GROUP BY order_total.meta_key
|
||||
", ARRAY_A );
|
||||
|
||||
$initial_order_total = is_null( $total_and_count ) ? 0 : $total_and_count['gross_total'];
|
||||
$initial_order_count = is_null( $total_and_count ) ? 0 : $total_and_count['count'];
|
||||
|
||||
// Don't double count resubscribe revenue and count
|
||||
$order_totals['initial_gross'] = $initial_order_total - $order_totals['resubscribe_gross'];
|
||||
$order_totals['initial_count'] = $initial_order_count - $order_totals['resubscribe_count'];
|
||||
|
||||
return $order_totals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets first and last subscription created dates.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function get_subscription_dates() {
|
||||
global $wpdb;
|
||||
|
||||
$min_max = $wpdb->get_row(
|
||||
"
|
||||
SELECT
|
||||
MIN( post_date_gmt ) as 'first', MAX( post_date_gmt ) as 'last'
|
||||
FROM {$wpdb->prefix}posts
|
||||
WHERE post_type = 'shop_subscription'
|
||||
AND post_status NOT IN ( 'trash', 'auto-draft' )
|
||||
",
|
||||
ARRAY_A
|
||||
);
|
||||
|
||||
if ( is_null( $min_max ) ) {
|
||||
$min_max = array(
|
||||
'first' => '-',
|
||||
'last' => '-',
|
||||
);
|
||||
}
|
||||
|
||||
return $min_max;
|
||||
}
|
||||
}
|
@@ -1221,6 +1221,12 @@ class WCS_Cart_Renewal {
|
||||
|
||||
$cart_fees = $cart->get_fees();
|
||||
|
||||
// Fees are naturally recurring if they have been applied to the renewal order. Generate a key (name + amount) for each fee applied to the order.
|
||||
$renewal_order_fees = array();
|
||||
foreach ( $this->get_order()->get_fees() as $item_id => $fee_line_item ) {
|
||||
$renewal_order_fees[ $item_id ] = $fee_line_item->get_name() . wc_format_decimal( $fee_line_item->get_total() );
|
||||
}
|
||||
|
||||
// WC doesn't have a method for removing fees individually so we clear them and re-add them where applicable.
|
||||
if ( is_callable( array( $cart, 'fees_api' ) ) ) { // WC 3.2 +
|
||||
$cart->fees_api()->remove_all_fees();
|
||||
@@ -1229,7 +1235,10 @@ class WCS_Cart_Renewal {
|
||||
}
|
||||
|
||||
foreach ( $cart_fees as $fee ) {
|
||||
if ( true === apply_filters( 'woocommerce_subscriptions_is_recurring_fee', false, $fee, $cart ) ) {
|
||||
// By default, a fee is automatically recurring if it was applied to the renewal order.
|
||||
$is_recurring_fee = in_array( $fee->name . wc_format_decimal( $fee->amount ), $renewal_order_fees );
|
||||
|
||||
if ( true === apply_filters( 'woocommerce_subscriptions_is_recurring_fee', $is_recurring_fee, $fee, $cart ) ) {
|
||||
if ( is_callable( array( $cart, 'fees_api' ) ) ) { // WC 3.2 +
|
||||
$cart->fees_api()->add_fee( $fee );
|
||||
} else {
|
||||
|
@@ -36,7 +36,7 @@ class WCS_Limiter {
|
||||
public static function admin_edit_product_fields() {
|
||||
global $post;
|
||||
|
||||
echo '<div class="options_group limit_subscription show_if_subscription show_if_variable-subscription">';
|
||||
echo '<div class="options_group limit_subscription show_if_subscription show_if_variable-subscription hidden">';
|
||||
|
||||
// Only one Subscription per customer
|
||||
woocommerce_wp_select( array(
|
||||
|
@@ -66,13 +66,14 @@ class WCS_Modal {
|
||||
return;
|
||||
}
|
||||
|
||||
$registered = true;
|
||||
$registered = true;
|
||||
$enqueue_scripts_action = is_admin() ? 'admin_enqueue_scripts' : 'wp_enqueue_scripts';
|
||||
|
||||
// If the scripts are being registered late (after 'wp_enqueue_scripts' has run), it's safe to enqueue them immediately.
|
||||
if ( did_action( 'wp_enqueue_scripts' ) ) {
|
||||
if ( did_action( $enqueue_scripts_action ) ) {
|
||||
self::enqueue_scripts_and_styles();
|
||||
} else {
|
||||
add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_scripts_and_styles' ) );
|
||||
add_action( $enqueue_scripts_action, array( __CLASS__, 'enqueue_scripts_and_styles' ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +84,7 @@ class WCS_Modal {
|
||||
*/
|
||||
public static function enqueue_scripts_and_styles() {
|
||||
wp_enqueue_script( 'wcs-modal-scripts', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/js/modal.js', array( 'jquery' ), WC_Subscriptions::$version, true );
|
||||
wp_enqueue_style( 'wcs-modal-styles', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/css/modal.css', array(), WC_Subscriptions::$version );
|
||||
wp_enqueue_style( 'wcs-modal-styles', plugin_dir_url( WC_Subscriptions::$plugin_file ) . 'assets/css/modal.css', array( 'dashicons' ), WC_Subscriptions::$version );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -100,7 +100,7 @@ class WCS_My_Account_Payment_Methods {
|
||||
|
||||
// translators: $1: the token/credit card label, 2$-3$: opening and closing strong and link tags
|
||||
$notice = sprintf( esc_html__( 'The deleted payment method was used for automatic subscription payments. To avoid failed renewal payments in future the subscriptions using this payment method have been updated to use your %1$s. To change the payment method of individual subscriptions go to your %2$sMy Account > Subscriptions%3$s page.', 'woocommerce-subscriptions' ),
|
||||
self::get_token_label( $new_token ),
|
||||
$new_token->get_display_name(),
|
||||
'<a href="' . esc_url( wc_get_account_endpoint_url( get_option( 'woocommerce_myaccount_subscriptions_endpoint', 'subscriptions' ) ) ) . '"><strong>',
|
||||
'</strong></a>'
|
||||
);
|
||||
@@ -111,19 +111,15 @@ class WCS_My_Account_Payment_Methods {
|
||||
/**
|
||||
* Get a WC_Payment_Token label. eg Visa ending in 1234
|
||||
*
|
||||
* @deprecated 2.7.2
|
||||
*
|
||||
* @param WC_Payment_Token payment token object
|
||||
* @return string WC_Payment_Token label
|
||||
* @since 2.2.7
|
||||
*/
|
||||
public static function get_token_label( $token ) {
|
||||
|
||||
if ( method_exists( $token, 'get_last4' ) && $token->get_last4() ) {
|
||||
$label = sprintf( __( '%s ending in %s', 'woocommerce-subscriptions' ), esc_html( wc_get_credit_card_type_label( $token->get_card_type() ) ), esc_html( $token->get_last4() ) );
|
||||
} else {
|
||||
$label = esc_html( wc_get_credit_card_type_label( $token->get_card_type() ) );
|
||||
}
|
||||
|
||||
return $label;
|
||||
wcs_deprecated_function( __METHOD__, '2.7.2', '$token->get_display_name()' );
|
||||
return $token->get_display_name();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,7 +147,7 @@ class WCS_My_Account_Payment_Methods {
|
||||
}
|
||||
|
||||
$notice = sprintf( esc_html__( 'Would you like to update your subscriptions to use this new payment method - %1$s?%2$sYes%4$s | %3$sNo%4$s', 'woocommerce-subscriptions' ),
|
||||
self::get_token_label( $default_token ),
|
||||
$default_token->get_display_name(),
|
||||
'</br><a href="' . esc_url( add_query_arg( array(
|
||||
'update-subscription-tokens' => 'true',
|
||||
'token-id' => $default_token_id,
|
||||
|
@@ -145,7 +145,7 @@ class WCS_Payment_Tokens extends WC_Payment_Tokens {
|
||||
* @since 2.2.7
|
||||
*/
|
||||
public static function get_customers_alternative_token( $token ) {
|
||||
$payment_tokens = self::get_customer_tokens( $token->get_gateway_id(), $token->get_user_id() );
|
||||
$payment_tokens = self::get_customer_tokens( $token->get_user_id(), $token->get_gateway_id() );
|
||||
$alternative_token = null;
|
||||
|
||||
// Remove the token we're trying to find an alternative for.
|
||||
|
@@ -166,9 +166,31 @@ class WCS_Switch_Totals_Calculator {
|
||||
continue;
|
||||
}
|
||||
|
||||
$switches[ $cart_item_key ] = new WCS_Switch_Cart_Item( $cart_item, $subscription, $existing_item );
|
||||
$switch_item = new WCS_Switch_Cart_Item( $cart_item, $subscription, $existing_item );
|
||||
} else {
|
||||
$switches[ $cart_item_key ] = new WCS_Add_Cart_Item( $cart_item, $subscription );
|
||||
$switch_item = new WCS_Add_Cart_Item( $cart_item, $subscription );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow third-parties to filter the switch item and its properties.
|
||||
*
|
||||
* @since 2.7.2
|
||||
*
|
||||
* @param WCS_Switch_Cart_Item $switch_item The switch item.
|
||||
* @param array $cart_item The item in the cart the switch item was created for.
|
||||
* @param string $cart_item_key The cart item key.
|
||||
*/
|
||||
$switches[ $cart_item_key ] = apply_filters( 'wcs_proration_switch_item_from_cart_item', $switch_item, $cart_item, $cart_item_key );
|
||||
|
||||
// Ensure the filtered item is the correct object type.
|
||||
if ( ! is_a( $switches[ $cart_item_key ], 'WCS_Switch_Cart_Item' ) ) {
|
||||
unset( $switches[ $cart_item_key ] );
|
||||
WC()->cart->remove_cart_item( $cart_item_key );
|
||||
|
||||
$error_notice = __( 'Your cart contained an invalid subscription switch request. It has been removed from your cart.', 'woocommerce-subscriptions' );
|
||||
if ( ! wc_has_notice( $error_notice, 'error' ) ) {
|
||||
wc_add_notice( $error_notice , 'error' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -139,6 +139,7 @@ class WCS_Webhooks {
|
||||
break;
|
||||
case 'wp_api_v1':
|
||||
case 'wp_api_v2':
|
||||
case 'wp_api_v3':
|
||||
$request = new WP_REST_Request( 'GET' );
|
||||
$controller = new WC_REST_Subscriptions_Controller;
|
||||
|
||||
|
@@ -125,10 +125,12 @@ class WCS_Early_Renewal_Modal_Handler {
|
||||
// Now that we've attempted to process the payment, refresh the order.
|
||||
$renewal_order = wc_get_order( $renewal_order->get_id() );
|
||||
|
||||
// Failed early renewals won't place the subscription on-hold so delete unsuccessful early renewal orders.
|
||||
// Failed early renewals won't place the subscription on-hold so delete unsuccessful early renewal orders and redirect the user to complete the payment via checkout.
|
||||
if ( $renewal_order->needs_payment() ) {
|
||||
$renewal_order->delete( true );
|
||||
wc_add_notice( __( 'Payment for this renewal order was unsuccessful, please try again.', 'woocommerce-subscriptions' ), 'error' );
|
||||
wc_add_notice( __( 'Payment for the renewal order was unsuccessful with your payment method on file, please try again.', 'woocommerce-subscriptions' ), 'error' );
|
||||
wp_redirect( wcs_get_early_renewal_url( $subscription ) );
|
||||
exit();
|
||||
} else {
|
||||
wcs_update_dates_after_early_renewal( $subscription, $renewal_order );
|
||||
wc_add_notice( __( 'Your early renewal order was successful.', 'woocommerce-subscriptions' ), 'success' );
|
||||
|
@@ -1,15 +0,0 @@
|
||||
template: |
|
||||
## next release – date
|
||||
|
||||
<!-- Move the individual changes below into the appropriate section -->
|
||||
|
||||
$CHANGES
|
||||
|
||||
**Added**
|
||||
**Changed**
|
||||
**Deprecated**
|
||||
**Removed**
|
||||
**Fixed**
|
||||
**Security**
|
||||
|
||||
change-template: '* $TITLE (PR #$NUMBER)'
|
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"name": "prospress/action-scheduler",
|
||||
"description": "Action Scheduler for WordPress and WooCommerce",
|
||||
"type": "wordpress-plugin",
|
||||
"license": "GPL-3.0",
|
||||
"minimum-stability": "dev",
|
||||
"require": {},
|
||||
"require-dev": {
|
||||
"wp-cli/wp-cli": "1.5.1"
|
||||
}
|
||||
}
|
@@ -83,7 +83,7 @@ class WCS_Retry_Post_Store extends WCS_Retry_Store {
|
||||
|
||||
$retry_post = get_post( $retry_id );
|
||||
|
||||
if ( null !== $retry_post ) {
|
||||
if ( null !== $retry_post && $retry_post->post_type === self::$post_type ) {
|
||||
|
||||
$rule_data = array();
|
||||
$post_meta = get_post_meta( $retry_id );
|
||||
|
@@ -654,7 +654,7 @@ function wcs_get_order_item_name( $order_item, $include = array() ) {
|
||||
$meta_key = wc_attribute_label( wc_sanitize_taxonomy_name( $meta_key ) );
|
||||
$meta_value = isset( $term->name ) ? $term->name : $meta_value;
|
||||
} else {
|
||||
$meta_key = apply_filters( 'woocommerce_attribute_label', wc_attribute_label( $meta_key ), $meta_key );
|
||||
$meta_key = wc_attribute_label( $meta_key );
|
||||
}
|
||||
|
||||
$attribute_strings[] = sprintf( '%s: %s', wp_kses_post( rawurldecode( $meta_key ) ), wp_kses_post( rawurldecode( $meta_value ) ) );
|
||||
@@ -707,7 +707,7 @@ function wcs_get_line_item_name( $line_item ) {
|
||||
$meta_key = wc_attribute_label( wc_sanitize_taxonomy_name( $meta_key ) );
|
||||
$meta_value = isset( $term->name ) ? $term->name : $meta_value;
|
||||
} else {
|
||||
$meta_key = apply_filters( 'woocommerce_attribute_label', wc_attribute_label( $meta_key ), $meta_key );
|
||||
$meta_key = wc_attribute_label( $meta_key );
|
||||
}
|
||||
|
||||
$item_meta_strings[] = sprintf( '%s: %s', rawurldecode( $meta_key ), rawurldecode( $meta_value ) );
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -33,12 +33,13 @@ global $wp_locale;
|
||||
<?php echo esc_html( WC_Subscriptions_Synchroniser::$sync_field_label ); ?>
|
||||
<?php echo wcs_help_tip( WC_Subscriptions_Synchroniser::$sync_description_year ); ?>
|
||||
</label>
|
||||
<input type="number" class="wc_input_subscription_payment_sync wc_input_subscription_payment_sync_day" name="variable_subscription_payment_sync_date_day[<?php echo esc_attr( $loop ); ?>]" value="<?php echo esc_attr( $payment_day ); ?>" placeholder="<?php echo esc_attr_x( 'Day', 'input field placeholder for day field for annual subscriptions', 'woocommerce-subscriptions' ); ?>" step="1" min="0" max="31">
|
||||
<select name="variable_subscription_payment_sync_date_month[<?php echo esc_attr( $loop ); ?>]" class="wc_input_subscription_payment_sync wc_input_subscription_payment_sync_month">
|
||||
<?php foreach ( $wp_locale->month as $key => $value ) : ?>
|
||||
<?php foreach ( WC_Subscriptions_Synchroniser::get_year_sync_options() as $key => $value ) : ?>
|
||||
<option value="<?php echo esc_attr( $key ); ?>" <?php selected( $key, $payment_month ); ?>><?php echo esc_html( $value ); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php $daysInMonth = $payment_month ? cal_days_in_month( CAL_GREGORIAN, (int) $payment_month, 2001 ) : 0; ?>
|
||||
<input type="number" class="wc_input_subscription_payment_sync wc_input_subscription_payment_sync_day" name="variable_subscription_payment_sync_date_day[<?php echo esc_attr( $loop ); ?>]" value="<?php echo esc_attr( $payment_day ); ?>" placeholder="<?php echo esc_attr_x( 'Day', 'input field placeholder for day field for annual subscriptions', 'woocommerce-subscriptions' ); ?>" step="1" min="<?php echo esc_attr( min( 1, $daysInMonth ) ); ?>" max="<?php echo esc_attr( $daysInMonth ); ?>" <?php disabled( 0, $payment_month, true ); ?> />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -15,7 +15,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
<?php if ( $modal->has_heading() ) : ?>
|
||||
<h2><?php echo esc_html( $modal->get_heading() ) ?></h2>
|
||||
<?php endif ?>
|
||||
<a href="#" onclick="return false;" type="button" class="close" style="text-decoration: none;"><i class="fas fa-times"></i></a>
|
||||
<a href="#" onclick="return false;" class="close" style="text-decoration: none;"><span class="dashicons dashicons-no"></span></a>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
|
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* @author Prospress
|
||||
* @category WooCommerce Subscriptions/Templates
|
||||
* @version 2.6.0
|
||||
* @version 2.6.4
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
@@ -71,9 +71,13 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
<?php if ( 1 < $current_page ) :
|
||||
printf( esc_html__( 'You have reached the end of subscriptions. Go to the %sfirst page%s.', 'woocommerce-subscriptions' ), '<a href="' . esc_url( wc_get_endpoint_url( 'subscriptions', 1 ) ) . '">', '</a>' );
|
||||
else :
|
||||
// translators: placeholders are opening and closing link tags to take to the shop page
|
||||
printf( esc_html__( 'You have no active subscriptions. Find your first subscription in the %sstore%s.', 'woocommerce-subscriptions' ), '<a href="' . esc_url( apply_filters( 'woocommerce_subscriptions_message_store_url', get_permalink( wc_get_page_id( 'shop' ) ) ) ) . '">', '</a>' );
|
||||
endif; ?>
|
||||
esc_html_e( 'You have no active subscriptions.', 'woocommerce-subscriptions' );
|
||||
?>
|
||||
<a class="woocommerce-Button button" href="<?php echo esc_url( apply_filters( 'woocommerce_return_to_shop_redirect', wc_get_page_permalink( 'shop' ) ) ); ?>">
|
||||
<?php esc_html_e( 'Browse products', 'woocommerce-subscriptions' ); ?>
|
||||
</a>
|
||||
<?php
|
||||
endif; ?>
|
||||
</p>
|
||||
|
||||
<?php endif; ?>
|
||||
|
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* @author Prospress
|
||||
* @category WooCommerce Subscriptions/Templates
|
||||
* @version 2.6.0
|
||||
* @version 2.6.2
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
@@ -36,7 +36,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
}
|
||||
|
||||
$item_count = $order->get_item_count();
|
||||
$order_date = wcs_get_datetime_utc_string( $order->get_date_created() );
|
||||
$order_date = $order->get_date_created();
|
||||
|
||||
?><tr class="order woocommerce-orders-table__row woocommerce-orders-table__row--status-<?php echo esc_attr( $order->get_status() ); ?>">
|
||||
<td class="order-number woocommerce-orders-table__cell woocommerce-orders-table__cell-order-number" data-title="<?php esc_attr_e( 'Order Number', 'woocommerce-subscriptions' ); ?>">
|
||||
@@ -45,7 +45,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
</a>
|
||||
</td>
|
||||
<td class="order-date woocommerce-orders-table__cell woocommerce-orders-table__cell-order-date" data-title="<?php esc_attr_e( 'Date', 'woocommerce-subscriptions' ); ?>">
|
||||
<time datetime="<?php echo esc_attr( gmdate( 'Y-m-d', wcs_date_to_time( $order_date ) ) ); ?>" title="<?php echo esc_attr( wcs_date_to_time( $order_date ) ); ?>"><?php echo wp_kses_post( date_i18n( get_option( 'date_format' ), wcs_date_to_time( $order_date ) ) ); ?></time>
|
||||
<time datetime="<?php echo esc_attr( $order_date->date( 'Y-m-d' ) ); ?>" title="<?php echo esc_attr( $order_date->getTimestamp() ); ?>"><?php echo wp_kses_post( $order_date->date_i18n( wc_date_format() ) ); ?></time>
|
||||
</td>
|
||||
<td class="order-status woocommerce-orders-table__cell woocommerce-orders-table__cell-order-status" data-title="<?php esc_attr_e( 'Status', 'woocommerce-subscriptions' ); ?>" style="white-space:nowrap;">
|
||||
<?php echo esc_html( wc_get_order_status_name( $order->get_status() ) ); ?>
|
||||
|
@@ -5,7 +5,7 @@
|
||||
* @author Prospress
|
||||
* @package WooCommerce_Subscription/Templates
|
||||
* @since 2.2.19
|
||||
* @version 2.6.0
|
||||
* @version 2.6.5
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
@@ -18,18 +18,16 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
<td><?php esc_html_e( 'Status', 'woocommerce-subscriptions' ); ?></td>
|
||||
<td><?php echo esc_html( wcs_get_subscription_status_name( $subscription->get_status() ) ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php echo esc_html_x( 'Start date', 'table heading', 'woocommerce-subscriptions' ); ?></td>
|
||||
<td><?php echo esc_html( $subscription->get_date_to_display( 'start_date' ) ); ?></td>
|
||||
</tr>
|
||||
<?php foreach (
|
||||
array(
|
||||
'last_order_date_created' => _x( 'Last order date', 'admin subscription table header', 'woocommerce-subscriptions' ),
|
||||
'next_payment' => _x( 'Next payment date', 'admin subscription table header', 'woocommerce-subscriptions' ),
|
||||
'end' => _x( 'End date', 'table heading', 'woocommerce-subscriptions' ),
|
||||
'trial_end' => _x( 'Trial end date', 'admin subscription table header', 'woocommerce-subscriptions' ),
|
||||
) as $date_type => $date_title
|
||||
) : ?>
|
||||
<?php do_action( 'wcs_subscription_details_table_before_dates', $subscription ); ?>
|
||||
<?php
|
||||
$dates_to_display = apply_filters( 'wcs_subscription_details_table_dates_to_display', array(
|
||||
'start_date' => _x( 'Start date', 'customer subscription table header', 'woocommerce-subscriptions' ),
|
||||
'last_order_date_created' => _x( 'Last order date', 'customer subscription table header', 'woocommerce-subscriptions' ),
|
||||
'next_payment' => _x( 'Next payment date', 'customer subscription table header', 'woocommerce-subscriptions' ),
|
||||
'end' => _x( 'End date', 'customer subscription table header', 'woocommerce-subscriptions' ),
|
||||
'trial_end' => _x( 'Trial end date', 'customer subscription table header', 'woocommerce-subscriptions' ),
|
||||
), $subscription );
|
||||
foreach ( $dates_to_display as $date_type => $date_title ) : ?>
|
||||
<?php $date = $subscription->get_date( $date_type ); ?>
|
||||
<?php if ( ! empty( $date ) ) : ?>
|
||||
<tr>
|
||||
@@ -38,6 +36,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
<?php do_action( 'wcs_subscription_details_table_after_dates', $subscription ); ?>
|
||||
<?php if ( WCS_My_Account_Auto_Renew_Toggle::can_subscription_auto_renewal_be_changed( $subscription ) ) : ?>
|
||||
<tr>
|
||||
<td><?php esc_html_e( 'Auto renew', 'woocommerce-subscriptions' ); ?></td>
|
||||
@@ -66,6 +65,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php do_action( 'wcs_subscription_details_table_before_payment_method', $subscription ); ?>
|
||||
<?php if ( $subscription->get_time( 'next_payment' ) > 0 ) : ?>
|
||||
<tr>
|
||||
<td><?php esc_html_e( 'Payment', 'woocommerce-subscriptions' ); ?></td>
|
||||
@@ -91,7 +91,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
</table>
|
||||
|
||||
<?php if ( $notes = $subscription->get_customer_order_notes() ) : ?>
|
||||
<h2><?php esc_html_e( 'Subscription Updates', 'woocommerce-subscriptions' ); ?></h2>
|
||||
<h2><?php esc_html_e( 'Subscription updates', 'woocommerce-subscriptions' ); ?></h2>
|
||||
<ol class="woocommerce-OrderUpdates commentlist notes">
|
||||
<?php foreach ( $notes as $note ) : ?>
|
||||
<li class="woocommerce-OrderUpdate comment note">
|
||||
|
@@ -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 ) {
|
||||
|
||||
|
@@ -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 <strong> 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' ),
|
||||
'<strong>', '</strong>',
|
||||
'<a href="http://docs.woocommerce.com/document/subscriptions/faq/#section-39" target="_blank">', '</a>',
|
||||
'<a href="https://docs.woocommerce.com/document/subscriptions-handles-staging-sites/" target="_blank">', '</a>',
|
||||
'<a href="' . esc_url( self::get_site_url_from_source( 'subscriptions_install' ) ) . '" target="_blank">', '</a>',
|
||||
esc_url( self::get_site_url_from_source( 'subscriptions_install' ) )
|
||||
)
|
||||
|
Reference in New Issue
Block a user