wcs-data-model-switching-gifting

WooCommerce Subscriptions data model, switcher, and gifting reference for exact order type names, product type slugs, subscription meta keys, schedule/date keys, related-order relation meta, switch cart data, switch order data, switched item types/meta, proration hooks, and WCS Gifting recipient storage. Use when code reads or writes shop_subscription, subscription, variable-subscription, subscription_variation, _billing_period, _schedule_next_payment, _subscription_switch_data, _subscription_switch, subscription_switch, _switched_subscription_item_id, wcsg_gift_recipients_email, _recipient_user, _recipient_user_email_address, wcsg_recipient, or when an agent needs the full WooCommerce Subscriptions switcher/gifting flow.

Best use case

wcs-data-model-switching-gifting is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

WooCommerce Subscriptions data model, switcher, and gifting reference for exact order type names, product type slugs, subscription meta keys, schedule/date keys, related-order relation meta, switch cart data, switch order data, switched item types/meta, proration hooks, and WCS Gifting recipient storage. Use when code reads or writes shop_subscription, subscription, variable-subscription, subscription_variation, _billing_period, _schedule_next_payment, _subscription_switch_data, _subscription_switch, subscription_switch, _switched_subscription_item_id, wcsg_gift_recipients_email, _recipient_user, _recipient_user_email_address, wcsg_recipient, or when an agent needs the full WooCommerce Subscriptions switcher/gifting flow.

Teams using wcs-data-model-switching-gifting should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/wcs-data-model-switching-gifting/SKILL.md --create-dirs "https://raw.githubusercontent.com/nvdigitalsolutions/mcp-ai-wpoos/main/addons/pro/includes/bundled-skills/wcs-data-model-switching-gifting/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/wcs-data-model-switching-gifting/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How wcs-data-model-switching-gifting Compares

Feature / Agentwcs-data-model-switching-giftingStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

WooCommerce Subscriptions data model, switcher, and gifting reference for exact order type names, product type slugs, subscription meta keys, schedule/date keys, related-order relation meta, switch cart data, switch order data, switched item types/meta, proration hooks, and WCS Gifting recipient storage. Use when code reads or writes shop_subscription, subscription, variable-subscription, subscription_variation, _billing_period, _schedule_next_payment, _subscription_switch_data, _subscription_switch, subscription_switch, _switched_subscription_item_id, wcsg_gift_recipients_email, _recipient_user, _recipient_user_email_address, wcsg_recipient, or when an agent needs the full WooCommerce Subscriptions switcher/gifting flow.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# WooCommerce Subscriptions: data model, switching, gifting

Use this when exact storage names or switch/gift internals matter. Prefer WCS CRUD functions and `WC_Subscription` methods for writes; use raw keys only for audits, migrations, debugging, or compatibility glue.

## Core names

| Entity | Name/key | Notes |
|---|---|---|
| Subscription order type | `shop_subscription` | Registered with `wc_register_order_type()`, class `WC_Subscription`. In CPT storage it is a post type; in HPOS it is an order type. |
| Simple subscription product type | `subscription` | `WC_Product_Subscription::get_type()`. |
| Variable subscription product type | `variable-subscription` | `WC_Product_Variable_Subscription::get_type()`. |
| Subscription variation product type | `subscription_variation` | `WC_Product_Subscription_Variation::get_type()`. |
| Action Scheduler group | `wc_subscription_scheduled_event` | Used for subscription scheduled events. |

Subscription statuses are WooCommerce order statuses with `wc-` prefix in storage: `wc-pending`, `wc-active`, `wc-on-hold`, `wc-cancelled`, `wc-switched`, `wc-expired`, and `wc-pending-cancel`. Object APIs usually use unprefixed values.

## Subscription meta keys

These keys map to `WC_Subscription` props in both CPT and HPOS subscription data stores.

