Documentation · Version 1.0.0

XC WooCommerce Subscriptions Lite

A complete subscription engine for WooCommerce. This guide covers everything you need to install, configure, operate, and extend the plugin — from the first license activation to advanced developer integrations.

Author: XaniaCode License: Lifetime, single domain Support: 6 months included

Introduction

XC WooCommerce Subscriptions Lite turns any WooCommerce store into a fully featured subscription business. It ships every operational tool a recurring-revenue business needs — billing automation, customer self-service, content gating, coupons, analytics, and six branded email templates — for one lifetime payment with six months of direct developer support included.

This documentation is structured top-to-bottom in the order you will need it. Read the first three sections to install and license the plugin. Skim the configuration sections to set defaults that match your business. Then dive into whichever feature area you need to use. The Developer reference and Troubleshooting sections are for when you need them.

Tip If you are migrating from another subscription plugin, jump to Troubleshooting first — the most common migration questions are addressed there.

What you can build with this plugin

  • Recurring digital products and memberships (newsletters, courses, communities)
  • Streaming and content services with €0-checkout free trials
  • Subscription boxes with weekly, monthly, or quarterly fulfillment cadences
  • Recurring services (gym, coaching, SaaS, donations) with sign-up fees
  • Premium content gated by an active subscription, page-by-page or inline
  • B2B annual subscriptions with extended trials and renewal reminders

What this plugin deliberately does not do

To stay focused, fast, and easy to support, the following functionality is intentionally excluded:

  • Variable / variation subscriptions (one billing schema per product)
  • Plan switching between subscriptions mid-cycle
  • Pro-rata billing calculations
  • Multiple subscriptions inside a single cart (one subscription per checkout)

If you require any of the above, this plugin is not the right fit and we will tell you so before purchase.

Server requirements

Before installing, verify your hosting environment meets the minimum baseline below. Most modern WordPress hosts comfortably exceed these requirements.

Requirement Minimum Recommended
WordPress6.06.7 or newer
WooCommerce8.09.0 or newer
PHP8.08.2 or 8.3
MySQL5.78.0+
MariaDB (alternative)10.410.6+
PHP memory limit128 MB256 MB
PHP max_execution_time30 s60 s
Disk space (plugin)~5 MB
HTTPS for license validationRequiredRequired

Required PHP extensions

These extensions ship with most PHP installations. Verify they are enabled by viewing Tools → Site Health → Info → Server in WordPress admin.

  • openssl — required for license-key encryption at rest
  • curl — required for license API and update checks
  • json — required for REST API endpoints
  • mbstring — required for safe string handling across locales
  • mysqli or pdo_mysql — required for database access

Cron requirements

The plugin uses two scheduled tasks: an hourly check for due renewals and trial-ending notices, and a daily activity-log cleanup. WordPress runs these via WP-Cron on every page load. For low-traffic sites, configure a real system cron instead so renewals fire on time:

*/15 * * * * curl -s https://your-site.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1
Note If WP-Cron is disabled (DISABLE_WP_CRON set to true), set up a real cron as shown above — otherwise renewals will never run.

Outbound network access

The plugin contacts xaniacode.com for two purposes only — license validation and update checks. There is no analytics, no telemetry, no third-party CDN. Allowlist these endpoints if your firewall blocks outbound HTTPS:

  • https://xaniacode.com/api/v1/license/* (license activate / verify / deactivate)
  • https://xaniacode.com/updates/wordpress (update info and download URL)

Compatibility matrix

HPOS (High-Performance Order Storage)✅ Full support, declared via FeaturesUtil
Cart & Checkout Blocks✅ Full compatibility declared
Multisite✅ Network or per-site activation
Page builders✅ Gutenberg, Elementor, Divi, Beaver Builder, Bricks
Themes✅ Theme-independent — works with any well-coded theme
WPML / Polylang⚠️ Strings are translatable; multi-currency on subscriptions requires a third-party multi-currency plugin
GDPR✅ No tracking, no third-party CDN, no analytics

Installation

The plugin is distributed as a standard WordPress ZIP. There are two ways to install it.

Method 1 — Upload through WordPress admin (recommended)

  1. Download xc-woocommerce-subscriptions-lite.zip from your XaniaCode account dashboard.
  2. In WordPress admin, go to Plugins → Add New → Upload Plugin.
  3. Click Choose File, select the ZIP, click Install Now.
  4. After installation completes, click Activate Plugin.
  5. If WooCommerce is not installed, the plugin shows a notice and refuses to load further. Install and activate WooCommerce first, then reactivate.

Method 2 — FTP / SFTP upload

  1. Unzip the plugin file locally.
  2. Upload the resulting xc-woocommerce-subscriptions-lite folder to /wp-content/plugins/ on your server using FTP or SFTP.
  3. In WordPress admin, go to Plugins and click Activate next to XC WooCommerce Subscriptions Lite.
Warning Do not unzip the plugin into a sub-directory like xc-woocommerce-subscriptions-lite/xc-woocommerce-subscriptions-lite/ — WordPress will not recognise it. The plugin's main .php file must sit one level deep inside /wp-content/plugins/.

What happens on activation

The first time the plugin activates it performs the following one-time setup tasks automatically:

  • Creates three custom database tables: {prefix}xc_wcsl_subscription_meta, {prefix}xc_wcsl_log, and {prefix}xc_wcsl_renewals
  • Adds 14 capabilities to the administrator and shop_manager roles for managing the subscription post type
  • Schedules two recurring cron events (xc_wcsl_check_subscriptions hourly, xc_wcsl_cleanup_logs daily)
  • Creates default settings under the xc_wcsl_settings option
  • Marks the rewrite rules for a one-shot flush, which happens automatically on the next admin page load
  • Starts the 14-day free trial countdown

