woocommerce-subscriptions
Included with Lifetime
$97 forever
Add subscription products to WooCommerce with automatic recurring billing, renewal notifications, and subscriber self-service management
platform-woocommercewoocommercesubscriptionsrecurring-paymentsbillingrenewalstripephp
What this skill does
# WooCommerce Subscriptions
## Overview
WooCommerce Subscriptions (the official premium plugin) adds subscription product types — simple subscriptions and variable subscriptions — with configurable billing periods (daily, weekly, monthly, yearly), free trials, sign-up fees, and prorated upgrades/downgrades. It integrates with Stripe, PayPal Reference Transactions, and other gateways that support automated recurring billing. Custom logic hooks into the subscription lifecycle via a rich set of WordPress actions and filters.
## When to Use This Skill
- When selling products or services on a recurring billing schedule (SaaS, memberships, box subscriptions)
- When implementing subscription upgrades, downgrades, or plan switching
- When building custom renewal logic or adding business rules around failed payment retry
- When integrating subscription status with access control (e.g., membership site content gates)
- When extending subscription emails or admin reporting with custom data
- When creating subscription add-ons or per-unit quantity scaling
## Core Instructions
1. **Create a subscription product programmatically**
```php
<?php
// Create a simple subscription product via code (e.g., in a migration script)
$product = new WC_Product_Subscription();
$product->set_name('Monthly Pro Plan');
$product->set_status('publish');
$product->set_regular_price('29.99');
// Save first so the product gets an ID
$product->save();
// Subscription-specific meta (product must be saved before setting post meta)
update_post_meta($product->get_id(), '_subscription_price', '29.99');
update_post_meta($product->get_id(), '_subscription_period', 'month');
update_post_meta($product->get_id(), '_subscription_period_interval', '1');
update_post_meta($product->get_id(), '_subscription_length', '0'); // 0 = forever
update_post_meta($product->get_id(), '_subscription_trial_length', '14');
update_post_meta($product->get_id(), '_subscription_trial_period', 'day');
update_post_meta($product->get_id(), '_subscription_sign_up_fee', '0');
```
2. **Hook into subscription lifecycle events**
WooCommerce Subscriptions fires specific actions at each lifecycle stage:
```php
<?php
// When a new subscription is created (after successful first payment)
add_action('woocommerce_subscription_status_active', function ($subscription) {
$user_id = $subscription->get_user_id();
$plan = $subscription->get_items(); // Array of WC_Order_Item_Product
// Grant access — e.g., set user role or update capabilities
$user = new WP_User($user_id);
$user->add_role('subscriber_member');
// Track in analytics
error_log("Subscription {$subscription->get_id()} activated for user {$user_id}");
});
// When a renewal payment succeeds
add_action('woocommerce_subscription_renewal_payment_complete', function ($subscription, $last_order) {
$user_id = $subscription->get_user_id();
// Extend access, send renewal receipt, update CRM
do_action('my_plugin_renewal_processed', $user_id, $subscription);
}, 10, 2);
// When a renewal payment fails
add_action('woocommerce_subscription_payment_failed', function ($subscription, $last_order) {
$user_id = $subscription->get_user_id();
$retry_count = $subscription->get_failed_payment_count();
// Notify user and optionally pause access
if ($retry_count >= 2) {
$user = new WP_User($user_id);
$user->remove_role('subscriber_member');
// Send dunning email
$subscription->update_status('on-hold');
}
}, 10, 2);
// When subscription is cancelled
add_action('woocommerce_subscription_status_cancelled', function ($subscription) {
$user_id = $subscription->get_user_id();
$user = new WP_User($user_id);
$user->remove_role('subscriber_member');
});
```
3. **Query subscriptions programmatically**
```php
<?php
// Get all active subscriptions for a user
function get_user_active_subscriptions(int $user_id): array {
return wcs_get_users_subscriptions($user_id, ['active']);
}
// Check if a user has an active subscription to a specific product
function user_has_active_subscription_to_product(int $user_id, int $product_id): bool {
$subscriptions = wcs_get_subscriptions_for_product($product_id, 'any', ['customer_id' => $user_id]);
foreach ($subscriptions as $subscription) {
if ($subscription->has_status('active')) {
return true;
}
}
return false;
}
// Get subscription by ID
function get_subscription_details(int $subscription_id): ?WC_Subscription {
$subscription = wcs_get_subscription($subscription_id);
if (!$subscription) return null;
return $subscription;
}
// Usage
$subscription = get_subscription_details(1234);
if ($subscription) {
echo $subscription->get_status(); // 'active', 'on-hold', 'cancelled', etc.
echo $subscription->get_next_payment_date(); // ISO 8601 date
echo $subscription->get_total(); // Current billing amount
}
```
4. **Handle plan upgrades and downgrades**
```php
<?php
// Add proration logic for plan switches
add_filter('woocommerce_subscriptions_switch_proration', function ($proration_amount, $subscription, $new_order, $product, $switch_cart_item) {
// Custom proration: charge/credit based on days remaining in billing period
$next_payment = strtotime($subscription->get_next_payment_date());
$last_payment = $subscription->get_date('last_payment');
$billing_period_days = ($next_payment - strtotime($last_payment)) / DAY_IN_SECONDS;
$days_remaining = ($next_payment - time()) / DAY_IN_SECONDS;
$old_daily_rate = (float)$subscription->get_total() / $billing_period_days;
$new_product_price = (float)$switch_cart_item['data']->get_price();
$new_daily_rate = $new_product_price / $billing_period_days;
// Credit remaining days at old rate, charge at new rate
$proration_amount = ($new_daily_rate - $old_daily_rate) * $days_remaining;
return round($proration_amount, 2);
}, 10, 5);
// Trigger a plan switch programmatically
function switch_subscription_plan(int $subscription_id, int $new_product_id): bool {
$subscription = wcs_get_subscription($subscription_id);
if (!$subscription) return false;
// Remove existing item and add new product
foreach ($subscription->get_items() as $item_id => $item) {
$subscription->remove_item($item_id);
}
$item = new WC_Order_Item_Product();
$item->set_product(wc_get_product($new_product_id));
$item->set_quantity(1);
$subscription->add_item($item);
// Recalculate totals
$subscription->calculate_totals();
$subscription->save();
return true;
}
```
5. **Retry failed payments and synchronize billing dates**
```php
<?php
// Trigger an immediate payment retry (e.g., from an admin action)
function retry_failed_subscription_payment(int $subscription_id): bool {
$subscription = wcs_get_subscription($subscription_id);
if (!$subscription || !$subscription->has_status('on-hold')) {
return false;
}
// Create a renewal order and attempt payment
$renewal_order = wcs_create_renewal_order($subscription);
if (is_wp_error($renewal_order)) {
return false;
}
// Process payment using the subscription's payment method
$payment_gateway = wc_get_payment_gateway_by_order($subscription);
if ($payment_gateway && method_exists($payment_gateway, 'scheduled_subscription_payment')) {
$payment_gateway->scheduled_subscription_payment(
$renewal_order->get_total(),
$renewal_order
Related in platform-woocommerce
woocommerce-plugin-development
IncludedCreate custom WooCommerce plugins using action/filter hooks, the Settings API, and REST API extensions to add features without modifying core
platform-woocommerce
woocommerce-blocks
IncludedCustomize WooCommerce checkout and cart pages using Gutenberg blocks with server-side rendering, slot-fills, and extensibility hooks
platform-woocommerce
woocommerce-rest-api
IncludedIntegrate or build headless frontends on WooCommerce using its REST API for products, orders, customers, and coupons with key authentication
platform-woocommerce
woocommerce-performance
IncludedFix slow WooCommerce stores by optimizing database queries, clearing transients, enabling Redis object caching, and configuring page caching
platform-woocommerce