This guide introduces the fundamentals of the data structures used to instantiate and work with subscription data with the WooCommerce Subscriptions extension. It is not intended to provide tutorials on how to achieve certain tasks with the subscription object, or as a comprehensive reference of all the subscription properties and methods.
This documentation is written for WooCommerce developers who want to extend or integrate with the WooCommerce Subscriptions plugin. To follow this documentation, you will need an advanced understanding of PHP and WordPress development.
If you are looking for a guide to creating and managing subscription products in a WooCommerce store, please refer to the Store Manager Guide instead.
Note: We are unable to provide support for customizations under our Support Policy. If you need to customize a snippet or extend its functionality, we recommend working with a Woo Agency Partner or finding a WooCommerce developer on Codeable.
Subscription Products vs. Subscriptions
↑ Back to topWooCommerce Subscriptions provides two different, but related items:
- Subscription products, which are offered to customers for purchase. These are an extension of WooCommerce products and includes simple subscriptions, variable subscriptions or subscription variations.
- Subscriptions, which are an agreement between your store and a customer for future transactions. These are an extension of WooCommerce orders.
Learn more about subscription products vs. subscriptions or subscriptions vs. orders.
Subscription Products
↑ Back to topA subscription product is a custom product type that can be selected when creating a new product. When referring to a subscription product in the WooCommerce Subscriptions code base, $product
or $product_id
will be used as the variable name.
Subscription product data is:
- stored with as a
product
orproduct_variation
custom post type in the database; and - instantiated as an instance of a child class of
WC_Product
in memory for use at the application level.
Subscriptions
↑ Back to topOnce a customer has purchased a subscription product, it is then stored and accessed as a subscription. This is a custom order type, which is referred to in the code base with variable names of $subscription
or $subscription_id
.
Subscription data is:
In the WordPress posts storage (legacy):
- stored with a
shop_subscription
custom post type in the database; and - instantiated as a
WC_Subscription
object in memory for use at the application level.
in the High-performance order storage (HPOS):
- stored with a
shop_subscription
type in thewc_orders
table; and - instantiated as a
WC_Subscription
object in memory for use at the application level.
For a more indepth, non-technical guide to these two objects, refer to the Guide to Subscription Products vs. Subscriptions.
Subscription Product Data Structure and Storage
↑ Back to topAs mentioned earlier, subscription product data is stored as a product
or product_variation
custom post type in the database. These two post types are registered and managed by WooCommerce.
Subscriptions extends these post types using a subscription
or variable-subscription
term value for the product_type
custom taxonomy. The product_type
taxonomy is registered and managed by WooCommerce. The subscription
or variable-subscription
term values are added by Subscriptions to create a custom product types.
The database schema for subscription products includes all the same data as the to the schema for WooCommerce corresponding products. Specifically:
- A simple subscription has all the same data as a simple product.
- A variable subscription has all the same data as a variable product.
- A subscription variation has all the same data as a variation.
To make a subscription product unique, they also have additional data, including the following rows store in the post meta table:
_subscription_price
: the recurring price for the subscription product._subscription_sign_up_fee
: an optional one-off amount to charge at the time of sign-up._subscription_period
: the unit of time for the recurring billing schedule, e.g. week, month or year._subscription_period_interval
: the number of units between each renewal for recurring billing schedule, e.g.2
._subscription_length
: the number of units of time to wait between sign-up and an automatic expiration date._subscription_trial_period
: an optional unit of time to add before the first renewal, e.g. week, month or year._subscription_trial_length
: the number of units of time to add before the first renewal, e.g.2
.
This is not an complete list of the additional meta data for subscription products. It includes only the most important and commonly used meta data.
A number of additional piece of meta data are used to store details on other subscription product features like _subscription_limit
for limiting subscription purchases, _subscription_one_time_shipping
for the One Time Shipping option and _subscription_payment_sync_date
for renewal synchronization.
Subscription Products at the Application Level
↑ Back to topAll subscription products are instantiated as an instance of a child class of WC_Product
.
Specifically:
- A simple subscription product is instantiated using
WC_Product_Subscription
, which extendsWC_Product_Simple
- A variable subscription product is instantiated using
WC_Product_Variable_Subscription
, which extendsWC_Product_Variable
- A subscription variation is instantiated using
WC_Product_Subscription_Variation
, which extendsWC_Product_Variation
This means you can use all the methods of the WC_Product
class and corresponding parent class on subscription products.
Working with Subscription Product Data
↑ Back to topSubscription provides an imperative API through the WC_Subscriptions_Product
which can be used to access subscription data. For example:
WC_Subscriptions_Product::get_period( $product )
: provides the unit of time for a given product’s renewal schedule (the_subscription_period
post meta mentioned above).WC_Subscriptions_Product::get_interval( $product )
: provides the number of units of time for a given product’s renewal schedule (the_subscription_period_interval
post meta mentioned above).WC_Subscriptions_Product::get_length( $product )
: provides the number of renewals to process before expiring the subscription (the_subscription_length
post meta mentioned above).
More information on the available functions in WC_Subscriptions_Product
can be found in the Subscription Product Function Reference Guide.
It is also possible to access subscription meta data directly via the product properties, but not recommended as it bypasses filters applied to that data. Subscriptions may in the future be changed to use an object interface on the subscription product classes for accessing subscription data, but for now, the imperative method is the best option.
Subscription Data Structure and Storage
↑ Back to topA subscription is almost identical to an order. They differ in their application – a subscription is agreement for transactions in the future, while an order is record of transcations in the past – but their data is very similar. Both have line items, customer details, status etc. Because of this, it makes sense for subscription data to be stored and accessed in the same way as order data.
Fortunately, WooCommerce offers a little known API for doing just that by creating custom order types. This API makes it possible to create orders for use cases other than simply recording purchase transactions. It is used internally by WooCommerce for refunds and used by Subscriptions to create, store and work with subscription data.
How is the Product linked to someone’s Subscription on the database level?
- The items in a subscription are stored as
order_items
- The
order_id
of a subscription-relatedorder_item
is actually the ID of a subscription
Subscription Storage
↑ Back to topSubscription data is stored as a shop_subscription
custom post type in the database. This post type is very similar to the shop_order
post type and indeed, is even registered by WooCommerce. Subscriptions requests a subscription order type be created and WooCommerce creates the corresponding post type.
The database schema for subscriptions includes all the same data as the schema for orders. Specifically subscriptions and orders both have the following data:
- Customer details: user ID, shipping address, billing address, email, phone number.
- Line items: product, shipping, tax, coupon/discount, fee items.
- Download permissions
- Payment method
- Order notes
- Status
A subscription also has additional data especially for managing renewals, including the following rows stored in the post meta table:
_schedule_trial_end
: a MySQL formatted date/time string in UTC timezone representing the time which the free trial on a subscription ends or ended._schedule_next_payment
: a MySQL formatted date/time string in UTC timezone representing the time which the next renewal payment for a subscription will be processed (or in the rare occasion this is in the past, the time it was processed)._schedule_end
: a MySQL formatted date/time string in UTC timezone representing the time which the subscription will expire or end if it is pending cancellation, or the date it has previously ended, if it has expired or was cancelled._requires_manual_renewal
: a flag indicating whether a subscription should use the manual renewal method.
This is not an complete list of the extra meta data that may exist on subscriptions. It includes only the most important and commonly used meta data.
A number of additional piece of meta data are used to store details on other subscription product features like _suspension_count
for keeping track of the number of suspensions. There is also some meta data stored in line item meta data table, like _has_trial
, which is mostly used for internal logic.
Updating the next payment date for subscriptions?
Changing the value of
_schedule_next_payment
does not re-schedule the scheduled action. If this value is updated directly without also rescheduling the scheduled action, the previous value will still be used to process the next renewal order. This can result in multiple renewal orders only a short amount of time apart. Instead, we recommend using the correct function to process these types of changes, in this case: WC_Subscription::update_dates
Subscriptions at the Application Level
↑ Back to topAll subscriptions are instantiated as an instance of a WC_Subscription
. As subscriptions are a custom order type, this class extends the WC_Order
and inherits all the methods of WC_Order
(as well as WC_Abstract_Order
).
This class also provides a number of subscription specific functions, including:
WC_Subscription::get_date( $date_type )
: gets a specific date, like next payment date.WC_Subscription::update_dates( $dates )
: sets a specific set of dates, like trial end and next payment date.WC_Subscription::calculate_date( $date_type )
: calculates a specific date, like next payment date, based on the subscription’s schedule.WC_Subscription::get_related_orders( $return_fields, $order_type )
: returns orders relating to a subscription, which can be renewal, switch or parent orders.WC_Subscription::is_manual()
: check whether a subscription is using the manual renewal method.WC_Subscription::update_manual( $is_manual )
: set whether a subscription should use the manual renewal method or not.
This is just a small sample of the available functions on a WC_Subscription
. More information on the available functions can be found in the Subscription Function Reference Guide.
Subscription ID
↑ Back to topAs a subscription is a custom post type, it has a post ID like any other WordPress post type. This is the way to refer to a unique subscription.
This ID can also be used to get the subscription using wcs_get_subscription()
.