agentsclimarketplace

Wcs subscription hooks

Skill Lonsdale201/wp-agent-skills/woocommerce/wcs-subscription-hooks

A community-maintained collection of agent skills for WordPress plugin and theme development.

Install
npx -y skills add Lonsdale201/wp-agent-skills --skill wcs-subscription-hooks

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.

What its author says it does

Copied from the file, not written here

Curated WooCommerce Subscriptions hook map for subscription creation, status/date transitions, renewal orders, scheduled payments, retries, gateway events, switching, gifting, related orders, APFS plans, REST, and account/admin UI. Use when choosing where to hook around WC_Subscription, wcs_create_subscription, wcs_create_renewal_order, woocommerce_scheduled_subscription_payment, payment_retry, wcsg_, subscription_switch, WCS_ATT, wcsatt_, or _wcsatt_scheme.

SKILL.md

24.7 KB, as published. Nobody here has run it

WooCommerce Subscriptions: hook map

Use this when building or reviewing an integration that needs to react to WooCommerce Subscriptions events. This is not an exhaustive dump of the 800+ hook calls in the plugin. It is a decision map for the hooks that are usually correct and the older/noisy hooks that AI agents tend to choose incorrectly.

Misconception this skill corrects

"Subscriptions are just orders, so hook woocommerce_order_status_changed or update _schedule_next_payment meta directly."

Subscriptions are WC_Subscription objects with their own lifecycle hooks, status transition hooks, date hooks, relation store, renewal order hooks, and scheduler bridge. Prefer WCS hooks and CRUD methods unless the task explicitly needs ordinary WC orders.

When to use this skill

Trigger when ANY of the following is true:

  • The user asks for WooCommerce Subscriptions actions/filters, lifecycle hooks, renewal hooks, status hooks, payment retry hooks, switching hooks, or gifting hooks.
  • You see WC_Subscription, wcs_get_subscription(), wcs_create_subscription(), wcs_create_renewal_order(), woocommerce_scheduled_subscription_payment, wcs_renewal_order_created, payment_retry, wcsg_, or subscription_switch.
  • You need to decide whether to hook at subscription creation, renewal order creation, gateway payment attempt, successful payment, failed payment, status change, or scheduled action time.

Workflow

  1. Identify the lifecycle point first: creation, status, date schedule, renewal order, gateway charge, retry, switch/gift, or UI/API.
  2. Prefer hooks that pass WC_Subscription or WC_Order objects over legacy hooks that pass subscription keys.
  3. For dynamic hooks, expand the real hook name from the runtime value: status, date type, payment method ID, or order relation type.
  4. Before implementing, inspect the exact source line in the installed plugin with:
rg -n "hook_name|function_name" wp-content/plugins/woocommerce-subscriptions/includes wp-content/plugins/woocommerce-subscriptions/src

Storage facts agents must not guess

Subscriptions registers shop_subscription as a WooCommerce order type. In CPT mode it appears as a post type; in HPOS it is an order type. Subscription product type slugs are subscription, variable-subscription, and subscription_variation.

Subscription prop meta keys include _billing_period, _billing_interval, _suspension_count, _cancelled_email_sent, _requires_manual_renewal, _trial_period, _last_order_date_created, _schedule_start, _schedule_trial_end, _schedule_next_payment, _schedule_cancelled, _schedule_end, _schedule_payment_retry, and _subscription_switch_data.

Related order meta keys are _subscription_renewal, _subscription_switch, and _subscription_resubscribe.

Switch cart items store subscription_switch cart item data. Gift cart items store wcsg_gift_recipients_email; gifted subscriptions use _recipient_user_email_address and _recipient_user, with parent order item meta wcsg_recipient.

WCS 9.0 bundles All Products for Subscriptions / Subscription Plans. APFS-selected plans store cart state under wcsatt_data.active_subscription_scheme and order item state under _wcsatt_scheme. Ordinary simple/variable products can be reported as subscriptions through the woocommerce_is_subscription filter when a plan is active.

Core hook map