| Meta key | Prop/date key | Purpose |
|---|---|---|
| `_billing_period` | `billing_period` | `day`, `week`, `month`, or `year`. |
| `_billing_interval` | `billing_interval` | Billing interval integer. |
| `_suspension_count` | `suspension_count` | Customer/admin suspension count. |
| `_cancelled_email_sent` | `cancelled_email_sent` | Cancellation email guard. |
| `_requires_manual_renewal` | `requires_manual_renewal` | Manual renewal flag. |
| `_trial_period` | `trial_period` | Trial period unit. |
| `_last_order_date_created` | `last_order_date_created` | Last related parent/renewal order created date used by WCS. |
| `_schedule_start` | `start` / `schedule_start` | Subscription start datetime. |
| `_schedule_trial_end` | `trial_end` / `schedule_trial_end` | Trial end datetime. |
| `_schedule_next_payment` | `next_payment` / `schedule_next_payment` | Next renewal datetime. |
| `_schedule_cancelled` | `cancelled` / `schedule_cancelled` | Cancellation datetime. |
| `_schedule_end` | `end` / `schedule_end` | End/expiration datetime. |
| `_schedule_payment_retry` | `payment_retry` / `schedule_payment_retry` | Retry datetime. |
| `_subscription_switch_data` | `switch_data` | Switch order execution payload. |

Use `WC_Subscription::update_dates()`, `delete_date()`, setters like `set_billing_period()`, and `save()`. Directly updating these meta keys can desync validation and scheduled actions.

## Product subscription meta

Subscription product data lives on `product` or `product_variation` posts.

| Meta key | Purpose |
|---|---|
| `_subscription_price` | Recurring price. |
| `_subscription_sign_up_fee` | Sign-up fee. |
| `_subscription_period` | Billing period. |
| `_subscription_period_interval` | Billing interval. |
| `_subscription_length` | Subscription length. |
| `_subscription_trial_period` | Trial period unit. |
| `_subscription_trial_length` | Trial length. |
| `_subscription_gifting` | Product-level gifting override: `enabled`, `disabled`, or empty for global setting. |
| `_subscription_one_time_shipping` | One-time shipping flag. |
| `_subscription_payment_sync_date` | Renewal synchronization setting. |

Use `WC_Subscriptions_Product` helpers such as `get_price()`, `get_period()`, `get_interval()`, `get_length()`, `get_trial_length()`, `get_sign_up_fee()`, and `get_gifting()`.

## Related order relation meta

WCS relates ordinary orders to subscriptions with order meta and relation stores. Do not infer relation from parent ID alone.

| Meta key | Relation |
|---|---|
| `_subscription_renewal` | Renewal order to subscription. |
| `_subscription_switch` | Switch order to subscription. |
| `_subscription_resubscribe` | Resubscribe order to subscription. |

Use `wcs_get_subscription_ids_for_order()`, `wcs_get_subscriptions_for_order()`, `wcs_get_subscriptions_for_renewal_order()`, `wcs_get_subscriptions_for_switch_order()`, and `$subscription->get_related_orders()`.

## Switcher flow

Switching replaces or adds subscription line items through checkout. It is not a simple product ID update.

1. A user clicks the switch link printed in My Account by `WC_Subscriptions_Switcher::print_switch_link()`.
2. The link points to the product/grouped product URL with `switch-subscription`, `item`, and `_wcsnonce` query args.
3. `subscription_switch_handler()` validates ownership, nonce, and item switchability.
4. `validate_switch_request()` blocks non-subscription products and identical product/variation/quantity switches.
5. `set_switch_details_in_cart()` adds cart item data under `subscription_switch`.
6. `WCS_Switch_Totals_Calculator` calculates proration, switch direction, first payment timestamp, and possible prepaid-term changes.
7. Checkout line item meta records prorated amounts on the switch order and switched item links on subscription items.
8. `process_checkout()` creates `_subscription_switch_data` on the switch order and may create pending switch items on the existing subscription.
9. When the switch order is paid/completed, `complete_subscription_switches()` applies the payload to the subscription.
10. WCS fires `woocommerce_subscriptions_switch_completed` and item-level switch actions after completion.

## Custom switch flows

WCS does not expose a simple customer REST endpoint for "switch this subscription item to that product". The built-in switcher is a cart/checkout/order-completion flow. Custom account UI, AJAX, or REST layers must wrap that flow or deliberately reproduce its order payload.

Safe pattern:

1. Verify the current user can switch the exact subscription item with `WC_Subscriptions_Switcher::can_item_be_switched_by_user()`.
2. Build a temporary cart/session context for the current user and add the replacement product with `subscription_switch` cart item data.
3. Let `WCS_Switch_Totals_Calculator` calculate prorations, `first_payment_timestamp`, `end_timestamp`, `force_payment`, and switch direction.
4. Return preview totals from the calculated cart/order data, not from hand-written price math.
5. On confirmation, create the switch order with the same `_subscription_switch_data` shape WCS checkout writes.
6. If an immediate payment is due, process it through the gateway/order payment flow; if no payment is due, complete/apply the switch through WCS completion logic.
7. Let `complete_subscription_switches()` apply the change and let WCS fire its normal hooks.

