Updates to 7.5.0
19
.wp-env.json
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": [
|
|
||||||
"https://downloads.wordpress.org/plugin/woocommerce.zip",
|
|
||||||
"https://downloads.wordpress.org/plugin/email-log.zip",
|
|
||||||
"https://github.com/woocommerce/woocommerce-gateway-dummy/releases/download/1.0.9/woocommerce-gateway-dummy.zip",
|
|
||||||
".",
|
|
||||||
"./tests/e2e/test-configuration-plugin"
|
|
||||||
],
|
|
||||||
"themes": [
|
|
||||||
"https://downloads.wordpress.org/theme/storefront.zip"
|
|
||||||
],
|
|
||||||
"env": {
|
|
||||||
"tests": {
|
|
||||||
"mappings": {
|
|
||||||
"wp-cli.yml": "./tests/e2e/bin/wp-cli.yml"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -90,3 +90,46 @@
|
|||||||
font-size: 1.4em;
|
font-size: 1.4em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.woocommerce-subscriptions-related-orders-pagination-links.woocommerce-pagination {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-subscriptions-related-orders-pagination-links .pagination-links a {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-subscriptions-related-orders-pagination-links .pagination-links a.disabled:hover {
|
||||||
|
cursor: default;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-subscriptions-related-orders-pagination-links .pagination-links a .symbol {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rtl .woocommerce-subscriptions-related-orders-pagination-links {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rtl .woocommerce-subscriptions-related-orders-pagination-links .pagination-links {
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media ( max-width: 30em ) {
|
||||||
|
.woocommerce-subscriptions-related-orders-pagination-links .pagination-links a {
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-subscriptions-related-orders-pagination-links .pagination-links a .label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-subscriptions-related-orders-pagination-links .pagination-links a .symbol {
|
||||||
|
display: inherit;
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 885 B After Width: | Height: | Size: 885 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 122 KiB |
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 109 KiB |
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 133 KiB |
Before Width: | Height: | Size: 172 KiB After Width: | Height: | Size: 172 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 250 KiB After Width: | Height: | Size: 250 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
134
assets/src/js/filters/index.js
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
|
import { registerCheckoutFilters } from '@woocommerce/blocks-checkout';
|
||||||
|
import { getSetting } from '@woocommerce/settings';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import {
|
||||||
|
getSwitchString,
|
||||||
|
isOneOffSubscription,
|
||||||
|
getBillingFrequencyString,
|
||||||
|
} from '../utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the filter integration API, it uses registerCheckoutFilters
|
||||||
|
* to register its filters, each filter is a key: function pair.
|
||||||
|
* The key the filter name, and the function is the filter.
|
||||||
|
*
|
||||||
|
* Each filter function is passed the previous (or default) value in that filter
|
||||||
|
* as the first parameter, the second parameter is a object of 3PD registered data.
|
||||||
|
* For WCS, we register out data with key `subscriptions`.
|
||||||
|
* Filters must return the previous value or a new value with the same type.
|
||||||
|
* If an error is thrown, it would be visible for store managers only.
|
||||||
|
*/
|
||||||
|
export const registerFilters = () => {
|
||||||
|
registerCheckoutFilters( 'woocommerce-subscriptions', {
|
||||||
|
// subscriptions data here comes from register_endpoint_data /cart registration.
|
||||||
|
totalLabel: ( label, { subscriptions } ) => {
|
||||||
|
if ( 0 < subscriptions?.length ) {
|
||||||
|
return __( 'Total due today', 'woocommerce-subscriptions' );
|
||||||
|
}
|
||||||
|
return label;
|
||||||
|
},
|
||||||
|
// subscriptions data here comes from register_endpoint_data /cart/items registration.
|
||||||
|
subtotalPriceFormat: ( label, { subscriptions } ) => {
|
||||||
|
if (
|
||||||
|
subscriptions?.billing_period &&
|
||||||
|
subscriptions?.billing_interval
|
||||||
|
) {
|
||||||
|
const {
|
||||||
|
billing_interval: billingInterval,
|
||||||
|
subscription_length: subscriptionLength,
|
||||||
|
} = subscriptions;
|
||||||
|
// We check if we have a length and its equal or less to the billing interval.
|
||||||
|
// When this is true, it means we don't have a next payment date.
|
||||||
|
if (
|
||||||
|
isOneOffSubscription( {
|
||||||
|
subscriptionLength,
|
||||||
|
billingInterval,
|
||||||
|
} )
|
||||||
|
) {
|
||||||
|
// An edge case when length is 1 so it doesn't have a length prefix
|
||||||
|
if ( 1 === subscriptionLength ) {
|
||||||
|
return getBillingFrequencyString(
|
||||||
|
subscriptions,
|
||||||
|
// translators: the word used to describe billing frequency, e.g. "for" 1 day or "for" 1 month.
|
||||||
|
__( 'for 1', 'woocommerce-subscriptions' ),
|
||||||
|
label
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return getBillingFrequencyString(
|
||||||
|
subscriptions,
|
||||||
|
// translators: the word used to describe billing frequency, e.g. "for" 6 days or "for" 2 weeks.
|
||||||
|
__( 'for', 'woocommerce-subscriptions' ),
|
||||||
|
label
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return getBillingFrequencyString(
|
||||||
|
subscriptions,
|
||||||
|
// translators: the word used to describe billing frequency, e.g. "every" 6 days or "every" 2 weeks.
|
||||||
|
__( 'every', 'woocommerce-subscriptions' ),
|
||||||
|
label
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return label;
|
||||||
|
},
|
||||||
|
saleBadgePriceFormat: ( label, { subscriptions } ) => {
|
||||||
|
if (
|
||||||
|
subscriptions?.billing_period &&
|
||||||
|
subscriptions?.billing_interval
|
||||||
|
) {
|
||||||
|
return getBillingFrequencyString( subscriptions, '/', label );
|
||||||
|
}
|
||||||
|
return label;
|
||||||
|
},
|
||||||
|
itemName: ( name, { subscriptions } ) => {
|
||||||
|
if ( subscriptions?.is_resubscribe ) {
|
||||||
|
return sprintf(
|
||||||
|
// translators: %s Product name.
|
||||||
|
__( '%s (resubscription)', 'woocommerce-subscriptions' ),
|
||||||
|
name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ( subscriptions?.switch_type ) {
|
||||||
|
return sprintf(
|
||||||
|
// translators: %1$s Product name, %2$s Switch type (upgraded, downgraded, or crossgraded).
|
||||||
|
__( '%1$s (%2$s)', 'woocommerce-subscriptions' ),
|
||||||
|
name,
|
||||||
|
getSwitchString( subscriptions.switch_type )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
},
|
||||||
|
cartItemPrice: ( pricePlaceholder, { subscriptions }, { context } ) => {
|
||||||
|
if ( subscriptions?.sign_up_fees ) {
|
||||||
|
return 'cart' === context
|
||||||
|
? sprintf(
|
||||||
|
/* translators: %s is the subscription price to pay immediately (ie: $10). */
|
||||||
|
__( 'Due today %s', 'woocommerce-subscriptions' ),
|
||||||
|
pricePlaceholder
|
||||||
|
)
|
||||||
|
: sprintf(
|
||||||
|
/* translators: %s is the subscription price to pay immediately (ie: $10). */
|
||||||
|
__( '%s due today', 'woocommerce-subscriptions' ),
|
||||||
|
pricePlaceholder
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pricePlaceholder;
|
||||||
|
},
|
||||||
|
placeOrderButtonLabel: ( label ) => {
|
||||||
|
const subscriptionsData = getSetting( 'subscriptions_data' );
|
||||||
|
|
||||||
|
if ( subscriptionsData?.place_order_override ) {
|
||||||
|
return subscriptionsData?.place_order_override;
|
||||||
|
}
|
||||||
|
|
||||||
|
return label;
|
||||||
|
},
|
||||||
|
} );
|
||||||
|
};
|
49
assets/src/js/index.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { registerPlugin } from '@wordpress/plugins';
|
||||||
|
import {
|
||||||
|
ExperimentalOrderMeta,
|
||||||
|
ExperimentalOrderShippingPackages,
|
||||||
|
} from '@woocommerce/blocks-checkout';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { SubscriptionsRecurringTotals } from './recurring-totals';
|
||||||
|
import { SubscriptionsRecurringPackages } from './recurring-packages';
|
||||||
|
import { registerFilters } from './filters';
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the first integration point between WooCommerce Subscriptions
|
||||||
|
* and Cart and Checkout blocks, it happens on two folds:
|
||||||
|
* - First, we register our code via `registerPlugin`, this React code
|
||||||
|
* is then going to be rendered hidden inside Cart and Checkout blocks
|
||||||
|
* (via <PluginArea /> component).
|
||||||
|
* - Second, we're using SlotFills[1] to move that code to where we want it
|
||||||
|
* inside the tree.
|
||||||
|
*/
|
||||||
|
const render = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ExperimentalOrderShippingPackages>
|
||||||
|
<SubscriptionsRecurringPackages />
|
||||||
|
</ExperimentalOrderShippingPackages>
|
||||||
|
<ExperimentalOrderMeta>
|
||||||
|
<SubscriptionsRecurringTotals />
|
||||||
|
</ExperimentalOrderMeta>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
registerPlugin( 'woocommerce-subscriptions', {
|
||||||
|
render,
|
||||||
|
scope: 'woocommerce-checkout',
|
||||||
|
} );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegisterFilters is the second part of the integration, and it handles filters
|
||||||
|
* like price, totals, and so on.
|
||||||
|
*/
|
||||||
|
registerFilters();
|
1
assets/src/js/index.scss
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// Add styles here.
|
66
assets/src/js/recurring-packages/index.js
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { useMemo } from '@wordpress/element';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component is responsible for rending recurring shippings.
|
||||||
|
* It has to be the highest level item directly inside the SlotFill
|
||||||
|
* to receive properties passed from Cart and Checkout.
|
||||||
|
*
|
||||||
|
* extensions is data registered into `/cart` endpoint.
|
||||||
|
*
|
||||||
|
* @param {Object} props Passed props from SlotFill to this component.
|
||||||
|
* @param {Object} props.extensions Data registered into `/cart` endpoint.
|
||||||
|
* @param {boolean} props.collapsible If shipping rates can collapse.
|
||||||
|
* @param {boolean} props.collapse If shipping rates should collapse.
|
||||||
|
* @param {boolean} props.showItems If shipping rates should show items inside them.
|
||||||
|
* @param {Element} props.noResultsMessage Message shown when no rate are found.
|
||||||
|
* @param {Function} props.renderOption Function that decides how rates are going to render.
|
||||||
|
* @param {Object} props.components
|
||||||
|
* @param {string} props.context This will be woocommerce/cart or woocommerce/checkout.
|
||||||
|
*/
|
||||||
|
export const SubscriptionsRecurringPackages = ( {
|
||||||
|
extensions,
|
||||||
|
collapsible,
|
||||||
|
collapse,
|
||||||
|
showItems,
|
||||||
|
noResultsMessage,
|
||||||
|
renderOption,
|
||||||
|
components,
|
||||||
|
context,
|
||||||
|
} ) => {
|
||||||
|
const { subscriptions = [] } = extensions;
|
||||||
|
const { ShippingRatesControlPackage } = components;
|
||||||
|
|
||||||
|
// Flatten all packages from recurring carts.
|
||||||
|
const packages = useMemo(
|
||||||
|
() =>
|
||||||
|
Object.values( subscriptions )
|
||||||
|
.map( ( recurringCart ) => recurringCart.shipping_rates )
|
||||||
|
.filter( Boolean )
|
||||||
|
.flat(),
|
||||||
|
[ subscriptions ]
|
||||||
|
);
|
||||||
|
const shouldCollapse = useMemo( () => 1 < packages.length || collapse, [
|
||||||
|
packages.length,
|
||||||
|
collapse,
|
||||||
|
] );
|
||||||
|
const shouldShowItems = useMemo( () => 1 < packages.length || showItems, [
|
||||||
|
packages.length,
|
||||||
|
showItems,
|
||||||
|
] );
|
||||||
|
return packages.map( ( { package_id: packageId, ...packageData } ) => (
|
||||||
|
<ShippingRatesControlPackage
|
||||||
|
key={ packageId }
|
||||||
|
packageId={ packageId }
|
||||||
|
packageData={ packageData }
|
||||||
|
collapsible={ collapsible }
|
||||||
|
collapse={ shouldCollapse }
|
||||||
|
showItems={ shouldShowItems }
|
||||||
|
noResultsMessage={ noResultsMessage }
|
||||||
|
renderOption={ renderOption }
|
||||||
|
highlightChecked={ 'woocommerce/checkout' === context }
|
||||||
|
/>
|
||||||
|
) );
|
||||||
|
};
|
319
assets/src/js/recurring-totals/index.js
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { sprintf, __ } from '@wordpress/i18n';
|
||||||
|
import {
|
||||||
|
Panel,
|
||||||
|
Subtotal,
|
||||||
|
TotalsItem,
|
||||||
|
TotalsTaxes,
|
||||||
|
TotalsWrapper,
|
||||||
|
} from '@woocommerce/blocks-checkout';
|
||||||
|
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
|
||||||
|
import { isWcVersion, getSetting } from '@woocommerce/settings';
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import {
|
||||||
|
getRecurringPeriodString,
|
||||||
|
getSubscriptionLengthString,
|
||||||
|
isOneOffSubscription,
|
||||||
|
} from '../utils';
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All data passed in get_script_data is available here, from all
|
||||||
|
* plugins (e.g WooCommerce Admin, WooCommerce Blocks).
|
||||||
|
*/
|
||||||
|
const DISPLAY_CART_PRICES_INCLUDING_TAX = getSetting(
|
||||||
|
'displayCartPricesIncludingTax',
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component responsible for rending the coupons discount totals item.
|
||||||
|
*
|
||||||
|
* @param {Object} props Props passed to component.
|
||||||
|
* @param {Object} props.currency Object containing currency data to format prices.
|
||||||
|
* @param {Object} props.values Recurring cart totals (shipping, taxes).
|
||||||
|
*/
|
||||||
|
const DiscountTotals = ( { currency, values } ) => {
|
||||||
|
const {
|
||||||
|
total_discount: totalDiscount,
|
||||||
|
total_discount_tax: totalDiscountTax,
|
||||||
|
} = values;
|
||||||
|
const discountValue = parseInt( totalDiscount, 10 );
|
||||||
|
|
||||||
|
if ( ! discountValue ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const discountTaxValue = parseInt( totalDiscountTax, 10 );
|
||||||
|
const discountTotalValue = DISPLAY_CART_PRICES_INCLUDING_TAX
|
||||||
|
? discountValue + discountTaxValue
|
||||||
|
: discountValue;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TotalsItem
|
||||||
|
className="wc-block-components-totals-discount"
|
||||||
|
currency={ currency }
|
||||||
|
label={ __( 'Discount', 'woocommerce-subscriptions' ) }
|
||||||
|
value={ discountTotalValue * -1 }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component responsible for rending the shipping totals item.
|
||||||
|
*
|
||||||
|
* @param {Object} props Props passed to component.
|
||||||
|
* @param {string|undefined} props.selectedRate Selected shipping method
|
||||||
|
* name.
|
||||||
|
* @param {boolean} props.needsShipping Boolean to indicate if we
|
||||||
|
* need shipping or not.
|
||||||
|
* @param {boolean} props.calculatedShipping Boolean to indicate if we
|
||||||
|
* calculated shipping or not.
|
||||||
|
* @param {Object} props.currency Object containing
|
||||||
|
* currency data to format prices.
|
||||||
|
* @param {Object} props.values Recurring cart totals (shipping, taxes).
|
||||||
|
*/
|
||||||
|
const ShippingTotal = ( {
|
||||||
|
values,
|
||||||
|
currency,
|
||||||
|
selectedRate,
|
||||||
|
needsShipping,
|
||||||
|
calculatedShipping,
|
||||||
|
} ) => {
|
||||||
|
if ( ! needsShipping || ! calculatedShipping ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const shippingTotals = DISPLAY_CART_PRICES_INCLUDING_TAX
|
||||||
|
? parseInt( values.total_shipping, 10 ) +
|
||||||
|
parseInt( values.total_shipping_tax, 10 )
|
||||||
|
: parseInt( values.total_shipping, 10 );
|
||||||
|
|
||||||
|
const valueToShow =
|
||||||
|
0 === shippingTotals && isWcVersion( '9.0', '>=' ) ? (
|
||||||
|
<strong>{ __( 'Free', 'woocommerce-subscriptions' ) }</strong>
|
||||||
|
) : (
|
||||||
|
shippingTotals
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<TotalsItem
|
||||||
|
value={ valueToShow }
|
||||||
|
label={ __( 'Shipping', 'woocommerce-subscriptions' ) }
|
||||||
|
currency={ currency }
|
||||||
|
description={
|
||||||
|
!! selectedRate &&
|
||||||
|
sprintf(
|
||||||
|
// translators: %s selected shipping rate (ex: flat rate)
|
||||||
|
__( 'via %s', 'woocommerce-subscriptions' ),
|
||||||
|
selectedRate
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Component responsible for rendering recurring cart description.
|
||||||
|
*
|
||||||
|
* @param {Object} props Props passed to component.
|
||||||
|
* @param {string} props.nextPaymentDate Formatted next payment date.
|
||||||
|
* @param {number} props.subscriptionLength Subscription length.
|
||||||
|
* @param {string} props.billingPeriod Recurring cart period (day, week, month, year).
|
||||||
|
* @param {number} props.billingInterval Recurring cart interval (1 - 6).
|
||||||
|
*/
|
||||||
|
const SubscriptionDescription = ( {
|
||||||
|
nextPaymentDate,
|
||||||
|
subscriptionLength,
|
||||||
|
billingPeriod,
|
||||||
|
billingInterval,
|
||||||
|
} ) => {
|
||||||
|
const subscriptionLengthString = getSubscriptionLengthString( {
|
||||||
|
subscriptionLength,
|
||||||
|
billingPeriod,
|
||||||
|
} );
|
||||||
|
const firstPaymentString = isOneOffSubscription( {
|
||||||
|
subscriptionLength,
|
||||||
|
billingInterval,
|
||||||
|
} )
|
||||||
|
? sprintf(
|
||||||
|
/* Translators: %1$s is a date. */
|
||||||
|
__( 'Due: %1$s', 'woocommerce-subscriptions' ),
|
||||||
|
nextPaymentDate
|
||||||
|
)
|
||||||
|
: sprintf(
|
||||||
|
/* Translators: %1$s is a date. */
|
||||||
|
__( 'Starting: %1$s', 'woocommerce-subscriptions' ),
|
||||||
|
nextPaymentDate
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
// Only render this section if we have a next payment date.
|
||||||
|
<span>
|
||||||
|
{ !! nextPaymentDate && firstPaymentString }{ ' ' }
|
||||||
|
{ !! subscriptionLength &&
|
||||||
|
subscriptionLength >= billingInterval && (
|
||||||
|
<span className="wcs-recurring-totals__subscription-length">
|
||||||
|
{ subscriptionLengthString }
|
||||||
|
</span>
|
||||||
|
) }
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component responsible for rendering recurring cart heading.
|
||||||
|
*
|
||||||
|
* @param {Object} props Props passed to component.
|
||||||
|
* @param {Object} props.currency Object containing currency data to format prices.
|
||||||
|
* @param {number} props.billingInterval Recurring cart interval (1 - 6).
|
||||||
|
* @param {string} props.billingPeriod Recurring cart period (day, week, month, year).
|
||||||
|
* @param {string} props.nextPaymentDate Formatted next payment date.
|
||||||
|
* @param {number} props.subscriptionLength Subscription length.
|
||||||
|
* @param {Object} props.totals Recurring cart totals (shipping, taxes).
|
||||||
|
*/
|
||||||
|
const TabHeading = ( {
|
||||||
|
currency,
|
||||||
|
billingInterval,
|
||||||
|
billingPeriod,
|
||||||
|
nextPaymentDate,
|
||||||
|
subscriptionLength,
|
||||||
|
totals,
|
||||||
|
} ) => {
|
||||||
|
// For future one off subscriptions, we show "Total" instead of a recurring title.
|
||||||
|
const title = isOneOffSubscription( {
|
||||||
|
billingInterval,
|
||||||
|
subscriptionLength,
|
||||||
|
} )
|
||||||
|
? __( 'Total', 'woocommerce-subscriptions' )
|
||||||
|
: getRecurringPeriodString( {
|
||||||
|
billingInterval,
|
||||||
|
billingPeriod,
|
||||||
|
} );
|
||||||
|
return (
|
||||||
|
<TotalsItem
|
||||||
|
className="wcs-recurring-totals-panel__title"
|
||||||
|
currency={ currency }
|
||||||
|
label={ title }
|
||||||
|
value={ totals }
|
||||||
|
description={
|
||||||
|
<SubscriptionDescription
|
||||||
|
nextPaymentDate={ nextPaymentDate }
|
||||||
|
subscriptionLength={ subscriptionLength }
|
||||||
|
billingInterval={ billingInterval }
|
||||||
|
billingPeriod={ billingPeriod }
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component responsible for rendering a single recurring total panel.
|
||||||
|
* We render several ones depending on how many recurring carts we have.
|
||||||
|
*
|
||||||
|
* @param {Object} props Props passed to component.
|
||||||
|
* @param {Object} props.subscription Recurring cart data that we registered
|
||||||
|
* with ExtendRestApi.
|
||||||
|
* @param {boolean} props.needsShipping Boolean to indicate if we need
|
||||||
|
* shipping or not.
|
||||||
|
* @param {boolean} props.calculatedShipping Boolean to indicate if we calculated
|
||||||
|
* shipping or not.
|
||||||
|
*/
|
||||||
|
const RecurringSubscription = ( {
|
||||||
|
subscription,
|
||||||
|
needsShipping,
|
||||||
|
calculatedShipping,
|
||||||
|
} ) => {
|
||||||
|
const {
|
||||||
|
totals,
|
||||||
|
billing_interval: billingInterval,
|
||||||
|
billing_period: billingPeriod,
|
||||||
|
next_payment_date: nextPaymentDate,
|
||||||
|
subscription_length: subscriptionLength,
|
||||||
|
shipping_rates: shippingRates,
|
||||||
|
} = subscription;
|
||||||
|
|
||||||
|
// We skip one off subscriptions
|
||||||
|
if ( ! nextPaymentDate ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedRate = shippingRates?.[ 0 ]?.shipping_rates?.find(
|
||||||
|
( { selected } ) => selected
|
||||||
|
)?.name;
|
||||||
|
|
||||||
|
const currency = getCurrencyFromPriceResponse( totals );
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="wcs-recurring-totals-panel">
|
||||||
|
<TabHeading
|
||||||
|
billingInterval={ billingInterval }
|
||||||
|
billingPeriod={ billingPeriod }
|
||||||
|
nextPaymentDate={ nextPaymentDate }
|
||||||
|
subscriptionLength={ subscriptionLength }
|
||||||
|
totals={ parseInt( totals.total_price, 10 ) }
|
||||||
|
currency={ currency }
|
||||||
|
/>
|
||||||
|
<Panel
|
||||||
|
className="wcs-recurring-totals-panel__details"
|
||||||
|
initialOpen={ false }
|
||||||
|
title={ __( 'Details', 'woocommerce-subscriptions' ) }
|
||||||
|
>
|
||||||
|
<TotalsWrapper>
|
||||||
|
<Subtotal currency={ currency } values={ totals } />
|
||||||
|
<DiscountTotals currency={ currency } values={ totals } />
|
||||||
|
</TotalsWrapper>
|
||||||
|
<TotalsWrapper className="wc-block-components-totals-shipping">
|
||||||
|
<ShippingTotal
|
||||||
|
currency={ currency }
|
||||||
|
needsShipping={ needsShipping }
|
||||||
|
calculatedShipping={ calculatedShipping }
|
||||||
|
values={ totals }
|
||||||
|
selectedRate={ selectedRate }
|
||||||
|
/>
|
||||||
|
</TotalsWrapper>
|
||||||
|
{ ! DISPLAY_CART_PRICES_INCLUDING_TAX && (
|
||||||
|
<TotalsWrapper>
|
||||||
|
<TotalsTaxes currency={ currency } values={ totals } />
|
||||||
|
</TotalsWrapper>
|
||||||
|
) }
|
||||||
|
<TotalsWrapper>
|
||||||
|
<TotalsItem
|
||||||
|
className="wcs-recurring-totals-panel__details-total"
|
||||||
|
currency={ currency }
|
||||||
|
label={ __( 'Total', 'woocommerce-subscriptions' ) }
|
||||||
|
value={ parseInt( totals.total_price, 10 ) }
|
||||||
|
/>
|
||||||
|
</TotalsWrapper>
|
||||||
|
</Panel>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component is responsible for rending recurring totals.
|
||||||
|
* It has to be the highest level item directly inside the SlotFill
|
||||||
|
* to receive properties passed from Cart and Checkout.
|
||||||
|
*
|
||||||
|
* extensions is data registered into `/cart` endpoint.
|
||||||
|
*
|
||||||
|
* @param {Object} props Passed props from SlotFill to this component.
|
||||||
|
* @param {Object} props.extensions data registered into `/cart` endpoint.
|
||||||
|
* @param {Object} props.cart cart endpoint data in readonly mode.
|
||||||
|
*/
|
||||||
|
export const SubscriptionsRecurringTotals = ( { extensions, cart } ) => {
|
||||||
|
const { subscriptions } = extensions;
|
||||||
|
const { cartNeedsShipping, cartHasCalculatedShipping } = cart;
|
||||||
|
if ( ! subscriptions || 0 === subscriptions.length ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return subscriptions.map( ( { key, ...subscription } ) => (
|
||||||
|
<RecurringSubscription
|
||||||
|
subscription={ subscription }
|
||||||
|
needsShipping={ cartNeedsShipping }
|
||||||
|
calculatedShipping={ cartHasCalculatedShipping }
|
||||||
|
key={ key }
|
||||||
|
/>
|
||||||
|
) );
|
||||||
|
};
|
72
assets/src/js/recurring-totals/index.scss
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// Shows a border with the current color and a custom opacity. That can't be achieved
|
||||||
|
// with normal border because `currentColor` doesn't allow tweaking the opacity, and
|
||||||
|
// setting the opacity of the entire element would change the children's opacity too.
|
||||||
|
@mixin with-translucent-border( $border-width: 1px, $opacity: 0.3 ) {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border-style: solid;
|
||||||
|
border-width: $border-width;
|
||||||
|
bottom: 0;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
left: 0;
|
||||||
|
opacity: $opacity;
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wcs-recurring-totals-panel {
|
||||||
|
@include with-translucent-border( 1px 0 );
|
||||||
|
padding: 1em 0 0;
|
||||||
|
|
||||||
|
+ .wcs-recurring-totals-panel::after {
|
||||||
|
border-top-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wc-block-components-panel .wc-block-components-totals-item {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wc-block-components-totals-item__label::first-letter {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
.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,
|
||||||
|
.wc-block-components-panel__button:hover,
|
||||||
|
.wc-block-components-panel__button:focus {
|
||||||
|
font-size: 0.875em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wc-block-components-panel__content > .wc-block-components-totals-item {
|
||||||
|
&:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wcs-recurring-totals-panel__details-total
|
||||||
|
.wc-block-components-totals-item__label {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wcs-recurring-totals__subscription-length {
|
||||||
|
float: right;
|
||||||
|
}
|
207
assets/src/js/utils/index.js
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { sprintf, __, _nx } from '@wordpress/i18n';
|
||||||
|
|
||||||
|
export function getAvailablePeriods( number ) {
|
||||||
|
return {
|
||||||
|
day: _nx(
|
||||||
|
'day',
|
||||||
|
'days',
|
||||||
|
number,
|
||||||
|
'Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular.',
|
||||||
|
'woocommerce-subscriptions'
|
||||||
|
),
|
||||||
|
week: _nx(
|
||||||
|
'week',
|
||||||
|
'weeks',
|
||||||
|
number,
|
||||||
|
'Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular.',
|
||||||
|
'woocommerce-subscriptions'
|
||||||
|
),
|
||||||
|
month: _nx(
|
||||||
|
'month',
|
||||||
|
'months',
|
||||||
|
number,
|
||||||
|
'Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular.',
|
||||||
|
'woocommerce-subscriptions'
|
||||||
|
),
|
||||||
|
year: _nx(
|
||||||
|
'year',
|
||||||
|
'years',
|
||||||
|
number,
|
||||||
|
'Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular.',
|
||||||
|
'woocommerce-subscriptions'
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a recurring string from a subscription
|
||||||
|
*
|
||||||
|
* Examples
|
||||||
|
* period recurring total
|
||||||
|
* Daily recurring total
|
||||||
|
* Weekly recurring total
|
||||||
|
* Monthly recurring total
|
||||||
|
* etc
|
||||||
|
* If subscription bills at non standard intervals, then the order is transposed, and the line reads:
|
||||||
|
* Recurring total every X day | week | month | quarter | year
|
||||||
|
* Recurring total every 3rd day
|
||||||
|
* Recurring total every 2nd week
|
||||||
|
* Recurring total every 4th month
|
||||||
|
* etc
|
||||||
|
*
|
||||||
|
* @param {Object} subscription Subscription object.
|
||||||
|
* @param {string} subscription.billingPeriod Period (month, day, week, year).
|
||||||
|
* @param {number} subscription.billingInterval Internal (1 month, 5 day, 4 week, 6 year).
|
||||||
|
*/
|
||||||
|
export function getRecurringPeriodString( { billingInterval, billingPeriod } ) {
|
||||||
|
switch ( billingInterval ) {
|
||||||
|
case 1:
|
||||||
|
if ( 'day' === billingPeriod ) {
|
||||||
|
return __(
|
||||||
|
'Daily recurring total',
|
||||||
|
'woocommerce-subscriptions'
|
||||||
|
);
|
||||||
|
} else if ( 'week' === billingPeriod ) {
|
||||||
|
return __(
|
||||||
|
'Weekly recurring total',
|
||||||
|
'woocommerce-subscriptions'
|
||||||
|
);
|
||||||
|
} else if ( 'month' === billingPeriod ) {
|
||||||
|
return __(
|
||||||
|
'Monthly recurring total',
|
||||||
|
'woocommerce-subscriptions'
|
||||||
|
);
|
||||||
|
} else if ( 'year' === billingPeriod ) {
|
||||||
|
return __(
|
||||||
|
'Yearly recurring total',
|
||||||
|
'woocommerce-subscriptions'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
return sprintf(
|
||||||
|
/* translators: %1$s is week, month, year */
|
||||||
|
__(
|
||||||
|
'Recurring total every 2nd %1$s',
|
||||||
|
'woocommerce-subscriptions'
|
||||||
|
),
|
||||||
|
billingPeriod
|
||||||
|
);
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
return sprintf(
|
||||||
|
/* Translators: %1$s is week, month, year */
|
||||||
|
__(
|
||||||
|
'Recurring total every 3rd %1$s',
|
||||||
|
'woocommerce-subscriptions'
|
||||||
|
),
|
||||||
|
billingPeriod
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return sprintf(
|
||||||
|
/* Translators: %1$d is number of weeks, months, days, years. %2$s is week, month, year */
|
||||||
|
__(
|
||||||
|
'Recurring total every %1$dth %2$s',
|
||||||
|
'woocommerce-subscriptions'
|
||||||
|
),
|
||||||
|
billingInterval,
|
||||||
|
billingPeriod
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSubscriptionLengthString( {
|
||||||
|
subscriptionLength,
|
||||||
|
billingPeriod,
|
||||||
|
} ) {
|
||||||
|
const periodsStings = getAvailablePeriods( subscriptionLength );
|
||||||
|
return sprintf(
|
||||||
|
'For %1$d %2$s',
|
||||||
|
subscriptionLength,
|
||||||
|
periodsStings[ billingPeriod ],
|
||||||
|
'woocommerce-subscriptions'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Creates a billing frequency string from a subscription
|
||||||
|
*
|
||||||
|
* Examples
|
||||||
|
* Every 6th week
|
||||||
|
* Every day
|
||||||
|
* Every month
|
||||||
|
* / day
|
||||||
|
* Each Week
|
||||||
|
* etc
|
||||||
|
*
|
||||||
|
* @param {Object} subscription Subscription object.
|
||||||
|
* @param {string} subscription.billing_period Period (month, day, week, year).
|
||||||
|
* @param {number} subscription.billing_interval Internal (1 month, 5 day, 4 week, 6 year).
|
||||||
|
* @param {string} separator A string to be prepended to frequency. followed by a space. Eg: (every, each, /)
|
||||||
|
* @param {string} price This is the string representation of the price of the product.
|
||||||
|
*/
|
||||||
|
export function getBillingFrequencyString(
|
||||||
|
{ billing_interval: billingInterval, billing_period: billingPeriod },
|
||||||
|
separator,
|
||||||
|
price
|
||||||
|
) {
|
||||||
|
const periodsStings = getAvailablePeriods( billingInterval );
|
||||||
|
const translatedPeriod = periodsStings[ billingPeriod ];
|
||||||
|
separator = separator.trim();
|
||||||
|
switch ( billingInterval ) {
|
||||||
|
case 1:
|
||||||
|
return `${ price } ${ separator } ${ translatedPeriod }`;
|
||||||
|
default:
|
||||||
|
return sprintf(
|
||||||
|
/*
|
||||||
|
* translators: %1$s is the price of the product. %2$s is the separator used e.g "every" or "/",
|
||||||
|
* %3$d is the length, %4$s is week, month, year
|
||||||
|
*/
|
||||||
|
__( `%1$s %2$s %3$d %4$s`, 'woocommerce-subscriptions' ),
|
||||||
|
price,
|
||||||
|
separator,
|
||||||
|
billingInterval,
|
||||||
|
translatedPeriod
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a switch string
|
||||||
|
*
|
||||||
|
* @param {string} switchType The switch type (upgraded, downgraded, crossgraded).
|
||||||
|
*
|
||||||
|
* @return {string} Translation ready switch name.
|
||||||
|
*/
|
||||||
|
export function getSwitchString( switchType ) {
|
||||||
|
switch ( switchType ) {
|
||||||
|
case 'upgraded':
|
||||||
|
return __( 'Upgrade', 'woocommerce-subscriptions' );
|
||||||
|
|
||||||
|
case 'downgraded':
|
||||||
|
return __( 'Downgrade', 'woocommerce-subscriptions' );
|
||||||
|
|
||||||
|
case 'crossgraded':
|
||||||
|
return __( 'Crossgrade', 'woocommerce-subscriptions' );
|
||||||
|
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks weather a subscription is a one off or not.
|
||||||
|
*
|
||||||
|
* @param {Object} subscription Subscription object data.
|
||||||
|
* @param {number} subscription.subscriptionLength Subscription length.
|
||||||
|
* @param {number} subscription.billingInterval Billing interval
|
||||||
|
* @return {boolean} whether this is a one off subscription or not.
|
||||||
|
*/
|
||||||
|
export function isOneOffSubscription( {
|
||||||
|
subscriptionLength,
|
||||||
|
billingInterval,
|
||||||
|
} ) {
|
||||||
|
return subscriptionLength === billingInterval;
|
||||||
|
}
|
2
build/index-rtl.css
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
.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}
|
||||||
|
|
1
build/index.asset.php
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?php return array('dependencies' => array('react', 'wc-blocks-checkout', 'wc-price-format', 'wc-settings', 'wp-element', 'wp-i18n', 'wp-plugins'), 'version' => 'b49e17b919b0ba384261');
|
2
build/index.css
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
.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}
|
||||||
|
|
35
build/index.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
(()=>{"use strict";var e={20:(e,r,s)=>{var t=s(609),n=Symbol.for("react.element"),i=Symbol.for("react.fragment"),o=Object.prototype.hasOwnProperty,c=t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,l={key:!0,ref:!0,__self:!0,__source:!0};function a(e,r,s){var t,i={},a=null,p=null;for(t in void 0!==s&&(a=""+s),void 0!==r.key&&(a=""+r.key),void 0!==r.ref&&(p=r.ref),r)o.call(r,t)&&!l.hasOwnProperty(t)&&(i[t]=r[t]);if(e&&e.defaultProps)for(t in r=e.defaultProps)void 0===i[t]&&(i[t]=r[t]);return{$$typeof:n,type:e,key:a,ref:p,props:i,_owner:c.current}}r.Fragment=i,r.jsx=a,r.jsxs=a},609:e=>{e.exports=window.React},848:(e,r,s)=>{e.exports=s(20)}},r={};const s=window.wp.plugins,t=window.wc.blocksCheckout,n=window.wp.i18n,i=window.wc.priceFormat,o=window.wc.wcSettings;function c(e){return{day:(0,n._nx)("day","days",e,"Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular.","woocommerce-subscriptions"),week:(0,n._nx)("week","weeks",e,"Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular.","woocommerce-subscriptions"),month:(0,n._nx)("month","months",e,"Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular.","woocommerce-subscriptions"),year:(0,n._nx)("year","years",e,"Used in recurring totals section in Cart. 2+ will need plural, 1 will need singular.","woocommerce-subscriptions")}}function l({billing_interval:e,billing_period:r},s,t){const i=c(e)[r];return s=s.trim(),1===e?`${t} ${s} ${i}`:(0,n.sprintf)(
|
||||||
|
/*
|
||||||
|
* translators: %1$s is the price of the product. %2$s is the separator used e.g "every" or "/",
|
||||||
|
* %3$d is the length, %4$s is week, month, year
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* translators: %1$s is the price of the product. %2$s is the separator used e.g "every" or "/",
|
||||||
|
* %3$d is the length, %4$s is week, month, year
|
||||||
|
*/
|
||||||
|
(0,n.__)("%1$s %2$s %3$d %4$s","woocommerce-subscriptions"),t,s,e,i)}function a({subscriptionLength:e,billingInterval:r}){return e===r}var p=function s(t){var n=r[t];if(void 0!==n)return n.exports;var i=r[t]={exports:{}};return e[t](i,i.exports,s),i.exports}(848);const u=(0,o.getSetting)("displayCartPricesIncludingTax",!1),m=({currency:e,values:r})=>{const{total_discount:s,total_discount_tax:i}=r,o=parseInt(s,10);if(!o)return null;const c=parseInt(i,10),l=u?o+c:o;return(0,p.jsx)(t.TotalsItem,{className:"wc-block-components-totals-discount",currency:e,label:(0,n.__)("Discount","woocommerce-subscriptions"),value:-1*l})},_=({values:e,currency:r,selectedRate:s,needsShipping:i,calculatedShipping:c})=>{if(!i||!c)return null;const l=u?parseInt(e.total_shipping,10)+parseInt(e.total_shipping_tax,10):parseInt(e.total_shipping,10),a=0===l&&(0,o.isWcVersion)("9.0",">=")?(0,p.jsx)("strong",{children:(0,n.__)("Free","woocommerce-subscriptions")}):l;return(0,p.jsx)(t.TotalsItem,{value:a,label:(0,n.__)("Shipping","woocommerce-subscriptions"),currency:r,description:!!s&&(0,n.sprintf)(
|
||||||
|
// translators: %s selected shipping rate (ex: flat rate)
|
||||||
|
// translators: %s selected shipping rate (ex: flat rate)
|
||||||
|
(0,n.__)("via %s","woocommerce-subscriptions"),s)})},g=({nextPaymentDate:e,subscriptionLength:r,billingPeriod:s,billingInterval:t})=>{const i=function({subscriptionLength:e,billingPeriod:r}){const s=c(e);return(0,n.sprintf)("For %1$d %2$s",e,s[r],"woocommerce-subscriptions")}({subscriptionLength:r,billingPeriod:s}),o=a({subscriptionLength:r,billingInterval:t})?(0,n.sprintf)(/* Translators: %1$s is a date. */ /* Translators: %1$s is a date. */
|
||||||
|
(0,n.__)("Due: %1$s","woocommerce-subscriptions"),e):(0,n.sprintf)(/* Translators: %1$s is a date. */ /* Translators: %1$s is a date. */
|
||||||
|
(0,n.__)("Starting: %1$s","woocommerce-subscriptions"),e);return(0,p.jsxs)("span",{children:[!!e&&o," ",!!r&&r>=t&&(0,p.jsx)("span",{className:"wcs-recurring-totals__subscription-length",children:i})]})},d=({currency:e,billingInterval:r,billingPeriod:s,nextPaymentDate:i,subscriptionLength:o,totals:c})=>{const l=a({billingInterval:r,subscriptionLength:o})?(0,n.__)("Total","woocommerce-subscriptions"):function({billingInterval:e,billingPeriod:r}){switch(e){case 1:if("day"===r)return(0,n.__)("Daily recurring total","woocommerce-subscriptions");if("week"===r)return(0,n.__)("Weekly recurring total","woocommerce-subscriptions");if("month"===r)return(0,n.__)("Monthly recurring total","woocommerce-subscriptions");if("year"===r)return(0,n.__)("Yearly recurring total","woocommerce-subscriptions");break;case 2:return(0,n.sprintf)(/* translators: %1$s is week, month, year */ /* translators: %1$s is week, month, year */
|
||||||
|
(0,n.__)("Recurring total every 2nd %1$s","woocommerce-subscriptions"),r);case 3:return(0,n.sprintf)(/* Translators: %1$s is week, month, year */ /* Translators: %1$s is week, month, year */
|
||||||
|
(0,n.__)("Recurring total every 3rd %1$s","woocommerce-subscriptions"),r);default:return(0,n.sprintf)(/* Translators: %1$d is number of weeks, months, days, years. %2$s is week, month, year */ /* Translators: %1$d is number of weeks, months, days, years. %2$s is week, month, year */
|
||||||
|
(0,n.__)("Recurring total every %1$dth %2$s","woocommerce-subscriptions"),e,r)}}({billingInterval:r,billingPeriod:s});return(0,p.jsx)(t.TotalsItem,{className:"wcs-recurring-totals-panel__title",currency:e,label:l,value:c,description:(0,p.jsx)(g,{nextPaymentDate:i,subscriptionLength:o,billingInterval:r,billingPeriod:s})})},b=({subscription:e,needsShipping:r,calculatedShipping:s})=>{const{totals:o,billing_interval:c,billing_period:l,next_payment_date:a,subscription_length:g,shipping_rates:b}=e;if(!a)return null;const w=b?.[0]?.shipping_rates?.find((({selected:e})=>e))?.name,h=(0,i.getCurrencyFromPriceResponse)(o);return(0,p.jsxs)("div",{className:"wcs-recurring-totals-panel",children:[(0,p.jsx)(d,{billingInterval:c,billingPeriod:l,nextPaymentDate:a,subscriptionLength:g,totals:parseInt(o.total_price,10),currency:h}),(0,p.jsxs)(t.Panel,{className:"wcs-recurring-totals-panel__details",initialOpen:!1,title:(0,n.__)("Details","woocommerce-subscriptions"),children:[(0,p.jsxs)(t.TotalsWrapper,{children:[(0,p.jsx)(t.Subtotal,{currency:h,values:o}),(0,p.jsx)(m,{currency:h,values:o})]}),(0,p.jsx)(t.TotalsWrapper,{className:"wc-block-components-totals-shipping",children:(0,p.jsx)(_,{currency:h,needsShipping:r,calculatedShipping:s,values:o,selectedRate:w})}),!u&&(0,p.jsx)(t.TotalsWrapper,{children:(0,p.jsx)(t.TotalsTaxes,{currency:h,values:o})}),(0,p.jsx)(t.TotalsWrapper,{children:(0,p.jsx)(t.TotalsItem,{className:"wcs-recurring-totals-panel__details-total",currency:h,label:(0,n.__)("Total","woocommerce-subscriptions"),value:parseInt(o.total_price,10)})})]})]})},w=({extensions:e,cart:r})=>{const{subscriptions:s}=e,{cartNeedsShipping:t,cartHasCalculatedShipping:n}=r;return s&&0!==s.length?s.map((({key:e,...r})=>(0,p.jsx)(b,{subscription:r,needsShipping:t,calculatedShipping:n},e))):null},h=window.wp.element,x=({extensions:e,collapsible:r,collapse:s,showItems:t,noResultsMessage:n,renderOption:i,components:o,context:c})=>{const{subscriptions:l=[]}=e,{ShippingRatesControlPackage:a}=o,u=(0,h.useMemo)((()=>Object.values(l).map((e=>e.shipping_rates)).filter(Boolean).flat()),[l]),m=(0,h.useMemo)((()=>1<u.length||s),[u.length,s]),_=(0,h.useMemo)((()=>1<u.length||t),[u.length,t]);return u.map((({package_id:e,...s})=>(0,p.jsx)(a,{packageId:e,packageData:s,collapsible:r,collapse:m,showItems:_,noResultsMessage:n,renderOption:i,highlightChecked:"woocommerce/checkout"===c},e)))};(0,s.registerPlugin)("woocommerce-subscriptions",{render:()=>(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(t.ExperimentalOrderShippingPackages,{children:(0,p.jsx)(x,{})}),(0,p.jsx)(t.ExperimentalOrderMeta,{children:(0,p.jsx)(w,{})})]}),scope:"woocommerce-checkout"}),(0,t.registerCheckoutFilters)("woocommerce-subscriptions",{totalLabel:(e,{subscriptions:r})=>0<r?.length?(0,n.__)("Total due today","woocommerce-subscriptions"):e,subtotalPriceFormat:(e,{subscriptions:r})=>{if(r?.billing_period&&r?.billing_interval){const{billing_interval:s,subscription_length:t}=r;return a({subscriptionLength:t,billingInterval:s})?l(r,1===t?
|
||||||
|
// translators: the word used to describe billing frequency, e.g. "for" 1 day or "for" 1 month.
|
||||||
|
// translators: the word used to describe billing frequency, e.g. "for" 1 day or "for" 1 month.
|
||||||
|
(0,n.__)("for 1","woocommerce-subscriptions"):
|
||||||
|
// translators: the word used to describe billing frequency, e.g. "for" 6 days or "for" 2 weeks.
|
||||||
|
// translators: the word used to describe billing frequency, e.g. "for" 6 days or "for" 2 weeks.
|
||||||
|
(0,n.__)("for","woocommerce-subscriptions"),e):l(r,
|
||||||
|
// translators: the word used to describe billing frequency, e.g. "every" 6 days or "every" 2 weeks.
|
||||||
|
// translators: the word used to describe billing frequency, e.g. "every" 6 days or "every" 2 weeks.
|
||||||
|
(0,n.__)("every","woocommerce-subscriptions"),e)}return e},saleBadgePriceFormat:(e,{subscriptions:r})=>r?.billing_period&&r?.billing_interval?l(r,"/",e):e,itemName:(e,{subscriptions:r})=>r?.is_resubscribe?(0,n.sprintf)(
|
||||||
|
// translators: %s Product name.
|
||||||
|
// translators: %s Product name.
|
||||||
|
(0,n.__)("%s (resubscription)","woocommerce-subscriptions"),e):r?.switch_type?(0,n.sprintf)(
|
||||||
|
// translators: %1$s Product name, %2$s Switch type (upgraded, downgraded, or crossgraded).
|
||||||
|
// translators: %1$s Product name, %2$s Switch type (upgraded, downgraded, or crossgraded).
|
||||||
|
(0,n.__)("%1$s (%2$s)","woocommerce-subscriptions"),e,function(e){switch(e){case"upgraded":return(0,n.__)("Upgrade","woocommerce-subscriptions");case"downgraded":return(0,n.__)("Downgrade","woocommerce-subscriptions");case"crossgraded":return(0,n.__)("Crossgrade","woocommerce-subscriptions");default:return""}}(r.switch_type)):e,cartItemPrice:(e,{subscriptions:r},{context:s})=>r?.sign_up_fees?"cart"===s?(0,n.sprintf)(/* translators: %s is the subscription price to pay immediately (ie: $10). */ /* translators: %s is the subscription price to pay immediately (ie: $10). */
|
||||||
|
(0,n.__)("Due today %s","woocommerce-subscriptions"),e):(0,n.sprintf)(/* translators: %s is the subscription price to pay immediately (ie: $10). */ /* translators: %s is the subscription price to pay immediately (ie: $10). */
|
||||||
|
(0,n.__)("%s due today","woocommerce-subscriptions"),e):e,placeOrderButtonLabel:e=>{const r=(0,o.getSetting)("subscriptions_data");return r?.place_order_override?r?.place_order_override:e}})})();
|
@@ -1,5 +1,11 @@
|
|||||||
*** WooCommerce Subscriptions Changelog ***
|
*** WooCommerce Subscriptions Changelog ***
|
||||||
|
|
||||||
|
2025-05-20 - version 7.5.0
|
||||||
|
* Update: Add pagination to the related orders list in the My Account > View Subscription page.
|
||||||
|
* Fix: Infinite loop when trying to load subscription related orders meta after cache busting.
|
||||||
|
* Fix: Replace blogname with site_title on translation files.
|
||||||
|
* Dev: Make the `wcs_get_subscriptions_for_order()` function more robust. It should not return any subscriptions if presented with an invalid order.
|
||||||
|
|
||||||
2025-04-14 - version 7.4.0
|
2025-04-14 - version 7.4.0
|
||||||
* Update: Increase the number of args accepted by wcs_get_subscriptions(), to bring about parity with wc_get_orders().
|
* Update: Increase the number of args accepted by wcs_get_subscriptions(), to bring about parity with wc_get_orders().
|
||||||
* Dev: Update wcs_maybe_prefix_key() and wcs_maybe_unprefix_key() to support an array of keys.
|
* Dev: Update wcs_maybe_prefix_key() and wcs_maybe_unprefix_key() to support an array of keys.
|
||||||
|
@@ -71,7 +71,7 @@ class WCS_Admin_Reports {
|
|||||||
/**
|
/**
|
||||||
* Add the 'Subscriptions' report type to the WooCommerce reports screen.
|
* Add the 'Subscriptions' report type to the WooCommerce reports screen.
|
||||||
*
|
*
|
||||||
* @param array Array of Report types & their labels, excluding the Subscription product type.
|
* @param array $reports Array of Report types & their labels, excluding the Subscription product type.
|
||||||
* @return array Array of Report types & their labels, including the Subscription product type.
|
* @return array Array of Report types & their labels, including the Subscription product type.
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
*/
|
*/
|
||||||
|
@@ -122,7 +122,7 @@ class WCS_Report_Cache_Manager {
|
|||||||
* This function is attached as a callback on the events in the $update_events_and_classes property.
|
* This function is attached as a callback on the events in the $update_events_and_classes property.
|
||||||
*
|
*
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
* @return null
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function set_reports_to_update() {
|
public function set_reports_to_update() {
|
||||||
if ( isset( $this->update_events_and_classes[ current_filter() ] ) ) {
|
if ( isset( $this->update_events_and_classes[ current_filter() ] ) ) {
|
||||||
@@ -175,7 +175,7 @@ class WCS_Report_Cache_Manager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use the index to space out caching of each report to make them 5 minutes apart so that on large sites, where we assume they'll get a request at least once every few minutes, we don't try to update the caches of all reports in the same request
|
// Use the index to space out caching of each report to make them 5 minutes apart so that on large sites, where we assume they'll get a request at least once every few minutes, we don't try to update the caches of all reports in the same request
|
||||||
as_schedule_single_action( gmdate( 'U' ) + MINUTE_IN_SECONDS * ( $index + 1 ) * 5, $this->cron_hook, $cron_args );
|
as_schedule_single_action( (int) gmdate( 'U' ) + MINUTE_IN_SECONDS * ( $index + 1 ) * 5, $this->cron_hook, $cron_args );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,7 +185,6 @@ class WCS_Report_Cache_Manager {
|
|||||||
* Update the cache data for a given report, as specified with $report_class, by call it's get_data() method.
|
* Update the cache data for a given report, as specified with $report_class, by call it's get_data() method.
|
||||||
*
|
*
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
* @return null
|
|
||||||
*/
|
*/
|
||||||
public function update_cache( $report_class ) {
|
public function update_cache( $report_class ) {
|
||||||
/**
|
/**
|
||||||
@@ -217,7 +216,10 @@ class WCS_Report_Cache_Manager {
|
|||||||
|
|
||||||
// Load report class dependencies
|
// Load report class dependencies
|
||||||
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
|
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
|
||||||
require_once( WC()->plugin_path() . '/includes/admin/reports/class-wc-admin-report.php' );
|
|
||||||
|
$wc_core_dir = getenv( 'CI' ) ? ( getenv( 'WC_CORE_DIR' ) ? getenv( 'WC_CORE_DIR' ) : '/tmp/woocommerce' ) : WC()->plugin_path() . '/woocommerce';
|
||||||
|
|
||||||
|
require_once( $wc_core_dir . '/includes/admin/reports/class-wc-admin-report.php' );
|
||||||
|
|
||||||
$reflector = new ReflectionMethod( $report_class, 'get_data' );
|
$reflector = new ReflectionMethod( $report_class, 'get_data' );
|
||||||
|
|
||||||
|
@@ -38,7 +38,7 @@ class WCS_Report_Retention_Rate extends WC_Admin_Report {
|
|||||||
* subscription may not have been active all of that time. Instead, it may have been on-hold for part of it.
|
* subscription may not have been active all of that time. Instead, it may have been on-hold for part of it.
|
||||||
*
|
*
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
* @return null
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function query_report_data() {
|
private function query_report_data() {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
@@ -128,7 +128,6 @@ class WCS_Report_Retention_Rate extends WC_Admin_Report {
|
|||||||
* Use a custom report as we don't need the date filters provided by the WooCommerce html-report-by-date.php template.
|
* Use a custom report as we don't need the date filters provided by the WooCommerce html-report-by-date.php template.
|
||||||
*
|
*
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
* @return null
|
|
||||||
*/
|
*/
|
||||||
public function output_report() {
|
public function output_report() {
|
||||||
include( WC_Subscriptions_Plugin::instance()->get_plugin_directory( 'includes/admin/views/html-report-by-period.php' ) );
|
include( WC_Subscriptions_Plugin::instance()->get_plugin_directory( 'includes/admin/views/html-report-by-period.php' ) );
|
||||||
@@ -138,7 +137,6 @@ class WCS_Report_Retention_Rate extends WC_Admin_Report {
|
|||||||
* Output the HTML and JavaScript to plot the chart
|
* Output the HTML and JavaScript to plot the chart
|
||||||
*
|
*
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
* @return null
|
|
||||||
*/
|
*/
|
||||||
public function get_main_chart() {
|
public function get_main_chart() {
|
||||||
|
|
||||||
@@ -153,6 +151,8 @@ class WCS_Report_Retention_Rate extends WC_Admin_Report {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$x_axes_label = '';
|
||||||
|
|
||||||
switch ( $this->report_data->interval_period ) {
|
switch ( $this->report_data->interval_period ) {
|
||||||
case 'day':
|
case 'day':
|
||||||
$x_axes_label = _x( 'Number of days after sign-up', 'X axis label on retention rate graph', 'woocommerce-subscriptions' );
|
$x_axes_label = _x( 'Number of days after sign-up', 'X axis label on retention rate graph', 'woocommerce-subscriptions' );
|
||||||
@@ -214,7 +214,7 @@ class WCS_Report_Retention_Rate extends WC_Admin_Report {
|
|||||||
color: '#aaa',
|
color: '#aaa',
|
||||||
position: "bottom",
|
position: "bottom",
|
||||||
tickDecimals: 0,
|
tickDecimals: 0,
|
||||||
axisLabel: "<?php echo esc_js( $x_axes_label ); ?>",
|
axisLabel: "<?php esc_js( $x_axes_label ); ?>",
|
||||||
axisLabelPadding: 18,
|
axisLabelPadding: 18,
|
||||||
font: {
|
font: {
|
||||||
color: "#aaa"
|
color: "#aaa"
|
||||||
|
@@ -57,11 +57,11 @@ class WCS_Report_Subscription_By_Product extends WP_List_Table {
|
|||||||
case 'product_name':
|
case 'product_name':
|
||||||
// If the product is a subscription variation, use the parent product's edit post link
|
// If the product is a subscription variation, use the parent product's edit post link
|
||||||
if ( $report_item->parent_product_id > 0 ) {
|
if ( $report_item->parent_product_id > 0 ) {
|
||||||
return edit_post_link( $report_item->product_name, ' - ', null, $report_item->parent_product_id );
|
edit_post_link( $report_item->product_name, ' - ', null, $report_item->parent_product_id );
|
||||||
} else {
|
} else {
|
||||||
return edit_post_link( $report_item->product_name, null, null, $report_item->product_id );
|
edit_post_link( $report_item->product_name, null, null, $report_item->product_id );
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'subscription_count':
|
case 'subscription_count':
|
||||||
return sprintf( '<a href="%s%d">%d</a>', admin_url( 'edit.php?post_type=shop_subscription&_wcs_product=' ), $report_item->product_id, $report_item->subscription_count );
|
return sprintf( '<a href="%s%d">%d</a>', admin_url( 'edit.php?post_type=shop_subscription&_wcs_product=' ), $report_item->product_id, $report_item->subscription_count );
|
||||||
|
|
||||||
|
@@ -36,7 +36,7 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get report data
|
* Get report data
|
||||||
* @return array
|
* @return stdClass
|
||||||
*/
|
*/
|
||||||
public function get_report_data() {
|
public function get_report_data() {
|
||||||
|
|
||||||
@@ -807,7 +807,7 @@ class WCS_Report_Subscription_Events_By_Date extends WC_Admin_Report {
|
|||||||
/**
|
/**
|
||||||
* Get the main chart
|
* Get the main chart
|
||||||
*
|
*
|
||||||
* @return string
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function get_main_chart() {
|
public function get_main_chart() {
|
||||||
global $wp_locale;
|
global $wp_locale;
|
||||||
|
@@ -18,7 +18,7 @@ class WCS_Report_Subscription_Payment_Retry extends WC_Admin_Report {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get report data
|
* Get report data
|
||||||
* @return array
|
* @return stdClass
|
||||||
*/
|
*/
|
||||||
public function get_report_data() {
|
public function get_report_data() {
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ class WCS_Report_Subscription_Payment_Retry extends WC_Admin_Report {
|
|||||||
/**
|
/**
|
||||||
* Get the main chart
|
* Get the main chart
|
||||||
*
|
*
|
||||||
* @return string
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function get_main_chart() {
|
public function get_main_chart() {
|
||||||
global $wp_locale;
|
global $wp_locale;
|
||||||
|
@@ -74,7 +74,7 @@ class WCS_Report_Upcoming_Recurring_Revenue extends WC_Admin_Report {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while ( $next_payment_timestamp > 0 && $next_payment_timestamp <= $this->end_date
|
} while ( $next_payment_timestamp > 0 && $next_payment_timestamp <= $this->end_date
|
||||||
&& isset( $key, $scheduled_ends[ $key ] )
|
&& isset( $scheduled_ends[ $key ] )
|
||||||
&& ( 0 == $scheduled_ends[ $key ] || $next_payment_timestamp < strtotime( $scheduled_ends[ $key ] ) ) );
|
&& ( 0 == $scheduled_ends[ $key ] || $next_payment_timestamp < strtotime( $scheduled_ends[ $key ] ) ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,7 +233,7 @@ class WCS_Report_Upcoming_Recurring_Revenue extends WC_Admin_Report {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the main chart
|
* Get the main chart
|
||||||
* @return string
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function get_main_chart() {
|
public function get_main_chart() {
|
||||||
global $wp_locale;
|
global $wp_locale;
|
||||||
|
@@ -79,6 +79,7 @@ class WC_REST_Subscription_System_Status_Manager {
|
|||||||
private static function get_payment_gateway_feature_support() {
|
private static function get_payment_gateway_feature_support() {
|
||||||
$gateway_features = array();
|
$gateway_features = array();
|
||||||
|
|
||||||
|
// @phpstan-ignore property.notFound
|
||||||
foreach ( WC()->payment_gateways->get_available_payment_gateways() as $gateway_id => $gateway ) {
|
foreach ( WC()->payment_gateways->get_available_payment_gateways() as $gateway_id => $gateway ) {
|
||||||
// Some gateways include array keys. For consistency, only send the values.
|
// Some gateways include array keys. For consistency, only send the values.
|
||||||
$gateway_features[ $gateway_id ] = array_values( (array) apply_filters( 'woocommerce_subscriptions_payment_gateway_features_list', $gateway->supports, $gateway ) );
|
$gateway_features[ $gateway_id ] = array_values( (array) apply_filters( 'woocommerce_subscriptions_payment_gateway_features_list', $gateway->supports, $gateway ) );
|
||||||
|
@@ -94,7 +94,7 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller {
|
|||||||
*
|
*
|
||||||
* @since 3.1.0
|
* @since 3.1.0
|
||||||
*
|
*
|
||||||
* @param WC_Data $object Subscription object.
|
* @param WC_Subscription $object Subscription object.
|
||||||
* @param WP_REST_Request $request Request object.
|
* @param WP_REST_Request $request Request object.
|
||||||
* @return WP_REST_Response
|
* @return WP_REST_Response
|
||||||
*/
|
*/
|
||||||
|
@@ -15,7 +15,6 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
* REST API Subscription Notes controller class.
|
* REST API Subscription Notes controller class.
|
||||||
*
|
*
|
||||||
* @package WooCommerce_Subscriptions/API
|
* @package WooCommerce_Subscriptions/API
|
||||||
* @extends WC_REST_Order_Notes_Controller
|
|
||||||
*/
|
*/
|
||||||
class WC_REST_Subscription_Notes_Controller extends WC_REST_Order_Notes_Controller {
|
class WC_REST_Subscription_Notes_Controller extends WC_REST_Order_Notes_Controller {
|
||||||
|
|
||||||
|
@@ -16,7 +16,6 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
* REST API Subscriptions controller class.
|
* REST API Subscriptions controller class.
|
||||||
*
|
*
|
||||||
* @package WooCommerce_Subscriptions/API
|
* @package WooCommerce_Subscriptions/API
|
||||||
* @extends WC_REST_Orders_Controller
|
|
||||||
*/
|
*/
|
||||||
class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller {
|
class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller {
|
||||||
|
|
||||||
@@ -76,7 +75,7 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller {
|
|||||||
*
|
*
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
* @param WP_REST_Response $response
|
* @param WP_REST_Response $response
|
||||||
* @param WP_POST $post
|
* @param WP_Post $post
|
||||||
* @param WP_REST_Request $request
|
* @param WP_REST_Request $request
|
||||||
*/
|
*/
|
||||||
public function filter_get_subscription_response( $response, $post, $request ) {
|
public function filter_get_subscription_response( $response, $post, $request ) {
|
||||||
@@ -123,7 +122,7 @@ class WC_REST_Subscriptions_Controller extends WC_REST_Orders_Controller {
|
|||||||
*
|
*
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
* @param WP_REST_Request $request
|
* @param WP_REST_Request $request
|
||||||
* @param WP_POST $post
|
* @param WP_Post $post
|
||||||
*/
|
*/
|
||||||
protected function update_order( $request, $post ) {
|
protected function update_order( $request, $post ) {
|
||||||
try {
|
try {
|
||||||
|
@@ -15,7 +15,6 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
* REST API Subscription Notes controller class.
|
* REST API Subscription Notes controller class.
|
||||||
*
|
*
|
||||||
* @package WooCommerce_Subscriptions/API
|
* @package WooCommerce_Subscriptions/API
|
||||||
* @extends WC_REST_Order_Notes_Controller
|
|
||||||
*/
|
*/
|
||||||
class WC_REST_Subscription_Notes_V1_Controller extends WC_REST_Order_Notes_V1_Controller {
|
class WC_REST_Subscription_Notes_V1_Controller extends WC_REST_Order_Notes_V1_Controller {
|
||||||
|
|
||||||
|
@@ -17,7 +17,6 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
* REST API Subscriptions controller class.
|
* REST API Subscriptions controller class.
|
||||||
*
|
*
|
||||||
* @package WooCommerce_Subscriptions/API
|
* @package WooCommerce_Subscriptions/API
|
||||||
* @extends WC_REST_Orders_Controller
|
|
||||||
*/
|
*/
|
||||||
class WC_REST_Subscriptions_V1_Controller extends WC_REST_Orders_V1_Controller {
|
class WC_REST_Subscriptions_V1_Controller extends WC_REST_Orders_V1_Controller {
|
||||||
|
|
||||||
@@ -75,7 +74,7 @@ class WC_REST_Subscriptions_V1_Controller extends WC_REST_Orders_V1_Controller {
|
|||||||
*
|
*
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
* @param WP_REST_Response $response
|
* @param WP_REST_Response $response
|
||||||
* @param WP_POST $post
|
* @param WP_Post $post
|
||||||
* @param WP_REST_Request $request
|
* @param WP_REST_Request $request
|
||||||
*/
|
*/
|
||||||
public function filter_get_subscription_response( $response, $post, $request ) {
|
public function filter_get_subscription_response( $response, $post, $request ) {
|
||||||
@@ -232,7 +231,6 @@ class WC_REST_Subscriptions_V1_Controller extends WC_REST_Orders_V1_Controller {
|
|||||||
*
|
*
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
* @param WP_REST_Request $request
|
* @param WP_REST_Request $request
|
||||||
* @param WP_POST $post
|
|
||||||
*/
|
*/
|
||||||
protected function update_order( $request ) {
|
protected function update_order( $request ) {
|
||||||
try {
|
try {
|
||||||
|
@@ -12,7 +12,6 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
* REST API Subscription Notes controller class.
|
* REST API Subscription Notes controller class.
|
||||||
*
|
*
|
||||||
* @package WooCommerce_Subscriptions/API
|
* @package WooCommerce_Subscriptions/API
|
||||||
* @extends WC_REST_Order_Notes_Controller
|
|
||||||
*/
|
*/
|
||||||
class WC_REST_Subscription_Notes_V2_Controller extends WC_REST_Order_Notes_V2_Controller {
|
class WC_REST_Subscription_Notes_V2_Controller extends WC_REST_Order_Notes_V2_Controller {
|
||||||
|
|
||||||
|
@@ -89,7 +89,7 @@ class WC_REST_Subscriptions_V2_Controller extends WC_REST_Orders_V2_Controller {
|
|||||||
*
|
*
|
||||||
* @since 6.4.0
|
* @since 6.4.0
|
||||||
*
|
*
|
||||||
* @param WC_Data $object Subscription object.
|
* @param WC_Subscription $object Subscription object.
|
||||||
* @param WP_REST_Request $request Request object.
|
* @param WP_REST_Request $request Request object.
|
||||||
*
|
*
|
||||||
* @return WP_REST_Response
|
* @return WP_REST_Response
|
||||||
|
@@ -18,7 +18,7 @@ class WCS_API {
|
|||||||
add_filter( 'woocommerce_api_classes', array( __CLASS__, 'includes' ) );
|
add_filter( 'woocommerce_api_classes', array( __CLASS__, 'includes' ) );
|
||||||
add_action( 'rest_api_init', array( __CLASS__, 'register_routes' ), 15 );
|
add_action( 'rest_api_init', array( __CLASS__, 'register_routes' ), 15 );
|
||||||
add_action( 'rest_api_init', array( __CLASS__, 'register_route_overrides' ), 15 );
|
add_action( 'rest_api_init', array( __CLASS__, 'register_route_overrides' ), 15 );
|
||||||
add_action( 'woocommerce_rest_set_order_item', [ __CLASS__, 'add_sign_up_fee_to_order_item' ], 15, 2 );
|
add_action( 'woocommerce_rest_set_order_item', array( __CLASS__, 'add_sign_up_fee_to_order_item' ), 15, 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,6 +63,7 @@ class WCS_API {
|
|||||||
);
|
);
|
||||||
|
|
||||||
foreach ( $endpoint_classes as $class ) {
|
foreach ( $endpoint_classes as $class ) {
|
||||||
|
// @phpstan-ignore class.nameCase
|
||||||
$controller = new $class();
|
$controller = new $class();
|
||||||
$controller->register_routes();
|
$controller->register_routes();
|
||||||
}
|
}
|
||||||
@@ -87,8 +88,8 @@ class WCS_API {
|
|||||||
*
|
*
|
||||||
* @since 6.3.0
|
* @since 6.3.0
|
||||||
*
|
*
|
||||||
* @param WC_Order_Item $item Order item object.
|
* @param WC_Order_Item_Product $item Order item object.
|
||||||
* @param array $item_request_data Data posted to the API about the order item.
|
* @param array $item_request_data Data posted to the API about the order item.
|
||||||
*/
|
*/
|
||||||
public static function add_sign_up_fee_to_order_item( $item, $item_request_data = array() ) {
|
public static function add_sign_up_fee_to_order_item( $item, $item_request_data = array() ) {
|
||||||
if ( 'line_item' !== $item->get_type() || ! self::is_orders_api_request() ) {
|
if ( 'line_item' !== $item->get_type() || ! self::is_orders_api_request() ) {
|
||||||
@@ -119,7 +120,13 @@ class WCS_API {
|
|||||||
$price = (float) $product->get_price() + $sign_up_fee;
|
$price = (float) $product->get_price() + $sign_up_fee;
|
||||||
}
|
}
|
||||||
|
|
||||||
$total = wc_get_price_excluding_tax( $product, [ 'qty' => $item->get_quantity(), 'price' => $price ] );
|
$total = wc_get_price_excluding_tax(
|
||||||
|
$product,
|
||||||
|
array(
|
||||||
|
'qty' => $item->get_quantity(),
|
||||||
|
'price' => $price,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
$item->set_total( $total );
|
$item->set_total( $total );
|
||||||
$item->set_subtotal( $total );
|
$item->set_subtotal( $total );
|
||||||
@@ -165,6 +172,7 @@ class WCS_API {
|
|||||||
*/
|
*/
|
||||||
public static function get_wc_api_endpoint_data( $endpoint ) {
|
public static function get_wc_api_endpoint_data( $endpoint ) {
|
||||||
if ( wcs_is_woocommerce_pre( '9.0.0' ) ) {
|
if ( wcs_is_woocommerce_pre( '9.0.0' ) ) {
|
||||||
|
// @phpstan-ignore-next-line Call to deprecated method.
|
||||||
return WC()->api->get_endpoint_data( $endpoint );
|
return WC()->api->get_endpoint_data( $endpoint );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -15,7 +15,7 @@ class WCS_Call_To_Action_Button_Text_Manager {
|
|||||||
*/
|
*/
|
||||||
public static function init() {
|
public static function init() {
|
||||||
add_filter( 'woocommerce_subscription_settings', array( __CLASS__, 'add_settings' ), 5 );
|
add_filter( 'woocommerce_subscription_settings', array( __CLASS__, 'add_settings' ), 5 );
|
||||||
add_filter( 'wc_subscription_product_add_to_cart_text', array( __CLASS__, 'filter_add_to_cart_text' ), 10, 2 );
|
add_filter( 'wc_subscription_product_add_to_cart_text', array( __CLASS__, 'filter_add_to_cart_text' ) );
|
||||||
add_filter( 'wcs_place_subscription_order_text', array( __CLASS__, 'filter_place_subscription_order_text' ) );
|
add_filter( 'wcs_place_subscription_order_text', array( __CLASS__, 'filter_place_subscription_order_text' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,8 +71,7 @@ class WCS_Call_To_Action_Button_Text_Manager {
|
|||||||
*
|
*
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*
|
*
|
||||||
* @param string $add_to_cart_text The product's add to cart text.
|
* @param string $add_to_cart_text The product's add to cart text.
|
||||||
* @param WC_Abstract_Product $product The product.
|
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
@@ -313,13 +313,14 @@ class WCS_Limited_Recurring_Coupon_Manager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Bail early if there are no limited coupons applied to the recurring cart or if there is no discount provided.
|
// Bail early if there are no limited coupons applied to the recurring cart or if there is no discount provided.
|
||||||
|
// @phpstan-ignore property.notFound
|
||||||
if ( empty( $limited_recurring_coupons ) || ! $recurring_cart->discount_cart ) {
|
if ( empty( $limited_recurring_coupons ) || ! $recurring_cart->discount_cart ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$has_expiring_coupon = false;
|
$has_expiring_coupon = false;
|
||||||
$subscription_length = wcs_cart_pluck( $recurring_cart, 'subscription_length' );
|
$subscription_length = wcs_cart_pluck( $recurring_cart, 'subscription_length' );
|
||||||
$subscription_payments = $subscription_length / wcs_cart_pluck( $recurring_cart, 'subscription_period_interval' );
|
$subscription_payments = (int) $subscription_length / (int) wcs_cart_pluck( $recurring_cart, 'subscription_period_interval' );
|
||||||
|
|
||||||
// Limited recurring coupons will always expire at some point on subscriptions with no length.
|
// Limited recurring coupons will always expire at some point on subscriptions with no length.
|
||||||
if ( empty( $subscription_length ) ) {
|
if ( empty( $subscription_length ) ) {
|
||||||
@@ -381,7 +382,6 @@ class WCS_Limited_Recurring_Coupon_Manager {
|
|||||||
*
|
*
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*
|
*
|
||||||
* @param string $message The current message indicating there are no payment methods available..
|
|
||||||
* @return string The filtered message indicating there are no payment methods available.
|
* @return string The filtered message indicating there are no payment methods available.
|
||||||
*/
|
*/
|
||||||
public static function no_available_payment_methods_message() {
|
public static function no_available_payment_methods_message() {
|
||||||
|
@@ -22,7 +22,7 @@ class WCS_Manual_Renewal_Manager {
|
|||||||
*
|
*
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
* @param $settings The full subscription settings array.
|
* @param $settings The full subscription settings array.
|
||||||
* @return $settings.
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function add_settings( $settings ) {
|
public static function add_settings( $settings ) {
|
||||||
|
|
||||||
|
@@ -26,8 +26,10 @@ class WCS_Subscriber_Role_Manager {
|
|||||||
* @return array Subscriptions settings.
|
* @return array Subscriptions settings.
|
||||||
*/
|
*/
|
||||||
public static function add_settings( $settings ) {
|
public static function add_settings( $settings ) {
|
||||||
|
$roles_options = array();
|
||||||
|
|
||||||
if ( ! function_exists( 'get_editable_roles' ) ) {
|
if ( ! function_exists( 'get_editable_roles' ) ) {
|
||||||
require_once( ABSPATH . 'wp-admin/includes/user.php' );
|
require_once ABSPATH . 'wp-admin/includes/user.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ( get_editable_roles() as $role => $details ) {
|
foreach ( get_editable_roles() as $role => $details ) {
|
||||||
|
@@ -103,7 +103,7 @@ class WCS_Upgrade_Notice_Manager {
|
|||||||
|
|
||||||
// translators: placeholder is Subscription version string ('3.1')
|
// translators: placeholder is Subscription version string ('3.1')
|
||||||
$notice->set_heading( sprintf( __( 'Welcome to WooCommerce Subscriptions %s!', 'woocommerce-subscriptions' ), $version ) );
|
$notice->set_heading( sprintf( __( 'Welcome to WooCommerce Subscriptions %s!', 'woocommerce-subscriptions' ), $version ) );
|
||||||
$notice->set_content_template( 'update-welcome-notice.php', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory() . '/includes/upgrades/templates/', array(
|
$notice->set_content_template( 'update-welcome-notice.php', WC_Subscriptions_Plugin::instance()->get_plugin_directory() . '/includes/upgrades/templates/', array(
|
||||||
'version' => $version,
|
'version' => $version,
|
||||||
'features' => $features,
|
'features' => $features,
|
||||||
) );
|
) );
|
||||||
|
@@ -133,17 +133,21 @@ class WCS_Webhooks {
|
|||||||
switch ( $webhook->get_api_version() ) {
|
switch ( $webhook->get_api_version() ) {
|
||||||
case 'legacy_v3':
|
case 'legacy_v3':
|
||||||
|
|
||||||
|
// @phpstan-ignore-next-line Ignore legacy referencies.
|
||||||
if ( is_null( wc()->api ) ) {
|
if ( is_null( wc()->api ) ) {
|
||||||
throw new \Exception( 'The Legacy REST API plugin is not installed on this site. More information: https://developer.woocommerce.com/2023/10/03/the-legacy-rest-api-will-move-to-a-dedicated-extension-in-woocommerce-9-0/ ' );
|
throw new \Exception( 'The Legacy REST API plugin is not installed on this site. More information: https://developer.woocommerce.com/2023/10/03/the-legacy-rest-api-will-move-to-a-dedicated-extension-in-woocommerce-9-0/ ' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @phpstan-ignore-next-line
|
||||||
WC()->api->WC_API_Subscriptions->register_routes( array() );
|
WC()->api->WC_API_Subscriptions->register_routes( array() );
|
||||||
|
// @phpstan-ignore-next-line
|
||||||
$payload = WC()->api->WC_API_Subscriptions->get_subscription( $resource_id );
|
$payload = WC()->api->WC_API_Subscriptions->get_subscription( $resource_id );
|
||||||
break;
|
break;
|
||||||
case 'wp_api_v1':
|
case 'wp_api_v1':
|
||||||
case 'wp_api_v2':
|
case 'wp_api_v2':
|
||||||
// There is no v2 subscritpion endpoint support so they fall back to v1.
|
// There is no v2 subscritpion endpoint support so they fall back to v1.
|
||||||
$request = new WP_REST_Request( 'GET' );
|
$request = new WP_REST_Request( 'GET' );
|
||||||
|
// @phpstan-ignore class.nameCase
|
||||||
$controller = new WC_REST_Subscriptions_v1_Controller();
|
$controller = new WC_REST_Subscriptions_v1_Controller();
|
||||||
|
|
||||||
$request->set_param( 'id', $resource_id );
|
$request->set_param( 'id', $resource_id );
|
||||||
|
@@ -60,7 +60,7 @@ class WCS_Zero_Initial_Payment_Checkout_Manager {
|
|||||||
*/
|
*/
|
||||||
public static function cart_needs_payment( $cart_needs_payment ) {
|
public static function cart_needs_payment( $cart_needs_payment ) {
|
||||||
if ( ! self::zero_initial_checkout_requires_payment() ) {
|
if ( ! self::zero_initial_checkout_requires_payment() ) {
|
||||||
remove_filter( 'woocommerce_cart_needs_payment', 'WC_Subscriptions_Cart::cart_needs_payment', 10, 2 );
|
remove_filter( 'woocommerce_cart_needs_payment', 'WC_Subscriptions_Cart::cart_needs_payment' );
|
||||||
}
|
}
|
||||||
|
|
||||||
return $cart_needs_payment;
|
return $cart_needs_payment;
|
||||||
@@ -77,7 +77,7 @@ class WCS_Zero_Initial_Payment_Checkout_Manager {
|
|||||||
*/
|
*/
|
||||||
public static function order_needs_payment( $needs_payment ) {
|
public static function order_needs_payment( $needs_payment ) {
|
||||||
if ( ! self::zero_initial_checkout_requires_payment() ) {
|
if ( ! self::zero_initial_checkout_requires_payment() ) {
|
||||||
remove_filter( 'woocommerce_order_needs_payment', 'WC_Subscriptions_Order::order_needs_payment', 10, 3 );
|
remove_filter( 'woocommerce_order_needs_payment', 'WC_Subscriptions_Order::order_needs_payment' );
|
||||||
}
|
}
|
||||||
|
|
||||||
return $needs_payment;
|
return $needs_payment;
|
||||||
|
@@ -461,7 +461,7 @@ class WC_Subscriptions_Admin {
|
|||||||
$billing_period = 'month';
|
$billing_period = 'month';
|
||||||
}
|
}
|
||||||
|
|
||||||
include WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/admin/html-variation-price.php' );
|
include WC_Subscriptions_Plugin::instance()->get_plugin_directory( 'templates/admin/html-variation-price.php' );
|
||||||
|
|
||||||
wp_nonce_field( 'wcs_subscription_variations', '_wcsnonce_save_variations', false );
|
wp_nonce_field( 'wcs_subscription_variations', '_wcsnonce_save_variations', false );
|
||||||
|
|
||||||
@@ -919,7 +919,7 @@ class WC_Subscriptions_Admin {
|
|||||||
$script_params['ajaxUrl'] = admin_url( 'admin-ajax.php' );
|
$script_params['ajaxUrl'] = admin_url( 'admin-ajax.php' );
|
||||||
$script_params['isWCPre24'] = var_export( wcs_is_woocommerce_pre( '2.4' ), true );
|
$script_params['isWCPre24'] = var_export( wcs_is_woocommerce_pre( '2.4' ), true );
|
||||||
|
|
||||||
wp_enqueue_script( 'woocommerce_subscriptions_admin', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/js/admin/admin.js' ), $dependencies, filemtime( WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'assets/js/admin/admin.js' ) ) );
|
wp_enqueue_script( 'woocommerce_subscriptions_admin', WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory_url( 'assets/js/admin/admin.js' ), $dependencies, filemtime( dirname( WC_Subscriptions::$plugin_file ) . '/assets/js/admin/admin.js' ) );
|
||||||
wp_localize_script( 'woocommerce_subscriptions_admin', 'WCSubscriptions', apply_filters( 'woocommerce_subscriptions_admin_script_parameters', $script_params ) );
|
wp_localize_script( 'woocommerce_subscriptions_admin', 'WCSubscriptions', apply_filters( 'woocommerce_subscriptions_admin_script_parameters', $script_params ) );
|
||||||
|
|
||||||
// Maybe add the pointers for first timers
|
// Maybe add the pointers for first timers
|
||||||
@@ -1702,7 +1702,7 @@ class WC_Subscriptions_Admin {
|
|||||||
'paginate' => false,
|
'paginate' => false,
|
||||||
),
|
),
|
||||||
'',
|
'',
|
||||||
WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' )
|
WC_Subscriptions_Plugin::instance()->get_plugin_directory( 'templates/' )
|
||||||
);
|
);
|
||||||
|
|
||||||
return ob_get_clean();
|
return ob_get_clean();
|
||||||
@@ -1862,11 +1862,11 @@ class WC_Subscriptions_Admin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When subscription items not editable (such as due to the payment gateway not supporting modifications),
|
* When subscription items not editable (such as due to the payment gateway not supporting modifications),
|
||||||
* change the text to explain why
|
* change the text to explain why
|
||||||
*
|
*
|
||||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.7
|
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.7
|
||||||
*/
|
*/
|
||||||
public static function change_order_item_editable_text( $translated_text, $text, $domain ) {
|
public static function change_order_item_editable_text( $translated_text, $text, $domain ) {
|
||||||
|
|
||||||
switch ( $text ) {
|
switch ( $text ) {
|
@@ -33,7 +33,7 @@ class WCS_Admin_Empty_List_Content_Manager {
|
|||||||
'html-admin-empty-list-table.php',
|
'html-admin-empty-list-table.php',
|
||||||
[],
|
[],
|
||||||
'',
|
'',
|
||||||
WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/admin/' )
|
WC_Subscriptions_Plugin::instance()->get_plugin_directory( 'templates/admin/' )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@@ -91,7 +91,7 @@ class WCS_Admin_Notice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$template_name = 'html-admin-notice.php';
|
$template_name = 'html-admin-notice.php';
|
||||||
$template_path = WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/admin/' );
|
$template_path = WC_Subscriptions_Plugin::instance()->get_plugin_directory( 'templates/admin/' );
|
||||||
|
|
||||||
if ( function_exists( 'wc_get_template' ) ) {
|
if ( function_exists( 'wc_get_template' ) ) {
|
||||||
wc_get_template( $template_name, array( 'notice' => $this ), '', $template_path );
|
wc_get_template( $template_name, array( 'notice' => $this ), '', $template_path );
|
@@ -684,9 +684,14 @@ class WCS_Admin_Post_Types {
|
|||||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.0
|
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.0
|
||||||
*/
|
*/
|
||||||
public static function get_date_column_content( $subscription, $column ) {
|
public static function get_date_column_content( $subscription, $column ) {
|
||||||
$date_type_map = array( 'last_payment_date' => 'last_order_date_created' );
|
$date_type_map = array( 'last_payment_date' => 'last_order_date_created' );
|
||||||
$date_type = array_key_exists( $column, $date_type_map ) ? $date_type_map[ $column ] : $column;
|
$date_type = array_key_exists( $column, $date_type_map ) ? $date_type_map[ $column ] : $column;
|
||||||
$date_timestamp = $subscription->get_time( $date_type );
|
|
||||||
|
if ( 'last_payment_date' === $column ) {
|
||||||
|
$date_timestamp = self::get_last_payment_date( $subscription );
|
||||||
|
} else {
|
||||||
|
$date_timestamp = $subscription->get_time( $date_type );
|
||||||
|
}
|
||||||
|
|
||||||
if ( 0 === $date_timestamp ) {
|
if ( 0 === $date_timestamp ) {
|
||||||
return '-';
|
return '-';
|
||||||
@@ -1834,6 +1839,26 @@ class WCS_Admin_Post_Types {
|
|||||||
return $pieces;
|
return $pieces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the last payment date for a subscription.
|
||||||
|
*
|
||||||
|
* @param WC_Subscription $subscription The subscription object.
|
||||||
|
* @return int The last payment date timestamp.
|
||||||
|
*/
|
||||||
|
private static function get_last_payment_date( $subscription ) {
|
||||||
|
$last_order_date_created = $subscription->get_last_order_date_created();
|
||||||
|
|
||||||
|
if ( ! empty( $last_order_date_created ) ) {
|
||||||
|
return $last_order_date_created;
|
||||||
|
}
|
||||||
|
|
||||||
|
$date_timestamp = $subscription->get_time( 'last_order_date_created' );
|
||||||
|
$subscription->set_last_order_date_created( $date_timestamp );
|
||||||
|
$subscription->save();
|
||||||
|
|
||||||
|
return $date_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds order table query clauses to sort the subscriptions list table by last payment date.
|
* Adds order table query clauses to sort the subscriptions list table by last payment date.
|
||||||
*
|
*
|
@@ -123,7 +123,7 @@ class WCS_Admin_System_Status {
|
|||||||
$section_tooltip = $section['tooltip'];
|
$section_tooltip = $section['tooltip'];
|
||||||
$debug_data = $section['data'];
|
$debug_data = $section['data'];
|
||||||
|
|
||||||
include WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/admin/status.php' );
|
include WC_Subscriptions_Plugin::instance()->get_plugin_directory( 'templates/admin/status.php' );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +216,7 @@ class WCS_Admin_System_Status {
|
|||||||
* @return array Theme override data.
|
* @return array Theme override data.
|
||||||
*/
|
*/
|
||||||
private static function get_theme_overrides() {
|
private static function get_theme_overrides() {
|
||||||
$wcs_template_dir = WC_Subscriptions_Core_Plugin::instance()->get_subscriptions_core_directory( 'templates/' );
|
$wcs_template_dir = WC_Subscriptions_Plugin::instance()->get_plugin_directory( 'templates/' );
|
||||||
$wc_template_path = trailingslashit( wc()->template_path() );
|
$wc_template_path = trailingslashit( wc()->template_path() );
|
||||||
$theme_root = trailingslashit( get_theme_root() );
|
$theme_root = trailingslashit( get_theme_root() );
|
||||||
$overridden = array();
|
$overridden = array();
|