NeedHookTypeArgsUse
Detect a loaded subscription objectwcs_get_subscriptionfilter`WC_Subscriptionfalse $subscription`
Create subscription programmaticallywcs_created_subscriptionfilterWC_Subscription $subscriptionModify the newly saved object before the post-create action.
Run after subscription creationwcs_create_subscriptionactionWC_Subscription $subscriptionAttach metadata, external IDs, logs, or provisioning.
Change default new statuswoocommerce_default_subscription_statusfilterstring $statusDefault is pending; return status without wc-.
Add/rename statuseswcs_subscription_statusesfilterarray $statusesKeys must use wc- prefix, e.g. wc-paused.
Allow status transitionwoocommerce_can_subscription_be_updated_to_{status}filterbool $can, WC_Subscription $subscriptionPermit a custom or normally blocked transition.
Before status updatewoocommerce_subscription_pre_update_statusaction$old_status, $new_status, WC_Subscription $subscriptionValidate/log before WCS mutates dates and saves.
Status reachedwoocommerce_subscription_status_{to}actionWC_Subscription $subscriptionReact to a specific target status, e.g. woocommerce_subscription_status_active.
Specific transitionwoocommerce_subscription_status_{from}_to_{to}actionWC_Subscription $subscriptionUse for exact transitions such as on-hold_to_active.
Generic status updatewoocommerce_subscription_status_updatedactionWC_Subscription $subscription, string $to, string $fromBest general hook for lifecycle integration.
WC-like status changedwoocommerce_subscription_status_changedactionint $subscription_id, string $from, string $to, WC_Subscription $subscriptionUseful when porting code shaped like woocommerce_order_status_changed.
Read a stored datewoocommerce_subscription_get_{date_type}_datefilter$date, WC_Subscription $subscription, string $timezoneDisplay/read override; do not use to reschedule.
Calculate a future datewoocommerce_subscription_calculated_{date_type}_datefilter$date, WC_Subscription $subscriptionChange calculated next_payment, trial_end, end, or end_of_prepaid_term.
Date changedwoocommerce_subscription_date_updatedactionWC_Subscription $subscription, string $date_type, string $datetimeScheduler listens here; good place for external sync.
Date deletedwoocommerce_subscription_date_deletedactionWC_Subscription $subscription, string $date_typeClean up external schedule/state.
Can date be changedwoocommerce_subscription_can_date_be_updatedfilterbool $can, string $date_type, WC_Subscription $subscriptionOpen/close date editing rules.
Query subscriptionswoocommerce_get_subscriptions_query_argsfilter$query_args, $working_argsModify wcs_get_subscriptions() query before execution.
After querywoocommerce_got_subscriptionsfilter$subscriptions, $working_argsPost-filter subscription results.
Related orderswoocommerce_subscription_related_ordersfilter$orders, WC_Subscription $subscription, $return_fields, $order_typeAdd/adjust parent, renewal, switch, resubscribe relations.

Renewal and scheduled payment hooks

NeedHookTypeArgsUse
Scheduled renewal is duewoocommerce_scheduled_subscription_paymentactionint $subscription_idFired by Action Scheduler/admin action. WCS prepares renewal at priority 1 and gateway processing runs at priority 10.
Renewal order creation failedwcs_failed_to_create_renewal_orderactionWP_Error $error, WC_Subscription $subscriptionAlert/log/retry externally.
Renewal order createdwcs_renewal_order_createdfilterWC_Order $renewal_order, WC_Subscription $subscriptionAdd order meta, line item data, external IDs. Return a WC_Order.
Gateway charge hookwoocommerce_scheduled_subscription_payment_{gateway_id}actionfloat $amount, WC_Order $renewal_orderPayment gateways implement recurring charge here, e.g. the stored ID stripe produces woocommerce_scheduled_subscription_payment_stripe.
Manual renewal order generatedwoocommerce_generated_manual_renewal_orderactionint $renewal_order_id, WC_Subscription $subscriptionNotify, adjust pending manual renewal order.
Renewal payment completewoocommerce_subscription_renewal_payment_completeactionWC_Subscription $subscription, WC_Order $last_orderProvision after a successful renewal, not before gateway payment.
Renewal payment failedwoocommerce_subscription_renewal_payment_failedactionWC_Subscription $subscription, WC_Order $related_orderHandle failed renewal consequences.
Any subscription payment completewoocommerce_subscription_payment_completeactionWC_Subscription $subscriptionFires for parent or renewal payment completion.
Any subscription payment failedwoocommerce_subscription_payment_failedactionWC_Subscription $subscription, string $new_statusReact to failure and resulting status.
Paid failed renewalwoocommerce_subscriptions_paid_for_failed_renewal_orderactionWC_Order $renewal_order, WC_Subscription $subscriptionUpdate failing payment method or clear retry state after customer pays a failed renewal.

Scheduler hooks

WCS uses Action Scheduler with group wc_subscription_scheduled_event, but the public integration point is the subscription date/status API. The scheduler listens to woocommerce_subscription_date_updated, woocommerce_subscription_date_deleted, and woocommerce_subscription_status_updated.

