agentsclimarketplace

Wcs data model switching gifting

Skill Lonsdale201/wp-agent-skills/woocommerce/wcs-data-model-switching-gifting

WooCommerce Subscriptions data model, switching, and gifting reference for order/product types, schedule and relation storage, switch cart/order payloads, proration hooks, recipient data, and WCS 9.0 APFS plan markers. Use for shop_subscription, _schedule_next_payment, _subscription_switch_data, subscription_switch, _switched_subscription_item_id, wcsg_gift_recipients_email, _recipient_user, _wcsatt_schemes, or _wcsatt_scheme.From its SKILL.md

Install
npx -y skills add Lonsdale201/wp-agent-skills --skill wcs-data-model-switching-gifting

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 21 stars21 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

16.5 KB, ~3.6k tokens by cl100k_base, as published. Nobody here has run it

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

EntityName/keyNotes
Subscription order typeshop_subscriptionRegistered 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 typesubscriptionWC_Product_Subscription::get_type().
Variable subscription product typevariable-subscriptionWC_Product_Variable_Subscription::get_type().
Subscription variation product typesubscription_variationWC_Product_Subscription_Variation::get_type().
Action Scheduler groupwc_subscription_scheduled_eventUsed 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 keyProp/date keyPurpose
_billing_periodbilling_periodday, week, month, or year.
_billing_intervalbilling_intervalBilling interval integer.
_suspension_countsuspension_countCustomer/admin suspension count.
_cancelled_email_sentcancelled_email_sentCancellation email guard.
_requires_manual_renewalrequires_manual_renewalManual renewal flag.
_trial_periodtrial_periodTrial period unit.
_last_order_date_createdlast_order_date_createdLast related parent/renewal order created date used by WCS.
_schedule_startstart / schedule_startSubscription start datetime.
_schedule_trial_endtrial_end / schedule_trial_endTrial end datetime.
_schedule_next_paymentnext_payment / schedule_next_paymentNext renewal datetime.
_schedule_cancelledcancelled / schedule_cancelledCancellation datetime.
_schedule_endend / schedule_endEnd/expiration datetime.
_schedule_payment_retrypayment_retry / schedule_payment_retryRetry datetime.
_subscription_switch_dataswitch_dataSwitch 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 keyPurpose
_subscription_priceRecurring price.
_subscription_sign_up_feeSign-up fee.
_subscription_periodBilling period.
_subscription_period_intervalBilling interval.
_subscription_lengthSubscription length.
_subscription_trial_periodTrial period unit.
_subscription_trial_lengthTrial length.
_subscription_giftingProduct-level gifting override: enabled, disabled, or empty for global setting.
_subscription_one_time_shippingOne-time shipping flag.
_subscription_payment_sync_dateRenewal 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().

APFS / Subscription Plans storage in WCS 9.0+

All Products for Subscriptions is bundled into WooCommerce Subscriptions 9.0 as Subscription Plans. It can make ordinary product types behave as subscriptions through runtime meta and woocommerce_is_subscription.

StorageKeyPurpose
Optionwcsatt_subscribe_to_cart_schemesStorewide plan definitions.
Product meta_wcsatt_schemes_statusProduct purchase mode: disable, override, or inherit.
Product meta_wcsatt_schemesProduct-specific custom plans in override mode.
Product meta_wcsatt_storewide_selection_modeall or specific storewide plan selection.
Product meta_wcsatt_selected_storewide_plansStorewide plan IDs allowed for a specific product.
Product meta_wcsatt_force_subscriptionyes means disable one-time purchase when plans are active.
Product meta_wcsatt_disabledLegacy one-time-only flag maintained for compatibility.
Cart item datawcsatt_data.active_subscription_schemeSelected plan key, false for one-time, null for undefined/default.
Order item meta_wcsatt_schemeSelected plan key persisted on order/subscription line items.
Order item meta_wcsatt_scheme_idLegacy APFS plan key.

Use WCS_ATT_Product::get_subscription_scheme_mode(), WCS_ATT_Product::set_subscription_scheme_mode(), WCS_ATT_Product_Schemes::get_subscription_schemes(), WCS_ATT_Cart::get_subscription_scheme(), and WCS_ATT_Order::get_subscription_scheme(). Do not infer APFS plans from the native _subscription_* product meta table above; APFS sets WCS-compatible values as runtime meta when a scheme is active.

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 keyRelation
_subscription_renewalRenewal order to subscription.
_subscription_switchSwitch order to subscription.
_subscription_resubscribeResubscribe 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 payload and extension reference

