Converting regular WooCommerce products to subscription products can be tricky. Recently, I needed to convert a bunch of products in bulk and ran into some interesting challenges that I’ll share with you along with the solution.
Without further ado, let’s see how we can properly convert both simple and variable products to their subscription counterparts.
First, let’s get our products. You can either work with specific product IDs or query them:
// Option 1: Specific IDs
$product_ids = array(123, 124, 125);
// Option 2: Query products
$product_ids = wc_get_products(array(
'status' => 'publish',
'limit' => -1,
'return' => 'ids',
));
Now for the conversion part. The tricky part here is that simply changing the product type isn’t enough, we need to set proper subscription meta and handle a couple of edge cases:
foreach ($product_ids as $product_id) {
$_product = wc_get_product($product_id);
if ($_product->is_type('variable')) {
// Convert variable product
wp_set_object_terms($product_id, 'variable-subscription', 'product_type');
// Get variations and convert them
$variations = $_product->get_children();
foreach ($variations as $variation_id) {
wp_set_object_terms($variation_id, 'subscription_variation', 'product_type');
set_variation_subscription_meta($variation_id);
}
// Important: Force the right product class and sync
$product = new WC_Product_Variable_Subscription($product_id);
WC_Subscriptions_Product::variable_subscription_product_sync($product);
$product->save();
} else {
// Convert simple product
wp_set_object_terms($product_id, 'subscription', 'product_type');
set_simple_subscription_meta($product_id);
}
// Clear caches
wc_delete_product_transients($product_id);
}
Here are the helper functions to set the subscription meta:
function set_variation_subscription_meta($variation_id) {
$variation = wc_get_product($variation_id);
// Set subscription settings
update_post_meta($variation_id, '_subscription_period', 'month');
update_post_meta($variation_id, '_subscription_period_interval', '1');
update_post_meta($variation_id, '_subscription_length', '0');
// Copy prices
$regular_price = $variation->get_regular_price();
if ($regular_price) {
update_post_meta($variation_id, '_subscription_price', $regular_price);
update_post_meta($variation_id, '_regular_price', $regular_price);
}
// Handle sale price if exists
$sale_price = $variation->get_sale_price();
if ($sale_price) {
update_post_meta($variation_id, '_sale_price', $sale_price);
update_post_meta($variation_id, '_price', $sale_price);
}
}
function set_simple_subscription_meta($product_id) {
$product = wc_get_product($product_id);
// Set subscription settings
update_post_meta($product_id, '_subscription_period', 'month');
update_post_meta($product_id, '_subscription_period_interval', '1');
update_post_meta($product_id, '_subscription_length', '0');
// Copy prices
$regular_price = $product->get_regular_price();
if ($regular_price) {
update_post_meta($product_id, '_subscription_price', $regular_price);
update_post_meta($product_id, '_regular_price', $regular_price);
}
// Handle sale price if exists
$sale_price = $product->get_sale_price();
if ($sale_price) {
update_post_meta($product_id, '_sale_price', $sale_price);
update_post_meta($product_id, '_price', $sale_price);
}
}
There are two important things to note here:
- For variable products, simply changing the product type isn’t enough. The product type tends to revert back when saved. That’s why we force the correct product class using
new WC_Product_Variable_Subscription()
and runvariable_subscription_product_sync()
to ensure all required meta is set. - The subscription meta needs to be set properly, including prices. Missing meta can cause various issues with the subscription functionality.
That’s it! You can now convert your products to subscription products programmatically. Just make sure to backup your database before running any conversion scripts.