NeedHookTypeArgsUse
Add/remove date types to schedulewoocommerce_subscriptions_date_types_to_schedulefilterstring[] $date_typesInclude custom subscription date types.
Change scheduled action hookwoocommerce_subscriptions_scheduled_action_hookfilterstring $hook, string $date_typeRoute a date type to a custom action.
Change scheduled argswoocommerce_subscriptions_scheduled_action_argsfilterarray $args, string $date_type, WC_Subscription $subscriptionAdd deterministic args for custom scheduled actions.
Change Action Scheduler prioritywoocommerce_subscriptions_scheduled_action_priorityfilterint $priority, string $action_hookDefault is priority 1.
Trial endedwoocommerce_subscription_trial_endedactionint $subscription_idFired from scheduled trial end handler.
Expiration/end hookswoocommerce_scheduled_subscription_expiration, woocommerce_scheduled_subscription_end_of_prepaid_termactionint $subscription_idInternal status handlers run here; attach after them if you need post-status side effects.

Payment retry hooks

NeedHookTypeArgsUse
Enable/disable retrieswcs_is_retry_enabledfilterbool $enabledFeature-level gate.
Replace default retry ruleswcs_default_retry_rulesfilterarray $rulesConfigure retry cadence/statuses.
Alter one retry rulewcs_get_retry_rule_raw, wcs_get_retry_rulefilter$rule, $retry_number, $order_idFine-grained retry rule customization.
Before/after applying rulewoocommerce_subscriptions_before_apply_retry_rule, woocommerce_subscriptions_after_apply_retry_ruleactionWCS_Retry_Rule $rule, WC_Order $last_order, WC_Subscription $subscriptionObserve scheduled retry creation.
Retry action is about to chargewoocommerce_subscriptions_before_payment_retryactionWCS_Retry $retry, WC_Order $last_orderPrepare/log before retry payment.
Retry charge finishedwoocommerce_subscriptions_after_payment_retryactionWCS_Retry $retry, WC_Order $last_orderRecord retry result.
Retry status/date changedwoocommerce_subscriptions_retry_status_updated, woocommerce_subscriptions_retry_date_updatedactionWCS_Retry ...External sync for retry objects.

Switching, early renewal, gifting

AreaHooksUse
Switch eligibilitywcs_is_product_switchable, woocommerce_subscriptions_can_item_be_switched, woocommerce_subscriptions_can_item_be_switched_by_userAllow/block switching by product, item, or user.
Switch pricingwcs_switch_should_prorate_recurring_price, wcs_switch_should_prorate_sign_up_fee, wcs_switch_sign_up_fee, wcs_switch_proration_extra_to_payAdjust proration math. In WCS 8.8+, wcs_switch_proration_extra_to_pay receives a 5th $switch_item argument.
Switch completionwoocommerce_subscriptions_switch_completedReact after switch order flow completes.
Early renewalwcs_is_early_renewal_enabled, woocommerce_subscriptions_can_user_renew_early, woocommerce_subscriptions_get_early_renewal_urlEnable/disable and route early renewal.
Gifting product/checkoutwcsg_enable_gifting, wcsg_is_enabled_for_all_products, wcsg_is_giftable_product, wcsg_cart_item_dataControl whether gifting is available and persisted in cart.
Gifting recipientwcsg_recipient_details_updated, woocommerce_subscriptions_gifting_recipient_changedSync recipient changes.

Subscription Plans / APFS hooks in WCS 9.0+

NeedHook/filterUse
Make ordinary products subscription-likewoocommerce_is_subscriptionAPFS hooks this so simple/variable/variation products with active plans participate in WCS logic. Do not override without preserving APFS result.
Add product type supportwcsatt_supported_product_typesAdd only product types whose pricing/cart behavior you have tested with WCS recurring logic.
Change default product APFS modewoocommerce_subscriptions_default_product_subscription_scheme_modeDefault is disable; alternatives are override or inherit.
Filter product planswcsatt_product_subscription_schemesAdjust resolved local/storewide plans for a product.
Filter cart item planswcsatt_cart_item_subscription_schemesAdjust plans available in a specific cart context.
Observe active scheme setwcsatt_set_product_subscription_schemeRuntime product object hook; not a database save hook.
Storewide plan REST savewcsatt_processed_cart_scheme_dataAdd custom plan fields before wcsatt_subscribe_to_cart_schemes is persisted.
Product plan REST savewcsatt_processed_scheme_dataAdd custom plan fields before _wcsatt_schemes is persisted.
Store API cart validationwoocommerce_store_api_validate_cart_itemAPFS throws woocommerce_store_api_subscription_plan_invalid when a selected plan is invalid.
Store API checkout validationwoocommerce_store_api_checkout_update_order_metaAPFS validates selected plans when the real Store API checkout order exists.