Cart items use subscription_switch; switch orders persist _subscription_switch_data; staged/archive items use custom *_pending_switch, *_switched, and line_item_removed types. These payloads include item IDs, proration results, schedule changes, coupons, fees, and shipping lines and are not a stable shortcut for direct mutation.

Use switching-reference.md for exact payload shapes, item meta, and hook signatures. In WCS 8.8+, wcs_switch_proration_extra_to_pay has a fifth $switch_item argument; register accepted args 5 when that context matters.

Gifting storage

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

StorageKeyPurpose
Cart item datawcsg_gift_recipients_emailRecipient email before checkout/subscription creation.
Subscription meta_recipient_user_email_addressRecipient email captured at subscription creation before a user is resolved.
Subscription meta_recipient_userRecipient user ID after account lookup/creation. Primary gifted-subscription marker.
Parent order item meta_wcsg_cart_keyLinks checkout order item to the recurring cart/subscription item.
Parent order item metawcsg_recipientValue format wcsg_recipient_id_{user_id}.
Parent order item metawcsg_deleted_recipient_dataJSON snapshot used after recipient deletion.
User metawcsg_update_accountRecipient account setup/update flag.
User metawcsg_recipient_just_reset_passwordRecipient 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.
  • In WCS 9.0 APFS, the Subscription Plans product panel can also write the product-level gifting override while saving ordinary products sold via plans.
  • 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

// 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-subscription-plans-apfs for the full WCS 9.0 Subscription Plans / APFS plan API, REST endpoints, and headless cart behavior.
  • Use wcs-renewal-scheduler for renewal dates, Action Scheduler, and payment retry timing.
  • Use wcs-subscription-downloads for linked downloadable products, download permission grants/revokes, and the subscription downloads mapping table.
  • Use wcm-data-model-subscriptions-link for Memberships CPT/meta and the Memberships-to-Subscriptions relation.

References

  • Official documentation: https://woocommerce.com/document/subscriptions/develop/
  • Verified source paths:
    • wp-content/plugins/woocommerce-subscriptions/includes/core/class-wc-subscriptions-core-plugin.php
    • wp-content/plugins/woocommerce-subscriptions/includes/core/class-wc-subscription.php
    • wp-content/plugins/woocommerce-subscriptions/includes/core/data-stores/class-wcs-subscription-data-store-cpt.php
    • wp-content/plugins/woocommerce-subscriptions/includes/core/data-stores/class-wcs-orders-table-subscription-data-store.php
    • wp-content/plugins/woocommerce-subscriptions/includes/core/class-wc-subscriptions-product.php
    • wp-content/plugins/woocommerce-subscriptions/includes/core/wcs-functions.php
    • wp-content/plugins/woocommerce-subscriptions/includes/core/wcs-switch-functions.php
    • wp-content/plugins/woocommerce-subscriptions/includes/switching/class-wc-subscriptions-switcher.php
    • wp-content/plugins/woocommerce-subscriptions/includes/switching/class-wcs-switch-totals-calculator.php
    • wp-content/plugins/woocommerce-subscriptions/includes/downloads/
    • wp-content/plugins/woocommerce-subscriptions/includes/apfs/class-wcs-att-product.php
    • wp-content/plugins/woocommerce-subscriptions/includes/apfs/product/class-wcs-att-product-schemes.php
    • wp-content/plugins/woocommerce-subscriptions/includes/apfs/class-wcs-att-cart.php
    • wp-content/plugins/woocommerce-subscriptions/includes/apfs/class-wcs-att-order.php
    • wp-content/plugins/woocommerce-subscriptions/includes/gifting/class-wcs-gifting.php
    • wp-content/plugins/woocommerce-subscriptions/includes/gifting/class-wcsg-product.php
    • wp-content/plugins/woocommerce-subscriptions/includes/gifting/class-wcsg-cart.php
    • wp-content/plugins/woocommerce-subscriptions/includes/gifting/class-wcsg-checkout.php
    • wp-content/plugins/woocommerce-subscriptions/includes/gifting/class-wcsg-recipient-management.php

What ships with it: 1 file

4.1 KB alongside SKILL.md

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.