With the release of Subscriptions v2.0, multiple subscription products could be purchased together in the one transaction. This guide provides an overview of the technical implementation of multiple subscription handling.
For a more comprehensive overview of the system, including the decisions involved in choosing this implementation, refer to the Store Manager Guide to Multiple Subscriptions. If you have not already, you should read that guide before continuing with this document.
Initial Implementation
The first implementation proposed was to create a separate subscription (i.e. 'shop_subscription'
) for each subscription product purchased in the transaction.
For example, if a customer purchases 2 x monthly subscription products and 3 x yearly subscription products in the one transaction, 5 x subscriptions would be created with each including a single line item for that product.
Issues with Initial Design
This system would be most similar to the v1.5 system, but it did not take full advantage of the flexibility of the new subscription object being introduced in v2.0. It applied the constraints of the v1.5 design to the new architecture.
Furthermore, to achieve the goals of consolidating renewal orders and reducing payment gateway fees, this system would need a batch processing system to group each subscription’s renewals into the one order.
Batch processing created a major issue: shipping could not accurately be calculated and agreed to on checkout. Because some shipping methods charge per order, and subscriptions were batched into renewal orders, any time a customer purchased new subscriptions or cancelled existing subscriptions, the shipping amount would be different at renewal to the time of sign-up. This issue was ultimately declared an unavoidable and unfixable bug with the implementation and so that design was abandoned.
Final Implementation: Grouping Subscriptions
The design ultimately chosen was the grouping of each subscription product with the same billing schedule into the one subscription product.
For example, if a customer purchases 2 x monthly subscriptions and 3 x yearly subscriptions in the one transaction, only 2 x subscriptions would be created – one with line items for the monthly subscription products and one with line items for the annual subscription products.
This allowed shipping to be accurately calculated and displayed during sign-up, while also consolidating renewal orders and reducing payment gateway fees for subscription products purchased in the same transaction.
Cart Grouping
To support the purchase of multiple subscriptions in the same transaction, the cart (WC_Cart
) now stores each subscription’s recurring totals in an array of carts (WC_Cart
objects) in a new WC_Cart::$recurring_carts
property. Previously, these details were stored as properties on the main cart, e.g. WC_Cart::$recurring_order_total
.
The WC_Cart::$recurring_carts
property includes an instance of WC_Cart
for each distinct billing schedule. For example, if the cart contains 2 x products renewing each year and 3 x products which renew each month, the WC_Cart::WC_Cart::$recurring_carts
property will contain two WC_Cart
objects – one for the items and totals of the annual products and one for the monthly products.
Recurring Cart Key
The grouping of items is handled by creating a key for each subscription product based on its:
- first payment date: this accounts for free trial periods, synchronised renewal dates and any prorated duration that results from switching a subscription.
- billing period and interval: a subscription’s billing period (e.g. month or week) and interval (i.e. every 2nd) is then added to group subscriptions based on their billing schedule.
- length: finally, if a subscription will expire at some time in the future, this is taken into account to avoid grouping subscriptions on the same schedule that do not expire with subscriptions that do expire.
The recurring cart key is created by the method: WC_Subscriptions_Cart::get_recurring_cart_key()
It can also be modified using the filter: 'woocommerce_subscriptions_recurring_cart_key'
Recurring Cart Key Examples
If purchasing a subscription on the 18th December 2015 that has 1 month free trial and then is $50 / month for 12 months, its recurring cart key will be: '2015_01_18_monthly_for_12_months'
.
If purchasing a subscription on the 21st December 2015 that has 4 weeks free trial and then is $50 every 2nd week, its recurring cart key will be: '2015_01_18_every_2nd_week'
.
Grouped Recurring Total Display
Subscriptions v1.5 displayed the recurring totals alongside the order totals on the cart and order review pages. However, by supporting multiple subscriptions in the one transaction, multiple different recurring periods needed to be displayed so that the customer understood the commitment they were making.
A few options were explored for how to display recurring totals for multiple subscriptions, including:
- do not display the totals – this is illegal in many countries and was barely considered, but is included here for posterity;
- continue to display recurring totals inside of the order totals section;
- add a new Recurring Totals section below the existing order totals section to display recurring subtotal, shipping, taxes and total.
- display a complete order table for each subscription below the Sign Up Now/Place Order button.
The Recurring Totals section was chosen as it was the most concise method that still provided accurate information for each recurring amount.
Each groups of subscription products will have a row in the Recurring Totals section for:
- subtotal
- shipping
- taxes
- discounts
- total
Order Grouping
As mentioned above, after purchasing multiple subscription products in the same transaction, the products with the same billing schedule will be grouped together as line items on the one subscription object (as opposed to each subscription having only one product/line item associated with it).
For example, the three screenshots below show:
- an order used to purchase 4 subscription products – it has 4 line items; and
- two subscriptions created to store data for the 4 subscription products – each has 2 line items.