Reactivation is idempotent — settings, capabilities, and database tables are preserved across deactivate / reactivate cycles.

License activation

The plugin runs in trial mode for 14 days from first activation, no license key required. Within that window, every feature is fully functional. To continue past the trial — and to receive automatic updates — activate your license.

Activate your license

  1. Open WooCommerce → XC Subscriptions Lite (License) in WordPress admin.
  2. Locate your license key in the order confirmation email from XaniaCode, or under My Account → My Licenses on xaniacode.com.
  3. Paste the key into the License key field.
  4. Click Activate. A success message confirms activation; the page now shows your activation status, expiry (if applicable), and remaining domain seats.

Deactivating the license on a site

If you are migrating the plugin to a different domain, deactivate the license on the old site first to free up the seat:

  1. Open WooCommerce → XC Subscriptions Lite (License).
  2. Click Deactivate license.
  3. Wait for the confirmation message before changing domains.
Note Activation rate-limits to 5 attempts per 15 minutes per user and IP, and failed activations show a generic error message. This is intentional — it prevents brute-force key enumeration and protects your license key from disclosure.

What happens after the license expires

The plugin is designed to never break paying customers. When the license expires:

  • ✅ Existing subscriptions continue running
  • ✅ Renewal orders are still generated automatically
  • ✅ Customer self-service (cancel, pause, reactivate) keeps working
  • ✅ All admin tooling stays available
  • New subscription sign-ups on your storefront are paused — the Subscribe button stops working until the license is renewed

A persistent admin notice on plugin pages reminds you to reactivate.

First-time setup

After activation, walk through the four settings tabs in order. Each one takes about a minute to configure for a typical store. Defaults are sensible — most stores can leave the General and Renewals tabs unchanged.

  1. Open WooCommerce → Subscriptions Settings.
  2. Review the General tab. Decide whether customers can self-serve cancel and pause, and pick the active and inactive subscriber roles.
  3. Review the Renewals tab. The defaults (3 retries, 2 days apart) work for most gateways.
  4. Review the Emails tab. Enable renewal reminders and set how many days before renewal the reminder is sent.
  5. Review the Advanced tab. Set log retention (default 60 days). Use the Run scheduler now button to verify cron tasks fire correctly.
  6. Create a test subscription product and complete a test checkout (see Creating products).

That's it — the plugin is now ready for production.

General settings

Found under WooCommerce → Subscriptions Settings → General.

Enable subscriptions enable_subscriptions
Default: yes
Master switch. When set to No, subscription products cannot be added to the cart and the customer's My Account portal is hidden. Existing subscriptions continue to run on the back end. Use this to temporarily disable subscriptions site-wide without uninstalling.
Allow customer cancellation allow_cancel
Default: yes
When enabled, customers see a Cancel button on each subscription in their My Account portal. Disable this if cancellation must go through customer support — the customer will see a contact link instead.
Allow customer pause allow_pause
Default: yes
When enabled, customers can pause and reactivate their own subscription from My Account. A paused subscription does not generate renewal orders until reactivated.
Mixed checkout mixed_checkout
Default: no
When disabled, the cart will reject mixing a subscription product with a regular product — customers must check out subscriptions and one-time products separately. Enable this if your products are commonly bought together.
Active subscriber role role_active
Default: subscriber
When a customer's subscription becomes Active, they are promoted to this WordPress role. Use a custom role with extra capabilities (e.g. premium_member) to grant access to gated content. Set to — No change — to leave roles untouched.
Inactive subscriber role role_inactive
Default: customer
When a customer no longer has any active subscription (cancelled, expired, on hold), they are demoted to this role. Set to — No change — to never demote.
Tip Roles are not changed for users with administrator or shop_manager roles, regardless of their subscription status. This protects against accidentally demoting your own staff accounts.

Renewal settings

Found under WooCommerce → Subscriptions Settings → Renewals. These options control what happens when a renewal payment fails.

Failed payment retries failed_payment_retries
Default: 3 · Range: 0–10
Total number of retry attempts before the subscription is moved to On hold. Set to 0 to skip retries entirely (subscription goes On hold immediately on first failure).
Days between retries failed_payment_retry_days
Default: 2 · Range: 1–30
Wait time between retry attempts. Use 1 day for aggressive recovery, 7 days for friendly dunning, 3 days for a balanced default.
Auto-complete paid renewals auto_complete_renewal
Default: yes
When a renewal order is paid, mark it Completed automatically rather than Processing. Useful for digital subscriptions where there is nothing to ship. Leave disabled if you handle renewal orders manually.
Cancellation grace period cancel_grace_days
Default: 0 · Range: 0–365
Days the subscription remains active after the customer cancels. Set to 0 to end immediately on cancel. Set to 30 to give cancelled customers another month of access (typical for paid memberships).

Email settings

Found under WooCommerce → Subscriptions Settings → Emails. Per-email customization (subject, heading, enable / disable each email individually) is under WooCommerce → Settings → Emails.

Send renewal reminders send_renewal_reminder
Default: yes
When enabled, customers receive a reminder email a configurable number of days before the next renewal payment. Recommended for annual subscriptions and any subscription with a high renewal price.
Reminder days before renewal renewal_reminder_days
Default: 3 · Range: 1–30
How many days in advance to send the renewal reminder. For monthly subscriptions, 3–7 days is standard. For annual subscriptions, 14–30 days reduces involuntary churn.