Use wcs-subscription-plans-apfs for storage, REST endpoints, cart data, and headless request details.

Gateway hooks

NeedHookTypeArgsUse
Gateway support checkwoocommerce_subscription_payment_gateway_supportsfilterbool $supports, string $feature, WC_Subscription $subscriptionAdd support for features like subscription_date_changes.
Status changed for gatewaywoocommerce_subscription_activated_{gateway_id}, woocommerce_subscription_on-hold_{gateway_id}, woocommerce_subscription_pending-cancel_{gateway_id}, woocommerce_subscription_cancelled_{gateway_id}, woocommerce_subscription_expired_{gateway_id}actionWC_Subscription $subscriptionGateway-specific remote profile updates.
Payment method updatedwoocommerce_subscription_payment_method_updatedactionWC_Subscription $subscription, string $new, string $oldSync token/payment method changes.
Payment method updated to/from gatewaywoocommerce_subscription_payment_method_updated_to_{gateway_id}, woocommerce_subscription_payment_method_updated_from_{gateway_id}actionWC_Subscription $subscription, string $other_gateway_idGateway-specific migration logic.
Failing method updatedwoocommerce_subscription_failing_payment_method_updated and ..._{gateway_id}actionWC_Subscription $subscription, WC_Order $renewal_orderAfter failed-renewal payment method handling. Use this for same-gateway failed-renewal retries in WCS 8.8+, because update_payment_method() hooks are skipped when the gateway did not actually change.
Payment meta fieldswoocommerce_subscription_payment_metafilterarray $payment_meta, WC_Subscription $subscriptionAdd fields to payment-method change UI.
Validate all payment metawoocommerce_subscription_validate_payment_metaactionstring $payment_method_id, array $payment_meta, WC_Subscription $subscriptionGeneric validator receives 3 arguments. Register with accepted args 3.
Validate one gateway's metawoocommerce_subscription_validate_payment_meta_{gateway_id}actionarray $payment_meta, WC_Subscription $subscriptionGateway-specific validator receives 2 arguments. Do not give the generic callback this signature.

Health Check and Processing reliability

WCS 8.8 adds operational surfaces that are not ordinary renewal hooks:

AreaSurfaceUse
Health Check tabAutomattic\WooCommerce_Subscriptions\Internal\HealthCheck\StatusTabWooCommerce > Status > Subscriptions scan UI. It stores run/candidate rows and uses nonce-protected actions/AJAX for scan, cancel, suggestion, and remediation.
Resolve actionsRemediationAdvisor, ToolRunnerBuilt-in remediation can switch a flagged subscription to automatic renewal or process a missed renewal now. Do not call these internal classes from plugin business logic.
Dedicated processingAutomattic\WooCommerce_Subscriptions\Internal\Queue_Management\ManagerMerchant setting for subscription Action Scheduler isolation/focused runs. Tune via filters instead of creating competing runners.
External web cron/wp-json/wc/v3/subscriptions/job-queue?wcs_token=...Tokenized, rate-limited queue trigger created by the Web cron support setting.

Use wcs-health-check-processing for implementation details and debugging patterns.

Abilities API caveat

WCS includes read-only Abilities API classes under src/Internal/Abilities, but registration is gated by woocommerce_subscriptions_abilities_enabled and defaults to false. The registrar also requires WooCommerce Core's 10.9 AbilitiesLoader. Do not assume these abilities exist on ordinary WCS installs, and do not build a production integration that depends on them unless your plugin explicitly controls that feature gate and Core version.

Customer action guardrails

For custom customer account actions, do not expose WCS admin REST writes directly. Load the subscription object, verify the current user owns it, then use WCS capabilities and object methods.

Status actions:

  • Check $subscription->get_user_id() === get_current_user_id() unless this is trusted admin/server code.
  • Check $subscription->can_be_updated_to( $target_status ) before calling $subscription->update_status( $target_status, $note, true ).
  • Prefer domain statuses: cancel to pending-cancel when the prepaid term should continue; cancel to cancelled only when immediate cancellation is intended and allowed.
  • Let WCS status hooks run; do not update post_status or order status meta directly.

Payment-method actions:

  • Verify the selected payment token belongs to the same WP user and gateway customer.
  • Do not update only payment meta/source IDs. Use WC_Subscriptions_Change_Payment_Gateway::update_payment_method() or the gateway's change-payment flow so hooks and remote gateway side effects run.
  • Preserve woocommerce_subscriptions_pre_update_payment_method and woocommerce_subscription_payment_method_updated when the gateway actually changes; gateways use them for remote profile cleanup and migration. For same-gateway failed-renewal retries in WCS 8.8+, use woocommerce_subscription_failing_payment_method_updated for retry side effects.