Do not implement switching by directly calling `$subscription->remove_item()` and `$subscription->add_product()` from a customer action. That bypasses switch orders, prorations, tax/fee/coupon handling, old item archival, pending switch item types, cancellation of older unpaid switch orders, and completion hooks.

For read-only previews or eligibility checks, it is fine to expose custom endpoints that return allowed products, switchable item IDs, and WCS-calculated preview totals. For writes, prefer a service that uses WCS cart/checkout objects internally.

## Switch cart data

The cart item key is `subscription_switch`. Typical shape:

```php
$cart_item['subscription_switch'] = array(
    'subscription_id'        => 123,
    'item_id'                => 456,
    'next_payment_timestamp' => 1770000000,
    'upgraded_or_downgraded' => 'upgraded', // or downgraded/crossgraded, after calculation
    'first_payment_timestamp' => 1771000000, // after proration calculation
    'end_timestamp'          => 1780000000, // when length changes
    'recurring_payment_prorated' => true,
    'force_payment'          => true,
);
```

`item_id` is the subscription line item being replaced. When adding an item to a subscription without replacing one, `item_id` can be empty and `wcs_cart_contains_switches( 'add' )` is relevant.

## Switch order data

Switch orders store `subscription_switch_data`, persisted as `_subscription_switch_data` on the order. Shape by subscription ID:

```php
$switch_data[ $subscription_id ] = array(
    'switches' => array(
        $switch_order_item_id => array(
            'remove_line_item'  => 456,
            'add_line_item'     => 789,
            'switch_direction'  => 'upgrade',
        ),
    ),
    'billing_schedule' => array(
        '_billing_period'   => 'month',
        '_billing_interval' => 1,
    ),
    'dates' => array(
        'update' => array(
            'next_payment' => '2026-06-01 00:00:00',
            'trial_end'    => 0,
            'end'          => '2027-06-01 00:00:00',
        ),
        'delete' => array( 'trial_end' ),
    ),
    'coupons'             => array( 111 ),
    'fee_items'           => array( 222 ),
    'shipping_line_items' => array( 333 ),
);
```

WCS can cancel older unpaid switch orders for the same subscription when a new switch order is created.

## Switched item types and meta

WCS uses custom order item types during and after switch execution.

| Item type | Meaning |
|---|---|
| `line_item_pending_switch` | New line item staged on a subscription before switch completion. |
| `line_item_switched` | Old subscription line item archived after replacement. |
| `line_item_removed` | Removed subscription line item. |
| `coupon_pending_switch`, `fee_pending_switch`, `shipping_pending_switch` | Staged recurring coupon/fee/shipping items. |
| `coupon_switched`, `fee_switched`, `shipping_switched` | Archived old recurring coupon/fee/shipping items. |

Important item meta:

| Item meta | Stored on | Purpose |
|---|---|---|
| `_switched_subscription_item_id` | New subscription line item | Old subscription item ID. |
| `_switched_subscription_new_item_id` | Old subscription line item | New subscription/order line item ID. |
| `_switched_subscription_sign_up_fee_prorated` | Switch order line item | Portion of order line total from prorated sign-up fee. |
| `_switched_subscription_price_prorated` | Switch order line item | Portion of order line total from prorated recurring price. |
| `_has_trial` | Pending switch item | Marks new item with trial. |

## Switch extension points