Advanced settings

Found under WooCommerce → Subscriptions Settings → Advanced. These are operational and developer-facing options.

Log retention (days) log_retention_days
Default: 60 · Range: 1–3650
Activity log entries older than this number of days are deleted automatically by the daily cleanup cron. Set higher (e.g. 365) for audit purposes; lower (e.g. 14) for high-traffic stores where the log table grows quickly.
Delete data on uninstall delete_data_on_uninstall
Default: no
When enabled and the plugin is removed via Plugins → Delete, all subscription posts, custom tables, options, and capabilities are permanently dropped. Default is disabled to protect against accidental data loss. Switch to Yes only when you intend to fully remove every trace.
Run scheduler now
Action button — no setting
Immediately runs the cron tasks (process due renewals, send trial-ending notices, send renewal reminders, expire past-due subscriptions). Useful for testing your setup without waiting for the next cron tick. Capability-checked and nonce-protected.
Warning Enabling Delete data on uninstall is irreversible. Take a database backup before uninstalling if you are unsure.

Creating subscription products

Subscription products are regular WooCommerce products with a different Product data type. Once you've configured the plugin, creating a subscription is a 60-second job.

Step-by-step

  1. Go to Products → Add New.
  2. Add a title, description, image, and category as you would for any product.
  3. Set the Regular price in the Product data box. This is the recurring price (the amount charged per billing cycle).
  4. In the Product data dropdown, select Simple subscription.
  5. Click the Subscription tab that appears.
  6. Configure the subscription fields (see reference below).
  7. Click Publish.

Subscription tab fields

Billing interval
Two inputs: a number (1, 2, 3…) and a period (day, week, month, year). Together they define the cadence. Examples: 1 month = monthly billing, 3 months = quarterly, 2 weeks = bi-weekly, 6 months = semi-annual, 1 year = annual.
Subscription length
Default: 0
Number of billing cycles before the subscription expires automatically. 0 means unlimited (until cancelled). Set to 12 with monthly billing to create an annual commitment that expires after a year. Set to 6 with monthly billing for a 6-month course or program.
Sign-up fee
Default: 0.00
A one-time charge added to the first order on top of the recurring price. Common for gym memberships (initiation fee), professional services (onboarding fee), and subscription boxes (welcome kit). Charged only on the parent (first) order, never on renewals.
Free trial — length
Default: 0
Length of the free trial in the chosen period (day / week / month / year). When greater than zero, the customer pays €0 at sign-up and the first recurring charge is scheduled for the trial end date. Sign-up fee, if any, is still charged.
Free trial — period
Default: day
Time unit for the trial length. Most stores use day (e.g. 7 days, 14 days, 30 days).

What gets stored

When you save the product, all these fields are persisted as post meta on the product. The plugin's WC_Product_XC_Subscription class exposes them via getters that match WooCommerce conventions, so any theme or extension built on the standard WC_Product API can read them.

Product examples

Ten concrete subscription configurations covering common business models. Use these as starting points.

Use case Price Billing Length Trial Sign-up fee
Newsletter premium€51 month0 (unlimited)
SaaS annual€991 year0 (unlimited)
Streaming with trial€121 month014 day
Subscription box quarterly€453 months0
Coffee weekly€151 week0
Gym membership€401 month0€100
6-month course€991 month6
Insurance bi-annual€2506 months0
B2B SaaS with trial€5001 year030 day
Recurring donation€101 month0

Customer experience

From the customer's point of view, buying and managing a subscription should feel exactly like buying any other WooCommerce product — only with a few clearly-marked recurring elements.

Single product page

The product page renders with three subscription-aware elements:

  • The price displays as a recurring schedule, e.g. "€28 / month" or "€45 every 3 months"
  • If a free trial is configured, a small label is added: "with 14-day free trial"
  • If a sign-up fee is set, a small label is added: "and a €100 sign-up fee"
  • The Add to cart button reads Subscribe instead of Add to cart

Cart page

In the cart, the subscription line item shows the recurring schedule. During an active free trial, the line price displays as Free trial and the cart subtotal is €0 (plus any sign-up fee). Below the cart totals, a small box explains the recurring billing:

Recurring totals
─────────────────
Subtotal:   €28.00 / month
Total:      €28.00 / month

First payment will be processed on May 19, 2026.

Checkout

Checkout filters available payment gateways automatically — only gateways with tokenization support or manual gateways (BACS, cheque) are offered for subscription carts. Guest checkout is disabled for subscription orders; the customer is required to create an account.

My Account portal

After purchase, the customer sees a new Subscriptions tab in their My Account page. The tab lists all their subscriptions with status, schedule, and next payment date. Clicking a row opens the single-subscription view with three actions:

  • Cancel — ends the subscription (or moves to grace-period state if configured)
  • Pause — temporarily stops renewals; can be reactivated anytime
  • Reactivate — visible only when the subscription is paused

All three actions are nonce-protected and only available to the subscription's owner.

Free trials and sign-up fees

Trials and sign-up fees are independent and can be combined in any way.

Free trial only

Configure a trial length on the product. The customer pays €0 at sign-up. The first recurring charge fires on the trial end date. A Trial ending email is sent automatically one day before the trial ends, giving the customer a chance to cancel if the service isn't for them.

Sign-up fee only

Configure a sign-up fee on the product. The customer pays the recurring price plus the fee at sign-up. Future renewals only charge the recurring price.

Trial plus sign-up fee

Both can coexist. The customer pays the sign-up fee at checkout (cart total = sign-up fee, recurring price = €0 during trial). The first recurring charge fires when the trial ends.