Switch actions:

  • Use WC_Subscriptions_Switcher::can_item_be_switched_by_user() for eligibility.
  • Wrap the switch cart/checkout flow or reproduce _subscription_switch_data deliberately. Direct line-item replacement is not a subscription switch.

Common mistakes

// WRONG: catches many normal orders and misses WCS-specific semantics.
add_action( 'woocommerce_order_status_changed', 'my_sync' );

// RIGHT: subscription transition with object.
add_action( 'woocommerce_subscription_status_updated', function ( WC_Subscription $subscription, string $to, string $from ): void {
    my_sync_subscription_status( $subscription->get_id(), $from, $to );
}, 10, 3 );

// WRONG: changing the schedule by writing meta bypasses validation and can desync Action Scheduler.
update_post_meta( $subscription_id, '_schedule_next_payment', '2026-05-01 00:00:00' );

// RIGHT: CRUD date update; WCS validates and reschedules via date hooks.
$subscription = wcs_get_subscription( $subscription_id );
if ( $subscription ) {
    $subscription->update_dates( array( 'next_payment' => '2026-05-01 00:00:00' ), 'gmt' );
}

// WRONG: use the scheduled-payment hook for fulfillment.
add_action( 'woocommerce_scheduled_subscription_payment', 'ship_box' );

// RIGHT: fulfill only after renewal payment is complete.
add_action( 'woocommerce_subscription_renewal_payment_complete', function ( WC_Subscription $subscription, WC_Order $order ): void {
    ship_box_for_renewal( $subscription, $order );
}, 10, 2 );

What this skill does NOT cover

  • Building a payment gateway from scratch.
  • HPOS order CRUD beyond the WCS-specific hooks here. Use wc-hpos-compatibility for general order storage issues.
  • Exhaustive hook cataloging. For full local discovery, run rg -n "do_action\\(|apply_filters\\(" wp-content/plugins/woocommerce-subscriptions.

Cross-references

  • Run wcs-data-model-switching-gifting when exact Subscriptions meta names, product type slugs, switch payloads, switched item meta/types, or WCS Gifting recipient storage matters.
  • Run wcs-subscription-plans-apfs when ordinary Woo products can be sold as subscriptions via WCS 9.0 Subscription Plans / APFS.
  • Run wcs-renewal-scheduler for changes to next payment dates, renewal order creation, scheduled actions, or payment retry timing.
  • Run wcs-health-check-processing for WCS 8.8 Health Check, Resolve actions, dedicated processing, and web-cron queue support.
  • Run wc-hpos-compatibility if the integration queries orders/subscriptions directly.

References

  • Official documentation: https://woocommerce.com/document/subscriptions/develop/
  • Verified source paths:
    • wp-content/plugins/woocommerce-subscriptions/includes/core/wcs-functions.php
    • wp-content/plugins/woocommerce-subscriptions/includes/core/class-wc-subscription.php
    • wp-content/plugins/woocommerce-subscriptions/includes/core/class-wc-subscriptions-change-payment-gateway.php
    • wp-content/plugins/woocommerce-subscriptions/includes/core/class-wc-subscriptions-core-plugin.php
    • wp-content/plugins/woocommerce-subscriptions/includes/core/class-wc-subscriptions-product.php
    • wp-content/plugins/woocommerce-subscriptions/includes/core/wcs-renewal-functions.php
    • wp-content/plugins/woocommerce-subscriptions/includes/core/class-wcs-action-scheduler.php
    • wp-content/plugins/woocommerce-subscriptions/includes/payment-retry/class-wcs-retry-manager.php
    • wp-content/plugins/woocommerce-subscriptions/includes/switching/class-wc-subscriptions-switcher.php
    • wp-content/plugins/woocommerce-subscriptions/includes/switching/class-wcs-cart-switch.php
    • wp-content/plugins/woocommerce-subscriptions/includes/gifting/class-wcs-gifting.php
    • wp-content/plugins/woocommerce-subscriptions/includes/gifting/class-wcsg-checkout.php
    • wp-content/plugins/woocommerce-subscriptions/includes/apfs/class-wcs-att-product.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/apfs/api/class-wcs-att-store-api.php
    • wp-content/plugins/woocommerce-subscriptions/src/Internal/HealthCheck/
    • wp-content/plugins/woocommerce-subscriptions/src/Internal/Queue_Management/
    • wp-content/plugins/woocommerce-subscriptions/src/Internal/Abilities/

Keep looking

Skills are one crate of 328,083. 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.