| Need | Hook/filter | Args |
|---|---|---|
| Check product switchability | `wcs_is_product_switchable` | `$is_switchable, $product, $variation` |
| Check item switchability | `woocommerce_subscriptions_can_item_be_switched` | `$can, $item, $subscription` |
| Check user can switch item | `woocommerce_subscriptions_can_item_be_switched_by_user` | `$can, $item, $subscription` |
| Switch URL | `woocommerce_subscriptions_switch_url` | `$url, $item_id, $item, $subscription` |
| Switch link markup/text/classes | `woocommerce_subscriptions_switch_link`, `woocommerce_subscriptions_switch_link_text`, `woocommerce_subscriptions_switch_link_classes` | Link context. |
| Retain coupons | `woocommerce_subscriptions_retain_coupon_on_switch` | `$retain, $coupon_code, $coupon, $subscription` |
| Switch added to cart | `woocommerce_subscriptions_switch_added_to_cart` | `$subscription, $existing_item, $cart_item_key, $cart_item` |
| Proration price/day | `wcs_switch_proration_old_price_per_day`, `wcs_switch_proration_new_price_per_day` | Calculator context. |
| Switch type | `wcs_switch_proration_switch_type` | `$type, $subscription, $cart_item, $old_price_per_day, $new_price_per_day` |
| Prorate recurring/sign-up fee | `wcs_switch_should_prorate_recurring_price`, `wcs_switch_should_prorate_sign_up_fee` | `$bool, $switch_item` |
| Extra amount | `wcs_switch_proration_extra_to_pay` | `$extra, $subscription, $cart_item, $days_in_old_cycle` |
| Completion | `woocommerce_subscriptions_switch_completed` | `$order` |
| Item switched | `woocommerce_subscriptions_switched_item` | `$subscription, $new_order_item, $old_subscription_item` |
| Subscription item switched | `woocommerce_subscription_item_switched` | `$order, $subscription, $new_item_id, $old_item_id` |

## Gifting storage

Gifting is included in Subscriptions. It lets purchaser and recipient differ.

| Storage | Key | Purpose |
|---|---|---|
| Cart item data | `wcsg_gift_recipients_email` | Recipient email before checkout/subscription creation. |
| Subscription meta | `_recipient_user_email_address` | Recipient email captured at subscription creation before a user is resolved. |
| Subscription meta | `_recipient_user` | Recipient user ID after account lookup/creation. Primary gifted-subscription marker. |
| Parent order item meta | `_wcsg_cart_key` | Links checkout order item to the recurring cart/subscription item. |
| Parent order item meta | `wcsg_recipient` | Value format `wcsg_recipient_id_{user_id}`. |
| Parent order item meta | `wcsg_deleted_recipient_data` | JSON snapshot used after recipient deletion. |
| User meta | `wcsg_update_account` | Recipient account setup/update flag. |
| User meta | `wcsg_recipient_just_reset_password` | Recipient onboarding flag. |

Gifted subscriptions are detected by `WCS_Gifting::is_gifted_subscription()`: true when `_recipient_user` exists or `_recipient_user_email_address` is present.

## Gifting flow

1. Product page/cart/checkout collects recipient email when `WCSG_Product::is_giftable()` is true.
2. Cart item stores `wcsg_gift_recipients_email`; gifting is blocked for renewal and switch cart items.
3. Checkout uses recipient email in recurring cart keys so different recipients produce separate subscriptions.
4. `woocommerce_checkout_subscription_created` writes `_recipient_user_email_address` to the subscription.
5. On parent order processing/completion, recipient management finds or creates the recipient user, writes `_recipient_user`, adds `wcsg_recipient` to the matching parent order item, and updates shipping fields from recipient user meta.
6. Recipients are granted view/pay/suspend/cancel capabilities for gifted subscriptions, but cannot change payment method.
7. `_recipient_user` is not copied to renewal orders.

Product giftability:

- Global enablement comes from WCSG admin settings.
- Product-level override is `_subscription_gifting`: `enabled`, `disabled`, or empty for global.
- Variable subscription parent returns giftable to render UI; each variation decides final `gifting` variation data.
- Product page gifting UI is suppressed during switching (`switch-subscription` query arg).

## Memberships integration for gifts

If WooCommerce Memberships is active and a giftable subscription product grants a plan:

- Membership access is granted to the recipient when order item meta has `wcsg_recipient`.
- Purchaser access is skipped unless the same product was also purchased for the purchaser.
- The created `wc_user_membership` still stores `_subscription_id`.
- Because one order can contain the same product for multiple recipients, link the membership to the recipient's subscription, not just the first subscription in the order.

## Common mistakes

```php
// WRONG: direct date meta write can desync Action Scheduler.
update_post_meta( $subscription_id, '_schedule_next_payment', '2026-06-01 00:00:00' );

// RIGHT:
$subscription = wcs_get_subscription( $subscription_id );
$subscription->update_dates( array( 'next_payment' => '2026-06-01 00:00:00' ), 'gmt' );

// WRONG: treating a switch as a product meta update.
$subscription->remove_item( $old_item_id );
$subscription->add_product( wc_get_product( $new_product_id ) );

// RIGHT: use WCS switch flow or reproduce its order payload deliberately.
$is_switch = wcs_order_contains_switch( $order );

// WRONG: gifted subscription recipient is not the subscription customer.
$recipient_id = $subscription->get_user_id();

// RIGHT:
$recipient_id = WCS_Gifting::get_recipient_user( $subscription );
```