Configuration Customer pays at checkout Customer pays at first renewal
Recurring €28/mo€28€28 (1 month later)
Recurring €28/mo + 14-day trial€0€28 (14 days later)
Recurring €40/mo + €100 sign-up fee€140€40 (1 month later)
Recurring €40/mo + €100 sign-up fee + 14-day trial€100€40 (14 days later)
Tip Trials shorter than 3 days rarely convert customers; trials longer than 30 days inflate refund requests. The sweet spot for most digital products is 7–14 days.

Subscription list

Found under WooCommerce → Subscriptions. This is the operational hub — every subscription on your store appears here.

What you see

Each row shows: subscription ID and title, customer name, status, recurring schedule, next payment date, and action links. The list is sortable by date and filterable by status (Pending, Active, On hold, Paused, Cancelled, Expired).

Status filter views

Above the list, status views show the count of subscriptions in each state:

All (412) | Pending (3) | Active (385) | On hold (12) | Paused (4) | Cancelled (8) | Expired (0)

Click any view to filter the list. The view "All" matches subscriptions in any status.

Search

The search box at the top of the list searches subscription IDs, titles, and now also customer email, login, and display name. Type any of those to find a customer's subscriptions instantly.

Custom filter dropdown

A custom Filter by status dropdown appears above the list with all six subscription states. Use it to narrow the visible list before applying a bulk action or exporting.

Bulk actions

Manage many subscriptions at once with the bulk-action dropdown above the list.

Available actions

  • Mark as Active — moves selected subscriptions to Active status
  • Pause — moves selected subscriptions to Paused
  • Put on hold — moves selected subscriptions to On hold
  • Cancel — moves selected subscriptions to Cancelled

How to use

  1. Tick the checkbox on each row you want to affect, or tick the header checkbox to select all visible rows.
  2. Open the Bulk actions dropdown and choose the action.
  3. Click Apply.
  4. A confirmation notice shows the number of subscriptions updated.
Warning Bulk actions trigger the same lifecycle hooks as individual changes — emails are sent, customer notes are written, role assignments fire. A bulk Cancel on 100 subscriptions will send 100 cancellation emails. Use carefully on large lists.

CSV export

Export the current filtered list of subscriptions to CSV with one click. Useful for reporting, accounting handoff, and spreadsheet analysis.

How to export

  1. Apply any filter (status, search) to scope the list to what you want to export.
  2. Click Export to CSV (button next to the bulk-action dropdown).
  3. A CSV file downloads immediately with filename xc-subscriptions-YYYY-MM-DD-HHMMSS.csv.

Exported columns

The CSV contains 17 columns:

  1. ID
  2. Status
  3. Customer ID
  4. Customer email
  5. Product ID
  6. Product name
  7. Recurring total
  8. Currency
  9. Period
  10. Interval
  11. Start date
  12. Next payment
  13. End date
  14. Parent order
  15. Completed payments
  16. Failed payments
  17. Payment method
Tip The CSV is written with a UTF-8 BOM byte sequence so Excel opens it without the encoding picker dialog and renders accented characters correctly out of the box.

Single subscription view

Click any subscription in the list to open the single-subscription edit screen.

Subscription details panel

The main panel summarises the subscription:

  • Status (with dropdown to change manually)
  • Customer name and link to user profile
  • Linked product
  • Recurring schedule (price + period)
  • Start date, next payment, end date
  • Parent order link
  • Payment method
  • Payments counter (completed / failed)
  • Recent activity log

Manual actions available

  • Change status — update the status dropdown and click Update
  • Create renewal order — generates the next renewal order immediately, bypassing the schedule (useful for testing or force-billing)
  • Update next payment date — change the meta directly to reschedule

Activity log

Every status change, every renewal order created, every failed payment, and every customer self-service action is logged in the activity feed at the bottom of the screen. The log is searchable by event type and stored in a custom database table.

Subscription notes

The Subscription notes meta box on the right side of the single-subscription screen lets you write two types of notes.

Private (admin only)

Visible only to administrators and shop managers in the meta box. Useful for internal reminders ("call back about pricing", "VIP — escalate any issue").

Customer-visible

Shown to the customer in their My Account portal under that subscription. When you submit a customer-visible note, the customer is also notified by email with the note content and a link to view the subscription.

How to add a note

  1. Type the note text in the textarea inside the Subscription notes meta box.
  2. Choose the visibility from the dropdown — Private (admin only) or Send to customer.
  3. Click Add note.
  4. The note appears at the top of the notes list. Customer-visible notes have a green left border; private notes have a blue one.

Dashboard KPI widget

The plugin adds a widget to the WordPress dashboard (Dashboard → Home) summarising your subscription business.

What it shows

  • Active subscribers — total count of subscriptions in Active status
  • On hold count — subscriptions waiting on a failed payment retry
  • Monthly recurring revenue (MRR) — sum of all active subscriptions normalised to monthly
  • New (last 30d) — count of subscriptions activated in the past 30 days
  • New (last 7d) — same metric over a 7-day window
  • Cancelled (last 30d) — count of cancellations in the past 30 days
  • Cancelled (last 7d) — same over 7 days

How MRR is calculated

The widget queries every active subscription's recurring total and billing cadence, then normalises to a monthly amount. Daily billing × 30, weekly × 4.333, monthly × 1, yearly ÷ 12. Currencies are summed per active currency without conversion. The result is an estimate, not a financial report — for accounting use the CSV export and your accounting software.

Caching

