Updates to 8.1.0
This commit is contained in:
parent
c8ec766bf2
commit
dda5b19e32
|
|
@ -34,6 +34,10 @@
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.woocommerce-cart-form__cart-item .wcsg_add_recipient_fields_container label {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.wcsg_add_recipient_fields_container .wcsg_add_recipient_fields .woocommerce_subscriptions_gifting_recipient_email {
|
||||
padding: 0;
|
||||
margin-bottom: 20px;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
/* global wc_subscription_downloads_product */
|
||||
jQuery( document ).ready( function ( $ ) {
|
||||
function subscriptionDownloadsChosen() {
|
||||
$( 'select.subscription-downloads-ids' ).ajaxChosen({
|
||||
method: 'GET',
|
||||
url: wc_subscription_downloads_product.ajax_url,
|
||||
dataType: 'json',
|
||||
afterTypeDelay: 100,
|
||||
minTermLength: 1,
|
||||
data: {
|
||||
action: 'wc_subscription_downloads_search',
|
||||
security: wc_subscription_downloads_product.security
|
||||
}
|
||||
}, function ( data ) {
|
||||
|
||||
var orders = {};
|
||||
|
||||
$.each( data, function ( i, val ) {
|
||||
orders[i] = val;
|
||||
});
|
||||
|
||||
return orders;
|
||||
});
|
||||
}
|
||||
|
||||
subscriptionDownloadsChosen();
|
||||
|
||||
$( 'body' ).on( 'woocommerce_variations_added', function () {
|
||||
subscriptionDownloadsChosen();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,2 +1,3 @@
|
|||
.wcs-recurring-totals-panel{padding:1em 0 0;position:relative}.wcs-recurring-totals-panel:after{border-style:solid;border-width:1px 0;bottom:0;content:"";display:block;right:0;opacity:.3;pointer-events:none;position:absolute;left:0;top:0}.wcs-recurring-totals-panel+.wcs-recurring-totals-panel:after{border-top-width:0}.wcs-recurring-totals-panel .wc-block-components-panel .wc-block-components-totals-item{padding-right:0;padding-left:0}.wcs-recurring-totals-panel .wc-block-components-totals-item__label:first-letter{text-transform:capitalize}.wcs-recurring-totals-panel .wcs-recurring-totals-panel__title .wc-block-components-totals-item__label{font-weight:700}.wcs-recurring-totals-panel__title{margin:0}.wcs-recurring-totals-panel__details .wc-block-components-panel__button,.wcs-recurring-totals-panel__details .wc-block-components-panel__button:focus,.wcs-recurring-totals-panel__details .wc-block-components-panel__button:hover{font-size:.875em}.wcs-recurring-totals-panel__details .wc-block-components-panel__content>.wc-block-components-totals-item:first-child{margin-top:0}.wcs-recurring-totals-panel__details .wc-block-components-panel__content>.wc-block-components-totals-item:last-child{margin-bottom:0}.wcs-recurring-totals-panel__details .wcs-recurring-totals-panel__details-total .wc-block-components-totals-item__label{font-weight:700}.wcs-recurring-totals__subscription-length{float:left}
|
||||
.wcs-recurring-totals-panel{padding:1em 0 0;position:relative}.wcs-recurring-totals-panel:after{border-style:solid;border-width:1px 0;bottom:0;content:"";display:block;right:0;opacity:.3;pointer-events:none;position:absolute;left:0;top:0}.wcs-recurring-totals-panel+.wcs-recurring-totals-panel:after{border-top-width:0}.wcs-recurring-totals-panel .wc-block-components-panel .wc-block-components-totals-item{padding-right:0;padding-left:0}.wcs-recurring-totals-panel .wc-block-components-totals-item__label:first-letter{text-transform:capitalize}.wcs-recurring-totals-panel .wcs-recurring-totals-panel__title .wc-block-components-totals-item__label{font-weight:500}.wcs-recurring-totals-panel__title{margin:0}.wc-block-components-main .wcs-recurring-totals-panel__details{padding:0 16px}.wcs-recurring-totals-panel__details .wc-block-components-panel__button,.wcs-recurring-totals-panel__details .wc-block-components-panel__button:focus,.wcs-recurring-totals-panel__details .wc-block-components-panel__button:hover{font-size:.875em}.wcs-recurring-totals-panel__details .wc-block-components-panel__content>.wc-block-components-totals-item:first-child{margin-top:0}.wcs-recurring-totals-panel__details .wc-block-components-panel__content>.wc-block-components-totals-item:last-child{margin-bottom:0}.wcs-recurring-totals-panel__details .wcs-recurring-totals-panel__details-total .wc-block-components-totals-item__label{font-weight:700}.wcs-recurring-totals__subscription-length{float:left}
|
||||
.wc-block-components-local-pickup-rates-control .wc-block-components-local-pickup-select:not(:last-child){margin-bottom:16px}
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
<?php return array('dependencies' => array('react', 'wc-blocks-checkout', 'wc-blocks-data-store', 'wc-price-format', 'wc-settings', 'wp-data', 'wp-element', 'wp-i18n', 'wp-plugins'), 'version' => '76dd98c6a2badbfb9781');
|
||||
<?php return array('dependencies' => array('react', 'wc-blocks-checkout', 'wc-blocks-data-store', 'wc-price-format', 'wc-settings', 'wp-data', 'wp-element', 'wp-i18n', 'wp-plugins'), 'version' => 'ac38e67791839651a41a');
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
.wcs-recurring-totals-panel{padding:1em 0 0;position:relative}.wcs-recurring-totals-panel:after{border-style:solid;border-width:1px 0;bottom:0;content:"";display:block;left:0;opacity:.3;pointer-events:none;position:absolute;right:0;top:0}.wcs-recurring-totals-panel+.wcs-recurring-totals-panel:after{border-top-width:0}.wcs-recurring-totals-panel .wc-block-components-panel .wc-block-components-totals-item{padding-left:0;padding-right:0}.wcs-recurring-totals-panel .wc-block-components-totals-item__label:first-letter{text-transform:capitalize}.wcs-recurring-totals-panel .wcs-recurring-totals-panel__title .wc-block-components-totals-item__label{font-weight:700}.wcs-recurring-totals-panel__title{margin:0}.wcs-recurring-totals-panel__details .wc-block-components-panel__button,.wcs-recurring-totals-panel__details .wc-block-components-panel__button:focus,.wcs-recurring-totals-panel__details .wc-block-components-panel__button:hover{font-size:.875em}.wcs-recurring-totals-panel__details .wc-block-components-panel__content>.wc-block-components-totals-item:first-child{margin-top:0}.wcs-recurring-totals-panel__details .wc-block-components-panel__content>.wc-block-components-totals-item:last-child{margin-bottom:0}.wcs-recurring-totals-panel__details .wcs-recurring-totals-panel__details-total .wc-block-components-totals-item__label{font-weight:700}.wcs-recurring-totals__subscription-length{float:right}
|
||||
.wcs-recurring-totals-panel{padding:1em 0 0;position:relative}.wcs-recurring-totals-panel:after{border-style:solid;border-width:1px 0;bottom:0;content:"";display:block;left:0;opacity:.3;pointer-events:none;position:absolute;right:0;top:0}.wcs-recurring-totals-panel+.wcs-recurring-totals-panel:after{border-top-width:0}.wcs-recurring-totals-panel .wc-block-components-panel .wc-block-components-totals-item{padding-left:0;padding-right:0}.wcs-recurring-totals-panel .wc-block-components-totals-item__label:first-letter{text-transform:capitalize}.wcs-recurring-totals-panel .wcs-recurring-totals-panel__title .wc-block-components-totals-item__label{font-weight:500}.wcs-recurring-totals-panel__title{margin:0}.wc-block-components-main .wcs-recurring-totals-panel__details{padding:0 16px}.wcs-recurring-totals-panel__details .wc-block-components-panel__button,.wcs-recurring-totals-panel__details .wc-block-components-panel__button:focus,.wcs-recurring-totals-panel__details .wc-block-components-panel__button:hover{font-size:.875em}.wcs-recurring-totals-panel__details .wc-block-components-panel__content>.wc-block-components-totals-item:first-child{margin-top:0}.wcs-recurring-totals-panel__details .wc-block-components-panel__content>.wc-block-components-totals-item:last-child{margin-bottom:0}.wcs-recurring-totals-panel__details .wcs-recurring-totals-panel__details-total .wc-block-components-totals-item__label{font-weight:700}.wcs-recurring-totals__subscription-length{float:right}
|
||||
.wc-block-components-local-pickup-rates-control .wc-block-components-local-pickup-select:not(:last-child){margin-bottom:16px}
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
|||
.wcsg-gifting-to-container-editing{display:flex;gap:5px;margin-top:12px}.wcsg-gifting-to-container-editing .wc-block-components-text-input{flex-grow:1;margin-top:0}.wcsg-gifting-to-container-editing .wp-element-button.gifting-update-button:not(.is-link){min-height:unset;padding:0 var(--xs,20px)}.wcsg-gifting-to-container-editing .components-base-control__field{margin-bottom:0}.wcsg-gifting-to-container-editing .wc-block-components-text-input input:-webkit-autofill{padding-top:.5em}.wcsg-gifting-to-container-editing .has-error .components-text-control__input{color:var(--wc-red,#cc1818)}.wp-block-woocommerce-mini-cart-contents .wcsg-gifting-to-container-editing{flex-direction:column}.wp-block-woocommerce-mini-cart-contents .gifting-update-button{height:40px}.wcsg-gifting-to-container-view{align-items:center;display:flex;flex-wrap:wrap;gap:5px;max-width:100%}.wcsg-gifting-to-container-view span{align-items:center;display:inline-flex;max-width:100%;word-break:break-all;word-wrap:break-word;gap:5px}.wcsg-gifting-to-container-view .components-button.is-link{color:var(--wp--preset--color--contrast);flex-shrink:0;font-size:medium}.wc-block-checkout,.wc-block-components-product-details__gifting-to{align-items:center;display:flex;flex-wrap:wrap;max-width:100%}.wc-block-checkout .wc-block-components-product-details__name:after,.wc-block-components-product-details__gifting-to .wc-block-components-product-details__name:after{content:" "}.wc-block-checkout .wc-block-components-product-details__value,.wc-block-components-product-details__gifting-to .wc-block-components-product-details__value{align-items:center;display:inline-flex;max-width:100%;word-break:break-all;word-wrap:break-word}.wcsg-block-recipient-container .components-checkbox-control__label{font-size:medium}.wc-block-cart .wc-block-components-product-details__gifting-to,.wc-block-cart .wc-block-components-product-details__gifting-to-hidden,.wc-block-cart .wc-block-components-product-details__item-key,.wc-block-checkout .wc-block-components-product-details__gifting-to-hidden,.wc-block-checkout .wc-block-components-product-details__item-key,.wp-block-woocommerce-mini-cart-contents .wc-block-components-product-details__gifting-to,.wp-block-woocommerce-mini-cart-contents .wc-block-components-product-details__gifting-to-hidden,.wp-block-woocommerce-mini-cart-contents .wc-block-components-product-details__item-key{display:none}
|
||||
.wcsg-gifting-to-container-editing{display:flex;gap:5px;margin-top:10px;min-width:210px}.wcsg-gifting-to-container-editing .wc-block-components-text-input{flex-grow:1;margin-top:0}.wcsg-gifting-to-container-editing .wp-element-button.gifting-update-button:not(.is-link){min-height:unset;padding:0 var(--xs,20px)}.wcsg-gifting-to-container-editing .components-base-control__field{margin-bottom:0}.wcsg-gifting-to-container-editing .wc-block-components-text-input input:-webkit-autofill{padding-top:.5em}.wcsg-gifting-to-container-editing .has-error .components-text-control__input{color:var(--wc-red,#cc1818)}.wp-block-woocommerce-mini-cart-contents .wcsg-gifting-to-container-editing{flex-direction:column}.wp-block-woocommerce-mini-cart-contents .gifting-update-button{height:40px}.wcsg-gifting-to-container-view{align-items:center;display:flex;flex-wrap:wrap;gap:5px;max-width:100%}.wcsg-gifting-to-container-view span{align-items:center;display:inline-flex;max-width:100%;word-break:break-all;word-wrap:break-word;gap:5px}.wcsg-gifting-to-container-view .components-button.is-link{color:var(--wp--preset--color--contrast);flex-shrink:0;font-size:medium}.wc-block-checkout,.wc-block-components-product-details__gifting-to{align-items:center;display:flex;flex-wrap:wrap;max-width:100%}.wc-block-checkout .wc-block-components-product-details__name:after,.wc-block-components-product-details__gifting-to .wc-block-components-product-details__name:after{content:" "}.wc-block-checkout .wc-block-components-product-details__value,.wc-block-components-product-details__gifting-to .wc-block-components-product-details__value{align-items:center;display:inline-flex;max-width:100%;word-break:break-all;word-wrap:break-word}.wcsg-block-recipient-container{font-size:var(--wp--preset--font-size--small,14px);line-height:20px}.wcsg-block-recipient-container .components-checkbox-control__label{font-size:var(--wp--preset--font-size--small,14px);margin-bottom:0}.wc-block-cart .wc-block-components-product-details__gifting-to,.wc-block-cart .wc-block-components-product-details__gifting-to-hidden,.wc-block-cart .wc-block-components-product-details__item-key,.wc-block-checkout .wc-block-components-product-details__gifting-to-hidden,.wc-block-checkout .wc-block-components-product-details__item-key,.wp-block-woocommerce-mini-cart-contents .wc-block-components-product-details__gifting-to,.wp-block-woocommerce-mini-cart-contents .wc-block-components-product-details__gifting-to-hidden,.wp-block-woocommerce-mini-cart-contents .wc-block-components-product-details__item-key{display:none}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
<?php return array('dependencies' => array('react', 'react-dom', 'wc-blocks-checkout', 'wp-components', 'wp-data', 'wp-i18n', 'wp-plugins', 'wp-url'), 'version' => 'e5022699093de48ed96e');
|
||||
<?php return array('dependencies' => array('react', 'react-dom', 'wc-blocks-checkout', 'wp-components', 'wp-data', 'wp-i18n', 'wp-plugins', 'wp-url'), 'version' => 'e7869a0a766c0f65ff8a');
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
.wcsg-gifting-to-container-editing{display:flex;gap:5px;margin-top:12px}.wcsg-gifting-to-container-editing .wc-block-components-text-input{flex-grow:1;margin-top:0}.wcsg-gifting-to-container-editing .wp-element-button.gifting-update-button:not(.is-link){min-height:unset;padding:0 var(--xs,20px)}.wcsg-gifting-to-container-editing .components-base-control__field{margin-bottom:0}.wcsg-gifting-to-container-editing .wc-block-components-text-input input:-webkit-autofill{padding-top:.5em}.wcsg-gifting-to-container-editing .has-error .components-text-control__input{color:var(--wc-red,#cc1818)}.wp-block-woocommerce-mini-cart-contents .wcsg-gifting-to-container-editing{flex-direction:column}.wp-block-woocommerce-mini-cart-contents .gifting-update-button{height:40px}.wcsg-gifting-to-container-view{align-items:center;display:flex;flex-wrap:wrap;gap:5px;max-width:100%}.wcsg-gifting-to-container-view span{align-items:center;display:inline-flex;max-width:100%;word-break:break-all;word-wrap:break-word;gap:5px}.wcsg-gifting-to-container-view .components-button.is-link{color:var(--wp--preset--color--contrast);flex-shrink:0;font-size:medium}.wc-block-checkout,.wc-block-components-product-details__gifting-to{align-items:center;display:flex;flex-wrap:wrap;max-width:100%}.wc-block-checkout .wc-block-components-product-details__name:after,.wc-block-components-product-details__gifting-to .wc-block-components-product-details__name:after{content:" "}.wc-block-checkout .wc-block-components-product-details__value,.wc-block-components-product-details__gifting-to .wc-block-components-product-details__value{align-items:center;display:inline-flex;max-width:100%;word-break:break-all;word-wrap:break-word}.wcsg-block-recipient-container .components-checkbox-control__label{font-size:medium}.wc-block-cart .wc-block-components-product-details__gifting-to,.wc-block-cart .wc-block-components-product-details__gifting-to-hidden,.wc-block-cart .wc-block-components-product-details__item-key,.wc-block-checkout .wc-block-components-product-details__gifting-to-hidden,.wc-block-checkout .wc-block-components-product-details__item-key,.wp-block-woocommerce-mini-cart-contents .wc-block-components-product-details__gifting-to,.wp-block-woocommerce-mini-cart-contents .wc-block-components-product-details__gifting-to-hidden,.wp-block-woocommerce-mini-cart-contents .wc-block-components-product-details__item-key{display:none}
|
||||
.wcsg-gifting-to-container-editing{display:flex;gap:5px;margin-top:10px;min-width:210px}.wcsg-gifting-to-container-editing .wc-block-components-text-input{flex-grow:1;margin-top:0}.wcsg-gifting-to-container-editing .wp-element-button.gifting-update-button:not(.is-link){min-height:unset;padding:0 var(--xs,20px)}.wcsg-gifting-to-container-editing .components-base-control__field{margin-bottom:0}.wcsg-gifting-to-container-editing .wc-block-components-text-input input:-webkit-autofill{padding-top:.5em}.wcsg-gifting-to-container-editing .has-error .components-text-control__input{color:var(--wc-red,#cc1818)}.wp-block-woocommerce-mini-cart-contents .wcsg-gifting-to-container-editing{flex-direction:column}.wp-block-woocommerce-mini-cart-contents .gifting-update-button{height:40px}.wcsg-gifting-to-container-view{align-items:center;display:flex;flex-wrap:wrap;gap:5px;max-width:100%}.wcsg-gifting-to-container-view span{align-items:center;display:inline-flex;max-width:100%;word-break:break-all;word-wrap:break-word;gap:5px}.wcsg-gifting-to-container-view .components-button.is-link{color:var(--wp--preset--color--contrast);flex-shrink:0;font-size:medium}.wc-block-checkout,.wc-block-components-product-details__gifting-to{align-items:center;display:flex;flex-wrap:wrap;max-width:100%}.wc-block-checkout .wc-block-components-product-details__name:after,.wc-block-components-product-details__gifting-to .wc-block-components-product-details__name:after{content:" "}.wc-block-checkout .wc-block-components-product-details__value,.wc-block-components-product-details__gifting-to .wc-block-components-product-details__value{align-items:center;display:inline-flex;max-width:100%;word-break:break-all;word-wrap:break-word}.wcsg-block-recipient-container{font-size:var(--wp--preset--font-size--small,14px);line-height:20px}.wcsg-block-recipient-container .components-checkbox-control__label{font-size:var(--wp--preset--font-size--small,14px);margin-bottom:0}.wc-block-cart .wc-block-components-product-details__gifting-to,.wc-block-cart .wc-block-components-product-details__gifting-to-hidden,.wc-block-cart .wc-block-components-product-details__item-key,.wc-block-checkout .wc-block-components-product-details__gifting-to-hidden,.wc-block-checkout .wc-block-components-product-details__item-key,.wp-block-woocommerce-mini-cart-contents .wc-block-components-product-details__gifting-to,.wp-block-woocommerce-mini-cart-contents .wc-block-components-product-details__gifting-to-hidden,.wp-block-woocommerce-mini-cart-contents .wc-block-components-product-details__item-key{display:none}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,5 +1,19 @@
|
|||
*** WooCommerce Subscriptions Changelog ***
|
||||
|
||||
2025-11-13 - version 8.1.0
|
||||
* Fix: Prevent a fatal error that can occur when previewing emails in WooCommerce email settings.
|
||||
* Fix: Prevent technical subscription-specific discount types from appearing in the coupon edit UI.
|
||||
* Fix: Add admin notice and debug tool to recreate the payment retry database table when it's missing.
|
||||
* Fix: Prevent resubscribe and reactivate buttons from showing for subscriptions containing disabled, deleted, draft, or limited products.
|
||||
* Fix: Prevent error that blocks the subscriptions list from loading when gifted subscriptions are purchased with certain payment methods.
|
||||
* Fix: Ensure gift recipient email address is displayed in the order confirmation email sent to the purchaser.
|
||||
* Fix: Prevent pickup location options from displaying incorrectly alongside shipping methods on the Blocks Checkout page.
|
||||
* Fix: Fix invalid HTML tags that cause fatal errors when using themes with WordPress Interactivity API.
|
||||
* Fix: Add password reset links to the new account email template for gifted subscription recipients.
|
||||
* Tweak: Improve the gift recipient email input field on Blocks Cart and Mini Cart to match the style of other checkout fields.
|
||||
* Dev: Improve housekeeping of output buffers when handling requests to change subscription payment methods.
|
||||
* Dev: Improve type safety in relation to the `wcs_get_subscription()` function.
|
||||
|
||||
2025-10-15 - version 8.0.0
|
||||
* Add: Blocks Checkout now displays a single shipping method selection for both initial and recurring carts, similar to Classic Checkout. This can be disabled using the `wcs_cart_totals_shipping_html_price_only` filter.
|
||||
* Fix: Resubscribing to a limited subscription from the product page will now reactivate the existing subscription.
|
||||
|
|
|
|||
|
|
@ -83,6 +83,10 @@ class WC_REST_Subscriptions_V1_Controller extends WC_REST_Orders_V1_Controller {
|
|||
if ( ! empty( $post->post_type ) && ! empty( $post->ID ) && 'shop_subscription' == $post->post_type ) {
|
||||
$subscription = wcs_get_subscription( $post->ID );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$response->data['billing_period'] = $subscription->get_billing_period();
|
||||
$response->data['billing_interval'] = $subscription->get_billing_interval();
|
||||
|
||||
|
|
@ -292,8 +296,13 @@ class WC_REST_Subscriptions_V1_Controller extends WC_REST_Orders_V1_Controller {
|
|||
return new WP_Error( 'woocommerce_rest_invalid_shop_subscription_id', __( 'Invalid subscription id.', 'woocommerce-subscriptions' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
$this->post_type = 'shop_order';
|
||||
$subscription = wcs_get_subscription( $id );
|
||||
$this->post_type = 'shop_order';
|
||||
$subscription = wcs_get_subscription( $id );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
return new WP_Error( 'woocommerce_rest_invalid_shop_subscription_id', __( 'Invalid subscription id.', 'woocommerce-subscriptions' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
$subscription_orders = $subscription->get_related_orders();
|
||||
|
||||
$orders = array();
|
||||
|
|
@ -371,6 +380,10 @@ class WC_REST_Subscriptions_V1_Controller extends WC_REST_Orders_V1_Controller {
|
|||
// In particular, the update_post_meta() called while _stripe_card_id is updated to _stripe_source_id
|
||||
$subscription = wcs_get_subscription( $subscription->get_id() );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
throw new WC_REST_Exception( 'woocommerce_rest_payment_update_failed', __( 'Subscription payment method could not be set updated due to technical issues.', 'woocommerce-subscriptions' ), 500 );
|
||||
}
|
||||
|
||||
if ( isset( $payment_method_meta[ $payment_method ] ) ) {
|
||||
$payment_method_meta = $payment_method_meta[ $payment_method ];
|
||||
|
||||
|
|
|
|||
|
|
@ -702,12 +702,16 @@ class WC_REST_Subscriptions_V2_Controller extends WC_REST_Orders_V2_Controller {
|
|||
$subscription->add_item( $item );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Fetch a fresh instance of the subscription because the current instance has an empty line item cache generated before we had copied the line items.
|
||||
* Fetching a new instance will ensure the line items are used when calculating totals.
|
||||
*/
|
||||
$subscription = wcs_get_subscription( $subscription->get_id() );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
throw new Exception( __( 'There was a problem completing this request. The subscription may have been deleted by another process.', 'woocommerce-subscriptions' ) );
|
||||
}
|
||||
|
||||
$subscription->calculate_totals();
|
||||
|
||||
/**
|
||||
|
|
@ -719,7 +723,13 @@ class WC_REST_Subscriptions_V2_Controller extends WC_REST_Orders_V2_Controller {
|
|||
*/
|
||||
do_action( "woocommerce_rest_insert_{$this->post_type}_object", $subscription, $request, true );
|
||||
|
||||
$response = $this->prepare_object_for_response( wcs_get_subscription( $subscription->get_id() ), $request );
|
||||
$fresh_subscription = wcs_get_subscription( $subscription->get_id() );
|
||||
|
||||
if ( ! $fresh_subscription ) {
|
||||
throw new Exception( __( 'There was a problem completing this request. The subscription may have been deleted by another process.', 'woocommerce-subscriptions' ) );
|
||||
}
|
||||
|
||||
$response = $this->prepare_object_for_response( $fresh_subscription, $request );
|
||||
$subscriptions[] = $this->prepare_response_for_collection( $response );
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
|
|
|
|||
|
|
@ -117,6 +117,13 @@ class WC_Subscriptions_Dependency_Manager {
|
|||
|
||||
$this->wc_version_cached = true;
|
||||
|
||||
// Try to get version from transient first
|
||||
$this->wc_active_version = get_transient( 'wcs_woocommerce_active_version' );
|
||||
|
||||
if ( false !== $this->wc_active_version ) {
|
||||
return $this->wc_active_version;
|
||||
}
|
||||
|
||||
// Load plugin.php if it's not already loaded.
|
||||
if ( ! function_exists( 'is_plugin_active' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
|
|
@ -139,9 +146,15 @@ class WC_Subscriptions_Dependency_Manager {
|
|||
|
||||
if ( $is_woocommerce && is_plugin_active( $plugin_slug ) ) {
|
||||
$this->wc_active_version = $plugin_data['Version'];
|
||||
break; // Found it, no need to continue looping
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the result in a transient for 1 hour
|
||||
if ( ! empty( $this->wc_active_version ) ) {
|
||||
set_transient( 'wcs_woocommerce_active_version', $this->wc_active_version, HOUR_IN_SECONDS );
|
||||
}
|
||||
|
||||
return $this->wc_active_version;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class WC_Subscriptions_Plugin extends WC_Subscriptions_Core_Plugin {
|
|||
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'maybe_show_welcome_message' ) );
|
||||
add_action( 'plugins_loaded', array( $this, 'init_gifting' ) );
|
||||
add_action( 'plugins_loaded', array( $this, 'init_downloads' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -286,6 +287,28 @@ class WC_Subscriptions_Plugin extends WC_Subscriptions_Core_Plugin {
|
|||
WCS_Gifting::init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to initialize additional downloads functionality.
|
||||
*
|
||||
* This functionality makes it possible to link downloadable products with a subscription
|
||||
* product. Purchasers of the subscription product then automatically get access to the files associated with downloadable product.
|
||||
*
|
||||
* Previously, this functionality existed as a standalone plugin (WooCommerce Subscription Downnloads) and so,
|
||||
* before initializing, we try to determine if the standalone plugin is active and has already loaded (if it is
|
||||
* active, we do not proceed).
|
||||
*/
|
||||
public function init_downloads() {
|
||||
if (
|
||||
! defined( 'WCS_ALLOW_SUBSCRIPTION_DOWNLOADS' )
|
||||
|| $this->is_plugin_being_activated( 'woocommerce-subscription-downloads' )
|
||||
|| class_exists( WC_Subscription_Downloads::class, false )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
WC_Subscription_Downloads::setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to determine if the specified plugin is being activated.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class WCS_Call_To_Action_Button_Text_Manager {
|
|||
public static function add_settings( $settings ) {
|
||||
$button_text_settings = array(
|
||||
array(
|
||||
'name' => __( 'Button Text', 'woocommerce-subscriptions' ),
|
||||
'name' => __( 'Button text', 'woocommerce-subscriptions' ),
|
||||
'type' => 'title',
|
||||
'desc' => '',
|
||||
'id' => WC_Subscriptions_Admin::$option_prefix . '_button_text',
|
||||
|
|
|
|||
|
|
@ -357,7 +357,12 @@ class WCS_Limited_Recurring_Coupon_Manager {
|
|||
$has_limited_coupon = false;
|
||||
|
||||
if ( $change_payment && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) ) ) {
|
||||
$subscription = wcs_get_subscription( $change_payment );
|
||||
$subscription = wcs_get_subscription( $change_payment );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
return $gateways;
|
||||
}
|
||||
|
||||
$has_limited_coupon = self::order_has_limited_recurring_coupon( $subscription );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,10 @@ class WCS_Subscriber_Role_Manager {
|
|||
),
|
||||
);
|
||||
|
||||
WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Admin::$option_prefix . '_button_text', $role_settings, 'multiple_settings', 'sectionend' );
|
||||
if ( ! WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Admin::$option_prefix . '_button_text', $role_settings, 'multiple_settings', 'sectionend' ) ) {
|
||||
$settings = array_merge( $settings, $role_settings );
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,18 @@ abstract class WCS_Table_Maker {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the schema option and recreates the tables.
|
||||
*
|
||||
* This forces the table schema to be regenerated by removing the stored
|
||||
* schema version and triggering the table registration process.
|
||||
*/
|
||||
public function recreate_tables() {
|
||||
delete_option( $this->get_schema_option_name() );
|
||||
|
||||
$this->register_tables();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table The name of the table
|
||||
*
|
||||
|
|
|
|||
|
|
@ -519,7 +519,7 @@ class WCS_Admin_Post_Types {
|
|||
'wcs-unknown-order-info-wrapper',
|
||||
esc_url( 'https://woocommerce.com/document/subscriptions/store-manager-guide/#section-19' ),
|
||||
// translators: Placeholder is a <br> HTML tag.
|
||||
wcs_help_tip( sprintf( __( "This subscription couldn't be loaded from the database. %s Click to learn more.", 'woocommerce-subscriptions' ), '</br>' ) ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
wcs_help_tip( sprintf( __( "This subscription couldn't be loaded from the database. %s Click to learn more.", 'woocommerce-subscriptions' ), '<br>' ) ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -711,12 +711,12 @@ class WCS_Admin_Post_Types {
|
|||
$tooltip_classes = 'woocommerce-help-tip';
|
||||
|
||||
if ( $datetime->getTimestamp() < time() ) {
|
||||
$tooltip_message .= __( '<b>Subscription payment overdue.</b></br>', 'woocommerce-subscriptions' );
|
||||
$tooltip_message .= '<b>' . esc_html__( 'Subscription payment overdue.', 'woocommerce-subscriptions' ) . '</b><br>';
|
||||
$tooltip_classes .= ' wcs-payment-overdue';
|
||||
}
|
||||
|
||||
if ( $subscription->payment_method_supports( 'gateway_scheduled_payments' ) && ! $subscription->is_manual() ) {
|
||||
$tooltip_message .= __( 'This date should be treated as an estimate only. The payment gateway for this subscription controls when payments are processed.</br>', 'woocommerce-subscriptions' );
|
||||
$tooltip_message .= esc_html__( 'This date should be treated as an estimate only. The payment gateway for this subscription controls when payments are processed.', 'woocommerce-subscriptions' ) . '<br>';
|
||||
$tooltip_classes .= ' wcs-offsite-renewal';
|
||||
}
|
||||
|
||||
|
|
@ -1503,9 +1503,20 @@ class WCS_Admin_Post_Types {
|
|||
|
||||
foreach ( $subscription_ids as $subscription_id ) {
|
||||
$subscription = wcs_get_subscription( $subscription_id );
|
||||
$note = _x( 'Subscription status changed by bulk edit:', 'Used in order note. Reason why status changed.', 'woocommerce-subscriptions' );
|
||||
|
||||
$note = _x( 'Subscription status changed by bulk edit:', 'Used in order note. Reason why status changed.', 'woocommerce-subscriptions' );
|
||||
|
||||
try {
|
||||
if ( ! $subscription ) {
|
||||
throw new Exception(
|
||||
sprintf(
|
||||
// Translators: 1: subscription ID.
|
||||
__( 'Subscription with ID %1$d does not exist and could not be updated.', 'woocommerce-subscriptions' ),
|
||||
$subscription_id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( 'cancelled' === $new_status ) {
|
||||
$subscription->cancel_order( $note );
|
||||
} else {
|
||||
|
|
@ -1542,6 +1553,11 @@ class WCS_Admin_Post_Types {
|
|||
|
||||
foreach ( $subscription_ids as $id ) {
|
||||
$subscription = wcs_get_subscription( $id );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$subscription->delete( $force_delete );
|
||||
$updated_subscription = wcs_get_subscription( $id );
|
||||
|
||||
|
|
@ -1571,7 +1587,13 @@ class WCS_Admin_Post_Types {
|
|||
|
||||
foreach ( $subscription_ids as $id ) {
|
||||
if ( $use_crud_method ) {
|
||||
$data_store->untrash_order( wcs_get_subscription( $id ) );
|
||||
$subscription = wcs_get_subscription( $id );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data_store->untrash_order( $subscription );
|
||||
} else {
|
||||
wp_untrash_post( $id );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
sprintf( // Translators: The %1 placeholder is the translated order relationship ("Parent Order"), %2 placeholder is a <br> HTML tag.
|
||||
__( 'This %1$s couldn\'t be loaded from the database. %1$s Click to learn more.', 'woocommerce-subscriptions' ),
|
||||
esc_html( $relationship ),
|
||||
'</br>'
|
||||
'<br>'
|
||||
)
|
||||
);
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -17,24 +17,6 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
|
||||
class WC_Product_Subscription_Variation extends WC_Product_Variation {
|
||||
|
||||
/**
|
||||
* A way to access the old array property.
|
||||
*/
|
||||
protected $subscription_variation_level_meta_data;
|
||||
|
||||
/**
|
||||
* Create a simple subscription product object.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $product
|
||||
*/
|
||||
public function __construct( $product = 0 ) {
|
||||
|
||||
parent::__construct( $product );
|
||||
|
||||
$this->subscription_variation_level_meta_data = new WCS_Array_Property_Post_Meta_Black_Magic( $this->get_id() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic __get method for backwards compatibility. Map legacy vars to WC_Subscriptions_Product getters.
|
||||
*
|
||||
|
|
@ -43,19 +25,11 @@ class WC_Product_Subscription_Variation extends WC_Product_Variation {
|
|||
*/
|
||||
public function __get( $key ) {
|
||||
|
||||
if ( 'subscription_variation_level_meta_data' === $key ) {
|
||||
$value = wcs_product_deprecated_property_handler( $key, $this );
|
||||
|
||||
wcs_deprecated_argument( __CLASS__ . '::$' . $key, '2.2.0', 'Product properties should not be accessed directly with WooCommerce 3.0+. Use the getter in WC_Subscriptions_Product instead.' );
|
||||
|
||||
$value = $this->subscription_variation_level_meta_data; // Behold, the horror that is the magic of WCS_Array_Property_Post_Meta_Black_Magic
|
||||
} else {
|
||||
|
||||
$value = wcs_product_deprecated_property_handler( $key, $this );
|
||||
|
||||
// No matching property found in wcs_product_deprecated_property_handler()
|
||||
if ( is_null( $value ) ) {
|
||||
$value = parent::__get( $key );
|
||||
}
|
||||
// No matching property found in wcs_product_deprecated_property_handler()
|
||||
if ( is_null( $value ) ) {
|
||||
$value = parent::__get( $key );
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
|
@ -89,7 +63,6 @@ class WC_Product_Subscription_Variation extends WC_Product_Variation {
|
|||
/**
|
||||
* Get the add to cart button text
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function add_to_cart_text() {
|
||||
|
|
@ -106,7 +79,6 @@ class WC_Product_Subscription_Variation extends WC_Product_Variation {
|
|||
/**
|
||||
* Get the add to cart button text for the single page
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function single_add_to_cart_text() {
|
||||
|
|
@ -116,7 +88,6 @@ class WC_Product_Subscription_Variation extends WC_Product_Variation {
|
|||
/**
|
||||
* Checks if the variable product this variation belongs to is purchasable.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function is_purchasable() {
|
||||
|
|
@ -128,12 +99,11 @@ class WC_Product_Subscription_Variation extends WC_Product_Variation {
|
|||
* Checks the product type to see if it is either this product's type or the parent's
|
||||
* product type.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $type Array or string of types
|
||||
* @return bool
|
||||
*/
|
||||
public function is_type( $type ) {
|
||||
if ( 'variation' == $type || ( is_array( $type ) && in_array( 'variation', $type ) ) ) {
|
||||
if ( 'variation' === $type || ( is_array( $type ) && in_array( 'variation', $type, true ) ) ) {
|
||||
return true;
|
||||
} else {
|
||||
return parent::is_type( $type );
|
||||
|
|
|
|||
|
|
@ -44,6 +44,14 @@ class WC_Subscription extends WC_Order {
|
|||
*/
|
||||
private $editable;
|
||||
|
||||
/**
|
||||
* Stores if the subscription is in the payment completed flow.
|
||||
* Allowing subscriptions to be renewed even if they have limited products.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $is_payment_completed_flow = false;
|
||||
|
||||
/**
|
||||
* Extra data for this object. Name value pairs (name + default value). Used to add additional information to parent.
|
||||
*
|
||||
|
|
@ -340,7 +348,9 @@ class WC_Subscription extends WC_Order {
|
|||
break;
|
||||
case 'completed': // core WC order status mapped internally to avoid exceptions
|
||||
case 'active':
|
||||
if ( $this->payment_method_supports( 'subscription_reactivation' ) && $this->has_status( 'on-hold' ) ) {
|
||||
if ( ! $this->is_payment_completed_flow && $this->contains_unavailable_product() ) {
|
||||
$can_be_updated = false;
|
||||
} elseif ( $this->payment_method_supports( 'subscription_reactivation' ) && $this->has_status( 'on-hold' ) ) {
|
||||
// If the subscription's end date is in the past, it cannot be reactivated.
|
||||
$end_time = $this->get_time( 'end' );
|
||||
if ( 0 !== $end_time && $end_time < gmdate( 'U' ) ) {
|
||||
|
|
@ -415,6 +425,23 @@ class WC_Subscription extends WC_Order {
|
|||
return apply_filters( 'woocommerce_can_subscription_be_updated_to_' . $new_status, $can_be_updated, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the subscription contains an unavailable product.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function contains_unavailable_product() {
|
||||
/** @var WC_Order_Item_Product $line_item */
|
||||
foreach ( $this->get_items() as $line_item ) {
|
||||
$product = $line_item->get_product();
|
||||
if ( ! $product instanceof WC_Product || ! $product->is_purchasable() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates status of the subscription
|
||||
*
|
||||
|
|
@ -1996,6 +2023,7 @@ class WC_Subscription extends WC_Order {
|
|||
* @param WC_Order $last_order
|
||||
*/
|
||||
public function payment_complete_for_order( $last_order ) {
|
||||
$this->is_payment_completed_flow = true;
|
||||
|
||||
// Clear the cached renewal payment counts
|
||||
if ( isset( $this->cached_payment_count['completed'] ) ) {
|
||||
|
|
|
|||
|
|
@ -1517,7 +1517,7 @@ class WC_Subscriptions_Cart {
|
|||
*/
|
||||
public static function pre_get_refreshed_fragments() {
|
||||
wcs_deprecated_function( __METHOD__, '2.5.0' );
|
||||
if ( defined( 'DOING_AJAX' ) && true === DOING_AJAX && ! defined( 'WOOCOMMERCE_CART' ) ) {
|
||||
if ( wp_doing_ajax() && ! defined( 'WOOCOMMERCE_CART' ) ) {
|
||||
define( 'WOOCOMMERCE_CART', true );
|
||||
WC()->cart->calculate_totals();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,6 +139,11 @@ class WC_Subscriptions_Change_Payment_Gateway {
|
|||
$subscription = wcs_get_subscription( absint( $wp->query_vars['order-pay'] ) );
|
||||
$subscription_key = isset( $_GET['key'] ) ? wc_clean( $_GET['key'] ) : '';
|
||||
|
||||
if ( ! $subscription ) {
|
||||
wc_print_notice( __( 'There was an unexpected problem with your request. Please try again.', 'woocommerce-subscriptions' ), 'error' );
|
||||
return;
|
||||
}
|
||||
|
||||
do_action( 'before_woocommerce_pay' );
|
||||
|
||||
/**
|
||||
|
|
@ -276,19 +281,27 @@ class WC_Subscriptions_Change_Payment_Gateway {
|
|||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.4
|
||||
*/
|
||||
public static function change_payment_method_via_pay_shortcode() {
|
||||
|
||||
if ( ! isset( $_POST['_wcsnonce'] ) || ! wp_verify_nonce( wc_clean( wp_unslash( $_POST['_wcsnonce'] ) ), 'wcs_change_payment_method' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$subscription_id = absint( wc_clean( wp_unslash( $_POST['woocommerce_change_payment'] ) ) );
|
||||
$subscription = wcs_get_subscription( $subscription_id );
|
||||
$subscription = wcs_get_subscription( $subscription_id );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
wc_add_notice( __( 'There was an unexpected problem with your request. Please try again.', 'woocommerce-subscriptions' ), 'error' );
|
||||
return;
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_subscription_change_payment_method_via_pay_shortcode', $subscription );
|
||||
|
||||
ob_start();
|
||||
if ( ! $subscription instanceof WC_Subscription || $subscription->get_order_key() !== wc_clean( wp_unslash( $_GET['key'] ?? '' ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $subscription->get_order_key() == wc_clean( wp_unslash( $_GET['key'] ) ) ) {
|
||||
try {
|
||||
// We open an output buffer to suppress any error noise that might break the redirect.
|
||||
$output_buffer_opened = ob_start();
|
||||
|
||||
$subscription_billing_country = $subscription->get_billing_country();
|
||||
$subscription_billing_state = $subscription->get_billing_state();
|
||||
|
|
@ -359,6 +372,11 @@ class WC_Subscriptions_Change_Payment_Gateway {
|
|||
*/
|
||||
$subscription = wcs_get_subscription( $subscription->get_id() );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
wc_add_notice( __( 'There was an unexpected problem with your request. Please try again.', 'woocommerce-subscriptions' ), 'error' );
|
||||
return;
|
||||
}
|
||||
|
||||
$subscription->set_requires_manual_renewal( false );
|
||||
$subscription->save();
|
||||
|
||||
|
|
@ -383,9 +401,13 @@ class WC_Subscriptions_Change_Payment_Gateway {
|
|||
wp_safe_redirect( $result['redirect'] );
|
||||
exit;
|
||||
}
|
||||
} finally {
|
||||
// Close the output buffer (if we exited, this will have happened automatically, so this is primarily here
|
||||
// to ensure we clean-up in the event that we returned early).
|
||||
if ( $output_buffer_opened ) {
|
||||
ob_clean();
|
||||
}
|
||||
}
|
||||
|
||||
ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -595,7 +617,12 @@ class WC_Subscriptions_Change_Payment_Gateway {
|
|||
*/
|
||||
if ( ! $is_change_payment_method_request && $cart_contains_failed_renewal ) {
|
||||
$subscription = wcs_get_subscription( $renewal_order_cart_item['subscription_renewal']['subscription_id'] );
|
||||
$cart_contains_failed_manual_renewal = $subscription->is_manual();
|
||||
|
||||
// If the subscription has been deleted (which is a reason $subscription may be false), we probably do not
|
||||
// need to concern ourselves with a failed manual renewal.
|
||||
if ( $subscription ) {
|
||||
$cart_contains_failed_manual_renewal = $subscription->is_manual();
|
||||
}
|
||||
}
|
||||
|
||||
if ( apply_filters( 'wcs_payment_gateways_change_payment_method', $is_change_payment_method_request || ( $cart_contains_failed_renewal && ! $cart_contains_failed_manual_renewal ) ) ) {
|
||||
|
|
@ -728,6 +755,7 @@ class WC_Subscriptions_Change_Payment_Gateway {
|
|||
}
|
||||
|
||||
$subscription = wcs_get_subscription( absint( $wp->query_vars['order-pay'] ) );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
return $title;
|
||||
}
|
||||
|
|
@ -823,19 +851,19 @@ class WC_Subscriptions_Change_Payment_Gateway {
|
|||
|
||||
$subscription = wcs_get_subscription( absint( $wp->query_vars['order-pay'] ) );
|
||||
|
||||
if ( $subscription ) {
|
||||
wc_add_notice( __( 'Please log in to your account below to choose a new payment method for your subscription.', 'woocommerce-subscriptions' ), 'notice' );
|
||||
|
||||
ob_start();
|
||||
woocommerce_login_form( array(
|
||||
'redirect' => $subscription->get_change_payment_method_url(),
|
||||
'message' => wc_print_notices( true ),
|
||||
) );
|
||||
|
||||
$content = ob_get_clean();
|
||||
if ( ! $subscription ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
return $content;
|
||||
wc_add_notice( __( 'Please log in to your account below to choose a new payment method for your subscription.', 'woocommerce-subscriptions' ), 'notice' );
|
||||
|
||||
ob_start();
|
||||
woocommerce_login_form( array(
|
||||
'redirect' => $subscription->get_change_payment_method_url(),
|
||||
'message' => wc_print_notices( true ),
|
||||
) );
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/** Deprecated Functions **/
|
||||
|
|
|
|||
|
|
@ -542,6 +542,9 @@ class WC_Subscriptions_Core_Plugin {
|
|||
update_option( WC_Subscriptions_Admin::$option_prefix . WC_Subscriptions_Email_Notifications::$switch_setting_string, 'yes' );
|
||||
}
|
||||
|
||||
// Setup downloads table.
|
||||
WC_Subscription_Downloads::install();
|
||||
|
||||
update_option( WC_Subscriptions_Admin::$option_prefix . '_is_active', true );
|
||||
|
||||
set_transient( $this->get_activation_transient(), true, 60 * 60 );
|
||||
|
|
|
|||
|
|
@ -756,7 +756,18 @@ class WC_Subscriptions_Coupon {
|
|||
* @return bool Whether the current page is the coupon edit page.
|
||||
*/
|
||||
public static function is_coupon_edit_page() {
|
||||
$current_post_type = $_GET['post_type'] ?? ''; // phpcs:ignore
|
||||
global $pagenow;
|
||||
|
||||
$current_post_type = '';
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
||||
if ( 'post.php' === $pagenow && isset( $_GET['post'] ) ) {
|
||||
$current_post_type = get_post_type( $_GET['post'] );
|
||||
} elseif ( isset( $_GET['post_type'] ) ) {
|
||||
$current_post_type = $_GET['post_type'];
|
||||
}
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
||||
|
||||
return 'shop_coupon' === $current_post_type;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -156,6 +156,11 @@ class WC_Subscriptions_Email_Notifications {
|
|||
switch ( current_action() ) {
|
||||
case 'woocommerce_scheduled_subscription_customer_notification_renewal':
|
||||
$subscription = wcs_get_subscription( $subscription_id );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $subscription->get_total() <= 0 ) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -167,6 +172,11 @@ class WC_Subscriptions_Email_Notifications {
|
|||
break;
|
||||
case 'woocommerce_scheduled_subscription_customer_notification_trial_expiration':
|
||||
$subscription = wcs_get_subscription( $subscription_id );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $subscription->is_manual() ) {
|
||||
$notification = $emails['WCS_Email_Customer_Notification_Manual_Trial_Expiration'];
|
||||
} else {
|
||||
|
|
@ -268,7 +278,7 @@ class WC_Subscriptions_Email_Notifications {
|
|||
|
||||
$notification_settings = [
|
||||
[
|
||||
'name' => __( 'Customer Notifications', 'woocommerce-subscriptions' ),
|
||||
'name' => __( 'Customer notifications', 'woocommerce-subscriptions' ),
|
||||
'type' => 'title',
|
||||
'id' => WC_Subscriptions_Admin::$option_prefix . '_customer_notifications',
|
||||
/* translators: Link to WC Settings > Email. */
|
||||
|
|
@ -304,7 +314,9 @@ class WC_Subscriptions_Email_Notifications {
|
|||
],
|
||||
];
|
||||
|
||||
WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Admin::$option_prefix . '_miscellaneous', $notification_settings, 'multiple_settings', 'sectionend' );
|
||||
if ( ! WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Admin::$option_prefix . '_miscellaneous', $notification_settings, 'multiple_settings', 'sectionend' ) ) {
|
||||
$settings = array_merge( $settings, $notification_settings );
|
||||
}
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -275,9 +275,10 @@ class WC_Subscriptions_Extend_Store_Endpoint {
|
|||
// Add extra package data to array.
|
||||
if ( count( $packages ) ) {
|
||||
$packages = array_map(
|
||||
function( $key, $package, $index ) use ( $cart ) {
|
||||
function ( $key, $package, $index ) use ( $cart ) {
|
||||
$package['package_id'] = isset( $package['package_id'] ) ? $package['package_id'] : $key;
|
||||
$package['package_name'] = isset( $package['package_name'] ) ? $package['package_name'] : self::get_shipping_package_name( $package, $cart );
|
||||
$package['rates'] = apply_filters( 'woocommerce_package_rates', $package['rates'], $package );
|
||||
return $package;
|
||||
},
|
||||
array_keys( $packages ),
|
||||
|
|
|
|||
|
|
@ -130,11 +130,10 @@ class WC_Subscriptions_Manager {
|
|||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.12
|
||||
*/
|
||||
public static function process_renewal( $subscription_id, $required_status, $order_note ) {
|
||||
|
||||
$subscription = wcs_get_subscription( $subscription_id );
|
||||
|
||||
// If the subscription is using manual payments, the gateway isn't active or it manages scheduled payments
|
||||
if ( ! empty( $subscription ) && $subscription->has_status( $required_status ) && ( 0 == $subscription->get_total() || $subscription->is_manual() || '' == $subscription->get_payment_method() || ! $subscription->payment_method_supports( 'gateway_scheduled_payments' ) ) ) {
|
||||
if ( $subscription instanceof WC_Subscription && $subscription->has_status( $required_status ) && ( 0 === absint( $subscription->get_total() ) || $subscription->is_manual() || '' === $subscription->get_payment_method() || ! $subscription->payment_method_supports( 'gateway_scheduled_payments' ) ) ) {
|
||||
|
||||
// Always put the subscription on hold in case something goes wrong while trying to process renewal
|
||||
$subscription->update_status( 'on-hold', $order_note );
|
||||
|
|
@ -2075,6 +2074,11 @@ class WC_Subscriptions_Manager {
|
|||
*/
|
||||
public static function maybe_process_failed_renewal_for_repair( $subscription_id ) {
|
||||
$subscription = wcs_get_subscription( $subscription_id );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'true' === $subscription->get_meta( '_wcs_repaired_2_0_2_needs_failed_payment', true ) ) {
|
||||
// Always put the subscription on hold in case something goes wrong while trying to process renewal
|
||||
$subscription->update_status( 'on-hold', _x( 'Subscription renewal payment due:', 'used in order note as reason for why subscription status changed', 'woocommerce-subscriptions' ) );
|
||||
|
|
|
|||
|
|
@ -1281,18 +1281,6 @@ class WC_Subscriptions_Product {
|
|||
return $button_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a product is being marked as not purchasable because it is limited and the customer has a subscription,
|
||||
* but the current request is to resubscribe to the subscription, then mark it as purchasable.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_purchasable( $is_purchasable, $product ) {
|
||||
_deprecated_function( __METHOD__, '2.1', 'WCS_Limiter::is_purchasable_product' );
|
||||
return WCS_Limiter::is_purchasable_product( $is_purchasable, $product );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current session has an order awaiting payment for a subscription to a specific product line item.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ class WC_Subscriptions_Synchroniser {
|
|||
public static function add_settings( $settings ) {
|
||||
$synchronisation_settings = array(
|
||||
array(
|
||||
'name' => __( 'Synchronisation', 'woocommerce-subscriptions' ),
|
||||
'name' => __( 'Synchronization', 'woocommerce-subscriptions' ),
|
||||
'type' => 'title',
|
||||
// translators: placeholders are opening and closing link tags
|
||||
'desc' => sprintf( _x( 'Align subscription renewal to a specific day of the week, month or year. For example, the first day of the month. %1$sLearn more%2$s.', 'used in the general subscription options page', 'woocommerce-subscriptions' ), '<a href="' . esc_url( 'https://woocommerce.com/document/subscriptions/renewal-synchronisation/' ) . '">', '</a>' ),
|
||||
|
|
|
|||
|
|
@ -237,7 +237,12 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager {
|
|||
protected function purge_subscription_user_cache( $subscription_id ) {
|
||||
wcs_deprecated_argument( __METHOD__, '2.3.0', sprintf( __( 'Customer subscription caching is now handled by %1$s and %2$s.', 'woocommerce-subscriptions' ), 'WCS_Customer_Store_Cached_CPT', 'WCS_Post_Meta_Cache_Manager' ) ); // phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
|
||||
|
||||
$subscription = wcs_get_subscription( $subscription_id );
|
||||
$subscription = wcs_get_subscription( $subscription_id );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$subscription_user_id = $subscription->get_user_id();
|
||||
$this->log( sprintf(
|
||||
'Clearing cache for user ID %1$s on %2$s hook.',
|
||||
|
|
|
|||
|
|
@ -604,6 +604,10 @@ class WCS_Cart_Renewal {
|
|||
|
||||
$subscription = wcs_get_subscription( $cart_renewal_item[ $this->cart_item_key ]['subscription_id'] );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
return $update_customer_data;
|
||||
}
|
||||
|
||||
$billing_address = array();
|
||||
if ( $checkout_object->checkout_fields['billing'] ) {
|
||||
foreach ( array_keys( $checkout_object->checkout_fields['billing'] ) as $field ) {
|
||||
|
|
@ -627,19 +631,6 @@ class WCS_Cart_Renewal {
|
|||
return $update_customer_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a product is being marked as not purchasable because it is limited and the customer has a subscription,
|
||||
* but the current request is to resubscribe to the subscription, then mark it as purchasable.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
||||
* @return bool
|
||||
*/
|
||||
public function is_purchasable( $is_purchasable, $product ) {
|
||||
_deprecated_function( __METHOD__, '2.1', 'WCS_Limiter::is_purchasable_renewal' );
|
||||
return WCS_Limiter::is_purchasable_renewal( $is_purchasable, $product );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag payment of manual renewal orders via an extra URL param.
|
||||
*
|
||||
|
|
@ -1195,7 +1186,12 @@ class WCS_Cart_Renewal {
|
|||
$cart_renewal_item = $this->cart_contains();
|
||||
|
||||
if ( false !== $cart_renewal_item ) {
|
||||
$subscription = wcs_get_subscription( $cart_renewal_item[ $this->cart_item_key ]['subscription_id'] );
|
||||
$subscription = wcs_get_subscription( $cart_renewal_item[ $this->cart_item_key ]['subscription_id'] );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$subscription_updated = false;
|
||||
|
||||
foreach ( [ 'billing', 'shipping' ] as $address_type ) {
|
||||
|
|
@ -1231,6 +1227,10 @@ class WCS_Cart_Renewal {
|
|||
if ( false !== $cart_renewal_item ) {
|
||||
$subscription = wcs_get_subscription( $cart_renewal_item[ $this->cart_item_key ]['subscription_id'] );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Billing address is a required field.
|
||||
foreach ( $request['billing_address'] as $key => $value ) {
|
||||
if ( is_callable( [ $customer, "set_billing_$key" ] ) ) {
|
||||
|
|
|
|||
|
|
@ -186,19 +186,6 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal {
|
|||
return $cart_item_session_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a product is being marked as not purchasable because it is limited and the customer has a subscription,
|
||||
* but the current request is to resubscribe to the subscription, then mark it as purchasable.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
||||
* @return bool
|
||||
*/
|
||||
public function is_purchasable( $is_purchasable, $product ) {
|
||||
_deprecated_function( __METHOD__, '2.1', 'WCS_Limiter::is_purchasable_renewal' );
|
||||
return WCS_Limiter::is_purchasable_renewal( $is_purchasable, $product );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the cart to see if it contains a subscription resubscribe item.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@ class WCS_Limiter {
|
|||
if ( wcs_is_frontend_request() || wcs_is_checkout_blocks_api_request() ) {
|
||||
add_filter( 'woocommerce_subscription_is_purchasable', __CLASS__ . '::is_purchasable_switch', 12, 2 );
|
||||
add_filter( 'woocommerce_subscription_variation_is_purchasable', __CLASS__ . '::is_purchasable_switch', 12, 2 );
|
||||
add_filter( 'woocommerce_subscription_is_purchasable', __CLASS__ . '::is_purchasable_renewal', 12, 2 );
|
||||
add_filter( 'woocommerce_subscription_variation_is_purchasable', __CLASS__ . '::is_purchasable_renewal', 12, 2 );
|
||||
add_filter( 'woocommerce_valid_order_statuses_for_order_again', array( __CLASS__, 'filter_order_again_statuses_for_limited_subscriptions' ) );
|
||||
}
|
||||
}
|
||||
|
|
@ -69,11 +67,52 @@ class WCS_Limiter {
|
|||
* @return bool
|
||||
*/
|
||||
public static function is_purchasable( $purchasable, $product ) {
|
||||
|
||||
// Prevents making a non purchasable product purchasable again.
|
||||
// This can happen if the product is disabled and limited and the customer is trying to renew the subscription for example.
|
||||
if ( ! $purchasable ) {
|
||||
return $purchasable;
|
||||
}
|
||||
|
||||
switch ( $product->get_type() ) {
|
||||
case 'subscription':
|
||||
case 'variable-subscription':
|
||||
if ( true === $purchasable && false === self::is_purchasable_product( $purchasable, $product ) ) {
|
||||
// Checks if the product is limited.
|
||||
if ( false === self::is_product_limited( $purchasable, $product ) ) {
|
||||
// Product is limited, so it is not purchasable.
|
||||
$purchasable = false;
|
||||
|
||||
// Unless it's resubscribing, renewing or restoring cart from session.
|
||||
$resubscribe_cart_item = wcs_cart_contains_resubscribe();
|
||||
|
||||
// Resubscribe logic
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
if ( ! empty( $_GET['resubscribe'] ) || false !== $resubscribe_cart_item ) {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
$subscription_id = ( isset( $_GET['resubscribe'] ) ) ? absint( $_GET['resubscribe'] ) : $resubscribe_cart_item['subscription_resubscribe']['subscription_id'];
|
||||
$subscription = wcs_get_subscription( $subscription_id );
|
||||
|
||||
if ( $subscription && $subscription->has_product( $product->get_id() ) && wcs_can_user_resubscribe_to( $subscription ) ) {
|
||||
$purchasable = true;
|
||||
}
|
||||
|
||||
// Renewal logic
|
||||
} elseif (
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
isset( $_GET['subscription_renewal'] ) ||
|
||||
wcs_cart_contains_renewal()
|
||||
) {
|
||||
$purchasable = true;
|
||||
|
||||
// Restoring cart from session, so need to check the cart in the session (wcs_cart_contains_renewal() only checks the cart).
|
||||
} elseif ( ! empty( WC()->session->cart ) ) {
|
||||
foreach ( WC()->session->cart as $cart_item_key => $cart_item ) {
|
||||
if ( (int) $product->get_id() === (int) $cart_item['product_id'] && ( isset( $cart_item['subscription_renewal'] ) || isset( $cart_item['subscription_resubscribe'] ) ) ) {
|
||||
$purchasable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'subscription_variation':
|
||||
|
|
@ -99,7 +138,6 @@ class WCS_Limiter {
|
|||
return $purchasable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If a product is limited and the customer already has a subscription, mark it as not purchasable.
|
||||
*
|
||||
|
|
@ -107,6 +145,17 @@ class WCS_Limiter {
|
|||
* @return bool
|
||||
*/
|
||||
public static function is_purchasable_product( $is_purchasable, $product ) {
|
||||
_deprecated_function( __METHOD__, '8.0.0', 'WCS_Limiter::is_product_limited' );
|
||||
return self::is_product_limited( $is_purchasable, $product );
|
||||
}
|
||||
|
||||
/**
|
||||
* If a product is limited and the customer already has a subscription, mark it as not purchasable.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.1, Moved from WC_Subscriptions_Product
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_product_limited( $is_purchasable, $product ) {
|
||||
|
||||
// Set up cache
|
||||
if ( ! isset( self::$is_purchasable_cache[ $product->get_id() ] ) ) {
|
||||
|
|
@ -197,33 +246,9 @@ class WCS_Limiter {
|
|||
* @return bool
|
||||
*/
|
||||
public static function is_purchasable_renewal( $is_purchasable, $product ) {
|
||||
if ( false === $is_purchasable && false === self::is_purchasable_product( $is_purchasable, $product ) ) {
|
||||
$resubscribe_cart_item = wcs_cart_contains_resubscribe();
|
||||
_deprecated_function( __METHOD__, '8.0.0', 'WCS_Limiter::is_product_limited' );
|
||||
|
||||
// Resubscribe logic
|
||||
if ( isset( $_GET['resubscribe'] ) || false !== $resubscribe_cart_item ) {
|
||||
$subscription_id = ( isset( $_GET['resubscribe'] ) ) ? absint( $_GET['resubscribe'] ) : $resubscribe_cart_item['subscription_resubscribe']['subscription_id'];
|
||||
$subscription = wcs_get_subscription( $subscription_id );
|
||||
|
||||
if ( false != $subscription && $subscription->has_product( $product->get_id() ) && wcs_can_user_resubscribe_to( $subscription ) ) {
|
||||
$is_purchasable = true;
|
||||
}
|
||||
|
||||
// Renewal logic
|
||||
} elseif ( isset( $_GET['subscription_renewal'] ) || wcs_cart_contains_renewal() ) {
|
||||
$is_purchasable = true;
|
||||
|
||||
// Restoring cart from session, so need to check the cart in the session (wcs_cart_contains_renewal() only checks the cart)
|
||||
} elseif ( ! empty( WC()->session->cart ) ) {
|
||||
foreach ( WC()->session->cart as $cart_item_key => $cart_item ) {
|
||||
if ( $product->get_id() == $cart_item['product_id'] && ( isset( $cart_item['subscription_renewal'] ) || isset( $cart_item['subscription_resubscribe'] ) ) ) {
|
||||
$is_purchasable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $is_purchasable;
|
||||
return ! self::is_product_limited( $is_purchasable, $product );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -187,14 +187,20 @@ class WCS_My_Account_Payment_Methods {
|
|||
return;
|
||||
}
|
||||
|
||||
// translators: 1: token display name, 2: opening link tag, 4: closing link tag, 3: opening link tag.
|
||||
$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' ),
|
||||
$notice = sprintf(
|
||||
// translators: 1: token display name, 2: opening link tag, 4: closing link tag, 3: opening link tag.
|
||||
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' ),
|
||||
$default_token->get_display_name(),
|
||||
'</br><a href="' . esc_url( add_query_arg( array(
|
||||
'update-subscription-tokens' => 'true',
|
||||
'token-id' => $default_token_id,
|
||||
'_wcsnonce' => wp_create_nonce( 'wcs-update-subscription-tokens' ),
|
||||
), wc_get_account_endpoint_url( 'payment-methods' ) ) ) . '"><strong>',
|
||||
'<br><a href="' . esc_url(
|
||||
add_query_arg(
|
||||
array(
|
||||
'update-subscription-tokens' => 'true',
|
||||
'token-id' => $default_token_id,
|
||||
'_wcsnonce' => wp_create_nonce( 'wcs-update-subscription-tokens' ),
|
||||
),
|
||||
wc_get_account_endpoint_url( 'payment-methods' )
|
||||
)
|
||||
) . '"><strong>',
|
||||
'<a href=""><strong>',
|
||||
'</strong></a>'
|
||||
);
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ class WCS_Staging {
|
|||
if ( 'subscriptions_install' === $source ) {
|
||||
$site_url = self::get_live_site_url();
|
||||
} elseif ( ! is_multisite() && defined( 'WP_SITEURL' ) ) {
|
||||
$site_url = WP_SITEURL;
|
||||
$site_url = WP_SITEURL; // @phpstan-ignore phpstanWP.wpConstant.fetch (Using constant for performance and staging-specific behavior)
|
||||
} else {
|
||||
$site_url = get_site_url();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -266,14 +266,14 @@ class WC_Subscriptions_Core_Payment_Gateways {
|
|||
}
|
||||
|
||||
$status_html .= '<span class="payment-method-features-info tips" data-tip="';
|
||||
$status_html .= esc_attr( '<strong><u>' . __( 'Supported features:', 'woocommerce-subscriptions' ) . '</u></strong></br>' . implode( '<br />', str_replace( '_', ' ', $core_features ) ) );
|
||||
$status_html .= esc_attr( '<strong><u>' . __( 'Supported features:', 'woocommerce-subscriptions' ) . '</u></strong><br>' . implode( '<br>', str_replace( '_', ' ', $core_features ) ) );
|
||||
|
||||
if ( ! empty( $subscription_features ) ) {
|
||||
$status_html .= esc_attr( '</br><strong><u>' . __( 'Subscription features:', 'woocommerce-subscriptions' ) . '</u></strong></br>' . implode( '<br />', str_replace( '_', ' ', $subscription_features ) ) );
|
||||
$status_html .= esc_attr( '<br><strong><u>' . __( 'Subscription features:', 'woocommerce-subscriptions' ) . '</u></strong><br>' . implode( '<br>', str_replace( '_', ' ', $subscription_features ) ) );
|
||||
}
|
||||
|
||||
if ( ! empty( $change_payment_method_features ) ) {
|
||||
$status_html .= esc_attr( '</br><strong><u>' . __( 'Change payment features:', 'woocommerce-subscriptions' ) . '</u></strong></br>' . implode( '<br />', str_replace( '_', ' ', $change_payment_method_features ) ) );
|
||||
$status_html .= esc_attr( '<br><strong><u>' . __( 'Change payment features:', 'woocommerce-subscriptions' ) . '</u></strong><br>' . implode( '<br>', str_replace( '_', ' ', $change_payment_method_features ) ) );
|
||||
}
|
||||
|
||||
$status_html .= '"></span>';
|
||||
|
|
|
|||
|
|
@ -1,79 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Simple Subscription Product Legacy Class
|
||||
*
|
||||
* Extends WC_Product_Subscription to provide compatibility methods when running WooCommerce < 3.0.
|
||||
*
|
||||
* @class WC_Product_Subscription_Legacy
|
||||
* @package WooCommerce Subscriptions
|
||||
* @category Class
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
*
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class WC_Product_Subscription_Legacy extends WC_Product_Subscription {
|
||||
|
||||
var $subscription_price;
|
||||
|
||||
var $subscription_period;
|
||||
|
||||
var $subscription_period_interval;
|
||||
|
||||
var $subscription_length;
|
||||
|
||||
var $subscription_trial_length;
|
||||
|
||||
var $subscription_trial_period;
|
||||
|
||||
var $subscription_sign_up_fee;
|
||||
|
||||
/**
|
||||
* Create a simple subscription product object.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $product
|
||||
*/
|
||||
public function __construct( $product ) {
|
||||
parent::__construct( $product );
|
||||
$this->product_type = 'subscription';
|
||||
|
||||
// Load all meta fields
|
||||
$this->product_custom_fields = get_post_meta( $this->id );
|
||||
|
||||
// Convert selected subscription meta fields for easy access
|
||||
if ( ! empty( $this->product_custom_fields['_subscription_price'][0] ) ) {
|
||||
$this->subscription_price = $this->product_custom_fields['_subscription_price'][0];
|
||||
}
|
||||
|
||||
if ( ! empty( $this->product_custom_fields['_subscription_sign_up_fee'][0] ) ) {
|
||||
$this->subscription_sign_up_fee = $this->product_custom_fields['_subscription_sign_up_fee'][0];
|
||||
}
|
||||
|
||||
if ( ! empty( $this->product_custom_fields['_subscription_period'][0] ) ) {
|
||||
$this->subscription_period = $this->product_custom_fields['_subscription_period'][0];
|
||||
}
|
||||
|
||||
if ( ! empty( $this->product_custom_fields['_subscription_period_interval'][0] ) ) {
|
||||
$this->subscription_period_interval = $this->product_custom_fields['_subscription_period_interval'][0];
|
||||
}
|
||||
|
||||
if ( ! empty( $this->product_custom_fields['_subscription_length'][0] ) ) {
|
||||
$this->subscription_length = $this->product_custom_fields['_subscription_length'][0];
|
||||
}
|
||||
|
||||
if ( ! empty( $this->product_custom_fields['_subscription_trial_length'][0] ) ) {
|
||||
$this->subscription_trial_length = $this->product_custom_fields['_subscription_trial_length'][0];
|
||||
}
|
||||
|
||||
if ( ! empty( $this->product_custom_fields['_subscription_trial_period'][0] ) ) {
|
||||
$this->subscription_trial_period = $this->product_custom_fields['_subscription_trial_period'][0];
|
||||
}
|
||||
|
||||
$this->subscription_payment_sync_date = ( ! isset( $this->product_custom_fields['_subscription_payment_sync_date'][0] ) ) ? 0 : maybe_unserialize( $this->product_custom_fields['_subscription_payment_sync_date'][0] );
|
||||
$this->subscription_one_time_shipping = ( ! isset( $this->product_custom_fields['_subscription_one_time_shipping'][0] ) ) ? 'no' : $this->product_custom_fields['_subscription_one_time_shipping'][0];
|
||||
$this->subscription_limit = ( ! isset( $this->product_custom_fields['_subscription_limit'][0] ) ) ? 'no' : $this->product_custom_fields['_subscription_limit'][0];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Subscription Product Variation Legacy Class
|
||||
*
|
||||
* Extends WC_Product_Subscription_Variation to provide compatibility methods when running WooCommerce < 3.0.
|
||||
*
|
||||
* @class WC_Product_Subscription_Variation_Legacy
|
||||
* @package WooCommerce Subscriptions
|
||||
* @category Class
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
*
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class WC_Product_Subscription_Variation_Legacy extends WC_Product_Subscription_Variation {
|
||||
|
||||
/**
|
||||
* Set default array value for WC 3.0's data property.
|
||||
* @var array
|
||||
*/
|
||||
protected $data = array();
|
||||
|
||||
/**
|
||||
* Create a simple subscription product object.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $product
|
||||
*/
|
||||
public function __construct( $product, $args = array() ) {
|
||||
|
||||
parent::__construct( $product, $args = array() );
|
||||
|
||||
$this->parent_product_type = $this->product_type;
|
||||
|
||||
$this->product_type = 'subscription_variation';
|
||||
|
||||
$this->subscription_variation_level_meta_data = array(
|
||||
'subscription_price' => 0,
|
||||
'subscription_period' => '',
|
||||
'subscription_period_interval' => 'day',
|
||||
'subscription_length' => 0,
|
||||
'subscription_trial_length' => 0,
|
||||
'subscription_trial_period' => 'day',
|
||||
'subscription_sign_up_fee' => 0,
|
||||
'subscription_payment_sync_date' => 0,
|
||||
);
|
||||
|
||||
$this->variation_level_meta_data = array_merge( $this->variation_level_meta_data, $this->subscription_variation_level_meta_data );
|
||||
}
|
||||
|
||||
/* Copied from WC 2.6 WC_Product_Variation */
|
||||
|
||||
/**
|
||||
* __isset function.
|
||||
*
|
||||
* @param mixed $key
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset( $key ) {
|
||||
if ( in_array( $key, array( 'variation_data', 'variation_has_stock' ) ) ) {
|
||||
return true;
|
||||
} elseif ( in_array( $key, array_keys( $this->variation_level_meta_data ) ) ) {
|
||||
return metadata_exists( 'post', $this->variation_id, '_' . $key );
|
||||
} elseif ( in_array( $key, array_keys( $this->variation_inherited_meta_data ) ) ) {
|
||||
return metadata_exists( 'post', $this->variation_id, '_' . $key ) || metadata_exists( 'post', $this->id, '_' . $key );
|
||||
} else {
|
||||
return metadata_exists( 'post', $this->id, '_' . $key );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get method returns variation meta data if set, otherwise in most cases the data from the parent.
|
||||
*
|
||||
* We need to use the WC_Product_Variation's __get() method, not the one in WC_Product_Subscription_Variation,
|
||||
* which handles deprecation notices.
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get( $key ) {
|
||||
return WC_Product_Variation::__get( $key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a WC 3.0 method for variations.
|
||||
*
|
||||
* WC < 3.0 products have a get_parent() method, but this is not equivalent to the get_parent_id() method
|
||||
* introduced in WC 3.0, because it derives the parent from $this->post->post_parent, but for variations,
|
||||
* $this->post refers to the parent variable object's post, so $this->post->post_parent will be 0 under
|
||||
* normal circumstances. Because of that, we can rely on wcs_get_objects_property( $this, 'parent_id' )
|
||||
* and define this get_parent_id() method for variations even when WC 3.0 is not active.
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_parent_id() {
|
||||
return $this->id; // When WC < 3.0 is active, the ID property is the parent variable product's ID
|
||||
}
|
||||
}
|
||||
|
|
@ -1,441 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Variable Subscription Product Legacy Class
|
||||
*
|
||||
* Extends WC_Product_Variable_Subscription to provide compatibility methods when running WooCommerce < 3.0.
|
||||
*
|
||||
* @class WC_Product_Variable_Subscription_Legacy
|
||||
* @package WooCommerce Subscriptions
|
||||
* @category Class
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
*
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class WC_Product_Variable_Subscription_Legacy extends WC_Product_Variable_Subscription {
|
||||
|
||||
var $subscription_price;
|
||||
|
||||
var $subscription_period;
|
||||
|
||||
var $max_variation_period;
|
||||
|
||||
var $subscription_period_interval;
|
||||
|
||||
var $max_variation_period_interval;
|
||||
|
||||
var $product_type;
|
||||
|
||||
protected $prices_array;
|
||||
|
||||
/**
|
||||
* Create a simple subscription product object.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $product
|
||||
*/
|
||||
public function __construct( $product ) {
|
||||
|
||||
parent::__construct( $product );
|
||||
|
||||
$this->parent_product_type = $this->product_type;
|
||||
|
||||
$this->product_type = 'variable-subscription';
|
||||
|
||||
// Load all meta fields
|
||||
$this->product_custom_fields = get_post_meta( $this->id );
|
||||
|
||||
// Convert selected subscription meta fields for easy access
|
||||
if ( ! empty( $this->product_custom_fields['_subscription_price'][0] ) ) {
|
||||
$this->subscription_price = $this->product_custom_fields['_subscription_price'][0];
|
||||
}
|
||||
|
||||
if ( ! empty( $this->product_custom_fields['_subscription_sign_up_fee'][0] ) ) {
|
||||
$this->subscription_sign_up_fee = $this->product_custom_fields['_subscription_sign_up_fee'][0];
|
||||
}
|
||||
|
||||
if ( ! empty( $this->product_custom_fields['_subscription_period'][0] ) ) {
|
||||
$this->subscription_period = $this->product_custom_fields['_subscription_period'][0];
|
||||
}
|
||||
|
||||
if ( ! empty( $this->product_custom_fields['_subscription_period_interval'][0] ) ) {
|
||||
$this->subscription_period_interval = $this->product_custom_fields['_subscription_period_interval'][0];
|
||||
}
|
||||
|
||||
if ( ! empty( $this->product_custom_fields['_subscription_length'][0] ) ) {
|
||||
$this->subscription_length = $this->product_custom_fields['_subscription_length'][0];
|
||||
}
|
||||
|
||||
if ( ! empty( $this->product_custom_fields['_subscription_trial_length'][0] ) ) {
|
||||
$this->subscription_trial_length = $this->product_custom_fields['_subscription_trial_length'][0];
|
||||
}
|
||||
|
||||
if ( ! empty( $this->product_custom_fields['_subscription_trial_period'][0] ) ) {
|
||||
$this->subscription_trial_period = $this->product_custom_fields['_subscription_trial_period'][0];
|
||||
}
|
||||
|
||||
$this->subscription_payment_sync_date = 0;
|
||||
$this->subscription_one_time_shipping = ( ! isset( $this->product_custom_fields['_subscription_one_time_shipping'][0] ) ) ? 'no' : $this->product_custom_fields['_subscription_one_time_shipping'][0];
|
||||
$this->subscription_limit = ( ! isset( $this->product_custom_fields['_subscription_limit'][0] ) ) ? 'no' : $this->product_custom_fields['_subscription_limit'][0];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the min or max variation (active) price.
|
||||
*
|
||||
* This is a copy of WooCommerce < 2.4's get_variation_price() method, because 2.4.0 introduced a new
|
||||
* transient caching system which assumes asort() on prices yields correct results for min/max prices
|
||||
* (which it does for prices alone, but that's not the full story for subscription prices). Unfortunately,
|
||||
* the new caching system is also hard to hook into so we'll just use the old system instead as the
|
||||
* @see self::variable_product_sync() uses the old method also.
|
||||
*
|
||||
* @param string $min_or_max - min or max
|
||||
* @param boolean $display Whether the value is going to be displayed
|
||||
* @return string
|
||||
*/
|
||||
public function get_variation_price( $min_or_max = 'min', $display = false ) {
|
||||
$variation_id = $this->get_meta( '_' . $min_or_max . '_price_variation_id', true );
|
||||
|
||||
if ( $display ) {
|
||||
if ( $variation = wc_get_product( $variation_id ) ) {
|
||||
if ( 'incl' == get_option( 'woocommerce_tax_display_shop' ) ) {
|
||||
$price = wcs_get_price_including_tax( $variation );
|
||||
} else {
|
||||
$price = wcs_get_price_excluding_tax( $variation );
|
||||
}
|
||||
} else {
|
||||
$price = '';
|
||||
}
|
||||
} else {
|
||||
$price = $this->get_meta( '_price', true );
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_get_variation_price', $price, $this, $min_or_max, $display );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of all sale and regular prices from all variations re-ordered after WC has done a standard sort, to reflect subscription terms.
|
||||
* The first and last element for each price type is the least and most expensive, respectively.
|
||||
*
|
||||
* @see WC_Product_Variable::get_variation_prices()
|
||||
* @param bool $include_taxes Should taxes be included in the prices.
|
||||
* @return array() Array of RAW prices, regular prices, and sale prices with keys set to variation ID.
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
*/
|
||||
public function get_variation_prices( $display = false ) {
|
||||
|
||||
$price_hash = $this->get_price_hash( $this, $display );
|
||||
|
||||
$this->prices_array[ $price_hash ] = parent::get_variation_prices( $display );
|
||||
|
||||
$children = array_keys( $this->prices_array[ $price_hash ]['price'] );
|
||||
sort( $children );
|
||||
|
||||
$min_max_data = $this->get_min_and_max_variation_data( $children );
|
||||
|
||||
$min_variation_id = $min_max_data['min']['variation_id'];
|
||||
$max_variation_id = $min_max_data['max']['variation_id'];
|
||||
|
||||
// Reorder the variable price arrays to reflect the min and max values so that WooCommerce will find them in the correct order
|
||||
foreach ( $this->prices_array as $price_hash => $prices ) {
|
||||
|
||||
// Loop over sale_price, regular_price & price values to update them on main array
|
||||
foreach ( $prices as $price_key => $variation_prices ) {
|
||||
|
||||
$min_price = $prices[ $price_key ][ $min_variation_id ];
|
||||
$max_price = $prices[ $price_key ][ $max_variation_id ];
|
||||
|
||||
unset( $prices[ $price_key ][ $min_variation_id ] );
|
||||
unset( $prices[ $price_key ][ $max_variation_id ] );
|
||||
|
||||
// append the minimum variation and prepend the maximum variation
|
||||
$prices[ $price_key ] = array( $min_variation_id => $min_price ) + $prices[ $price_key ];
|
||||
$prices[ $price_key ] += array( $max_variation_id => $max_price );
|
||||
|
||||
$this->prices_array[ $price_hash ][ $price_key ] = $prices[ $price_key ];
|
||||
}
|
||||
}
|
||||
|
||||
$this->subscription_price = $min_max_data['min']['price'];
|
||||
$this->subscription_period = $min_max_data['min']['period'];
|
||||
$this->subscription_period_interval = $min_max_data['min']['interval'];
|
||||
|
||||
$this->max_variation_price = $min_max_data['max']['price'];
|
||||
$this->max_variation_period = $min_max_data['max']['period'];
|
||||
$this->max_variation_period_interval = $min_max_data['max']['interval'];
|
||||
|
||||
$this->min_variation_price = $min_max_data['min']['price'];
|
||||
$this->min_variation_regular_price = $min_max_data['min']['regular_price'];
|
||||
|
||||
return $this->prices_array[ $price_hash ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create unique cache key based on the tax location (affects displayed/cached prices), product version and active price filters.
|
||||
* DEVELOPERS should filter this hash if offering conditional pricing to keep it unique.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
* @param WC_Product
|
||||
* @param bool $display Are prices for display? If so, taxes will be calculated.
|
||||
* @return string
|
||||
*/
|
||||
protected function get_price_hash( $display = false ) {
|
||||
global $wp_filter;
|
||||
|
||||
if ( $display ) {
|
||||
$price_hash = array( get_option( 'woocommerce_tax_display_shop', 'excl' ), WC_Tax::get_rates() );
|
||||
} else {
|
||||
$price_hash = array( false );
|
||||
}
|
||||
|
||||
$filter_names = array( 'woocommerce_variation_prices_price', 'woocommerce_variation_prices_regular_price', 'woocommerce_variation_prices_sale_price' );
|
||||
|
||||
foreach ( $filter_names as $filter_name ) {
|
||||
if ( ! empty( $wp_filter[ $filter_name ] ) ) {
|
||||
$price_hash[ $filter_name ] = array();
|
||||
|
||||
foreach ( $wp_filter[ $filter_name ] as $priority => $callbacks ) {
|
||||
$price_hash[ $filter_name ][] = array_values( wp_list_pluck( $callbacks, 'function' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$price_hash = md5( json_encode( apply_filters( 'woocommerce_get_variation_prices_hash', $price_hash, $this, $display ) ) );
|
||||
|
||||
return $price_hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync variable product prices with the children lowest/highest prices.
|
||||
*
|
||||
* @param int $product_id The ID of the product.
|
||||
* @return void
|
||||
*/
|
||||
public function variable_product_sync( $product_id = 0 ) {
|
||||
|
||||
WC_Product_Variable::variable_product_sync( $product_id );
|
||||
|
||||
$child_variation_ids = $this->get_children( true );
|
||||
|
||||
if ( $child_variation_ids ) {
|
||||
|
||||
$min_max_data = wcs_get_min_max_variation_data( $this, $child_variation_ids );
|
||||
|
||||
$this->set_min_and_max_variation_data( $min_max_data, $child_variation_ids );
|
||||
|
||||
update_post_meta( $this->id, '_min_price_variation_id', $min_max_data['min']['variation_id'] );
|
||||
update_post_meta( $this->id, '_max_price_variation_id', $min_max_data['max']['variation_id'] );
|
||||
|
||||
update_post_meta( $this->id, '_price', $min_max_data['min']['price'] );
|
||||
update_post_meta( $this->id, '_min_variation_price', $min_max_data['min']['price'] );
|
||||
update_post_meta( $this->id, '_max_variation_price', $min_max_data['max']['price'] );
|
||||
update_post_meta( $this->id, '_min_variation_regular_price', $min_max_data['min']['regular_price'] );
|
||||
update_post_meta( $this->id, '_max_variation_regular_price', $min_max_data['max']['regular_price'] );
|
||||
update_post_meta( $this->id, '_min_variation_sale_price', $min_max_data['min']['sale_price'] );
|
||||
update_post_meta( $this->id, '_max_variation_sale_price', $min_max_data['max']['sale_price'] );
|
||||
|
||||
update_post_meta( $this->id, '_min_variation_period', $min_max_data['min']['period'] );
|
||||
update_post_meta( $this->id, '_max_variation_period', $min_max_data['max']['period'] );
|
||||
update_post_meta( $this->id, '_min_variation_period_interval', $min_max_data['min']['interval'] );
|
||||
update_post_meta( $this->id, '_max_variation_period_interval', $min_max_data['max']['interval'] );
|
||||
|
||||
update_post_meta( $this->id, '_subscription_price', $min_max_data['min']['price'] );
|
||||
update_post_meta( $this->id, '_subscription_sign_up_fee', $min_max_data['subscription']['signup-fee'] );
|
||||
update_post_meta( $this->id, '_subscription_period', $min_max_data['min']['period'] );
|
||||
update_post_meta( $this->id, '_subscription_period_interval', $min_max_data['min']['interval'] );
|
||||
update_post_meta( $this->id, '_subscription_trial_period', $min_max_data['subscription']['trial_period'] );
|
||||
update_post_meta( $this->id, '_subscription_trial_length', $min_max_data['subscription']['trial_length'] );
|
||||
update_post_meta( $this->id, '_subscription_length', $min_max_data['subscription']['length'] );
|
||||
|
||||
$this->subscription_price = $min_max_data['min']['price'];
|
||||
$this->subscription_period = $min_max_data['min']['period'];
|
||||
$this->subscription_period_interval = $min_max_data['min']['interval'];
|
||||
$this->subscription_sign_up_fee = $min_max_data['subscription']['signup-fee'];
|
||||
$this->subscription_trial_period = $min_max_data['subscription']['trial_period'];
|
||||
$this->subscription_trial_length = $min_max_data['subscription']['trial_length'];
|
||||
$this->subscription_length = $min_max_data['subscription']['length'];
|
||||
|
||||
if ( function_exists( 'wc_delete_product_transients' ) ) {
|
||||
wc_delete_product_transients( $this->id );
|
||||
} else {
|
||||
WC()->clear_product_transients( $this->id );
|
||||
}
|
||||
} else { // No variations yet
|
||||
|
||||
$this->subscription_price = '';
|
||||
$this->subscription_sign_up_fee = '';
|
||||
$this->subscription_period = 'day';
|
||||
$this->subscription_period_interval = 1;
|
||||
$this->subscription_trial_period = 'day';
|
||||
$this->subscription_trial_length = 1;
|
||||
$this->subscription_length = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the price in html format.
|
||||
*
|
||||
* @access public
|
||||
* @param string $price (default: '')
|
||||
* @return string
|
||||
*/
|
||||
public function get_price_html( $price = '' ) {
|
||||
|
||||
if ( ! isset( $this->subscription_period ) || ! isset( $this->subscription_period_interval ) || ! isset( $this->max_variation_period ) || ! isset( $this->max_variation_period_interval ) ) {
|
||||
$this->variable_product_sync();
|
||||
}
|
||||
|
||||
// Only create the subscription price string when a price has been set
|
||||
if ( $this->subscription_price !== '' ) {
|
||||
|
||||
$price = '';
|
||||
|
||||
if ( $this->is_on_sale() && isset( $this->min_variation_price ) && $this->min_variation_regular_price !== $this->get_price() ) {
|
||||
|
||||
if ( ! $this->min_variation_price || $this->min_variation_price !== $this->max_variation_price ) {
|
||||
$price .= wcs_get_price_html_from_text( $this );
|
||||
}
|
||||
|
||||
$variation_id = $this->get_meta( '_min_price_variation_id', true );
|
||||
$variation = wc_get_product( $variation_id );
|
||||
$tax_display_mode = get_option( 'woocommerce_tax_display_shop' );
|
||||
|
||||
$sale_price_args = array(
|
||||
'qty' => 1,
|
||||
'price' => $variation->get_sale_price(),
|
||||
);
|
||||
$regular_price_args = array(
|
||||
'qty' => 1,
|
||||
'price' => $variation->get_regular_price(),
|
||||
);
|
||||
|
||||
if ( 'incl' == $tax_display_mode ) {
|
||||
$sale_price = wcs_get_price_including_tax( $variation, $sale_price_args );
|
||||
$regular_price = wcs_get_price_including_tax( $variation, $regular_price_args );
|
||||
} else {
|
||||
$sale_price = wcs_get_price_excluding_tax( $variation, $sale_price_args );
|
||||
$regular_price = wcs_get_price_excluding_tax( $variation, $regular_price_args );
|
||||
}
|
||||
|
||||
$price .= $this->get_price_html_from_to( $regular_price, $sale_price );
|
||||
|
||||
} else {
|
||||
|
||||
if ( $this->min_variation_price !== $this->max_variation_price ) {
|
||||
$price .= wcs_get_price_html_from_text( $this );
|
||||
}
|
||||
|
||||
$price .= wc_price( $this->get_variation_price( 'min', true ) );
|
||||
|
||||
}
|
||||
|
||||
// Make sure the price contains "From:" when billing schedule differs between variations
|
||||
if ( false === strpos( $price, wcs_get_price_html_from_text( $this ) ) ) {
|
||||
if ( $this->subscription_period !== $this->max_variation_period ) {
|
||||
$price = wcs_get_price_html_from_text( $this ) . $price;
|
||||
} elseif ( $this->subscription_period_interval !== $this->max_variation_period_interval ) {
|
||||
$price = wcs_get_price_html_from_text( $this ) . $price;
|
||||
}
|
||||
}
|
||||
|
||||
$price .= $this->get_price_suffix();
|
||||
|
||||
$price = WC_Subscriptions_Product::get_price_string( $this, array( 'price' => $price ) );
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_variable_subscription_price_html', $price, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the WC_Data::get_meta() function when WC < 3.0 is active.
|
||||
*
|
||||
* @param string $meta_key
|
||||
* @param bool $single
|
||||
* @param string $context
|
||||
* @return object WC_Product_Subscription or WC_Product_Subscription_Variation
|
||||
*/
|
||||
function get_meta( $meta_key = '', $single = true, $context = 'view' ) {
|
||||
return $this->get_meta( $meta_key, $single );
|
||||
}
|
||||
|
||||
/**
|
||||
* get_child function.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $child_id
|
||||
* @return object WC_Product_Subscription or WC_Product_Subscription_Variation
|
||||
*/
|
||||
public function get_child( $child_id ) {
|
||||
return wc_get_product( $child_id, array(
|
||||
'product_type' => 'Subscription_Variation',
|
||||
'parent_id' => $this->id,
|
||||
'parent' => $this,
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default attributes.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
* @param string $context
|
||||
* @return array
|
||||
*/
|
||||
public function get_default_attributes( $context = 'view' ) {
|
||||
return $this->get_variation_default_attributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the product's min and max variation data.
|
||||
*
|
||||
* @param array $min_and_max_data The min and max variation data returned by @see wcs_get_min_max_variation_data(). Optional.
|
||||
* @param array $variation_ids The visible child variation IDs. Optional. By default this value be generated by @see WC_Product_Variable->get_children( true ).
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.0
|
||||
*/
|
||||
public function set_min_and_max_variation_data( $min_and_max_data = array(), $variation_ids = array() ) {
|
||||
|
||||
if ( empty( $variation_ids ) ) {
|
||||
$variation_ids = $this->get_children( true );
|
||||
}
|
||||
|
||||
if ( empty( $min_and_max_data ) ) {
|
||||
$min_and_max_data = wcs_get_min_max_variation_data( $this, $variation_ids );
|
||||
}
|
||||
|
||||
update_post_meta( $this->id, '_min_max_variation_data', $min_and_max_data, true );
|
||||
update_post_meta( $this->id, '_min_max_variation_ids_hash', $this->get_variation_ids_hash( $variation_ids ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the min and max variation data.
|
||||
*
|
||||
* This is a wrapper for @see wcs_get_min_max_variation_data() but to avoid calling
|
||||
* that resource intensive function multiple times per request, check the value
|
||||
* stored in meta or cached in memory before calling that function.
|
||||
*
|
||||
* @param array $variation_ids An array of variation IDs.
|
||||
* @return array The variable product's min and max variation data.
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.0
|
||||
*/
|
||||
public function get_min_and_max_variation_data( $variation_ids ) {
|
||||
$variation_ids_hash = $this->get_variation_ids_hash( $variation_ids );
|
||||
|
||||
// If this variable product has no min and max variation data, set it.
|
||||
if ( ! metadata_exists( 'post', $this->id, '_min_max_variation_ids_hash' ) ) {
|
||||
$this->set_min_and_max_variation_data();
|
||||
}
|
||||
|
||||
if ( $variation_ids_hash === $this->get_meta( '_min_max_variation_ids_hash', true ) ) {
|
||||
$min_and_max_variation_data = $this->get_meta( '_min_max_variation_data', true );
|
||||
} elseif ( ! empty( $this->min_max_variation_data[ $variation_ids_hash ] ) ) {
|
||||
$min_and_max_variation_data = $this->min_max_variation_data[ $variation_ids_hash ];
|
||||
} else {
|
||||
$min_and_max_variation_data = wcs_get_min_max_variation_data( $this, $variation_ids );
|
||||
$this->min_max_variation_data[ $variation_ids_hash ] = $min_and_max_variation_data;
|
||||
}
|
||||
|
||||
return $min_and_max_variation_data;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,776 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Subscription Legacy Object
|
||||
*
|
||||
* Extends WC_Subscription to provide WC 3.0 methods when running WooCommerce < 3.0.
|
||||
*
|
||||
* @class WC_Subscription_Legacy
|
||||
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.1
|
||||
* @package WooCommerce Subscriptions/Classes
|
||||
* @category Class
|
||||
* @author Brent Shepherd
|
||||
*/
|
||||
|
||||
class WC_Subscription_Legacy extends WC_Subscription {
|
||||
|
||||
protected $schedule;
|
||||
|
||||
protected $status_transition = false;
|
||||
|
||||
/**
|
||||
* Whether the object has been read. Pre WC 3.0 subscription objects are always read by default.
|
||||
* Provides an accessible variable equivalent to WC_Data::$object_read pre WC 3.0.
|
||||
*
|
||||
* @protected boolean
|
||||
*/
|
||||
protected $object_read = true;
|
||||
|
||||
/**
|
||||
* Initialize the subscription object.
|
||||
*
|
||||
* @param int|WC_Subscription $subscription
|
||||
*/
|
||||
public function __construct( $subscription ) {
|
||||
|
||||
parent::__construct( $subscription );
|
||||
|
||||
$this->order_type = 'shop_subscription';
|
||||
|
||||
$this->schedule = new stdClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates a subscription from the loaded post data.
|
||||
*
|
||||
* @param mixed $result
|
||||
*/
|
||||
public function populate( $result ) {
|
||||
parent::populate( $result );
|
||||
|
||||
if ( $this->post->post_parent > 0 ) {
|
||||
$this->order = wc_get_order( $this->post->post_parent );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique ID for this object.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_id() {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parent order ID.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
* @return int
|
||||
*/
|
||||
public function get_parent_id() {
|
||||
return $this->post->post_parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets order currency.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_currency() {
|
||||
return $this->get_order_currency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get customer_note.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_customer_note( $context = 'view' ) {
|
||||
return $this->customer_note;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get prices_include_tax.
|
||||
*
|
||||
* @param string $context
|
||||
* @return bool
|
||||
*/
|
||||
public function get_prices_include_tax( $context = 'view' ) {
|
||||
return $this->prices_include_tax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the payment method.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_payment_method( $context = 'view' ) {
|
||||
return $this->payment_method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the payment method's title.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_payment_method_title( $context = 'view' ) {
|
||||
return $this->payment_method_title;
|
||||
}
|
||||
|
||||
/** Address Getters **/
|
||||
|
||||
/**
|
||||
* Get billing_first_name.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_billing_first_name( $context = 'view' ) {
|
||||
return $this->billing_first_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get billing_last_name.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_billing_last_name( $context = 'view' ) {
|
||||
return $this->billing_last_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get billing_company.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_billing_company( $context = 'view' ) {
|
||||
return $this->billing_company;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get billing_address_1.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_billing_address_1( $context = 'view' ) {
|
||||
return $this->billing_address_1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get billing_address_2.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string $value
|
||||
*/
|
||||
public function get_billing_address_2( $context = 'view' ) {
|
||||
return $this->billing_address_2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get billing_city.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string $value
|
||||
*/
|
||||
public function get_billing_city( $context = 'view' ) {
|
||||
return $this->billing_city;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get billing_state.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_billing_state( $context = 'view' ) {
|
||||
return $this->billing_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get billing_postcode.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_billing_postcode( $context = 'view' ) {
|
||||
return $this->billing_postcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get billing_country.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_billing_country( $context = 'view' ) {
|
||||
return $this->billing_country;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get billing_email.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_billing_email( $context = 'view' ) {
|
||||
return $this->billing_email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get billing_phone.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_billing_phone( $context = 'view' ) {
|
||||
return $this->billing_phone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shipping_first_name.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_shipping_first_name( $context = 'view' ) {
|
||||
return $this->shipping_first_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shipping_last_name.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_shipping_last_name( $context = 'view' ) {
|
||||
return $this->shipping_last_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shipping_company.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_shipping_company( $context = 'view' ) {
|
||||
return $this->shipping_company;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shipping_address_1.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_shipping_address_1( $context = 'view' ) {
|
||||
return $this->shipping_address_1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shipping_address_2.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_shipping_address_2( $context = 'view' ) {
|
||||
return $this->shipping_address_2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shipping_city.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_shipping_city( $context = 'view' ) {
|
||||
return $this->shipping_city;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shipping_state.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_shipping_state( $context = 'view' ) {
|
||||
return $this->shipping_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shipping_postcode.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_shipping_postcode( $context = 'view' ) {
|
||||
return $this->shipping_postcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shipping_country.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_shipping_country( $context = 'view' ) {
|
||||
return $this->shipping_country;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get order key.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_order_key( $context = 'view' ) {
|
||||
return $this->order_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get date_created.
|
||||
*
|
||||
* Used by parent::get_date()
|
||||
*
|
||||
* @throws WC_Data_Exception
|
||||
* @return DateTime|NULL object if the date is set or null if there is no date.
|
||||
*/
|
||||
public function get_date_created( $context = 'view' ) {
|
||||
|
||||
if ( '0000-00-00 00:00:00' != $this->post->post_date_gmt ) {
|
||||
$datetime = new WC_DateTime( $this->post->post_date_gmt, new DateTimeZone( 'UTC' ) );
|
||||
$datetime->setTimezone( new DateTimeZone( wc_timezone_string() ) );
|
||||
} else {
|
||||
$datetime = new WC_DateTime( $this->post->post_date, new DateTimeZone( wc_timezone_string() ) );
|
||||
}
|
||||
|
||||
// Cache it in $this->schedule for backward compatibility
|
||||
if ( ! isset( $this->schedule->start ) ) {
|
||||
$this->schedule->start = wcs_get_datetime_utc_string( $datetime );
|
||||
}
|
||||
|
||||
return $datetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get date_modified.
|
||||
*
|
||||
* Used by parent::get_date()
|
||||
*
|
||||
* @throws WC_Data_Exception
|
||||
* @return DateTime|NULL object if the date is set or null if there is no date.
|
||||
*/
|
||||
public function get_date_modified( $context = 'view' ) {
|
||||
|
||||
if ( '0000-00-00 00:00:00' != $this->post->post_modified_gmt ) {
|
||||
$datetime = new WC_DateTime( $this->post->post_modified_gmt, new DateTimeZone( 'UTC' ) );
|
||||
$datetime->setTimezone( new DateTimeZone( wc_timezone_string() ) );
|
||||
} else {
|
||||
$datetime = new WC_DateTime( $this->post->post_modified, new DateTimeZone( wc_timezone_string() ) );
|
||||
}
|
||||
|
||||
return $datetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given line item on the subscription had a sign-up fee, and if so, return the value of the sign-up fee.
|
||||
*
|
||||
* The single quantity sign-up fee will be returned instead of the total sign-up fee paid. For example, if 3 x a product
|
||||
* with a 10 BTC sign-up fee was purchased, a total 30 BTC was paid as the sign-up fee but this function will return 10 BTC.
|
||||
*
|
||||
* @param array|int Either an order item (in the array format returned by self::get_items()) or the ID of an order item.
|
||||
* @param string $tax_inclusive_or_exclusive Whether or not to adjust sign up fee if prices inc tax - ensures that the sign up fee paid amount includes the paid tax if inc
|
||||
* @return bool
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
||||
*/
|
||||
public function get_items_sign_up_fee( $line_item, $tax_inclusive_or_exclusive = 'exclusive_of_tax' ) {
|
||||
|
||||
if ( ! is_array( $line_item ) ) {
|
||||
$line_item = wcs_get_order_item( $line_item, $this );
|
||||
}
|
||||
|
||||
$parent_order = $this->get_parent();
|
||||
|
||||
// If there was no original order, nothing was paid up-front which means no sign-up fee
|
||||
if ( false == $parent_order ) {
|
||||
|
||||
$sign_up_fee = 0;
|
||||
|
||||
} else {
|
||||
|
||||
$original_order_item = '';
|
||||
|
||||
// Find the matching item on the order
|
||||
foreach ( $parent_order->get_items() as $order_item ) {
|
||||
if ( wcs_get_canonical_product_id( $line_item ) == wcs_get_canonical_product_id( $order_item ) ) {
|
||||
$original_order_item = $order_item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No matching order item, so this item wasn't purchased in the original order
|
||||
if ( empty( $original_order_item ) ) {
|
||||
|
||||
$sign_up_fee = 0;
|
||||
|
||||
} elseif ( isset( $line_item['item_meta']['_has_trial'] ) ) {
|
||||
|
||||
// Sign up is total amount paid for this item on original order when item has a free trial
|
||||
$sign_up_fee = $original_order_item['line_total'] / $original_order_item['qty'];
|
||||
} elseif ( isset( $original_order_item['item_meta']['_synced_sign_up_fee'] ) ) {
|
||||
$sign_up_fee = $original_order_item['item_meta']['_synced_sign_up_fee'] / $original_order_item['qty'];
|
||||
|
||||
// The synced sign up fee meta contains the raw product sign up fee, if the subscription totals are inclusive of tax, we need to adjust the synced sign up fee to match tax inclusivity.
|
||||
if ( $this->get_prices_include_tax() ) {
|
||||
$line_item_total = $original_order_item['line_total'] + $original_order_item['line_tax'];
|
||||
$signup_fee_portion = $sign_up_fee / $line_item_total;
|
||||
$sign_up_fee = $original_order_item['line_total'] * $signup_fee_portion;
|
||||
}
|
||||
} else {
|
||||
|
||||
// Sign-up fee is any amount on top of recurring amount
|
||||
$sign_up_fee = max( $original_order_item['line_total'] / $original_order_item['qty'] - $line_item['line_total'] / $line_item['qty'], 0 );
|
||||
}
|
||||
|
||||
// If prices don't inc tax, ensure that the sign up fee amount includes the tax.
|
||||
if ( 'inclusive_of_tax' === $tax_inclusive_or_exclusive && ! empty( $original_order_item ) && ! empty( $sign_up_fee ) ) {
|
||||
$sign_up_fee_proportion = $sign_up_fee / ( $original_order_item['line_total'] / $original_order_item['qty'] );
|
||||
$sign_up_fee_tax = $original_order_item['line_tax'] * $sign_up_fee_proportion;
|
||||
|
||||
$sign_up_fee += $sign_up_fee_tax;
|
||||
$sign_up_fee = wc_format_decimal( $sign_up_fee, wc_get_price_decimals() );
|
||||
}
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_subscription_items_sign_up_fee', $sign_up_fee, $line_item, $this, $tax_inclusive_or_exclusive );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to make sure when WC_Subscription calls get_prop() from
|
||||
* it's new getters that the property is both retrieved from the legacy class
|
||||
* property and done so from post meta.
|
||||
*
|
||||
* For inherited dates props, like date_created, date_modified, date_paid,
|
||||
* date_completed, we want to use our own get_date() function rather simply
|
||||
* getting the stored value. Otherwise, we either get the prop set in memory
|
||||
* or post meta if it's not set yet, because __get() in WC < 3.0 would fallback
|
||||
* to post meta.
|
||||
*
|
||||
* @param string
|
||||
* @param string
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_prop( $prop, $context = 'view' ) {
|
||||
|
||||
if ( 'switch_data' == $prop ) {
|
||||
$prop = 'subscription_switch_data';
|
||||
}
|
||||
|
||||
// The requires manual renewal prop uses boolean values but is stored as a string so needs special handling, it also needs to be handled before the checks on $this->$prop to avoid triggering __isset() & __get() magic methods for $this->requires_manual_renewal
|
||||
if ( 'requires_manual_renewal' === $prop ) {
|
||||
$value = $this->get_meta( '_' . $prop, true );
|
||||
|
||||
if ( 'false' === $value || '' === $value ) {
|
||||
$value = false;
|
||||
} else {
|
||||
$value = true;
|
||||
}
|
||||
} elseif ( ! isset( $this->$prop ) || empty( $this->$prop ) ) {
|
||||
$value = $this->get_meta( '_' . $prop, true );
|
||||
} else {
|
||||
$value = $this->$prop;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stored date for a specific schedule.
|
||||
*
|
||||
* @param string $date_type 'date_created', 'trial_end', 'next_payment', 'last_order_date_created' or 'end'
|
||||
*/
|
||||
protected function get_date_prop( $date_type ) {
|
||||
|
||||
$datetime = parent::get_date_prop( $date_type );
|
||||
|
||||
// Cache the string equalivent of it in $this->schedule for backward compatibility
|
||||
if ( ! isset( $this->schedule->{$date_type} ) ) {
|
||||
if ( ! is_object( $datetime ) ) {
|
||||
$this->schedule->{$date_type} = 0;
|
||||
} else {
|
||||
$this->schedule->{$date_type} = wcs_get_datetime_utc_string( $datetime );
|
||||
}
|
||||
}
|
||||
|
||||
return wcs_get_datetime_from( wcs_date_to_time( $datetime ) );
|
||||
}
|
||||
|
||||
/*** Setters *****************************************************/
|
||||
|
||||
/**
|
||||
* Set the unique ID for this object.
|
||||
*
|
||||
* @param int
|
||||
*/
|
||||
public function set_id( $id ) {
|
||||
$this->id = absint( $id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set parent order ID. We don't use WC_Abstract_Order::set_parent_id() because we want to allow false
|
||||
* parent IDs, like 0.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
* @param int $value
|
||||
*/
|
||||
public function set_parent_id( $value ) {
|
||||
// Update the parent in the database
|
||||
wp_update_post( array(
|
||||
'ID' => $this->id,
|
||||
'post_parent' => $value,
|
||||
) );
|
||||
|
||||
// And update the parent in memory
|
||||
$this->post->post_parent = $value;
|
||||
$this->order = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set subscription status.
|
||||
*
|
||||
* @param string $new_status Status to change the order to. No internal wc- prefix is required.
|
||||
* @return array details of change
|
||||
*/
|
||||
public function set_status( $new_status, $note = '', $manual_update = false ) {
|
||||
|
||||
$old_status = $this->get_status();
|
||||
$prefix = substr( $new_status, 0, 3 );
|
||||
$new_status = 'wc-' === $prefix ? substr( $new_status, 3 ) : $new_status;
|
||||
|
||||
wp_update_post(
|
||||
array(
|
||||
'ID' => $this->get_id(),
|
||||
'post_status' => wcs_maybe_prefix_key( $new_status, 'wc-' ),
|
||||
)
|
||||
);
|
||||
$this->post_status = $this->post->post_status = wcs_maybe_prefix_key( $new_status, 'wc-' );
|
||||
|
||||
if ( $old_status !== $new_status ) {
|
||||
$this->status_transition = array(
|
||||
'from' => ! empty( $this->status_transition['from'] ) ? $this->status_transition['from'] : $old_status,
|
||||
'to' => $new_status,
|
||||
'note' => $note,
|
||||
'manual' => (bool) $manual_update,
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'from' => $old_status,
|
||||
'to' => $new_status,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to make sure when WC_Subscription calls set_prop() that property is
|
||||
* both set in the legacy class property and saved in post meta immediately.
|
||||
*
|
||||
* @param string $prop
|
||||
* @param mixed $value
|
||||
*/
|
||||
protected function set_prop( $prop, $value ) {
|
||||
|
||||
if ( 'switch_data' == $prop ) {
|
||||
$prop = 'subscription_switch_data';
|
||||
}
|
||||
|
||||
$this->$prop = $value;
|
||||
|
||||
// The requires manual renewal prop uses boolean values but it stored as a string
|
||||
if ( 'requires_manual_renewal' === $prop ) {
|
||||
if ( false === $value || '' === $value ) {
|
||||
$value = 'false';
|
||||
} else {
|
||||
$value = 'true';
|
||||
}
|
||||
}
|
||||
|
||||
update_post_meta( $this->get_id(), '_' . $prop, $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the stored date for a specific schedule.
|
||||
*
|
||||
* @param string $date_type 'trial_end', 'next_payment', 'cancelled', 'payment_retry' or 'end'
|
||||
* @param int $value UTC timestamp
|
||||
*/
|
||||
protected function set_date_prop( $date_type, $value ) {
|
||||
$datetime = wcs_get_datetime_from( $value );
|
||||
$date = ! is_null( $datetime ) ? wcs_get_datetime_utc_string( $datetime ) : 0;
|
||||
|
||||
$this->set_prop( $this->get_date_prop_key( $date_type ), $date );
|
||||
$this->schedule->{$date_type} = $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a certain date type for the last order on the subscription.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
* @param string $date_type
|
||||
* @param string|integer|object
|
||||
* @return WC_DateTime|NULL object if the date is set or null if there is no date.
|
||||
*/
|
||||
protected function set_last_order_date( $date_type, $date = null ) {
|
||||
|
||||
$last_order = $this->get_last_order( 'all' );
|
||||
|
||||
if ( $last_order ) {
|
||||
|
||||
$datetime = wcs_get_datetime_from( $date );
|
||||
|
||||
switch ( $date_type ) {
|
||||
case 'date_paid':
|
||||
update_post_meta( $last_order->id, '_paid_date', ! is_null( $date ) ? $datetime->date( 'Y-m-d H:i:s' ) : '' );
|
||||
// Preemptively set the UTC timestamp for WC 3.0+ also to avoid incorrect values when the site's timezone is changed between now and upgrading to WC 3.0
|
||||
update_post_meta( $last_order->id, '_date_paid', ! is_null( $date ) ? $datetime->getTimestamp() : '' );
|
||||
break;
|
||||
|
||||
case 'date_completed':
|
||||
update_post_meta( $last_order->id, '_completed_date', ! is_null( $date ) ? $datetime->date( 'Y-m-d H:i:s' ) : '' );
|
||||
// Preemptively set the UTC timestamp for WC 3.0+ also to avoid incorrect values when the site's timezone is changed between now and upgrading to WC 3.0
|
||||
update_post_meta( $last_order->id, '_date_completed', ! is_null( $date ) ? $datetime->getTimestamp() : '' );
|
||||
break;
|
||||
|
||||
case 'date_modified':
|
||||
wp_update_post( array(
|
||||
'ID' => $last_order->id,
|
||||
'post_modified' => $datetime->date( 'Y-m-d H:i:s' ),
|
||||
'post_modified_gmt' => wcs_get_datetime_utc_string( $datetime ),
|
||||
) );
|
||||
break;
|
||||
|
||||
case 'date_created':
|
||||
wp_update_post( array(
|
||||
'ID' => $last_order->id,
|
||||
'post_date' => $datetime->date( 'Y-m-d H:i:s' ),
|
||||
'post_date_gmt' => wcs_get_datetime_utc_string( $datetime ),
|
||||
) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set date_created.
|
||||
*
|
||||
* Used by parent::update_dates()
|
||||
*
|
||||
* @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date.
|
||||
* @throws WC_Data_Exception
|
||||
*/
|
||||
public function set_date_created( $date = null ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( ! is_null( $date ) ) {
|
||||
|
||||
$datetime_string = wcs_get_datetime_utc_string( wcs_get_datetime_from( $date ) );
|
||||
|
||||
// Don't use wp_update_post() to avoid infinite loops here
|
||||
$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_date = %s, post_date_gmt = %s WHERE ID = %d", get_date_from_gmt( $datetime_string ), $datetime_string, $this->get_id() ) );
|
||||
|
||||
$this->post->post_date = get_date_from_gmt( $datetime_string );
|
||||
$this->post->post_date_gmt = $datetime_string;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set discount_total.
|
||||
*
|
||||
* @param string $value
|
||||
* @throws WC_Data_Exception
|
||||
*/
|
||||
public function set_discount_total( $value ) {
|
||||
$this->set_total( $value, 'cart_discount' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set discount_tax.
|
||||
*
|
||||
* @param string $value
|
||||
* @throws WC_Data_Exception
|
||||
*/
|
||||
public function set_discount_tax( $value ) {
|
||||
$this->set_total( $value, 'cart_discount_tax' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set shipping_total.
|
||||
*
|
||||
* @param string $value
|
||||
* @throws WC_Data_Exception
|
||||
*/
|
||||
public function set_shipping_total( $value ) {
|
||||
$this->set_total( $value, 'shipping' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set shipping_tax.
|
||||
*
|
||||
* @param string $value
|
||||
* @throws WC_Data_Exception
|
||||
*/
|
||||
public function set_shipping_tax( $value ) {
|
||||
$this->set_total( $value, 'shipping_tax' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cart tax.
|
||||
*
|
||||
* @param string $value
|
||||
* @throws WC_Data_Exception
|
||||
*/
|
||||
public function set_cart_tax( $value ) {
|
||||
$this->set_total( $value, 'tax' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save data to the database. Nothing to do here as it's all done separately when calling @see this->set_prop().
|
||||
*
|
||||
* @return int order ID
|
||||
*/
|
||||
public function save() {
|
||||
$this->status_transition();
|
||||
return $this->get_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update meta data by key or ID, if provided.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @param int $meta_id
|
||||
*/
|
||||
public function update_meta_data( $key, $value, $meta_id = '' ) {
|
||||
if ( ! empty( $meta_id ) ) {
|
||||
update_metadata_by_mid( 'post', $meta_id, $value, $key );
|
||||
} else {
|
||||
update_post_meta( $this->get_id(), $key, $value );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save subscription date changes to the database.
|
||||
* Nothing to do here as all date properties are saved when calling @see $this->set_prop().
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.6
|
||||
*/
|
||||
public function save_dates() {
|
||||
// Nothing to do here.
|
||||
}
|
||||
}
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* There is "magic" in PHP, and then there is this.
|
||||
*
|
||||
* Story time: once upon a time, in a land not too far away, WooCommerce 3.0 deprecated accessing
|
||||
* all properties on objects. A conventicle of wizards known as __get(), __set() and __isset() came
|
||||
* together to make sure that properties on Subscriptions products could still be used, despite not being
|
||||
* accessible. However, a dark cloud hung over properties which were arrays. None of the conventicle
|
||||
* new of magic powerful enough to deal with such a problem. Enter Cesar, who summoned the dark arts
|
||||
* to call upon the ArrayAccess incantation.
|
||||
*
|
||||
* In other words, this class is used to access specific items on an array from within the magic methods
|
||||
* of other objects, like WC_Product_Subscription_Variation::__get() for the property formerly known as
|
||||
* $subscription_variation_level_meta_data.
|
||||
*
|
||||
* @package WooCommerce Subscriptions
|
||||
* @category Class
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
*
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class WCS_Array_Property_Post_Meta_Black_Magic implements ArrayAccess {
|
||||
|
||||
/**
|
||||
* Store the ID this class is being used against so that we use it for post meta calls.
|
||||
*/
|
||||
protected $product_id;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $product
|
||||
*/
|
||||
public function __construct( $product_id ) {
|
||||
$this->product_id = $product_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* offsetGet
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetGet( $key ) {
|
||||
return get_post_meta( $this->product_id, $this->maybe_prefix_meta_key( $key ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* offsetSet
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetSet( $key, $value ) {
|
||||
update_post_meta( $this->product_id, $this->maybe_prefix_meta_key( $key ), $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* offsetExists
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetExists( $key ) {
|
||||
return metadata_exists( 'post', $this->product_id, $this->maybe_prefix_meta_key( $key ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Nothing to do here as we access post meta directly.
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetUnset( $key ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* We only work with post meta data that has meta keys prefixed with an underscore, so
|
||||
* add a prefix if it is not already set.
|
||||
*/
|
||||
protected function maybe_prefix_meta_key( $key ) {
|
||||
if ( '_' != substr( $key, 0, 1 ) ) {
|
||||
$key = '_' . $key;
|
||||
}
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Legacy Subscription Product Handler
|
||||
*
|
||||
* Ensures subscription products work with versions of WooCommerce prior to 3.0 by loading
|
||||
* legacy classes to provide CRUD methods only added with WC 3.0.
|
||||
*
|
||||
* @package WooCommerce Subscriptions
|
||||
* @subpackage WCS_Product_Legacy
|
||||
* @category Class
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
*/
|
||||
class WCS_Product_Legacy {
|
||||
|
||||
/**
|
||||
* Set up the class, including it's hooks & filters, when the file is loaded.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
**/
|
||||
public static function init() {
|
||||
|
||||
// Use our legacy product classes when WC 3.0+ is not active
|
||||
add_filter( 'woocommerce_product_class', __CLASS__ . '::set_product_class', 100, 4 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Use legacy classes for WC < 3.0
|
||||
*
|
||||
* @return string $classname The name of the WC_Product_* class which should be instantiated to create an instance of this product.
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
*/
|
||||
public static function set_product_class( $classname, $product_type, $post_type, $product_id ) {
|
||||
|
||||
if ( wcs_is_woocommerce_pre( '3.0' ) && in_array( $classname, array( 'WC_Product_Subscription', 'WC_Product_Variable_Subscription', 'WC_Product_Subscription_Variation' ) ) ) {
|
||||
$classname .= '_Legacy';
|
||||
}
|
||||
|
||||
return $classname;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -226,6 +226,11 @@ class WC_Subscriptions_Upgrader {
|
|||
if ( version_compare( self::$stored_plugin_version, '7.8.0', '<' ) ) {
|
||||
WCS_Plugin_Upgrade_7_8_0::check_gifting_plugin_is_enabled();
|
||||
}
|
||||
|
||||
if ( false && version_compare( self::$stored_plugin_version, '8.2.0', '<' ) ) {
|
||||
// TODO: remove false from the above conditional, once we are ready to make subscription downloads functionality available.
|
||||
WCS_Plugin_Upgrade_8_1_0::check_downloads_plugin_is_enabled();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
/**
|
||||
* Upgrade script for version 8.1.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class WCS_Plugin_Upgrade_8_1_0 {
|
||||
|
||||
/**
|
||||
* Check if the Gifting plugin is enabled and update the settings.
|
||||
*
|
||||
* @since 8.1.0
|
||||
*/
|
||||
public static function check_downloads_plugin_is_enabled() {
|
||||
|
||||
WCS_Upgrade_Logger::add( 'Checking if the Downloads plugin is enabled...' );
|
||||
|
||||
$active_plugins = get_option( 'active_plugins', array() );
|
||||
$is_downloads_plugin_active = false;
|
||||
|
||||
foreach ( $active_plugins as $plugin ) {
|
||||
if ( strpos( $plugin, 'woocommerce-subscription-downloads.php' ) !== false ) {
|
||||
$is_downloads_plugin_active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $is_downloads_plugin_active ) {
|
||||
WCS_Upgrade_Logger::add( 'Downloads plugin is not enabled via active_plugins, skipping...' );
|
||||
return;
|
||||
}
|
||||
|
||||
WCS_Upgrade_Logger::add( 'Downloads plugin is enabled, updating Downloads settings...' );
|
||||
|
||||
update_option( WC_Subscriptions_Admin::$option_prefix . '_enable_downloadable_file_linking', 'yes' );
|
||||
}
|
||||
}
|
||||
|
|
@ -224,19 +224,19 @@ class WCS_Upgrade_1_2 {
|
|||
// Upgrading with WC 1.x
|
||||
if ( is_callable( array( $item_meta, 'add' ) ) ) {
|
||||
|
||||
$item_meta->add( '_subscription_period', $order_subscription_periods[ $product_id ] );
|
||||
$item_meta->add( '_subscription_interval', $subscription_interval );
|
||||
$item_meta->add( '_subscription_length', $subscription_length );
|
||||
$item_meta->add( '_subscription_trial_length', $subscription_trial_length );
|
||||
$item_meta->add( '_subscription_period', $order_subscription_periods[ $product_id ] ); // @phpstan-ignore method.notFound (Legacy upgrade code with proper defensive checks)
|
||||
$item_meta->add( '_subscription_interval', $subscription_interval ); // @phpstan-ignore method.notFound (Legacy upgrade code with proper defensive checks)
|
||||
$item_meta->add( '_subscription_length', $subscription_length ); // @phpstan-ignore method.notFound (Legacy upgrade code with proper defensive checks)
|
||||
$item_meta->add( '_subscription_trial_length', $subscription_trial_length ); // @phpstan-ignore method.notFound (Legacy upgrade code with proper defensive checks)
|
||||
|
||||
$item_meta->add( '_subscription_recurring_amount', $order_item['line_subtotal'] ); // WC_Subscriptions_Product::get_price() would return a price without filters applied
|
||||
$item_meta->add( '_subscription_sign_up_fee', $subscription_sign_up_fee );
|
||||
$item_meta->add( '_subscription_recurring_amount', $order_item['line_subtotal'] ); // @phpstan-ignore method.notFound (Legacy upgrade code with proper defensive checks)
|
||||
$item_meta->add( '_subscription_sign_up_fee', $subscription_sign_up_fee ); // @phpstan-ignore method.notFound (Legacy upgrade code with proper defensive checks)
|
||||
|
||||
// Set recurring amounts for the item
|
||||
$item_meta->add( '_recurring_line_total', $order_item['line_total'] );
|
||||
$item_meta->add( '_recurring_line_tax', $order_item['line_tax'] );
|
||||
$item_meta->add( '_recurring_line_subtotal', $order_item['line_subtotal'] );
|
||||
$item_meta->add( '_recurring_line_subtotal_tax', $order_item['line_subtotal_tax'] );
|
||||
$item_meta->add( '_recurring_line_total', $order_item['line_total'] ); // @phpstan-ignore method.notFound (Legacy upgrade code with proper defensive checks)
|
||||
$item_meta->add( '_recurring_line_tax', $order_item['line_tax'] ); // @phpstan-ignore method.notFound (Legacy upgrade code with proper defensive checks)
|
||||
$item_meta->add( '_recurring_line_subtotal', $order_item['line_subtotal'] ); // @phpstan-ignore method.notFound (Legacy upgrade code with proper defensive checks)
|
||||
$item_meta->add( '_recurring_line_subtotal_tax', $order_item['line_subtotal_tax'] ); // @phpstan-ignore method.notFound (Legacy upgrade code with proper defensive checks)
|
||||
|
||||
$order_item['item_meta'] = $item_meta->meta;
|
||||
|
||||
|
|
|
|||
|
|
@ -516,7 +516,7 @@ function wcs_is_checkout_blocks_api_request( $endpoint = '' ) {
|
|||
* @return bool True if it's a WordPress cron request, false otherwise.
|
||||
*/
|
||||
function wcs_doing_cron() {
|
||||
return function_exists( 'wp_doing_cron' ) ? wp_doing_cron() : defined( 'DOING_CRON' ) && DOING_CRON;
|
||||
return function_exists( 'wp_doing_cron' ) ? wp_doing_cron() : defined( 'DOING_CRON' ) && DOING_CRON; // @phpstan-ignore phpstanWP.wpConstant.fetch (Compatibility fallback for older WordPress versions)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -527,7 +527,7 @@ function wcs_doing_cron() {
|
|||
* @return bool True if it's a WordPress Ajax request, false otherwise.
|
||||
*/
|
||||
function wcs_doing_ajax() {
|
||||
return function_exists( 'wp_doing_ajax' ) ? wp_doing_ajax() : defined( 'DOING_AJAX' ) && DOING_AJAX;
|
||||
return function_exists( 'wp_doing_ajax' ) ? wp_doing_ajax() : defined( 'DOING_AJAX' ) && DOING_AJAX; // @phpstan-ignore phpstanWP.wpConstant.fetch (Compatibility fallback for older WordPress versions)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -73,13 +73,24 @@ function wcs_do_subscriptions_exist() {
|
|||
/**
|
||||
* Main function for returning subscriptions. Wrapper for the wc_get_order() method.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
||||
* @since 2.0.0 Introduced.
|
||||
* @since 8.1.0 Type safety improved.
|
||||
*
|
||||
* @param mixed $the_subscription Post object or post ID of the order.
|
||||
*
|
||||
* @return WC_Subscription|false The subscription object, or false if it cannot be found.
|
||||
*/
|
||||
function wcs_get_subscription( $the_subscription ) {
|
||||
|
||||
if ( empty( $the_subscription ) ) {
|
||||
wc_get_logger()->debug(
|
||||
'Subscription could not be loaded, as an empty value was supplied.',
|
||||
array(
|
||||
'backtrace' => true,
|
||||
'requested_subscription' => $the_subscription,
|
||||
'requested_subscription_type' => gettype( $the_subscription ),
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -87,13 +98,52 @@ function wcs_get_subscription( $the_subscription ) {
|
|||
$the_subscription = $the_subscription->get_id();
|
||||
}
|
||||
|
||||
/** @var WC_Subscription $subscription */
|
||||
$subscription = WC()->order_factory->get_order( $the_subscription );
|
||||
|
||||
if ( ! wcs_is_subscription( $subscription ) ) {
|
||||
$subscription = false;
|
||||
}
|
||||
|
||||
return apply_filters( 'wcs_get_subscription', $subscription );
|
||||
/**
|
||||
* The subscription object being supplied to the caller, or else (bool) false if it could not be loaded.
|
||||
*
|
||||
* If a callback turns $subscription into some other type, that value will be rejected and (bool) false
|
||||
* will ultimately be returned instead.
|
||||
*
|
||||
* @since 2.0.0 Introduced.
|
||||
* @since 8.1.0 Type safety improved.
|
||||
*
|
||||
* @param WC_Subscription|false $subscription The subscription object being supplied to the caller, or (bool) false.
|
||||
*/
|
||||
$return_val = apply_filters( 'wcs_get_subscription', $subscription );
|
||||
|
||||
if ( false === $return_val ) {
|
||||
wc_get_logger()->debug(
|
||||
'Subscription could not be loaded.',
|
||||
array(
|
||||
'backtrace' => true,
|
||||
'requested_subscription' => $the_subscription,
|
||||
'requested_subscription_type' => is_object( $the_subscription ) ? get_class( $the_subscription ) : gettype( $the_subscription ),
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
} elseif ( ! $return_val instanceof WC_Subscription ) {
|
||||
wc_get_logger()->warning(
|
||||
'Subscriptions obtained via wcs_get_subscription() must be instances of WC_Subscription.',
|
||||
array(
|
||||
'backtrace' => true,
|
||||
'filtered_type' => is_object( $return_val ) ? get_class( $return_val ) : gettype( $return_val ),
|
||||
'requested_subscription' => $the_subscription,
|
||||
'requested_subscription_type' => is_object( $the_subscription ) ? get_class( $the_subscription ) : gettype( $the_subscription ),
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $return_val;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -675,7 +725,12 @@ function wcs_get_subscriptions_for_product( $product_ids, $fields = 'ids', $args
|
|||
function wcs_get_line_items_with_a_trial( $subscription_id ) {
|
||||
/** @var WC_Subscription $subscription */
|
||||
$subscription = ( is_object( $subscription_id ) ) ? $subscription_id : wcs_get_subscription( $subscription_id );
|
||||
$trial_items = array();
|
||||
|
||||
if ( ! $subscription ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$trial_items = array();
|
||||
|
||||
foreach ( $subscription->get_items() as $line_item_id => $line_item ) {
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ function wcs_get_users_resubscribe_link_for_product( $product_id ) {
|
|||
* Checks the cart to see if it contains a subscription product renewal.
|
||||
*
|
||||
* @param bool|array $cart The cart item containing the renewal, else false.
|
||||
* @return string
|
||||
* @return array|false
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
||||
*/
|
||||
function wcs_cart_contains_resubscribe( $cart = null ) {
|
||||
|
|
@ -184,6 +184,10 @@ function wcs_can_user_resubscribe_to( $subscription, $user_id = 0 ) {
|
|||
|
||||
$can_user_resubscribe = false;
|
||||
|
||||
} elseif ( $subscription->contains_unavailable_product() ) {
|
||||
|
||||
$can_user_resubscribe = false;
|
||||
|
||||
} else {
|
||||
|
||||
$resubscribe_order_ids = $subscription->get_related_orders( 'ids', 'resubscribe' );
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* WooCommerce Subscription Downloads Ajax.
|
||||
*
|
||||
* @package WC_Subscription_Downloads_Ajax
|
||||
* @category Ajax
|
||||
* @author WooThemes
|
||||
*/
|
||||
class WC_Subscription_Downloads_Ajax {
|
||||
|
||||
/**
|
||||
* Ajax actions.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'wp_ajax_wc_subscription_downloads_search', array( $this, 'search_subscriptions' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Search subscription products.
|
||||
*/
|
||||
public function search_subscriptions() {
|
||||
ob_start();
|
||||
|
||||
global $wpdb;
|
||||
|
||||
check_ajax_referer( 'search-products', 'security' );
|
||||
|
||||
$term = wc_clean( stripslashes( $_GET['term'] ) );
|
||||
|
||||
if ( empty( $term ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
$found_subscriptions = array();
|
||||
|
||||
$term = apply_filters( 'woocommerce_subscription_downloads_json_search_order_number', $term );
|
||||
|
||||
// Find subscription products by title.
|
||||
$query_subscriptions = $wpdb->get_results( $wpdb->prepare( "
|
||||
SELECT ID
|
||||
FROM $wpdb->posts AS posts
|
||||
LEFT JOIN $wpdb->term_relationships AS t_relationships ON(posts.ID = t_relationships.object_id)
|
||||
LEFT JOIN $wpdb->term_taxonomy AS t_taxonomy ON(t_relationships.term_taxonomy_id = t_taxonomy.term_taxonomy_id)
|
||||
LEFT JOIN $wpdb->terms AS terms ON(t_taxonomy.term_id = terms.term_id)
|
||||
WHERE posts.post_type = 'product'
|
||||
AND posts.post_status = 'publish'
|
||||
AND posts.post_title LIKE %s
|
||||
AND t_taxonomy.taxonomy = 'product_type'
|
||||
AND (terms.slug = 'subscription' OR terms.slug = 'variable-subscription')
|
||||
ORDER BY posts.post_date DESC
|
||||
", '%' . $term . '%' ) );
|
||||
|
||||
if ( $query_subscriptions ) {
|
||||
foreach ( $query_subscriptions as $item ) {
|
||||
$_product = wc_get_product( $item->ID );
|
||||
$found_subscriptions[ $item->ID ] = sanitize_text_field( $_product->get_formatted_name() );
|
||||
|
||||
if ( 'variable-subscription' == $_product->get_type() ) {
|
||||
$chindren = get_children( array( 'post_parent' => $_product->get_id(), 'post_type' => 'product_variation' ) );
|
||||
|
||||
foreach ( $chindren as $child ) {
|
||||
$_child_product = wc_get_product( $child );
|
||||
$found_subscriptions[ $child->ID ] = sanitize_text_field( $_child_product->get_formatted_name() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wp_send_json( $found_subscriptions );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* WooCommerce Subscription Downloads Install.
|
||||
*
|
||||
* @package WC_Subscription_Downloads_Install
|
||||
* @category Install
|
||||
* @author WooThemes
|
||||
*/
|
||||
class WC_Subscription_Downloads_Install {
|
||||
|
||||
/**
|
||||
* Run the install.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->create_table();
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the plugin table.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function create_table() {
|
||||
global $wpdb;
|
||||
|
||||
$version = get_option( 'woocommerce_subscription_downloads_version' );
|
||||
|
||||
if ( ! $version ) {
|
||||
add_option( 'woocommerce_subscription_downloads_version', WC_Subscriptions::$version );
|
||||
|
||||
$collate = '';
|
||||
|
||||
if ( $wpdb->has_cap( 'collation' ) ) {
|
||||
if ( ! empty( $wpdb->charset ) ) {
|
||||
$collate .= "DEFAULT CHARACTER SET $wpdb->charset";
|
||||
}
|
||||
if ( ! empty( $wpdb->collate ) ) {
|
||||
$collate .= " COLLATE $wpdb->collate";
|
||||
}
|
||||
}
|
||||
|
||||
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
|
||||
|
||||
$create = "
|
||||
CREATE TABLE {$wpdb->prefix}woocommerce_subscription_downloads (
|
||||
id bigint(20) NOT NULL auto_increment,
|
||||
product_id bigint(20) NOT NULL,
|
||||
subscription_id bigint(20) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) $collate;
|
||||
";
|
||||
|
||||
dbDelta( $create );
|
||||
} else {
|
||||
update_option( 'woocommerce_subscription_downloads_version', WC_Subscriptions::$version );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* WooCommerce Subscription Downloads Order.
|
||||
*
|
||||
* @package WC_Subscription_Downloads_Order
|
||||
* @category Order
|
||||
* @author WooThemes
|
||||
*/
|
||||
class WC_Subscription_Downloads_Order {
|
||||
|
||||
/**
|
||||
* Order actions.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'woocommerce_subscription_status_changed', array( $this, 'download_permissions' ), 10, 4 );
|
||||
add_action( 'woocommerce_email_after_order_table', array( $this, 'email_list_downloads' ), 10, 3 );
|
||||
add_action( 'woocommerce_subscriptions_switched_item', array( $this, 'handle_download_switch' ), 10, 3 );
|
||||
add_filter( 'woocommerce_order_get_downloadable_items', array( $this, 'remove_subscription_download_duplicates' ), 1, 2 );
|
||||
add_filter( 'woocommerce_customer_available_downloads', array( $this, 'remove_customer_download_duplicates' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the download permissions in the subscription depending on the status.
|
||||
*
|
||||
* @param int $subscription_id Subscription ID.
|
||||
* @param string $old_status Old status.
|
||||
* @param string $new_status New status.
|
||||
* @param WC_Subscription $subscription Subscription object.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function download_permissions( $subscription_id, $old_status, $new_status, $subscription ) {
|
||||
if ( ! in_array( $new_status, array( 'active', 'expired', 'cancelled' ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$product_item_ids = array_map( function( $item ) {
|
||||
return $item['product_id'];
|
||||
}, $subscription->get_items() );
|
||||
|
||||
foreach ( $subscription->get_items() as $item ) {
|
||||
|
||||
// Gets the downloadable products.
|
||||
$downloadable_products = WC_Subscription_Downloads::get_downloadable_products( $item['product_id'], $item['variation_id'] );
|
||||
|
||||
if ( $downloadable_products ) {
|
||||
|
||||
foreach ( $downloadable_products as $product_id ) {
|
||||
$_product = wc_get_product( $product_id );
|
||||
|
||||
if ( ! $_product ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// @phpstan-ignore property.notFound
|
||||
$product_status = version_compare( WC_VERSION, '3.0', '<' ) ? $_product->post->post_status : $_product->get_status();
|
||||
|
||||
if ( 'expired' === $new_status || 'cancelled' === $new_status ) {
|
||||
WCS_Download_Handler::revoke_downloadable_file_permission( $product_id, $subscription_id, $subscription->get_user_id() );
|
||||
}
|
||||
// Adds the downloadable files to the subscription.
|
||||
else if ( $_product && $_product->exists() && $_product->is_downloadable() && 'publish' === $product_status ) {
|
||||
WCS_Download_Handler::revoke_downloadable_file_permission( $product_id, $subscription_id, $subscription->get_user_id() );
|
||||
$downloads = version_compare( WC_VERSION, '3.0', '<' ) ? $_product->get_files() : $_product->get_downloads();
|
||||
|
||||
foreach ( array_keys( $downloads ) as $download_id ) {
|
||||
wc_downloadable_file_permission( $download_id, $product_id, $subscription );
|
||||
}
|
||||
|
||||
if ( ! in_array( $_product->get_id(), $product_item_ids ) ) {
|
||||
// Skip wrong recalculation of totals by adding a 0 amount Subscriptions.
|
||||
$totals = array(
|
||||
'subtotal' => wc_format_decimal( 0 ),
|
||||
'total' => wc_format_decimal( 0 ),
|
||||
'subtotal_tax' => wc_format_decimal( 0 ),
|
||||
'tax' => wc_format_decimal( 0 ),
|
||||
);
|
||||
|
||||
$subscription->add_product( $_product, 1, array( 'totals' => $totals ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove downloads duplicates on subscriptions.
|
||||
*
|
||||
* @since 1.1.29
|
||||
*
|
||||
* @param array $downloads List of downloads.
|
||||
* @param WC_Order $order The order.
|
||||
*
|
||||
* @return array Array of downloads.
|
||||
*/
|
||||
public static function remove_subscription_download_duplicates( $downloads, $order ) {
|
||||
if ( is_a( $order, 'WC_Subscription' ) ) {
|
||||
$downloads = array_unique( $downloads, SORT_REGULAR );
|
||||
}
|
||||
return $downloads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove customer download duplicates that were added to the same order.
|
||||
*
|
||||
* @since 1.1.30
|
||||
*
|
||||
* @param array $downloads List of downloads.
|
||||
* @param int $customer_id The customer id.
|
||||
*
|
||||
* @return array Array of downloads.
|
||||
*/
|
||||
public static function remove_customer_download_duplicates( $downloads, $customer_id ) {
|
||||
// As downloads have an order_id, the following only removes download duplicates from the same order.
|
||||
$downloads = array_unique( $downloads, SORT_REGULAR );
|
||||
|
||||
return $downloads;
|
||||
}
|
||||
|
||||
/**
|
||||
* List the downloads in order emails.
|
||||
*
|
||||
* @param WC_Order $order Order data
|
||||
* @param bool $sent_to_admin Sent or not to admin.
|
||||
* @param bool $plain_text Plain or HTML email.
|
||||
*/
|
||||
public function email_list_downloads( $order, $sent_to_admin = false, $plain_text = false ) {
|
||||
// @phpstan-ignore property.notFound
|
||||
$order_status = version_compare( WC_VERSION, '3.0', '<' ) ? $order->status : $order->get_status();
|
||||
|
||||
if ( $sent_to_admin && ! in_array( $order_status, array( 'processing', 'completed' ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$downloads = WC_Subscription_Downloads::get_order_downloads( $order );
|
||||
|
||||
if ( $downloads && $plain_text ) {
|
||||
$html = apply_filters( 'woocommerce_subscription_downloads_my_downloads_title', __( 'Available downloads', 'woocommerce-subscriptions' ) );
|
||||
$html .= PHP_EOL . PHP_EOL;
|
||||
|
||||
foreach ( $downloads as $download ) {
|
||||
$html .= $download['name'] . ': ' . $download['download_url'] . PHP_EOL;
|
||||
}
|
||||
|
||||
$html .= PHP_EOL;
|
||||
$html .= '****************************************************';
|
||||
$html .= PHP_EOL . PHP_EOL;
|
||||
|
||||
echo esc_html( wp_strip_all_tags( $html ) );
|
||||
|
||||
} elseif ( $downloads && ! $plain_text ) {
|
||||
$html = '<h2>' . esc_html( apply_filters( 'woocommerce_subscription_downloads_my_downloads_title', __( 'Available downloads', 'woocommerce-subscriptions' ) ) ) . '</h2>';
|
||||
|
||||
$html .= '<table cellspacing="0" cellpadding="0" style="width: 100%; vertical-align: top;" border="0">';
|
||||
$html .= '<tr>';
|
||||
$html .= '<td valign="top">';
|
||||
$html .= '<ul class="digital-downloads">';
|
||||
foreach ( $downloads as $download ) {
|
||||
$html .= sprintf( '<li><a href="%1$s" title="%2$s" target="_blank">%2$s</a></li>', esc_url( $download['download_url'] ), esc_html( $download['name'] ) );
|
||||
}
|
||||
$html .= '</ul>';
|
||||
$html .= '</td>';
|
||||
$html .= '</tr>';
|
||||
$html .= '</table>';
|
||||
|
||||
/**
|
||||
* The following HTML output consists of both static content and variable elements.
|
||||
* The variable elements, such as user-generated content or database values, are properly escaped to prevent security vulnerabilities.
|
||||
*
|
||||
* If this HTML is ever exposed externally via a filter or if more variable elements are added, additional security measures should be taken into account.
|
||||
* Consider using the necessary escaping functions/methods to ensure the continued safety of the output.
|
||||
*
|
||||
* Note: The warning 'WordPress.Security.EscapeOutput.OutputNotEscaped' has been suppressed intentionally, but ensure that the code adheres to the required security standards.
|
||||
*/
|
||||
echo $html; // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke download permissions granted on the old switch item.
|
||||
*
|
||||
* @param WC_Subscription $subscription
|
||||
* @param array $new_item
|
||||
* @param array $old_item
|
||||
*/
|
||||
public function handle_download_switch( $subscription, $new_item, $old_item ) {
|
||||
if ( ! is_object( $subscription ) ) {
|
||||
$subscription = wcs_get_subscription( $subscription );
|
||||
}
|
||||
|
||||
$subscription_id = $subscription->get_id();
|
||||
$downloadable_products = WC_Subscription_Downloads::get_downloadable_products( $old_item['product_id'], $old_item['variation_id'] );
|
||||
$subscription_items = $subscription->get_items();
|
||||
|
||||
// Remove old item attached to the subscription.
|
||||
foreach ( $subscription_items as $item ) {
|
||||
if ( in_array( $item['product_id'], $downloadable_products ) || in_array( $item['variation_id'], $downloadable_products ) ) {
|
||||
$item = $subscription->get_item( $item );
|
||||
if ( $item ) {
|
||||
$item->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Further, remove all attached downloadable products to the subscription.
|
||||
foreach ( $downloadable_products as $product_id ) {
|
||||
WCS_Download_Handler::revoke_downloadable_file_permission( $product_id, $subscription_id, $subscription->get_user_id() );
|
||||
}
|
||||
|
||||
// Re-trigger download permissions. It will automatically add permissions to the new items.
|
||||
$this->download_permissions( $subscription_id, '', 'active', $subscription );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,385 @@
|
|||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* WooCommerce Subscription Downloads Products.
|
||||
*
|
||||
* @package WC_Subscription_Downloads_Products
|
||||
* @category Products
|
||||
* @author WooThemes
|
||||
*/
|
||||
class WC_Subscription_Downloads_Products {
|
||||
|
||||
/**
|
||||
* Products actions.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'woocommerce_product_options_downloads', array( $this, 'simple_write_panel_options' ), 10 );
|
||||
add_action( 'woocommerce_variation_options_download', array( $this, 'variable_write_panel_options' ), 10, 3 );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'scripts' ) );
|
||||
add_action( 'woocommerce_process_product_meta_simple', array( $this, 'save_simple_product_data' ), 10 );
|
||||
add_action( 'woocommerce_save_product_variation', array( $this, 'save_variation_product_data' ), 10, 2 );
|
||||
add_action( 'init', array( $this, 'init' ) );
|
||||
}
|
||||
|
||||
public function init() {
|
||||
if ( version_compare( WC_VERSION, '3.0', '<' ) ) {
|
||||
add_action( 'woocommerce_duplicate_product', array( $this, 'save_subscriptions_when_duplicating_product' ), 10, 2 );
|
||||
} else {
|
||||
add_action( 'woocommerce_product_duplicate', array( $this, 'save_subscriptions_when_duplicating_product' ), 10, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Product screen scripts.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function scripts() {
|
||||
$screen = get_current_screen();
|
||||
|
||||
if ( 'product' == $screen->id && version_compare( WC_VERSION, '2.3.0', '<' ) ) {
|
||||
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
|
||||
|
||||
wp_enqueue_script( 'wc_subscription_downloads_writepanel', plugins_url( 'assets/js/admin/writepanel' . $suffix . '.js', plugin_dir_path( __FILE__ ) ), array( 'ajax-chosen', 'chosen' ), WC_Subscriptions::$version, true );
|
||||
|
||||
wp_localize_script(
|
||||
'wc_subscription_downloads_writepanel',
|
||||
'wc_subscription_downloads_product',
|
||||
array(
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'security' => wp_create_nonce( 'search-products' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple product write panel options.
|
||||
*/
|
||||
public function simple_write_panel_options() {
|
||||
global $post;
|
||||
?>
|
||||
<p class="form-field _subscription_downloads_field">
|
||||
<label for="subscription-downloads-ids"><?php esc_html_e( 'Included subscription products', 'woocommerce-subscriptions' ); ?></label>
|
||||
|
||||
<select id="subscription-downloads-ids" multiple="multiple" data-action="wc_subscription_downloads_search" data-placeholder="<?php esc_attr_e( 'Select subscriptions', 'woocommerce-subscriptions' ); ?>" class="subscription-downloads-ids wc-product-search" name="_subscription_downloads_ids[]" style="width: 50%;">
|
||||
<?php
|
||||
$subscriptions_ids = WC_Subscription_Downloads::get_subscriptions( $post->ID );
|
||||
if ( empty( $subscriptions_ids ) ) {
|
||||
$subscriptions_ids = get_post_meta( $post->ID, '_subscription_downloads_ids', true );
|
||||
}
|
||||
if ( $subscriptions_ids ) {
|
||||
foreach ( $subscriptions_ids as $subscription_id ) {
|
||||
$_subscription = wc_get_product( $subscription_id );
|
||||
|
||||
if ( $_subscription ) {
|
||||
echo '<option value="' . esc_attr( $subscription_id ) . '" selected="selected">' . esc_html( wp_strip_all_tags( $_subscription->get_formatted_name() ) ) . '</option>';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
|
||||
<?php echo wc_help_tip( wc_sanitize_tooltip( __( 'Select subscription products that will include this downloadable product.', 'woocommerce-subscriptions' ) ) ); ?>
|
||||
</p>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Variable product write panel options.
|
||||
*/
|
||||
public function variable_write_panel_options( $loop, $variation_data, $variation ) {
|
||||
?>
|
||||
<tr class="show_if_variation_downloadable">
|
||||
<td colspan="2">
|
||||
<p class="form-field form-row form-row-full">
|
||||
<label><?php esc_html_e( 'Included subscription products', 'woocommerce-subscriptions' ); ?>:</label>
|
||||
<?php echo wc_help_tip( wc_sanitize_tooltip( __( 'Select subscription products that will include this downloadable product.', 'woocommerce-subscriptions' ) ) ); ?>
|
||||
|
||||
<select multiple="multiple" data-placeholder="<?php esc_html_e( 'Select subscriptions', 'woocommerce-subscriptions' ); ?>" class="subscription-downloads-ids wc-product-search" name="_variable_subscription_downloads_ids[<?php echo esc_attr( $loop ); ?>][]" style="width: 100%">
|
||||
<?php
|
||||
$subscriptions_ids = WC_Subscription_Downloads::get_subscriptions( $variation->ID );
|
||||
if ( $subscriptions_ids ) {
|
||||
foreach ( $subscriptions_ids as $subscription_id ) {
|
||||
$_subscription = wc_get_product( $subscription_id );
|
||||
|
||||
if ( $_subscription ) {
|
||||
echo '<option value="' . esc_attr( $subscription_id ) . '" selected="selected">' . esc_html( wp_strip_all_tags( $_subscription->get_formatted_name() ) ) . '</option>';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Search orders from subscription product ID.
|
||||
*
|
||||
* @param int $subscription_product_id
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_orders( $subscription_product_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$orders = array();
|
||||
$meta_key = '_product_id';
|
||||
|
||||
// Check if subscription product has parent (i.e. is a variable subscription product).
|
||||
$parent_id = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT post_parent AS parent_id
|
||||
FROM {$wpdb->prefix}posts
|
||||
WHERE ID = %d;
|
||||
",
|
||||
$subscription_product_id
|
||||
)
|
||||
);
|
||||
|
||||
// If the subscription product is a variation, use variation meta key to find related orders.
|
||||
if ( ! empty( $parent_id ) ) {
|
||||
$meta_key = '_variation_id';
|
||||
}
|
||||
|
||||
$results = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"SELECT order_items.order_id AS id
|
||||
FROM {$wpdb->prefix}woocommerce_order_items as order_items
|
||||
LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS itemmeta ON order_items.order_item_id = itemmeta.order_item_id
|
||||
WHERE itemmeta.meta_key = %s
|
||||
AND itemmeta.meta_value = %d;
|
||||
",
|
||||
$meta_key,
|
||||
$subscription_product_id
|
||||
)
|
||||
);
|
||||
|
||||
foreach ( $results as $order ) {
|
||||
$orders[] = $order->id;
|
||||
}
|
||||
|
||||
$orders = apply_filters( 'woocommerce_subscription_downloads_get_orders', $orders, $subscription_product_id );
|
||||
|
||||
return $orders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke access to download.
|
||||
*
|
||||
* @param bool $download_id
|
||||
* @param bool $product_id
|
||||
* @param bool $order_id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function revoke_access_to_download( $download_id, $product_id, $order_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$wpdb->query( $wpdb->prepare( "
|
||||
DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
|
||||
WHERE order_id = %d AND product_id = %d AND download_id = %s;
|
||||
", $order_id, $product_id, $download_id ) );
|
||||
|
||||
do_action( 'woocommerce_ajax_revoke_access_to_product_download', $download_id, $product_id, $order_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update subscription downloads table and orders.
|
||||
*
|
||||
* @param int $product_id
|
||||
* @param array $subscriptions
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function update_subscription_downloads( $product_id, $subscriptions ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( version_compare( WC_VERSION, '3.0', '<' ) && ! empty( $subscriptions ) ) {
|
||||
$subscriptions = explode( ',', $subscriptions );
|
||||
}
|
||||
|
||||
$current = WC_Subscription_Downloads::get_subscriptions( $product_id );
|
||||
|
||||
// Delete items.
|
||||
$delete_ids = array_diff( $current, $subscriptions );
|
||||
if ( $delete_ids ) {
|
||||
foreach ( $delete_ids as $delete ) {
|
||||
$wpdb->delete(
|
||||
$wpdb->prefix . 'woocommerce_subscription_downloads',
|
||||
array(
|
||||
'product_id' => $product_id,
|
||||
'subscription_id' => $delete,
|
||||
),
|
||||
array(
|
||||
'%d',
|
||||
'%d',
|
||||
)
|
||||
);
|
||||
|
||||
$_orders = $this->get_orders( $delete );
|
||||
foreach ( $_orders as $order_id ) {
|
||||
$_product = wc_get_product( $product_id );
|
||||
$downloads = version_compare( WC_VERSION, '3.0', '<' ) ? $_product->get_files() : $_product->get_downloads();
|
||||
|
||||
// Adds the downloadable files to the order/subscription.
|
||||
foreach ( array_keys( $downloads ) as $download_id ) {
|
||||
$this->revoke_access_to_download( $download_id, $product_id, $order_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add items.
|
||||
$add_ids = array_diff( $subscriptions, $current );
|
||||
if ( $add_ids ) {
|
||||
foreach ( $add_ids as $add ) {
|
||||
$wpdb->insert(
|
||||
$wpdb->prefix . 'woocommerce_subscription_downloads',
|
||||
array(
|
||||
'product_id' => $product_id,
|
||||
'subscription_id' => $add,
|
||||
),
|
||||
array(
|
||||
'%d',
|
||||
'%d',
|
||||
)
|
||||
);
|
||||
|
||||
$_orders = $this->get_orders( $add );
|
||||
foreach ( $_orders as $order_id ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
if ( ! is_a( $order, 'WC_Subscription' ) ) {
|
||||
// avoid adding permissions to orders and it's
|
||||
// subscription for the same user, causing duplicates
|
||||
// to show up
|
||||
continue;
|
||||
}
|
||||
|
||||
$_product = wc_get_product( $product_id );
|
||||
$downloads = version_compare( WC_VERSION, '3.0', '<' ) ? $_product->get_files() : $_product->get_downloads();
|
||||
|
||||
// Adds the downloadable files to the order/subscription.
|
||||
foreach ( array_keys( $downloads ) as $download_id ) {
|
||||
wc_downloadable_file_permission( $download_id, $product_id, $order );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save simple product data.
|
||||
*
|
||||
* @param int $product_id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save_simple_product_data( $product_id ) {
|
||||
$subscription_ids = ! empty( $_POST['_subscription_downloads_ids'] ) ? wc_clean( wp_unslash( $_POST['_subscription_downloads_ids'] ) ) : '';
|
||||
|
||||
if ( ! isset( $_POST['_downloadable'] ) || 'publish' !== get_post_status( $product_id ) ) {
|
||||
update_post_meta( $product_id, '_subscription_downloads_ids', $subscription_ids );
|
||||
return;
|
||||
}
|
||||
|
||||
delete_post_meta( $product_id, '_subscription_downloads_ids', $subscription_ids );
|
||||
$subscriptions = $subscription_ids ?: array();
|
||||
|
||||
$this->update_subscription_downloads( $product_id, $subscriptions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save variable product data.
|
||||
*
|
||||
* @param int $variation_id
|
||||
* @param int $index
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save_variation_product_data( $variation_id, $index ) {
|
||||
if ( ! isset( $_POST['variable_is_downloadable'][ $index ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$subscriptions = isset( $_POST['_variable_subscription_downloads_ids'][ $index ] ) ? wc_clean( wp_unslash( $_POST['_variable_subscription_downloads_ids'][ $index ] ) ) : array();
|
||||
|
||||
if ( version_compare( WC_VERSION, '3.0.0', '<' ) ) {
|
||||
$subscriptions = explode( ',', $subscriptions );
|
||||
}
|
||||
|
||||
$subscriptions = array_filter( $subscriptions ); // nosemgrep: audit.php.lang.misc.array-filter-no-callback -- $subscriptions are already passed through wc_clean() and wp_unslash().
|
||||
|
||||
$this->update_subscription_downloads( $variation_id, $subscriptions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save subscriptions information when duplicating a product.
|
||||
*
|
||||
* @param int|WC_Product $id_or_product Duplicated product ID
|
||||
* @param WP_Post|WC_Product $post Product being duplicated
|
||||
*/
|
||||
public function save_subscriptions_when_duplicating_product( $id_or_product, $post ) {
|
||||
$post_id = is_a( $post, 'WC_Product' ) ? $post->get_parent_id() : $post->ID;
|
||||
$new_id = is_a( $id_or_product, 'WC_Product' ) ? $id_or_product->get_id() : $id_or_product;
|
||||
|
||||
$subscriptions = WC_Subscription_Downloads::get_subscriptions( $post_id );
|
||||
if ( ! empty( $subscriptions ) ) {
|
||||
$this->update_subscription_downloads( $new_id, $subscriptions );
|
||||
}
|
||||
|
||||
$children_products = get_children( 'post_parent=' . $post_id . '&post_type=product_variation' );
|
||||
if ( empty( $children_products ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create assoc array where keys are flatten variation attributes and values
|
||||
// are original product variations.
|
||||
$children_ids_by_variation_attributes = array();
|
||||
foreach ( $children_products as $child ) {
|
||||
$str_attributes = $this->get_str_variation_attributes( $child );
|
||||
if ( ! empty( $str_attributes ) ) {
|
||||
$children_ids_by_variation_attributes[ $str_attributes ] = $child;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy variations' subscriptions.
|
||||
$exclude = apply_filters( 'woocommerce_duplicate_product_exclude_children', false );
|
||||
$new_children_products = get_children( 'post_parent=' . $new_id . '&post_type=product_variation' );
|
||||
if ( ! $exclude && ! empty( $new_children_products ) ) {
|
||||
foreach ( $new_children_products as $child ) {
|
||||
$str_attributes = $this->get_str_variation_attributes( $child );
|
||||
if ( ! empty( $children_ids_by_variation_attributes[ $str_attributes ] ) ) {
|
||||
$this->save_subscriptions_when_duplicating_product(
|
||||
$child->ID,
|
||||
$children_ids_by_variation_attributes[ $str_attributes ]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string representation of variation attributes from a given product variation.
|
||||
*
|
||||
* @param mixed $product_variation Product variation
|
||||
*
|
||||
* @return string Variation attributes
|
||||
*/
|
||||
protected function get_str_variation_attributes( $product_variation ) {
|
||||
$product_variation = wc_get_product( $product_variation );
|
||||
if ( ! is_callable( array( $product_variation, 'get_formatted_variation_attributes' ) ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (string) wc_get_formatted_variation( $product_variation, true );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Registers and manages settings related to linked downloadable files functionality.
|
||||
*
|
||||
* @internal This class is used internally by WooCommerce Subscriptions. It is not intended for third party use, and may change at any time.
|
||||
*/
|
||||
class WC_Subscription_Downloads_Settings {
|
||||
public function __construct() {
|
||||
add_filter( 'woocommerce_subscription_settings', array( $this, 'add_settings' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds our settings to the main subscription settings page.
|
||||
*
|
||||
* @param array $settings The full subscription settings array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_settings( array $settings ): array {
|
||||
$download_settings = array(
|
||||
array(
|
||||
'name' => __( 'Downloads', 'woocommerce-subscriptions' ),
|
||||
'type' => 'title',
|
||||
'id' => WC_Subscriptions_Admin::$option_prefix . '_downloads_settings',
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Enable product linking to subscriptions', 'woocommerce-subscriptions' ),
|
||||
'desc' => __( 'Allow simple and variable downloadable products to be included with subscription products.', 'woocommerce-subscriptions' ),
|
||||
'id' => WC_Subscriptions_Admin::$option_prefix . '_enable_downloadable_file_linking',
|
||||
'default' => 'no',
|
||||
'type' => 'checkbox',
|
||||
'row_class' => 'enable-downloadable-file-linking',
|
||||
),
|
||||
array(
|
||||
'type' => 'sectionend',
|
||||
'id' => WC_Subscriptions_Admin::$option_prefix . '_downloads_settings',
|
||||
),
|
||||
);
|
||||
|
||||
// Insert the switch settings in after the synchronisation section otherwise add them to the end.
|
||||
if ( ! WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Admin::$option_prefix . '_gifting', $download_settings, 'multiple-settings', 'sectionend' ) ) {
|
||||
$settings = array_merge( $settings, $download_settings );
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Subscriptions Downloads is enabled.
|
||||
* @since 8.1.0
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_enabled() {
|
||||
return get_option( WC_Subscriptions_Admin::$option_prefix . '_enable_downloadable_file_linking', 'no' ) === 'yes';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Point of entry for our 'linked downloadable files' functionality.
|
||||
*
|
||||
* Along with other classes in this directory, this used to exist as a standalone plugin (important to note because, for
|
||||
* backwards compatibility reasons, that may place limits on future refactoring).
|
||||
*
|
||||
* The overall goal is to let merchants associate individual downloadable products with subscription products.
|
||||
* Customers who purchase the subscription product then automatically are granted acccess to the relevant downloadable
|
||||
* files.
|
||||
*
|
||||
* This class sets up the functionality, and also provides a high-level interface through methods such as
|
||||
* get_order_downloads( $order ) and get_subscriptions( $product_id ).
|
||||
*
|
||||
* @since 8.1.0
|
||||
*/
|
||||
class WC_Subscription_Downloads {
|
||||
/**
|
||||
* Initialize the various subsystems that drive 'linked downloadable files' functionality.
|
||||
*/
|
||||
public static function setup(): void {
|
||||
|
||||
if ( WC_Subscription_Downloads_Settings::is_enabled() ) {
|
||||
new WC_Subscription_Downloads_Order();
|
||||
|
||||
if ( is_admin() ) {
|
||||
new WC_Subscription_Downloads_Products();
|
||||
new WC_Subscription_Downloads_Ajax();
|
||||
}
|
||||
}
|
||||
|
||||
// Needs to load on admin even when downloads is disabled.
|
||||
// To ensure the settings are added to the subscription settings page.
|
||||
if ( is_admin() ) {
|
||||
new WC_Subscription_Downloads_Settings();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the plugin.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function install() {
|
||||
new WC_Subscription_Downloads_Install();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get subscriptions from a downloadable product.
|
||||
*
|
||||
* @param int $product_id
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscriptions( $product_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$query = $wpdb->get_results( $wpdb->prepare( "SELECT subscription_id FROM {$wpdb->prefix}woocommerce_subscription_downloads WHERE product_id = %d", $product_id ), ARRAY_A );
|
||||
|
||||
$subscriptions = array();
|
||||
foreach ( $query as $item ) {
|
||||
$subscriptions[] = $item['subscription_id'];
|
||||
}
|
||||
|
||||
return $subscriptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get downloadable products from a subscription.
|
||||
*
|
||||
* @param int $subscription_id
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_downloadable_products( $subscription_id, $subscription_variable_id = '' ) {
|
||||
global $wpdb;
|
||||
|
||||
$query = $wpdb->get_results( $wpdb->prepare( "SELECT product_id FROM {$wpdb->prefix}woocommerce_subscription_downloads WHERE subscription_id = %d OR subscription_id = %d", $subscription_id, $subscription_variable_id ), ARRAY_A );
|
||||
|
||||
$products = array();
|
||||
foreach ( $query as $item ) {
|
||||
$products[] = $item['product_id'];
|
||||
}
|
||||
|
||||
return $products;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get order download files.
|
||||
*
|
||||
* @param WC_Order $order Order data.
|
||||
*
|
||||
* @return array Download data (name, file and download_url).
|
||||
*/
|
||||
public static function get_order_downloads( $order ) {
|
||||
$downloads = array();
|
||||
|
||||
if ( class_exists( 'WC_Subscriptions_Core_Plugin' ) || version_compare( WC_Subscriptions::$version, '2.0.0', '>=' ) ) {
|
||||
$contains_subscription = wcs_order_contains_subscription( $order );
|
||||
} else {
|
||||
$contains_subscription = WC_Subscriptions_Order::order_contains_subscription( $order );
|
||||
}
|
||||
|
||||
if ( 0 < count( $order->get_items() ) && $contains_subscription && $order->is_download_permitted() ) {
|
||||
foreach ( $order->get_items() as $item ) {
|
||||
|
||||
// Gets the downloadable products.
|
||||
$downloadable_products = self::get_downloadable_products( $item['product_id'], $item['variation_id'] );
|
||||
|
||||
if ( $downloadable_products ) {
|
||||
foreach ( $downloadable_products as $product_id ) {
|
||||
$_item = array(
|
||||
'product_id' => $product_id,
|
||||
'variation_id' => '',
|
||||
);
|
||||
|
||||
// Get the download data.
|
||||
if ( version_compare( WC_VERSION, '3.0', '<' ) ) {
|
||||
$_downloads = $order->get_item_downloads( $_item );
|
||||
} else {
|
||||
$order_item = new WC_Order_Item_Product();
|
||||
$product = wc_get_product( $product_id );
|
||||
if ( empty( $product ) ) {
|
||||
continue;
|
||||
}
|
||||
$order_item->set_product( $product );
|
||||
$order_item->set_order_id( $order->get_id() );
|
||||
$_downloads = $order_item->get_item_downloads();
|
||||
}
|
||||
|
||||
if ( empty( $_downloads ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $_downloads as $download ) {
|
||||
$downloads[] = $download;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $downloads;
|
||||
}
|
||||
}
|
||||
|
|
@ -178,6 +178,10 @@ class WCS_Early_Renewal_Modal_Handler {
|
|||
$user_id = ! empty( $user_id ) ? absint( $user_id ) : get_current_user_id();
|
||||
$subscription = wcs_get_subscription( $subscription );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! WCS_Early_Renewal_Manager::is_early_renewal_via_modal_enabled() || ! wcs_can_user_renew_early( $subscription, $user_id ) ) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -468,7 +468,7 @@ class WCS_Gifting {
|
|||
<?php
|
||||
if ( 'WooCommerce Memberships' === $plugin_name ) {
|
||||
// translators: 1$-2$: opening and closing <strong> tags, 3$ plugin name, 4$ required plugin version, 5$-6$: opening and closing link tags, leads to plugins.php in admin, 7$: line break, 8$-9$ Opening and closing small tags.
|
||||
printf( esc_html__( '%1$sWooCommerce Subscriptions Gifting Membership integration is inactive.%2$s In order to integrate with WooCommerce Memberships, WooCommerce Subscriptions Gifting requires %3$s %4$s or newer. %5$sPlease update »%6$s %7$s%8$sNote: All other WooCommerce Subscriptions Gifting features will remain available, however purchasing membership plans for recipients will fail to grant the membership to the gift recipient.%9$s', 'woocommerce-subscriptions' ), '<strong>', '</strong>', esc_html( $plugin_name ), esc_html( $required_version ), '<a href="' . esc_url( admin_url( 'plugins.php' ) ) . '">', '</a>', '</br>', '<small>', '</small>' );
|
||||
printf( esc_html__( '%1$sWooCommerce Subscriptions Gifting Membership integration is inactive.%2$s In order to integrate with WooCommerce Memberships, WooCommerce Subscriptions Gifting requires %3$s %4$s or newer. %5$sPlease update »%6$s %7$s%8$sNote: All other WooCommerce Subscriptions Gifting features will remain available, however purchasing membership plans for recipients will fail to grant the membership to the gift recipient.%9$s', 'woocommerce-subscriptions' ), '<strong>', '</strong>', esc_html( $plugin_name ), esc_html( $required_version ), '<a href="' . esc_url( admin_url( 'plugins.php' ) ) . '">', '</a>', '<br>', '<small>', '</small>' );
|
||||
} else {
|
||||
// translators: 1$-2$: opening and closing <strong> tags, 3$ plugin name, 4$ required plugin version, 5$-6$: opening and closing link tags, leads to plugins.php in admin.
|
||||
printf( esc_html__( '%1$sWooCommerce Subscriptions Gifting is inactive.%2$s This version of WooCommerce Subscriptions Gifting requires %3$s %4$s or newer. %5$sPlease update »%6$s', 'woocommerce-subscriptions' ), '<strong>', '</strong>', esc_html( $plugin_name ), esc_html( $required_version ), '<a href="' . esc_url( admin_url( 'plugins.php' ) ) . '">', '</a>' );
|
||||
|
|
@ -654,20 +654,17 @@ class WCS_Gifting {
|
|||
* Retrieve the recipient user ID from a subscription.
|
||||
*
|
||||
* @param WC_Subscription $subscription Subscription object.
|
||||
*
|
||||
* @return string The recipient's user ID. Returns an empty string if there is no recipient set.
|
||||
*/
|
||||
public static function get_recipient_user( $subscription ) {
|
||||
$recipient_user_id = '';
|
||||
|
||||
if ( method_exists( $subscription, 'get_meta' ) ) {
|
||||
if ( $subscription->meta_exists( '_recipient_user' ) ) {
|
||||
$recipient_user_id = $subscription->get_meta( '_recipient_user' );
|
||||
}
|
||||
} else { // WC < 3.0.
|
||||
$recipient_user_id = $subscription->recipient_user;
|
||||
// There may be cases, especially when emails are being previewed in the customizer, where we receive something
|
||||
// other than a WC_Subscription object.
|
||||
if ( $subscription instanceof WC_Subscription && $subscription->meta_exists( '_recipient_user' ) ) {
|
||||
return $subscription->get_meta( '_recipient_user' );
|
||||
}
|
||||
|
||||
return $recipient_user_id;
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -677,8 +674,9 @@ class WCS_Gifting {
|
|||
* @param int $user_id The user ID of the user to set as the recipient on the subscription.
|
||||
* @param string $save Whether to save the data or not, 'save' to save the data, otherwise it won't be saved.
|
||||
* @param int $meta_id The meta ID of existing meta data if you wish to overwrite an existing recipient meta value.
|
||||
* @param WC_Order $order Order object.
|
||||
*/
|
||||
public static function set_recipient_user( &$subscription, $user_id, $save = 'save', $meta_id = 0 ) {
|
||||
public static function set_recipient_user( &$subscription, $user_id, $save = 'save', $meta_id = 0, ?WC_Order $order = null ) {
|
||||
$current_user_id = absint( self::get_recipient_user( $subscription ) );
|
||||
$subscription->recipient_user = $user_id;
|
||||
|
||||
|
|
@ -690,7 +688,9 @@ class WCS_Gifting {
|
|||
$gifting_subcription_item = reset( $gifting_subscription_items );
|
||||
|
||||
if ( ! empty( $gifting_subcription_item ) ) {
|
||||
$order = wc_get_order( $subscription->get_parent_id() );
|
||||
if ( ! $order ) {
|
||||
$order = wc_get_order( $subscription->get_parent_id() );
|
||||
}
|
||||
foreach ( $order->get_items() as $order_item ) {
|
||||
if ( $order_item->get_meta( '_wcsg_cart_key' ) === $gifting_subcription_item->get_meta( '_wcsg_cart_key' ) ) {
|
||||
$order_item->add_meta_data( 'wcsg_recipient', 'wcsg_recipient_id_' . $user_id, true );
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class WCSG_Admin {
|
|||
|
||||
add_filter( 'woocommerce_order_items_meta_get_formatted', __CLASS__ . '::remove_recipient_order_item_meta', 1, 1 );
|
||||
|
||||
add_filter( 'woocommerce_subscription_settings', __CLASS__ . '::add_settings', 10, 1 );
|
||||
add_filter( 'woocommerce_subscription_settings', __CLASS__ . '::add_settings' );
|
||||
|
||||
if ( wcsg_is_wc_subscriptions_pre( '2.3.5' ) ) {
|
||||
add_filter( 'request', __CLASS__ . '::request_query', 11, 1 );
|
||||
|
|
@ -112,7 +112,12 @@ class WCSG_Admin {
|
|||
|
||||
if ( 'order_title' === $column && WCS_Gifting::is_gifted_subscription( $subscription ) ) {
|
||||
|
||||
$recipient_id = WCS_Gifting::get_recipient_user( $subscription );
|
||||
$recipient_id = WCS_Gifting::get_recipient_user( $subscription );
|
||||
|
||||
if ( ! $recipient_id ) {
|
||||
return $column_content;
|
||||
}
|
||||
|
||||
$recipient_user = get_userdata( $recipient_id );
|
||||
$recipient_name = '<a href="' . esc_url( get_edit_user_link( $recipient_id ) ) . '">';
|
||||
|
||||
|
|
@ -172,50 +177,52 @@ class WCSG_Admin {
|
|||
* @return array $settings New set of settings.
|
||||
*/
|
||||
public static function add_settings( $settings ) {
|
||||
|
||||
return array_merge(
|
||||
$settings,
|
||||
$gifting_settings = array(
|
||||
array(
|
||||
array(
|
||||
'name' => __( 'Gifting', 'woocommerce-subscriptions' ),
|
||||
'type' => 'title',
|
||||
'id' => self::$option_prefix,
|
||||
'name' => __( 'Gifting', 'woocommerce-subscriptions' ),
|
||||
'type' => 'title',
|
||||
'id' => self::$option_prefix,
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Enable gifting', 'woocommerce-subscriptions' ),
|
||||
'desc' => __( 'Allow shoppers to gift a subscription', 'woocommerce-subscriptions' ),
|
||||
'id' => self::$option_prefix . '_enable_gifting',
|
||||
'default' => 'no',
|
||||
'type' => 'checkbox',
|
||||
'row_class' => 'enable-gifting',
|
||||
),
|
||||
array(
|
||||
'name' => '',
|
||||
'desc' => __( 'You can override this global setting on each product.', 'woocommerce-subscriptions' ),
|
||||
'id' => self::$option_prefix . '_default_option',
|
||||
'default' => 'disabled',
|
||||
'type' => 'radio',
|
||||
'desc_at_end' => true,
|
||||
'row_class' => 'gifting-radios',
|
||||
'options' => array(
|
||||
'enabled' => __( 'Enabled for all products', 'woocommerce-subscriptions' ),
|
||||
'disabled' => __( 'Disabled for all products', 'woocommerce-subscriptions' ),
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Enable gifting', 'woocommerce-subscriptions' ),
|
||||
'desc' => __( 'Allow shoppers to gift a subscription', 'woocommerce-subscriptions' ),
|
||||
'id' => self::$option_prefix . '_enable_gifting',
|
||||
'default' => 'no',
|
||||
'type' => 'checkbox',
|
||||
'row_class' => 'enable-gifting',
|
||||
),
|
||||
array(
|
||||
'name' => '',
|
||||
'desc' => __( 'You can override this global setting on each product.', 'woocommerce-subscriptions' ),
|
||||
'id' => self::$option_prefix . '_default_option',
|
||||
'default' => 'disabled',
|
||||
'type' => 'radio',
|
||||
'desc_at_end' => true,
|
||||
'row_class' => 'gifting-radios',
|
||||
'options' => array(
|
||||
'enabled' => __( 'Enabled for all products', 'woocommerce-subscriptions' ),
|
||||
'disabled' => __( 'Disabled for all products', 'woocommerce-subscriptions' ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Gifting Checkbox Text', 'woocommerce-subscriptions' ),
|
||||
'desc' => __( 'This is what shoppers will see in the product page and cart.', 'woocommerce-subscriptions' ),
|
||||
'id' => self::$option_prefix . '_gifting_checkbox_text',
|
||||
'default' => __( 'This is a gift', 'woocommerce-subscriptions' ),
|
||||
'type' => 'text',
|
||||
'row_class' => 'gifting-checkbox-text',
|
||||
),
|
||||
array(
|
||||
'type' => 'sectionend',
|
||||
'id' => self::$option_prefix,
|
||||
),
|
||||
)
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Gifting Checkbox Text', 'woocommerce-subscriptions' ),
|
||||
'desc' => __( 'This is what shoppers will see in the product page and cart.', 'woocommerce-subscriptions' ),
|
||||
'id' => self::$option_prefix . '_gifting_checkbox_text',
|
||||
'default' => __( 'This is a gift', 'woocommerce-subscriptions' ),
|
||||
'type' => 'text',
|
||||
'row_class' => 'gifting-checkbox-text',
|
||||
),
|
||||
array(
|
||||
'type' => 'sectionend',
|
||||
'id' => self::$option_prefix,
|
||||
),
|
||||
);
|
||||
|
||||
if ( ! WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Admin::$option_prefix . '_renewal_options', $gifting_settings, 'multiple_settings', 'sectionend' ) ) {
|
||||
return array_merge( $settings, $gifting_settings );
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -277,9 +284,12 @@ class WCSG_Admin {
|
|||
$user_string = '';
|
||||
$user_id = '';
|
||||
if ( WCS_Gifting::is_gifted_subscription( $subscription ) ) {
|
||||
$user_id = WCS_Gifting::get_recipient_user( $subscription );
|
||||
$user = get_user_by( 'id', $user_id );
|
||||
$user_string = esc_html( $user->display_name ) . ' (#' . absint( $user->ID ) . ' – ' . esc_html( $user->user_email );
|
||||
$user_id = WCS_Gifting::get_recipient_user( $subscription );
|
||||
|
||||
if ( $user_id ) {
|
||||
$user = get_user_by( 'id', $user_id );
|
||||
$user_string = esc_html( $user->display_name ) . ' (#' . absint( $user->ID ) . ' – ' . esc_html( $user->user_email );
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_callable( array( 'WCS_Select2', 'render' ) ) ) {
|
||||
|
|
|
|||
|
|
@ -79,11 +79,6 @@ class WCSG_Email {
|
|||
* Hooks up all of WCS Gifting emails after the WooCommerce object is constructed.
|
||||
*/
|
||||
public static function hook_email() {
|
||||
|
||||
add_action( 'woocommerce_created_customer', __CLASS__ . '::maybe_remove_wc_new_customer_email', 9, 2 );
|
||||
add_action( 'woocommerce_created_customer', __CLASS__ . '::send_new_recipient_user_email', 10, 3 );
|
||||
add_action( 'woocommerce_created_customer', __CLASS__ . '::maybe_reattach_wc_new_customer_email', 11, 2 );
|
||||
|
||||
add_action( 'subscriptions_activated_for_order', __CLASS__ . '::maybe_send_recipient_order_emails', 11, 1 );
|
||||
|
||||
$renewal_notification_actions = array(
|
||||
|
|
@ -154,50 +149,6 @@ class WCSG_Email {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a cart item contains recipient data matching the new customer, dont send the core WooCommerce new customer email.
|
||||
*
|
||||
* @param int $customer_id The ID of the new customer being created.
|
||||
* @param array $new_customer_data Array of data associated to the new customer.
|
||||
*/
|
||||
public static function maybe_remove_wc_new_customer_email( $customer_id, $new_customer_data ) {
|
||||
|
||||
if ( ! WC()->cart || ! WC()->cart->cart_contents ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( WC()->cart->cart_contents as $key => $item ) {
|
||||
if ( ! empty( $item['wcsg_gift_recipients_email'] ) ) {
|
||||
if ( $item['wcsg_gift_recipients_email'] == $new_customer_data['user_email'] ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
|
||||
remove_action( current_filter(), array( 'WC_Emails', 'send_transactional_email' ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a cart item contains recipient data matching the new customer, reattach the core WooCommerce new customer email.
|
||||
*
|
||||
* @param int $customer_id The ID of the new customer being created.
|
||||
* @param array $new_customer_data Array of data associated to the new customer.
|
||||
*/
|
||||
public static function maybe_reattach_wc_new_customer_email( $customer_id, $new_customer_data ) {
|
||||
|
||||
if ( ! WC()->cart || ! WC()->cart->cart_contents ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( WC()->cart->cart_contents as $key => $item ) {
|
||||
if ( ! empty( $item['wcsg_gift_recipients_email'] ) ) {
|
||||
if ( $item['wcsg_gift_recipients_email'] == $new_customer_data['user_email'] ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
|
||||
add_action( current_filter(), array( 'WC_Emails', 'send_transactional_email' ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates purchaser new recipient user email.
|
||||
*
|
||||
|
|
@ -217,28 +168,6 @@ class WCSG_Email {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a cart item contains recipient data matching the new customer, init the mailer and call the notification for new recipient customers.
|
||||
*
|
||||
* @param int $customer_id The ID of the new customer being created.
|
||||
* @param array $new_customer_data Recipient's user data.
|
||||
* @param bool $password_generated Whether the password has been generated for the customer.
|
||||
*/
|
||||
public static function send_new_recipient_user_email( $customer_id, $new_customer_data, $password_generated ) {
|
||||
if ( ! WC()->cart || ! WC()->cart->cart_contents ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( WC()->cart->cart_contents as $key => $item ) {
|
||||
if ( isset( $item['wcsg_gift_recipients_email'] ) ) {
|
||||
if ( $item['wcsg_gift_recipients_email'] === $new_customer_data['user_email'] ) {
|
||||
self::generate_new_recipient_user_email( get_current_user_id(), $customer_id );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will get the necessary data to resend the new recipient new email.
|
||||
*
|
||||
|
|
@ -457,15 +386,34 @@ class WCSG_Email {
|
|||
}
|
||||
|
||||
/**
|
||||
* If a cart item contains recipient data matching the new customer, init the mailer and call the notification for new recipient customers.
|
||||
*
|
||||
* @param int $customer_id The ID of the new customer being created.
|
||||
* @param array $new_customer_data Customer data.
|
||||
* @param bool $password_generated Whether the password has been generated for the customer.
|
||||
* @deprecated 2.0
|
||||
* Hooks into the WooCommerce created customer action to prevent sending the core WooCommerce new customer email and send the Gifting new recipient user email instead.
|
||||
*/
|
||||
public static function send_new_recient_user_email( $customer_id, $new_customer_data, $password_generated ) {
|
||||
_deprecated_function( __METHOD__, '2.0.0', __CLASS__ . '::send_new_recipient_user_email()' );
|
||||
self::send_new_recipient_user_email( $customer_id, $new_customer_data, $password_generated );
|
||||
public static function use_gifting_new_account_email() {
|
||||
add_action( 'woocommerce_created_customer', __CLASS__ . '::remove_wc_new_customer_email', 9, 0 );
|
||||
add_action( 'woocommerce_created_customer', __CLASS__ . '::send_new_recipient_user_email', 10, 1 );
|
||||
add_action( 'woocommerce_created_customer', __CLASS__ . '::reattach_wc_new_customer_email', 11, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent sending the core WooCommerce new customer email.
|
||||
*/
|
||||
public static function remove_wc_new_customer_email() {
|
||||
remove_action( current_filter(), array( 'WC_Emails', 'send_transactional_email' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the Gifting new recipient user email. Overriding the core WooCommerce new customer email.
|
||||
*
|
||||
* @param int $customer_id The ID of the new customer being created.
|
||||
*/
|
||||
public static function send_new_recipient_user_email( $customer_id ) {
|
||||
self::generate_new_recipient_user_email( get_current_user_id(), $customer_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reattaches the core WooCommerce new customer email after sending the gifting new account email.
|
||||
*/
|
||||
public static function reattach_wc_new_customer_email() {
|
||||
add_action( current_filter(), array( 'WC_Emails', 'send_transactional_email' ) );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ class WCSG_Recipient_Management {
|
|||
add_action( 'woocommerce_subscription_status_updated', __CLASS__ . '::maybe_update_recipient_role', 10, 2 );
|
||||
|
||||
// Hooked onto priority 8 for compatibility with WooCommerce Memberships.
|
||||
add_action( 'woocommerce_order_status_completed', __CLASS__ . '::maybe_create_recipient', 8 );
|
||||
add_action( 'woocommerce_order_status_processing', __CLASS__ . '::maybe_create_recipient', 8 );
|
||||
add_action( 'woocommerce_order_status_completed', __CLASS__ . '::maybe_create_recipient', 8, 2 );
|
||||
add_action( 'woocommerce_order_status_processing', __CLASS__ . '::maybe_create_recipient', 8, 2 );
|
||||
|
||||
if ( wcsg_is_woocommerce_pre( '3.0' ) ) {
|
||||
add_action( 'woocommerce_add_order_item_meta', __CLASS__ . '::maybe_add_recipient_order_item_meta', 10, 2 );
|
||||
|
|
@ -619,12 +619,13 @@ class WCSG_Recipient_Management {
|
|||
* When orders are processed/completed, create new recipients and attach shipping information to gifted subscriptions.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param WC_Order $order Order object.
|
||||
*/
|
||||
public static function maybe_create_recipient( $order_id ) {
|
||||
public static function maybe_create_recipient( $order_id, ?WC_Order $order = null ) {
|
||||
$subscriptions = wcs_get_subscriptions_for_order( $order_id );
|
||||
|
||||
foreach( $subscriptions as $subscription ) {
|
||||
self::maybe_create_recipient_and_attach_shipping_information( $subscription );
|
||||
self::maybe_create_recipient_and_attach_shipping_information( $subscription, $order );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -632,8 +633,9 @@ class WCSG_Recipient_Management {
|
|||
* Maybe create a recipient user and attach shipping information to a subscription.
|
||||
*
|
||||
* @param WC_Subscription $subscription The subscription object.
|
||||
* @param WC_Order $order Order object.
|
||||
*/
|
||||
public static function maybe_create_recipient_and_attach_shipping_information( $subscription ) {
|
||||
public static function maybe_create_recipient_and_attach_shipping_information( $subscription, ?WC_Order $order = null ) {
|
||||
$recipient_user_email_address = $subscription->get_meta( '_recipient_user_email_address' );
|
||||
|
||||
if ( ! $recipient_user_email_address ) {
|
||||
|
|
@ -644,6 +646,7 @@ class WCSG_Recipient_Management {
|
|||
|
||||
// Create a new user if the recipient's email doesn't already exist.
|
||||
if ( ! $recipient_user_id ) {
|
||||
WCSG_Email::use_gifting_new_account_email();
|
||||
$recipient_user_id = WCS_Gifting::create_recipient_user( $recipient_user_email_address );
|
||||
}
|
||||
|
||||
|
|
@ -651,7 +654,7 @@ class WCSG_Recipient_Management {
|
|||
return;
|
||||
}
|
||||
|
||||
WCS_Gifting::set_recipient_user( $subscription, $recipient_user_id );
|
||||
WCS_Gifting::set_recipient_user( $subscription, $recipient_user_id, 'save', 0, $order );
|
||||
|
||||
$subscription->set_shipping_first_name( get_user_meta( $recipient_user_id, 'shipping_first_name', true ) );
|
||||
$subscription->set_shipping_last_name( get_user_meta( $recipient_user_id, 'shipping_last_name', true ) );
|
||||
|
|
@ -665,14 +668,4 @@ class WCSG_Recipient_Management {
|
|||
|
||||
$subscription->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach WooCommerce version dependent hooks
|
||||
*
|
||||
* @since 7.8.0 - Originally implemented in WooCommerce Subscriptions Gifting 1.0.1.
|
||||
* @deprecated 2.0.0
|
||||
*/
|
||||
public static function attach_dependant_hooks() {
|
||||
_deprecated_function( __METHOD__, '2.0.0', __CLASS__ . '::init()' );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,12 @@ class WCS_Retry_Manager {
|
|||
self::$setting_id = WC_Subscriptions_Admin::$option_prefix . '_enable_retry';
|
||||
self::$admin = new WCS_Retry_Admin( self::$setting_id );
|
||||
|
||||
// Show admin notice if the retry table is missing.
|
||||
add_action( 'admin_notices', array( __CLASS__, 'maybe_show_missing_table_notice' ) );
|
||||
|
||||
// Add debug tools to the WooCommerce > Status > Tools administration screen.
|
||||
add_filter( 'woocommerce_debug_tools', array( __CLASS__, 'add_retry_manager_debug_tools' ) );
|
||||
|
||||
if ( self::is_retry_enabled() ) {
|
||||
WCS_Retry_Email::init();
|
||||
|
||||
|
|
@ -525,4 +531,88 @@ class WCS_Retry_Manager {
|
|||
public static function init_store() {
|
||||
self::store()->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the payment retry table exists.
|
||||
*
|
||||
* @return bool True if the table exists, false otherwise.
|
||||
*/
|
||||
public static function retry_table_exists(): bool {
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . 'wcs_payment_retries';
|
||||
|
||||
return $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ) ) === $table_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an admin notice if the retry table is missing.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function maybe_show_missing_table_notice() {
|
||||
if (
|
||||
! current_user_can( 'manage_woocommerce' ) ||
|
||||
! self::is_retry_enabled() ||
|
||||
self::retry_table_exists()
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate the URL to the debug tool.
|
||||
$recreate_url = wp_nonce_url(
|
||||
admin_url( 'admin.php?page=wc-status&tab=tools&action=retry_manager' ),
|
||||
'debug_action'
|
||||
);
|
||||
|
||||
$message = sprintf(
|
||||
/* translators: %s: URL to recreate the table */
|
||||
__( 'The WooCommerce Subscriptions payment retry table is missing. This may affect the automatic payment retry functionality. <a href="%s">Click here to recreate the table</a>.', 'woocommerce-subscriptions' ),
|
||||
esc_url( $recreate_url )
|
||||
);
|
||||
|
||||
wcs_add_admin_notice( $message, 'error' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add retry manager debug tools to the WooCommerce > Status > Tools administration screen.
|
||||
*
|
||||
* @param array $tools The array of tools.
|
||||
* @return array The array of tools.
|
||||
*/
|
||||
public static function add_retry_manager_debug_tools( $tools ) {
|
||||
if ( ! self::is_retry_enabled() ) {
|
||||
return $tools;
|
||||
}
|
||||
|
||||
$tools['retry_manager'] = [
|
||||
'name' => __( 'Recreate subscriptions payment retry table', 'woocommerce-subscriptions' ),
|
||||
'button' => __( 'Recreate', 'woocommerce-subscriptions' ),
|
||||
'desc' => __( 'This tool will recreate the subscription payment retry table if it is missing.', 'woocommerce-subscriptions' ),
|
||||
'callback' => array( __CLASS__, 'recreate_payment_retry_table' ),
|
||||
];
|
||||
|
||||
return $tools;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recreate the payment retry table.
|
||||
*
|
||||
* @return string Informative string to show after the tool is triggered in UI.
|
||||
*/
|
||||
public static function recreate_payment_retry_table(): string {
|
||||
// Check if the table already exists.
|
||||
if ( self::retry_table_exists() ) {
|
||||
return __( 'The payment retry table already exists.', 'woocommerce-subscriptions' );
|
||||
}
|
||||
|
||||
// Create the table.
|
||||
if ( ! self::$table_maker ) {
|
||||
self::$table_maker = new WCS_Retry_Table_Maker();
|
||||
}
|
||||
|
||||
self::$table_maker->recreate_tables();
|
||||
|
||||
return __( 'Payment retry table has been successfully created.', 'woocommerce-subscriptions' );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1211,7 +1211,7 @@ class WC_Subscriptions_Switcher {
|
|||
public static function cart_contains_switches( $item_action = 'switch' ) {
|
||||
$subscription_switches = [];
|
||||
|
||||
if ( is_admin() && ( ! defined( 'DOING_AJAX' ) || false == DOING_AJAX ) ) {
|
||||
if ( is_admin() && ! wp_doing_ajax() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1312,7 +1312,12 @@ class WC_Subscriptions_Switcher {
|
|||
return;
|
||||
}
|
||||
|
||||
$subscription = wcs_get_subscription( $cart_item_data['subscription_switch']['subscription_id'] );
|
||||
$subscription = wcs_get_subscription( $cart_item_data['subscription_switch']['subscription_id'] );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$existing_item = wcs_get_order_item( $cart_item_data['subscription_switch']['item_id'], $subscription );
|
||||
$cart_item = WC()->cart->get_cart_item( $cart_item_key );
|
||||
|
||||
|
|
@ -1360,8 +1365,13 @@ class WC_Subscriptions_Switcher {
|
|||
}
|
||||
|
||||
$subscription = wcs_get_subscription( absint( $_GET['switch-subscription'] ) );
|
||||
$item_id = absint( $_GET['item'] );
|
||||
$item = wcs_get_order_item( $item_id, $subscription );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
throw new Exception( __( 'The subscription may have been deleted.', 'woocommerce-subscriptions' ) );
|
||||
}
|
||||
|
||||
$item_id = absint( $_GET['item'] );
|
||||
$item = wcs_get_order_item( $item_id, $subscription );
|
||||
|
||||
// Prevent switching to non-subscription product
|
||||
if ( ! WC_Subscriptions_Product::is_subscription( $product_id ) ) {
|
||||
|
|
@ -1438,6 +1448,10 @@ class WC_Subscriptions_Switcher {
|
|||
|
||||
$subscription = wcs_get_subscription( absint( $_GET['switch-subscription'] ) );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
throw new Exception( __( 'The subscription may have been deleted.', 'woocommerce-subscriptions' ) );
|
||||
}
|
||||
|
||||
// Requesting a switch for someone elses subscription
|
||||
if ( ! current_user_can( 'switch_shop_subscription', $subscription->get_id() ) ) {
|
||||
wc_add_notice( __( 'You can not switch this subscription. It appears you do not own the subscription.', 'woocommerce-subscriptions' ), 'error' );
|
||||
|
|
@ -1983,6 +1997,10 @@ class WC_Subscriptions_Switcher {
|
|||
// Subscription objects hold an internal cache of line items so we need to get an updated subscription object after changing the line item types directly in the database.
|
||||
$subscription = wcs_get_subscription( $subscription_id );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! empty( $add_note ) ) {
|
||||
$subscription->add_order_note( $add_note );
|
||||
}
|
||||
|
|
@ -2056,7 +2074,11 @@ class WC_Subscriptions_Switcher {
|
|||
$subscription->save();
|
||||
|
||||
// We just changed above the type of some items related to this subscription, so we need to reload it to get the newest items
|
||||
wcs_get_subscription( $subscription->get_id() )->calculate_totals();
|
||||
$refreshed_subscription = wcs_get_subscription( $subscription->get_id() );
|
||||
|
||||
if ( $refreshed_subscription ) {
|
||||
$refreshed_subscription->calculate_totals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2102,6 +2124,10 @@ class WC_Subscriptions_Switcher {
|
|||
|
||||
$subscription = wcs_get_subscription( $cart_item['subscription_switch']['subscription_id'] );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$is_manual_subscription = $subscription->is_manual();
|
||||
|
||||
// Check for $0 / period to a non-zero $ / period and manual subscription
|
||||
|
|
@ -2546,6 +2572,10 @@ class WC_Subscriptions_Switcher {
|
|||
|
||||
$subscription = wcs_get_subscription( $cart_item['subscription_switch']['subscription_id'] );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
! self::is_single_item_subscription( $subscription ) && (
|
||||
self::has_different_length( $recurring_cart, $subscription ) ||
|
||||
|
|
@ -2607,6 +2637,11 @@ class WC_Subscriptions_Switcher {
|
|||
}
|
||||
|
||||
$subscription = wcs_get_subscription( $cart_item['subscription_switch']['subscription_id'] );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$switch_order = $subscription->get_last_order( 'all', 'switch' );
|
||||
|
||||
if ( empty( $switch_order ) ) {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
575
phpstan.neon
575
phpstan.neon
|
|
@ -66,236 +66,6 @@ parameters:
|
|||
count: 3
|
||||
path: includes/api/class-wc-rest-subscriptions-controller.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_API_Subscriptions_Customers\\:\\:\\$base\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions-customers.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_API_Subscriptions_Customers\\:\\:\\$server\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions-customers.php
|
||||
|
||||
-
|
||||
message: "#^Access to constant READABLE on an unknown class WC_API_SERVER\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions-customers.php
|
||||
|
||||
-
|
||||
message: "#^Access to private property WooCommerce\\:\\:\\$api\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions-customers.php
|
||||
|
||||
-
|
||||
message: "#^Access to property \\$WC_API_Subscriptions on an unknown class WC_API\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions-customers.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_API_Subscriptions_Customers\\:\\:validate_request\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions-customers.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\$server of method WC_API_Subscriptions_Customers\\:\\:__construct\\(\\) has invalid type WC_API_Server\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions-customers.php
|
||||
|
||||
-
|
||||
message: "#^WC_API_Subscriptions_Customers\\:\\:__construct\\(\\) calls parent\\:\\:__construct\\(\\) but WC_API_Subscriptions_Customers does not extend any class\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions-customers.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_API_Subscriptions\\:\\:\\$post_type\\.$#"
|
||||
count: 7
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_API_Subscriptions\\:\\:\\$server\\.$#"
|
||||
count: 5
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WooCommerce\\:\\:\\$payment_gateways\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Access to constant ACCEPT_DATA on an unknown class WC_API_Server\\.$#"
|
||||
count: 4
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Access to constant CREATABLE on an unknown class WC_API_Server\\.$#"
|
||||
count: 2
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Access to constant DELETABLE on an unknown class WC_API_SERVER\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Access to constant DELETABLE on an unknown class WC_API_Server\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Access to constant EDITABLE on an unknown class WC_API_SERVER\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Access to constant EDITABLE on an unknown class WC_API_Server\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Access to constant READABLE on an unknown class WC_API_Server\\.$#"
|
||||
count: 7
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Access to private property WooCommerce\\:\\:\\$api\\.$#"
|
||||
count: 2
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Access to property \\$WC_API_Customers on an unknown class WC_API\\.$#"
|
||||
count: 2
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_API_Subscriptions\\:\\:create_order\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_API_Subscriptions\\:\\:create_order_note\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_API_Subscriptions\\:\\:delete\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_API_Subscriptions\\:\\:delete_order_note\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_API_Subscriptions\\:\\:edit_order\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_API_Subscriptions\\:\\:edit_order_note\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_API_Subscriptions\\:\\:get_order\\(\\)\\.$#"
|
||||
count: 2
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_API_Subscriptions\\:\\:get_order_note\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_API_Subscriptions\\:\\:get_order_notes\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_API_Subscriptions\\:\\:get_orders_count\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_API_Subscriptions\\:\\:is_readable\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_API_Subscriptions\\:\\:merge_query_args\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_API_Subscriptions\\:\\:validate_request\\(\\)\\.$#"
|
||||
count: 4
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to method getCode\\(\\) on an unknown class WC_API_Exception\\.$#"
|
||||
count: 2
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to method getErrorCode\\(\\) on an unknown class WC_API_Exception\\.$#"
|
||||
count: 2
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Call to method getMessage\\(\\) on an unknown class WC_API_Exception\\.$#"
|
||||
count: 2
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Caught class WC_API_Exception not found\\.$#"
|
||||
count: 2
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Default value of the parameter \\#4 \\$page \\(int\\) of method WC_API_Subscriptions\\:\\:get_subscriptions\\(\\) is incompatible with type null\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Instantiated class WC_API_Exception not found\\.$#"
|
||||
count: 6
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^PHPDoc tag @param has invalid value \\(array data raw order data\\)\\: Unexpected token \"data\", expected variable at offset 67$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^PHPDoc tag @param references unknown parameter\\: \\$fields$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^PHPDoc tag @param references unknown parameter\\: \\$id$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^is_wp_error\\(WC_Subscription\\) will always evaluate to false\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-api-subscriptions.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WooCommerce\\:\\:\\$payment_gateways\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-rest-subscriptions-controller.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined static method WC_REST_Orders_Controller\\:\\:create_order\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-rest-subscriptions-controller.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined static method WC_REST_Orders_Controller\\:\\:update_order\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/api/legacy/class-wc-rest-subscriptions-controller.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WC_Order_Item\\:\\:get_product\\(\\)\\.$#"
|
||||
count: 1
|
||||
|
|
@ -1416,351 +1186,6 @@ parameters:
|
|||
count: 1
|
||||
path: includes/core/gateways/paypal/includes/templates/html-ipn-failure-notice.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Subscription_Legacy\\:\\:\\$product_custom_fields\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Subscription_Legacy\\:\\:\\$product_type\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Subscription_Legacy\\:\\:\\$subscription_limit\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Subscription_Legacy\\:\\:\\$subscription_one_time_shipping\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Subscription_Legacy\\:\\:\\$subscription_payment_sync_date\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Subscription_Variation_Legacy\\:\\:\\$parent_product_type\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-subscription-variation-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Subscription_Variation_Legacy\\:\\:\\$product_type\\.$#"
|
||||
count: 2
|
||||
path: includes/core/legacy/class-wc-product-subscription-variation-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Subscription_Variation_Legacy\\:\\:\\$variation_id\\.$#"
|
||||
count: 2
|
||||
path: includes/core/legacy/class-wc-product-subscription-variation-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Subscription_Variation_Legacy\\:\\:\\$variation_inherited_meta_data\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-subscription-variation-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Subscription_Variation_Legacy\\:\\:\\$variation_level_meta_data\\.$#"
|
||||
count: 3
|
||||
path: includes/core/legacy/class-wc-product-subscription-variation-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Method WC_Product_Subscription_Variation\\:\\:__construct\\(\\) invoked with 2 parameters, 0\\-1 required\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-subscription-variation-legacy.php
|
||||
|
||||
-
|
||||
message: "#^PHPDoc tag @param references unknown parameter\\: \\$key$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-subscription-variation-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property \\$this\\(WC_Product_Variable_Subscription_Legacy\\)\\:\\:\\$max_variation_price\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property \\$this\\(WC_Product_Variable_Subscription_Legacy\\)\\:\\:\\$min_variation_regular_price\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property \\$this\\(WC_Product_Variable_Subscription_Legacy\\)\\:\\:\\$subscription_length\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property \\$this\\(WC_Product_Variable_Subscription_Legacy\\)\\:\\:\\$subscription_sign_up_fee\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property \\$this\\(WC_Product_Variable_Subscription_Legacy\\)\\:\\:\\$subscription_trial_length\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property \\$this\\(WC_Product_Variable_Subscription_Legacy\\)\\:\\:\\$subscription_trial_period\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Variable_Subscription_Legacy\\:\\:\\$max_variation_price\\.$#"
|
||||
count: 2
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Variable_Subscription_Legacy\\:\\:\\$min_variation_price\\.$#"
|
||||
count: 2
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Variable_Subscription_Legacy\\:\\:\\$min_variation_regular_price\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Variable_Subscription_Legacy\\:\\:\\$parent_product_type\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Variable_Subscription_Legacy\\:\\:\\$product_custom_fields\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Variable_Subscription_Legacy\\:\\:\\$subscription_length\\.$#"
|
||||
count: 2
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Variable_Subscription_Legacy\\:\\:\\$subscription_limit\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Variable_Subscription_Legacy\\:\\:\\$subscription_one_time_shipping\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Variable_Subscription_Legacy\\:\\:\\$subscription_payment_sync_date\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Variable_Subscription_Legacy\\:\\:\\$subscription_sign_up_fee\\.$#"
|
||||
count: 2
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Variable_Subscription_Legacy\\:\\:\\$subscription_trial_length\\.$#"
|
||||
count: 2
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Product_Variable_Subscription_Legacy\\:\\:\\$subscription_trial_period\\.$#"
|
||||
count: 2
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method WooCommerce\\:\\:clear_product_transients\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Method WC_Product_Variable_Subscription_Legacy\\:\\:get_price_hash\\(\\) invoked with 2 parameters, 0\\-1 required\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^PHPDoc tag @param has invalid value \\(WC_Product\\)\\: Unexpected token \"\\\\n\\\\t \\* \", expected variable at offset 318$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^PHPDoc tag @param references unknown parameter\\: \\$include_taxes$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-product-variable-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$billing_address_1\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$billing_address_2\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$billing_city\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$billing_company\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$billing_country\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$billing_email\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$billing_first_name\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$billing_last_name\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$billing_phone\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$billing_postcode\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$billing_state\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$customer_note\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$order_key\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$payment_method\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$payment_method_title\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$post\\.$#"
|
||||
count: 13
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$post_status\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$prices_include_tax\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$shipping_address_1\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$shipping_address_2\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$shipping_city\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$shipping_company\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$shipping_country\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$shipping_first_name\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$shipping_last_name\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$shipping_postcode\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property WC_Subscription_Legacy\\:\\:\\$shipping_state\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Default value of the parameter \\#3 \\$meta_id \\(string\\) of method WC_Subscription_Legacy\\:\\:update_meta_data\\(\\) is incompatible with type int\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^Method WC_Subscription_Legacy\\:\\:set_last_order_date\\(\\) should return WC_DateTime\\|null but return statement is missing\\.$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^PHPDoc tag @param has invalid value \\(array\\|int Either an order item \\(in the array format returned by self\\:\\:get_items\\(\\)\\) or the ID of an order item\\.\\)\\: Unexpected token \"Either\", expected variable at offset 399$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^PHPDoc tag @param has invalid value \\(int\\)\\: Unexpected token \"\\\\n\\\\t \", expected variable at offset 61$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^PHPDoc tag @param has invalid value \\(string\\)\\: Unexpected token \"\\\\n\\\\t \\* \", expected variable at offset 555$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^PHPDoc tag @param has invalid value \\(string\\)\\: Unexpected token \"\\\\n\\\\t \\* \", expected variable at offset 573$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^PHPDoc tag @param has invalid value \\(string\\|integer\\|object\\)\\: Unexpected token \"\\\\n\\\\t \\* \", expected variable at offset 203$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wc-subscription-legacy.php
|
||||
|
||||
-
|
||||
message: "#^PHPDoc tag @param references unknown parameter\\: \\$product$#"
|
||||
count: 1
|
||||
path: includes/core/legacy/class-wcs-array-property-post-meta-black-magic.php
|
||||
|
||||
-
|
||||
message: "#^Function as_next_scheduled_action not found\\.$#"
|
||||
count: 3
|
||||
|
|
|
|||
|
|
@ -0,0 +1,256 @@
|
|||
// This data is sent under ['extensions']['wc_subscriptions].
|
||||
{
|
||||
|
||||
generation_timestamp: 1704067200, // int - unix timestamp when this data was generated
|
||||
total_generation_time: 342.56, // float - time taken to generate this data in milliseconds
|
||||
telemetry_cache: "miss" // string - hit|miss. Cache status - "hit" if from cache, "miss" if freshly generated
|
||||
|
||||
// --- Orders data
|
||||
order_trends: {
|
||||
|
||||
by_order_type: { // object - monthly order data grouped by order type
|
||||
store_gross: [ // array - store's total GMV (all orders, not just subscription-related)
|
||||
{
|
||||
month: "2025-01", // string - YYYY-MM format
|
||||
gross: 1250.50, // float - total value of all orders in this month
|
||||
},
|
||||
{
|
||||
month: "2025-02",
|
||||
gross: 1500.75,
|
||||
},
|
||||
// ... more months
|
||||
],
|
||||
|
||||
initial: [ // array - parent orders (orders that created subscriptions)
|
||||
{
|
||||
month: "2025-01", // string - YYYY-MM format
|
||||
count: 15, // int - count of initial orders in this month
|
||||
gross: 750.00, // float - total value of initial orders in this month
|
||||
non_zero_count: 12, // int - count of initial orders with non-zero total in this month
|
||||
quantity: 20, // int - total quantity of items in initial orders in this month
|
||||
non_zero_quantity: 18, // int - total quantity of items in non-zero initial orders in this month
|
||||
},
|
||||
{
|
||||
month: "2025-02",
|
||||
count: 18,
|
||||
gross: 900.00,
|
||||
non_zero_count: 15,
|
||||
quantity: 24,
|
||||
non_zero_quantity: 22,
|
||||
},
|
||||
// ... more months
|
||||
],
|
||||
|
||||
renewal: [ // array - renewal orders (recurring subscription payments)
|
||||
{
|
||||
month: "2025-01",
|
||||
count: 10,
|
||||
gross: 500.00,
|
||||
non_zero_count: 8,
|
||||
},
|
||||
{
|
||||
month: "2025-02",
|
||||
count: 12,
|
||||
gross: 600.00,
|
||||
non_zero_count: 10,
|
||||
},
|
||||
// ... more months
|
||||
],
|
||||
|
||||
switch: [ // array - switch orders (subscription product changes)
|
||||
{
|
||||
month: "2025-01",
|
||||
count: 5,
|
||||
gross: 250.00,
|
||||
non_zero_count: 4,
|
||||
},
|
||||
// ... more months
|
||||
],
|
||||
|
||||
resubscribe: [ // array - resubscribe orders (reactivated cancelled subscriptions)
|
||||
{
|
||||
month: "2025-01",
|
||||
count: 2,
|
||||
gross: 100.00,
|
||||
non_zero_count: 2,
|
||||
},
|
||||
// ... more months
|
||||
],
|
||||
},
|
||||
|
||||
by_payment_gateway: { // object - monthly order data grouped by payment gateway
|
||||
stripe: [ // string key - payment gateway identifier (empty string for none)
|
||||
{
|
||||
month: "2024-01", // string - YYYY-MM format
|
||||
count: 145, // int - count of orders for this gateway in this month
|
||||
gross: 12345.67, // float - total value of orders for this gateway in this month
|
||||
},
|
||||
{
|
||||
month: "2024-02",
|
||||
count: 150,
|
||||
gross: 13500.00,
|
||||
},
|
||||
// ... more months for this gateway
|
||||
],
|
||||
paypal: [
|
||||
{
|
||||
month: "2024-01",
|
||||
count: 30,
|
||||
gross: 2500.00,
|
||||
},
|
||||
// ... more months for this gateway
|
||||
],
|
||||
"": [ // empty string key represents orders with no payment method
|
||||
{
|
||||
month: "2024-01",
|
||||
count: 5,
|
||||
gross: 0.00,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
// --- Subscription products data
|
||||
products: {
|
||||
|
||||
frequencies: [ // array of objects - billing frequencies for published subscription products
|
||||
{
|
||||
period: "month", // string - 'day'|'week'|'month'|'year'
|
||||
interval: 1, // int - billing interval (1, 2, 3, etc.)
|
||||
count: 45 // int - count of products with this frequency
|
||||
},
|
||||
{
|
||||
period: "month",
|
||||
interval: 3,
|
||||
count: 12
|
||||
},
|
||||
// ... more period/interval combinations
|
||||
],
|
||||
|
||||
giftable: 23, // int - count of active products eligible for gifting
|
||||
},
|
||||
|
||||
// --- Subscriptions data
|
||||
subscriptions: {
|
||||
|
||||
gifted: 15, // int - count of gifted subscriptions
|
||||
renewing_automatically: 185, // int - count of active subscriptions renewing automatically
|
||||
renewing_manually: 15, // int - count of active subscriptions requiring manual renewal
|
||||
subscriber_count: 142, // int - count of unique customers with at least one active subscription
|
||||
|
||||
payment_methods: [ // array of objects - active subscriptions grouped by payment gateway
|
||||
{
|
||||
payment_method: "stripe", // string - payment gateway identifier (empty string for none)
|
||||
active_subscription_count: 127, // int - count of active subscriptions
|
||||
inactive_subscription_count: 36, // int - count of inactive subscriptions
|
||||
method_renews_off_site: "yes", // string - 'yes'|'no'|'unknown'. Whether the payment gateway supports "gateway_scheduled_payments"
|
||||
manual_renewal_only: "no", // string - 'yes'|'no'|'unknown'. Whether the payment gateway supports "subscriptions"
|
||||
},
|
||||
{
|
||||
payment_method: "", // empty string represents subscriptions with no payment method
|
||||
active_subscription_count: 58,
|
||||
inactive_subscription_count: 14,
|
||||
method_renews_off_site: "unknown", // "unknown" used when the paymeny gateway associated with the subscription isn't found in WC_Payment_Gateways
|
||||
manual_renewal_only: "unknown",
|
||||
}
|
||||
// ... more payment gateways
|
||||
],
|
||||
|
||||
renewal_frequencies: [ // array of objects - billing frequencies for active subscriptions
|
||||
{
|
||||
period: "month", // string - 'day'|'week'|'month'|'year'
|
||||
interval: 1, // int - billing interval (1, 2, 3, etc.)
|
||||
count: 150 // int - count of subscriptions with this frequency
|
||||
},
|
||||
{
|
||||
period: "month",
|
||||
interval: 3,
|
||||
count: 35
|
||||
},
|
||||
// ... more period/interval combinations
|
||||
],
|
||||
|
||||
// --- Legacy subscriptions data
|
||||
// Subscription dates
|
||||
first: "2023-01-15 10:23:45", // string - date of first subscription in 'Y-m-d H:i:s' format, or '-' if none
|
||||
last: "2024-12-28 16:42:12", // string - date of last subscription in 'Y-m-d H:i:s' format, or '-' if none
|
||||
|
||||
// Subscription counts by status
|
||||
"wc-active": "387", // string - count of active subscriptions
|
||||
"wc-on-hold": "23", // string - count of on-hold subscriptions
|
||||
"wc-pending": "12", // string - count of pending subscriptions
|
||||
"wc-cancelled": "145", // string - count of cancelled subscriptions
|
||||
"wc-expired": "67", // string - count of expired subscriptions
|
||||
"wc-pending-cancel": "5", // string - count of pending cancellation subscriptions
|
||||
"wc-switched": "0", // string - count of switched subscriptions
|
||||
},
|
||||
|
||||
// --- Legacy subscription orders data
|
||||
subscription_orders: {
|
||||
initial_count: "523", // string - count of initial orders
|
||||
initial_gross: "45234.50", // string - total gross for initial orders
|
||||
|
||||
switch_count: "78", // string - count of switch orders
|
||||
switch_gross: "3421.25", // string - total gross for switch orders
|
||||
|
||||
renewal_count: "1247", // string - count of renewal orders
|
||||
renewal_gross: "89234.75", // string - total gross for renewal orders
|
||||
|
||||
resubscribe_count: "34", // string - count of resubscribe orders
|
||||
resubscribe_gross: "2156.00", // string - total gross for resubscribe orders
|
||||
},
|
||||
|
||||
// --- Settings data
|
||||
settings: {
|
||||
// Staging and live site
|
||||
wc_subscriptions_staging: "live", // string - 'staging'|'live'
|
||||
wc_subscriptions_live_url: "https://example.com", // string - URL of live site
|
||||
|
||||
// Button text
|
||||
add_to_cart_button_text: "Sign up now", // string - Add to Cart Button Text
|
||||
order_button_text: "Sign up now", // string - Place Order Button Text
|
||||
|
||||
// Roles
|
||||
subscriber_role: "subscriber", // string - Subscriber Default Role
|
||||
cancelled_role: "customer", // string - Inactive Subscriber Role
|
||||
|
||||
// Renewals
|
||||
accept_manual_renewals: "no", // string - Accept Manual Renewals
|
||||
turn_off_automatic_payments: "none", // string - Turn off Automatic Payments
|
||||
enable_auto_renewal_toggle: "no", // string - Auto Renewal Toggle
|
||||
|
||||
// Early renewal
|
||||
enable_early_renewal: "yes", // string - Accept Early Renewal Payments
|
||||
enable_early_renewal_via_modal: "yes", // string - Accept Early Renewal Payments via a Modal
|
||||
|
||||
// Switching
|
||||
allow_switching: "no", // string - Between Subscription Variations and Between Grouped Subscriptions
|
||||
apportion_recurring_price: "none", // string - Prorate Recurring Payment
|
||||
apportion_sign_up_fee: "none", // string - Prorate Sign up Fee
|
||||
apportion_length: "none", // string - Prorate Subscription Length
|
||||
switch_button_text: "Upgrade or Downgrade", // string - Switch Button Text
|
||||
|
||||
// Gifting
|
||||
gifting_enable_gifting: "no", // string - Enable gifting
|
||||
gifting_default_option: "none", // string - Default gifting option
|
||||
gifting_gifting_checkbox_text: "This is a gift", // string - Gifting Checkbox Text
|
||||
gifting_downloadable_products: "no", // string - Downloadable Products
|
||||
|
||||
// Synchronization
|
||||
sync_payments: "no", // string - Synchronise renewals
|
||||
prorate_synced_payments: "none", // string - Prorate First Renewal
|
||||
days_no_fee: "none", // string - Sign-up grace period
|
||||
|
||||
// Miscellaneous
|
||||
max_customer_suspensions: "0", // string - Customer Suspensions
|
||||
multiple_purchase: "no", // string - Mixed Checkout
|
||||
allow_zero_initial_order_without_payment_method: "no", // string - $0 Initial Checkout
|
||||
drip_downloadable_content_on_renewal: "no", // string - Drip Downloadable Content
|
||||
enable_retry: "yes", // string - Retry Failed Payments
|
||||
|
||||
// Notifications
|
||||
enable_notification_reminders: "no", // string - Enable Reminders
|
||||
customer_notifications_offset_number: "none", // string - Reminder Timing (number)
|
||||
customer_notifications_offset_unit: "none", // string - Reminder Timing (unit)
|
||||
},
|
||||
}
|
||||
|
|
@ -63,7 +63,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
echo esc_html( wc_get_order_status_name( $order->get_status() ) );
|
||||
if ( ! in_array( $order->get_status(), apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $order ), true ) ) {
|
||||
if ( get_current_user_id() != $order->get_user_id() ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
|
||||
echo '</br><small>' . esc_html( 'Purchased by ' . $order->get_user()->display_name ) . '</small>';
|
||||
echo '<br><small>' . esc_html( 'Purchased by ' . $order->get_user()->display_name ) . '</small>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ $include_item_removal_links = $include_switch_links = false;
|
|||
'<strong>' . esc_html( date_i18n( wc_date_format(), $subscription->get_time( 'next_payment', 'site' ) ) ) . '</strong>'
|
||||
) );
|
||||
}?>
|
||||
</br>
|
||||
<br>
|
||||
<?php echo wp_kses_post( sprintf(
|
||||
__( 'Want to renew early via the checkout? Click %shere.%s', 'woocommerce-subscriptions' ),
|
||||
'<a href="' . esc_url( wcs_get_early_renewal_url( $subscription ) ) . '">',
|
||||
|
|
|
|||
|
|
@ -14,10 +14,7 @@ if (PHP_VERSION_ID < 50600) {
|
|||
echo $err;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
$err,
|
||||
E_USER_ERROR
|
||||
);
|
||||
throw new RuntimeException($err);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
|
|
|||
|
|
@ -26,12 +26,23 @@ use Composer\Semver\VersionParser;
|
|||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
|
||||
* @internal
|
||||
*/
|
||||
private static $selfDir = null;
|
||||
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private static $installedIsLocalDir;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
|
|
@ -309,6 +320,24 @@ class InstalledVersions
|
|||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
|
||||
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
|
||||
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
|
||||
// so we have to assume it does not, and that may result in duplicate data being returned when listing
|
||||
// all installed packages for example
|
||||
self::$installedIsLocalDir = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private static function getSelfDir()
|
||||
{
|
||||
if (self::$selfDir === null) {
|
||||
self::$selfDir = strtr(__DIR__, '\\', '/');
|
||||
}
|
||||
|
||||
return self::$selfDir;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -322,19 +351,27 @@ class InstalledVersions
|
|||
}
|
||||
|
||||
$installed = array();
|
||||
$copiedLocalDir = false;
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
$selfDir = self::getSelfDir();
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
$vendorDir = strtr($vendorDir, '\\', '/');
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require $vendorDir.'/composer/installed.php';
|
||||
$installed[] = self::$installedByVendor[$vendorDir] = $required;
|
||||
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||
self::$installed = $installed[count($installed) - 1];
|
||||
self::$installedByVendor[$vendorDir] = $required;
|
||||
$installed[] = $required;
|
||||
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
|
||||
self::$installed = $required;
|
||||
self::$installedIsLocalDir = true;
|
||||
}
|
||||
}
|
||||
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
|
||||
$copiedLocalDir = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -350,7 +387,7 @@ class InstalledVersions
|
|||
}
|
||||
}
|
||||
|
||||
if (self::$installed !== array()) {
|
||||
if (self::$installed !== array() && !$copiedLocalDir) {
|
||||
$installed[] = self::$installed;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -137,4 +137,10 @@ return array(
|
|||
'WCSG_Recipient_Management' => $baseDir . '/includes/gifting/class-wcsg-recipient-management.php',
|
||||
'WCSG_Template_Loader' => $baseDir . '/includes/gifting/class-wcsg-template-loader.php',
|
||||
'WCS_Gifting' => $baseDir . '/includes/gifting/class-wcs-gifting.php',
|
||||
'WC_Subscription_Downloads' => $baseDir . '/includes/downloads/class-wc-subscription-downloads.php',
|
||||
'WC_Subscription_Downloads_Ajax' => $baseDir . '/includes/downloads/class-wc-subscription-downloads-ajax.php',
|
||||
'WC_Subscription_Downloads_Install' => $baseDir . '/includes/downloads/class-wc-subscription-downloads-install.php',
|
||||
'WC_Subscription_Downloads_Order' => $baseDir . '/includes/downloads/class-wc-subscription-downloads-order.php',
|
||||
'WC_Subscription_Downloads_Products' => $baseDir . '/includes/downloads/class-wc-subscription-downloads-products.php',
|
||||
'WC_Subscription_Downloads_Settings' => $baseDir . '/includes/downloads/class-wc-subscription-downloads-settings.php',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,22 +7,22 @@ namespace Composer\Autoload;
|
|||
class ComposerStaticInitcb45de1ca955f89ec737c442c7cf101c
|
||||
{
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'C' =>
|
||||
'C' =>
|
||||
array (
|
||||
'Composer\\Installers\\' => 20,
|
||||
),
|
||||
'A' =>
|
||||
'A' =>
|
||||
array (
|
||||
'Automattic\\WooCommerce_Subscriptions\\' => 37,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'Composer\\Installers\\' =>
|
||||
'Composer\\Installers\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers',
|
||||
),
|
||||
'Automattic\\WooCommerce_Subscriptions\\' =>
|
||||
'Automattic\\WooCommerce_Subscriptions\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/../..' . '/src',
|
||||
),
|
||||
|
|
@ -160,6 +160,12 @@ class ComposerStaticInitcb45de1ca955f89ec737c442c7cf101c
|
|||
'WCSG_Recipient_Management' => __DIR__ . '/../..' . '/includes/gifting/class-wcsg-recipient-management.php',
|
||||
'WCSG_Template_Loader' => __DIR__ . '/../..' . '/includes/gifting/class-wcsg-template-loader.php',
|
||||
'WCS_Gifting' => __DIR__ . '/../..' . '/includes/gifting/class-wcs-gifting.php',
|
||||
'WC_Subscription_Downloads' => __DIR__ . '/../..' . '/includes/downloads/class-wc-subscription-downloads.php',
|
||||
'WC_Subscription_Downloads_Ajax' => __DIR__ . '/../..' . '/includes/downloads/class-wc-subscription-downloads-ajax.php',
|
||||
'WC_Subscription_Downloads_Install' => __DIR__ . '/../..' . '/includes/downloads/class-wc-subscription-downloads-install.php',
|
||||
'WC_Subscription_Downloads_Order' => __DIR__ . '/../..' . '/includes/downloads/class-wc-subscription-downloads-order.php',
|
||||
'WC_Subscription_Downloads_Products' => __DIR__ . '/../..' . '/includes/downloads/class-wc-subscription-downloads-products.php',
|
||||
'WC_Subscription_Downloads_Settings' => __DIR__ . '/../..' . '/includes/downloads/class-wc-subscription-downloads-settings.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => 'woocommerce/woocommerce-subscriptions',
|
||||
'pretty_version' => 'dev-release/8.0.0',
|
||||
'version' => 'dev-release/8.0.0',
|
||||
'reference' => 'fae6f1f47d4716196c53f3d73845d84afd815c63',
|
||||
'pretty_version' => 'dev-release/8.1.0',
|
||||
'version' => 'dev-release/8.1.0',
|
||||
'reference' => '073151600fa05dc26b7244faf4808c0f49e63436',
|
||||
'type' => 'wordpress-plugin',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
|
|
@ -29,9 +29,9 @@
|
|||
'dev_requirement' => false,
|
||||
),
|
||||
'woocommerce/woocommerce-subscriptions' => array(
|
||||
'pretty_version' => 'dev-release/8.0.0',
|
||||
'version' => 'dev-release/8.0.0',
|
||||
'reference' => 'fae6f1f47d4716196c53f3d73845d84afd815c63',
|
||||
'pretty_version' => 'dev-release/8.1.0',
|
||||
'version' => 'dev-release/8.1.0',
|
||||
'reference' => '073151600fa05dc26b7244faf4808c0f49e63436',
|
||||
'type' => 'wordpress-plugin',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@ if ($issues) {
|
|||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
throw new \RuntimeException(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@
|
|||
* Description: Sell products and services with recurring payments in your WooCommerce Store.
|
||||
* Author: WooCommerce
|
||||
* Author URI: https://woocommerce.com/
|
||||
* Version: 8.0.0
|
||||
* Version: 8.1.0
|
||||
* Requires Plugins: woocommerce
|
||||
*
|
||||
* WC requires at least: 10.1.0
|
||||
* WC requires at least: 10.2.0
|
||||
* WC tested up to: 10.3.0
|
||||
* Requires PHP: 7.4
|
||||
*
|
||||
|
|
@ -47,6 +47,15 @@ add_action(
|
|||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_init',
|
||||
function () {
|
||||
// Overrides the WooCommerce version to the WC()->version.
|
||||
// This prevents the wrong version being stored in the transient during a WooCommerce core downgrade.
|
||||
set_transient( 'wcs_woocommerce_active_version', WC()->version, HOUR_IN_SECONDS );
|
||||
}
|
||||
);
|
||||
|
||||
// Subscribe to automated translations.
|
||||
add_filter( 'woocommerce_translations_updates_for_woocommerce-subscriptions', '__return_true' );
|
||||
|
||||
|
|
@ -75,7 +84,7 @@ class WC_Subscriptions {
|
|||
public static $plugin_file = __FILE__;
|
||||
|
||||
/** @var string */
|
||||
public static $version = '8.0.0'; // WRCS: DEFINED_VERSION.
|
||||
public static $version = '8.1.0'; // WRCS: DEFINED_VERSION.
|
||||
|
||||
/** @var string */
|
||||
public static $wc_minimum_supported_version = '7.7';
|
||||
|
|
|
|||
Loading…
Reference in New Issue