1. Documentation /
  2. Introduction to Woo Subscriptions /
  3. Introduction to Subscriptions Developer Documentation /
  4. Subscriptions Data Structures & Storage

Subscriptions Data Structures & Storage

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. If you need to extend WooCommerce Subscriptions and are not a developer, you can find a developer in the WooExperts directory.
This guide introduces the fundamentals of the data structures used to instantiate and work with a 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.

Subscription Products vs. Subscriptions

↑ Back to top
WooCommerce 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.

Subscription Products

↑ Back to top
A 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 or product_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 top
Once 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:
  • 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.
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 top
As 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 top
All 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 extends WC_Product_Simple
  • A variable subscription product is instantiated using WC_Product_Variable_Subscription, which extends WC_Product_Variable
  • A subscription variation is instantiated using WC_Product_Subscription_Variation, which extends WC_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 top
Subscription 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 top
A 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-related order_item is actually the ID of a subscription

Subscription Storage

↑ Back to top
Subscription 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 top
All 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 top
As 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(). This ID also replaced a subscription key that was used in Subscriptions v1.5 and older.