KPIs are cached in a transient for 5 minutes to keep the dashboard fast. After bulk actions or major changes, KPIs may take up to 5 minutes to update.

Note Sign-up and churn counts come from the activity log, not from post creation dates. This means metrics reflect actual status changes, so a subscription cancelled and reactivated in the same week shows correctly in both columns.

Content gating

Restrict pages, posts, or specific content blocks to active subscribers. Three integration points are provided — pick whichever fits your use case.

Method 1 — Page-level meta box

The simplest method. Restricts an entire post or page.

  1. Edit any post or page.
  2. In the right sidebar, find the XC Subscription access meta box.
  3. Tick Restrict to active subscribers.
  4. Optionally pick a specific subscription product from the dropdown — only customers subscribed to that product will see this page.
  5. Optionally enter a redirect URL — non-subscribers will be sent there. Leave empty to show a deny message instead.
  6. Optionally enter a custom deny message. Falls back to a generic message with a login / shop link.
  7. Click Update on the post.

Method 2 — Shortcode

For inline content gating inside any post, page, or widget.

Basic usage

[xc_wcsl_member]
This text is only visible to active subscribers.
[/xc_wcsl_member]

Restrict to a specific product

[xc_wcsl_member product_id="123"]
Only customers with an active subscription to product 123 see this.
[/xc_wcsl_member]

Custom deny message

[xc_wcsl_member message="Become a member to read the full article"]
Premium content here…
[/xc_wcsl_member]

Method 3 — Helper functions (PHP)

For theme integration. Use these in header.php, single.php, custom templates, or any plugin code.

// Returns true if the current user has at least one active subscription
if ( xc_wcsl_user_has_active_subscription() ) {
    // Show member-only menu, button, or section
}

// Returns true if the current user has an active subscription for product 123
if ( xc_wcsl_user_has_active_subscription_for_product( 123 ) ) {
    // Show product-specific gated content
}

// Both functions accept an optional user_id argument
xc_wcsl_user_has_active_subscription( $other_user_id );
xc_wcsl_user_has_active_subscription_for_product( 123, $other_user_id );

Capability bypass

Users with the manage_woocommerce capability (administrators and shop managers) can always view restricted content, regardless of subscription status. This prevents you from locking yourself out of pages while editing them.

Subscription-aware coupons

The plugin extends WooCommerce's standard coupon system with three subscription-specific scopes. Configure on each coupon individually under Marketing → Coupons → Edit coupon.

The three scopes

First payment only
Default scope for all coupons
Standard WooCommerce behaviour — the discount applies to the parent order only. Renewal orders are charged at full recurring price. Use for "first month half-off" promotions.
Every renewal payment
The coupon discount is automatically re-applied to every renewal order generated by this subscription. Use for "10% off forever" loyalty deals or partner discounts.
Sign-up fee only
The discount applies only to the sign-up fee line, not to the recurring price. Use for "waive setup fee" promotions where the recurring price stays full.

How to set the scope

  1. Edit a coupon under Marketing → Coupons.
  2. Scroll to the General section of the coupon data tabs.
  3. Find the XC Subscription scope dropdown.
  4. Select the desired scope.
  5. Save the coupon.

How recurring re-application works

When a renewal order is generated, the plugin checks every coupon used on the parent order. For each coupon with scope Every renewal payment, it calls WooCommerce's standard apply_coupon() on the renewal order before totals are calculated. Coupons with other scopes are ignored on renewals.

Note The scope dropdown applies to subscription products only. On orders with regular products, all coupons behave exactly as standard WooCommerce coupons.

Email system

Six branded email templates ship with the plugin. Each is a full WC_Email subclass and integrates with the standard WooCommerce email system.

The six emails

Email Trigger Audience
Subscription ActivatedStatus changes to ActiveCustomer
Subscription PausedStatus changes to PausedCustomer
Subscription CancelledStatus changes to CancelledCustomer
Subscription ExpiredStatus changes to ExpiredCustomer
Renewal ReminderN days before next payment (configurable)Customer
Trial Ending1 day before trial end dateCustomer

Customising emails

Each email can be customised at WooCommerce → Settings → Emails. Click Manage on the email row to:

  • Enable or disable the email
  • Change the subject line (with placeholders like {site_title}, {subscription_id})
  • Change the heading shown at the top of the email body
  • Override the HTML and plain-text templates

Template files

To override the HTML or plain-text template, copy the relevant file from:

/wp-content/plugins/xc-woocommerce-subscriptions-lite/templates/emails/

To your active theme:

/wp-content/themes/your-theme/woocommerce/emails/

WooCommerce's standard template loader will pick up your override automatically.

Renewal engine

The plugin's renewal engine generates renewal orders on schedule and handles payment retries, race conditions, and end-of-life transitions automatically.

How renewals are processed

Once an hour, the xc_wcsl_check_subscriptions cron runs XC_WCSL_Renewal::process_due(), which:

  1. Acquires a global transient lock xc_wcsl_renewal_running (5-minute TTL) to prevent concurrent runs.
  2. Queries up to 50 subscriptions in Active status with _next_payment_date <= now.
  3. For each subscription, acquires a per-subscription lock (10-minute TTL) to prevent the same row being processed twice.
  4. If the subscription has reached its end date, transitions it to Expired and skips renewal.
  5. Otherwise, creates a new WooCommerce order linked back to the subscription via meta, and triggers the gateway-specific renewal-payment hook.
  6. Releases per-subscription lock and moves to the next.
  7. Releases the global lock at the end of the run.

Payment retry logic