## Cross-references

- Use `wcs-subscription-hooks` for general lifecycle hook selection.
- Use `wcs-renewal-scheduler` for renewal dates, Action Scheduler, and payment retry timing.
- Use `wcm-data-model-subscriptions-link` for Memberships CPT/meta and the Memberships-to-Subscriptions relation.

Related Skills

wcm-data-model-subscriptions-link

5
from nvdigitalsolutions/mcp-ai-wpoos

WooCommerce Memberships storage and relationship map for membership plan CPTs, user membership CPTs, post statuses, plan/user membership meta keys, rule storage, profile-field storage, order grant meta, and WooCommerce Subscriptions-linked memberships. Use when code reads or writes wc_membership_plan, wc_user_membership, wcm-* statuses, wc_memberships_rules, _subscription_id, _has_installment_plan, _free_trial_end_date, membership plan access meta, user membership dates, product/order grant meta, or when an agent needs exact Memberships CPT/meta names and the Memberships-Subscriptions relation.

wc-variations-data

5
from nvdigitalsolutions/mcp-ai-wpoos

Read, query, and write WooCommerce product variations correctly — the WC_Product_Variable (parent) vs WC_Product_Variation (child) class split, the parent's get_variation_prices( $for_display ) cached aggregation and how to bust the wc_var_prices_<id> transient, programmatic variation creation via WC_Product_Variation + set_parent_id + set_attributes + save followed by WC_Product_Variable::sync, the inherited-vs-own variation stock model (parent flag, variation flag, derived stock_status), get_available_variations for frontend variation data, and the $for_display tax-handling parameter that breaks display logic when forgotten. Use when scaffolding plugin code that creates / queries / modifies variations or when debugging stale variation data after programmatic writes. Triggers on WC_Product_Variation, WC_Product_Variable, get_variation_prices, get_available_variations, product_variation post type, wc_var_prices, sync_variation, or programmatic variation creation context.

webapp-testing

5
from nvdigitalsolutions/mcp-ai-wpoos

Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.

web-artifacts-builder

5
from nvdigitalsolutions/mcp-ai-wpoos

Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.

valyu

5
from nvdigitalsolutions/mcp-ai-wpoos

Search the live web and 36+ specialised data sources including SEC filings, PubMed, ChEMBL, clinical trials, FRED economic indicators, and patent databases. Use when current, authoritative, or paywalled data is required.

ui-ux-pro-max

5
from nvdigitalsolutions/mcp-ai-wpoos

AI-powered design intelligence with 67 UI styles, 161 color palettes, 57 font pairings, 99 UX guidelines, and 25 chart types across 15+ tech stacks. Generates complete design systems for any product type with industry-specific reasoning rules.

theme-factory

5
from nvdigitalsolutions/mcp-ai-wpoos

Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.

slack-gif-creator

5
from nvdigitalsolutions/mcp-ai-wpoos

Knowledge and utilities for creating animated GIFs optimized for Slack. Provides constraints, validation tools, and animation concepts. Use when users request animated GIFs for Slack like "make me a GIF of X doing Y for Slack."

skill-creator

5
from nvdigitalsolutions/mcp-ai-wpoos

Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, update or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.

shannon

5
from nvdigitalsolutions/mcp-ai-wpoos

Autonomous AI security pen testing. Executes real exploits against web applications to find SQL injection, XSS, SSRF, authentication flaws, and IDOR vulnerabilities. Reports only confirmed, reproducible findings — no false positives.

remotion

5
from nvdigitalsolutions/mcp-ai-wpoos

Create programmatic videos using React and Remotion. Translate natural language descriptions into working Remotion components for product demos, release announcements, explainer videos, and animated content.

planetscale

5
from nvdigitalsolutions/mcp-ai-wpoos

Design schemas and write queries for PlanetScale serverless MySQL using branch-based workflows. Ensures index coverage, avoids foreign key anti-patterns, and treats every schema change as a reviewable, reversible deploy request.