When a renewal order is marked Failed, the plugin increments the failed-payments counter on the subscription and reschedules the next attempt by the configured retry interval. After the configured retry count is exceeded, the subscription is moved to On hold and the customer receives no further automatic charges until they update their payment method through customer support or self-service flows.

Manual scheduler runner

For testing — or to force the queue to flush immediately — use the Run scheduler now button under WooCommerce → Subscriptions Settings → Advanced. This fires process_due() synchronously and reports back the number of renewals processed.

Action hooks for gateway integration

Custom payment gateways can subscribe to the following actions to handle automatic re-charging of saved payment methods on renewals:

// Fired when a new renewal order is created
do_action( 'xc_wcsl_renewal_order_created', $renewal_order, $subscription );

// Generic gateway-aware hook (replaces {gateway} with the gateway slug)
do_action( "xc_wcsl_process_renewal_payment_{$gateway}", $renewal_order, $subscription );

Most modern gateways (Stripe, PayPal Payments, Mollie) ship with subscription-friendly tokenization and re-charge saved payment methods automatically when these actions fire. Manual gateways (BACS, cheque) leave the order in Pending payment and the customer pays the renewal manually.

REST API

The plugin exposes a small REST API under namespace xc-wcsl/v1 for automation, dashboards, and external integrations. All endpoints require authentication via standard WP REST authentication (cookies, application passwords, or JWT) and capability checks.

Endpoints

Method Endpoint Capability required Purpose
GET/subscriptionsedit_xc_wcsl_subscriptionsList subscriptions, filterable by status
GET/subscriptions/<id>edit_xc_wcsl_subscriptionGet a single subscription
POST/subscriptions/<id>/statusedit_xc_wcsl_subscriptionUpdate status
POST/subscriptions/<id>/renewedit_xc_wcsl_subscriptionManually trigger a renewal order

List subscriptions

GET /wp-json/xc-wcsl/v1/subscriptions?status=active&per_page=20

Query parameters:
  status    : pending | active | on-hold | paused | cancelled | expired | any
  per_page  : 1–100 (default 20)
  page      : 1+ (default 1)
  customer  : user ID (optional, filter by customer)

Response (excerpt):

{
  "subscriptions": [
    {
      "id": 412,
      "status": "xcsl-active",
      "customer_id": 89,
      "product_id": 17,
      "recurring_total": "28.00",
      "currency": "EUR",
      "period": "month",
      "interval": 1,
      "start_date": "2026-04-15 12:30:00",
      "next_payment": "2026-05-15 12:30:00",
      "completed_payments": 1,
      "failed_payments": 0
    }
  ],
  "total": 412,
  "pages": 21
}

Update status

POST /wp-json/xc-wcsl/v1/subscriptions/412/status
Content-Type: application/json
X-WP-Nonce: <nonce>

{ "status": "xcsl-cancelled", "note": "Cancelled by API" }

Trigger renewal

POST /wp-json/xc-wcsl/v1/subscriptions/412/renew
X-WP-Nonce: <nonce>

Returns the new renewal order ID on success, or a WP_Error with HTTP 4xx on failure.

Tip Use WordPress Application Passwords for server-to-server automation. They are scoped to a single user and revocable, and they work cleanly with cURL, fetch, and Postman.

Hooks reference

The plugin provides extensive action and filter hooks for developers. Below are the most useful ones for theme and plugin integration.

Action hooks (events)

HookFired whenArgs
xc_wcsl_subscription_createdA new subscription is created (typically at checkout)$subscription, $args
xc_wcsl_subscription_status_changedStatus changes (any direction)$subscription, $old, $new
xc_wcsl_subscription_status_xcsl-activeSubscription transitions to Active$subscription, $old
xc_wcsl_subscription_status_xcsl-cancelledSubscription transitions to Cancelled$subscription, $old
xc_wcsl_subscription_status_xcsl-pausedSubscription transitions to Paused$subscription, $old
xc_wcsl_subscription_status_xcsl-expiredSubscription transitions to Expired$subscription, $old
xc_wcsl_renewal_order_createdA renewal order is generated$order, $subscription
xc_wcsl_send_renewal_reminderRenewal reminder email is being sent$subscription
xc_wcsl_send_trial_endingTrial-ending email is being sent$subscription

Filter hooks (modify values)

HookModifies
xc_wcsl_add_to_cart_textThe "Subscribe" button label on subscription products
xc_wcsl_restrict_post_typesList of post types where the access meta box is shown (default: post, page)

Helper functions

// Subscription access checks
xc_wcsl_user_has_active_subscription( $user_id = 0 ): bool
xc_wcsl_user_has_active_subscription_for_product( $product_id, $user_id = 0 ): bool

// Working with the subscription object
$subscription = new XC_WCSL_Subscription( $post_id );
$subscription->get_status();           // 'xcsl-active' (without wc- prefix)
$subscription->get_customer_id();
$subscription->get_product_id();
$subscription->get_recurring_total();
$subscription->get_next_payment_date();
$subscription->update_status( 'xcsl-cancelled', 'Reason' );
$subscription->can_be_cancelled();
$subscription->can_be_paused();
$subscription->can_be_reactivated();
$subscription->get_formatted_schedule(); // "€28 every month"

Database tables

The plugin creates three custom tables on activation. All names are prefixed with the WordPress table prefix (default wp_).

{prefix}xc_wcsl_subscription_meta

Reserved for subscription-specific metadata that should not live in postmeta. Currently used sparingly; most subscription data lives in standard postmeta on the subscription post type.

meta_id          BIGINT UNSIGNED PK AUTO_INCREMENT
subscription_id  BIGINT UNSIGNED  -- foreign reference to wp_posts.ID
meta_key         VARCHAR(255)
meta_value       LONGTEXT

{prefix}xc_wcsl_log

Activity log. Every status change, every payment success or failure, every customer-initiated action, every admin note is recorded here. Pruned daily by the xc_wcsl_cleanup_logs cron based on Log retention (days) setting.

log_id           BIGINT UNSIGNED PK AUTO_INCREMENT
subscription_id  BIGINT UNSIGNED
user_id          BIGINT UNSIGNED
level            VARCHAR(20)    -- info, warning, error
event            VARCHAR(100)   -- status_change, renewal_created, admin_note, customer_note, ...
message          TEXT
context          LONGTEXT       -- JSON-encoded extra data
created_at       DATETIME

{prefix}xc_wcsl_renewals

Tracks every renewal order created, scheduled, and processed. Useful for reporting and reconciliation.

renewal_id       BIGINT UNSIGNED PK AUTO_INCREMENT
subscription_id  BIGINT UNSIGNED
order_id         BIGINT UNSIGNED  -- linked WC order
status           VARCHAR(50)
scheduled_for    DATETIME
processed_at    DATETIME
amount           DECIMAL(19,4)
currency         VARCHAR(10)
Warning These tables are dropped automatically when the plugin is uninstalled only if you enable Delete data on uninstall under Advanced settings. Otherwise they are preserved across reinstalls.

Troubleshooting

Solutions to the most common issues, in order of frequency.

"Subscribe" button is missing on the product page

The Subscribe button only appears for products configured as Simple subscription. Verify:

  • Open the product edit screen and confirm the Product data dropdown shows Simple subscription, not Simple product.
  • Confirm the product status is Published, not Draft.
  • Confirm a price is set under Regular price.
  • Clear any caching plugin (cache, opcode cache, CDN) — old HTML may be served.

If the product type dropdown does not show Simple subscription as an option, the plugin is not active. Check Plugins and reactivate.

Renewals are not running

Most renewal issues come down to WP-Cron not firing. Verify in this order:

  1. Open WooCommerce → Subscriptions Settings → Advanced and click Run scheduler now. If renewals process, the plugin works correctly — the issue is cron.
  2. Check that DISABLE_WP_CRON is not set to true in wp-config.php. If it is, configure a real system cron (see Server requirements).
  3. For low-traffic sites, WP-Cron only runs when a page is loaded. Set up a real cron pinging wp-cron.php every 15 minutes.
  4. Verify the cron event exists: install the WP Crontrol plugin and look for xc_wcsl_check_subscriptions. If missing, deactivate and reactivate the subscription plugin.

Emails are not being sent

If transactional emails are missing, check:

  1. Open WooCommerce → Settings → Emails and confirm the relevant subscription email is Enabled in its settings.
  2. Send a test of any standard WooCommerce email (e.g. New Order). If that also fails, the issue is your server's mail configuration, not the plugin.
  3. Install an SMTP plugin (FluentSMTP, WP Mail SMTP) and configure a real SMTP server. wp_mail() via PHP's mail() is unreliable on most hosts.
  4. For Renewal Reminders specifically, check that Send renewal reminders is enabled under Subscription Settings → Emails.

License activation fails with a generic error

For security reasons, the activation endpoint returns a generic error rather than disclosing whether the key is invalid, expired, revoked, or out of seats. Try:

  • Verify the key in your XaniaCode account dashboard under My Licenses.
  • If you previously activated this key on another domain, deactivate it there first.
  • Confirm the site has outbound HTTPS access to xaniacode.com — some firewalls block outgoing connections.
  • If you've hit the rate limit (5 failed attempts per 15 minutes), wait 15 minutes before retrying.
  • Open a support ticket from your XaniaCode dashboard if the key still fails after the above checks.

Cart shows the wrong total during a free trial

During an active trial, the cart line price should display as Free trial and the subtotal should reflect only the sign-up fee, if any. If the cart shows the full recurring price:

  • Confirm the trial length on the product is greater than zero.
  • Empty the cart and re-add the product (the trial pricing applies on add-to-cart, not retroactively).
  • Clear any cart-level caching (page builders, fragment caches).
  • Check for theme overrides of the cart template that might bypass the woocommerce_cart_item_price filter.

HPOS-related conflicts

The plugin declares full HPOS compatibility. If you see warnings about plugin compatibility under WooCommerce → Status → Logs, the issue is usually a different plugin in your stack — not this one. Disable other plugins one by one to identify the conflict.

Plugin conflict — site shows critical error after activation

The plugin's bootstrap is wrapped in a try/catch block — a critical-error page typically means a fatal PHP error from a different plugin or theme. Diagnose:

  1. Enable WP_DEBUG in wp-config.php: define( 'WP_DEBUG', true ); and define( 'WP_DEBUG_LOG', true );.
  2. Reproduce the error and inspect /wp-content/debug.log for the actual fatal message and file/line.
  3. If the file is in xc-woocommerce-subscriptions-lite, contact support with the log excerpt.
  4. If the file is in another plugin or theme, that's where the conflict lies.

Customer cannot cancel from My Account

Verify:

  • Under WooCommerce → Subscriptions Settings → General, Allow customer cancellation is set to Yes.
  • The customer is logged in to the same account that owns the subscription.
  • The subscription is in a state that can be cancelled (Active, On hold, Paused, Pending). Already-cancelled or Expired subscriptions cannot be re-cancelled.

"Translation loading triggered too early" notice in WordPress 6.7+

This notice appears when a plugin loads its textdomain too early. The plugin loads its textdomain on init priority 1 (the WP 6.7+ best practice), so this notice should never come from this plugin. If you see it pointing at xc-wcs-lite textdomain, contact support — and confirm you're on the latest plugin version.

"Subscribe" button POSTs but nothing happens

Usually a JavaScript error blocking form submission. Open the browser console (F12) and look for errors. If errors point to a different plugin or theme, that's where to investigate. Also check that the AJAX add-to-cart isn't failing silently — disable AJAX add-to-cart temporarily under WooCommerce → Settings → Products → General.

Restored subscriptions don't trigger emails

By design, manually re-activating a subscription via the admin Status dropdown does fire the activation email. If it doesn't, see the email troubleshooting section above. Bulk-activating large batches of subscriptions will send one email per subscription — confirm your mail server can handle the volume.

Technical FAQ

Can I change the subscription post type slug?

No — the slug xc_wcsl_subscription is hard-coded by design. Renaming it would invalidate every existing subscription record. If you need to integrate with a different system, use the REST API or the action hooks rather than altering the post type.

Does the plugin work with Multisite?

Yes. Activate per-site or network-wide. Each site has its own custom tables, options, and subscription records. License activation is per-site (one license seat per site) unless you have a multi-domain license.

Can I bulk-import subscriptions from another system?

The plugin does not ship with an import UI. For migrations, use the helper class:

$subscription = XC_WCSL_Subscription::create([
    'customer_id'     => 89,
    'parent_order'    => 0,             // 0 if no original order
    'product_id'      => 17,
    'period'          => 'month',
    'interval'        => 1,
    'recurring_total' => 28.00,
    'currency'        => 'EUR',
    'status'          => 'xcsl-active',
]);

Loop this in a small migration script. The created subscription will behave exactly as if it had been created through the normal checkout flow.

Are there any deprecated PHP functions used?

No. The plugin requires PHP 8.0+ and uses modern syntax throughout — typed properties, return type declarations, match expressions, named arguments where appropriate. No create_function, no implicit nullable types.

How does the plugin handle currency switches?

Currency is stored on each subscription at creation time. If your store later switches base currency, existing subscriptions keep billing in their original currency. New subscriptions use the new base currency. The plugin does not auto-convert — for multi-currency stores, use a third-party multi-currency plugin and ensure it stores the currency at order creation.

What happens if WooCommerce is deactivated while the plugin is active?

The plugin's bootstrap detects WooCommerce is missing and shows an admin notice; no further code runs. Existing subscription data is preserved. Reactivating WooCommerce restores normal operation.

Can I extend the subscription model with custom fields?

Yes. The subscription is a regular WordPress post type — use add_post_meta() / update_post_meta() to attach arbitrary fields. To expose them in the admin, add a meta box on the xc_wcsl_subscription post type.

How are timezones handled?

All dates are stored in UTC (gmdate) and displayed in the site's configured timezone via date_i18n. Customer-facing emails show the customer's local time when WooCommerce email helpers are used.

What is the maximum subscription throughput?

The hourly cron processes up to 50 due renewals per run (configurable via the xc_wcsl_process_due_batch_size filter). At one run per hour, that's 1,200 renewals per day per site — well within WordPress's typical capacity. For higher throughput, increase the batch size and run cron more frequently.

Does the plugin modify core WordPress or WooCommerce files?

No. All integration is through public hooks and APIs. The plugin can be deactivated cleanly without leaving residue (other than the database tables and post records, which are preserved unless Delete data on uninstall is enabled).

Are there any security audits available?

The plugin follows WordPress and WooCommerce security best practices: prepared statements throughout, capability checks on every admin action, nonce verification on every form, encrypted license storage, rate-limited license activation. The codebase has been reviewed for $_GET / $_POST sanitization, SQL injection vectors, and XSS in template output. Independent third-party audits are not currently published.

Can I disable the dashboard widget?

Yes. Add this to your theme's functions.php or a small mu-plugin:

add_action( 'wp_dashboard_setup', function() {
    remove_meta_box( 'xc_wcsl_kpi', 'dashboard', 'normal' );
}, 100 );

Where do I find logs for debugging?

Three places:

  • WooCommerce → Status → Logs — the plugin writes critical events to a log source named xc-wcs-lite
  • Per-subscription activity log — visible at the bottom of the single subscription edit screen
  • WordPress debug log — when WP_DEBUG_LOG is enabled, fatal errors and stack traces land here

Support

Every license includes 6 months of direct developer support via your XaniaCode account dashboard. After the initial 6 months, support can be renewed for a small annual fee.

Before you contact support

Most issues are resolved by checking the relevant troubleshooting entry. When you do contact support, include:

  • WordPress version
  • WooCommerce version
  • PHP version
  • Active theme name
  • List of active plugins (a screenshot of the Plugins page is fine)
  • Steps to reproduce the issue
  • Any error messages from /wp-content/debug.log
  • If the issue is renewal-related, the subscription ID

The WooCommerce → Status → System Info screen has all the technical details — copy and paste it into your ticket.

How to open a ticket

  1. Sign in to your account at xaniacode.com.
  2. Go to My Account → Support.
  3. Click Open new ticket, choose XC WooCommerce Subscriptions Lite from the product list, and describe the issue.
  4. Tickets receive a first response within 1–2 business days, typically faster.

Bug reports and feature requests

Both are welcome through the same support ticket system. Bug reports with reproducible steps get priority. Feature requests are reviewed monthly — popular requests are added to the roadmap and the new release notifies all license holders.