Run Custom Code After a Win with uspw_after_coupon_won
The uspw_after_coupon_won action lets developers run custom logic immediately after a visitor finishes a spin and the entry is saved to the database. It is the primary integration point for connecting Ultimate Spin Wheel to external systems such as CRMs, SMS gateways, or custom analytics.
Important: this hook — like every uspw_* hook in the plugin — only fires when the separate Ultimate Spin Wheel Pro plugin is active. In the free plugin the call is wrapped in if ( apply_filters( 'ultimate_spin_wheel_pro_init', false ) ), so none of the snippets below will run on a free-only install.
Key facts:
- Type: Action (
do_action). - Location:
includes/core/class-spin-wheel.php. - Trigger: Fires during the spin AJAX request, after the entry row is inserted into the leads table.
- Requires Pro: Gated behind
apply_filters( 'ultimate_spin_wheel_pro_init', false ).
When It Fires: Two Spin Flows
Ultimate Spin Wheel saves a spin through one of two AJAX paths, and the hook fires from both. The payload shape passed as $data is not identical between them, so write your handlers defensively.
- Legacy flow — the client-declared
ultimate_spin_wheel_spinnedaction (handled byspin_wheel_spinned()). This is the flow this page documents. Here$datais the raw database insert array. - Modern flow — the secure server-side
ultimate_spin_wheel_process_spinaction (handled byspin_wheel_process_spin()), where the winner is drawn on the server. Here$datais a flat$user_dataarray with every field at the top level.
Parameters
$campaign_id(int): The ID of the spin wheel campaign.$data(array): The entry data. Register with a priority and an accepted-args count of 2, e.g.add_action( 'uspw_after_coupon_won', 'my_handler', 10, 2 ).
The $data Array: Legacy vs Modern
These fields are always present as top-level keys in both flows:
name— visitor name (empty if the field was skipped).email— visitor email.phone— visitor phone (the phone input field is a Pro feature).campaign_idandcampaign_title.
Modern flow only — the flat $user_data array also exposes these as top-level keys: coupon_code, coupon_title, status (for example won), segment_index, optin (1 or 0), and message (the win or lose text, which may still contain the {{discount_label}} placeholder).
Legacy flow difference (read this before copying older examples): in the legacy $data array the coupon details are not at the top level. Instead, coupon_title, coupon_code, and status are nested inside $data['others_data'], which is a JSON-encoded string. The legacy array also does not include message, segment_index, or optin. It does carry an extra user_data JSON string with ip_address, device_id, and user_agent. To read a coupon in the legacy flow, decode it: $extra = json_decode( $data['others_data'], true ); then use $extra['coupon_code'].
Where the Data Lives
Both flows insert the entry into the custom leads table wp_wdengage_entries before the hook runs, so the visitor and prize data has already been persisted by the time your handler executes. Unique coupon codes are resolved on the server and are never exposed in the page source before a win.
Example Use Cases
Log Every Winner (Debugging)
Hook the action, read $data['email'] (safe in both flows), and write a line to your debug log with error_log(). To include the prize label, use $data['coupon_title'] on the modern flow, or decode $data['others_data'] first on the legacy flow.
Send Lead Data to a Webhook (Zapier / Make)
Push the win to any external service that is not natively integrated. Build a payload from the $data keys and send it with wp_remote_post(). Set 'blocking' => false so the request does not slow down the visitor’s result screen.
Note: Ultimate Spin Wheel Pro already ships native integrations for Mailchimp, MailPoet, Klaviyo, ActiveCampaign, HubSpot, Zapier, and Pabbly, so use a manual webhook only for services the plugin does not cover.
Assign a User Role to Logged-In Winners
Look the user up by their email with get_user_by( 'email', $data['email'] ) and, if a matching account exists, grant a role with $user->add_role( 'vip_customer' ). Gate it to a specific campaign by checking $data['campaign_id'] first.
Send an SMS Notification
Because collecting a phone number requires the Pro phone input field, confirm $data['phone'] is not empty, strip it to digits with preg_replace( '/[^0-9]/', '', $phone ), then call your SMS gateway with wp_remote_get() or wp_remote_post() using 'blocking' => false. Pull the coupon from $data['coupon_code'] on the modern flow, or from the decoded others_data on the legacy flow.
Important Notes
- Keep it non-blocking: Heavy work in a blocking external call can make the result screen hang. Use
'blocking' => falsefor outbound HTTP requests. - Guard every key: Optional fields such as name and phone may be empty, so check with
isset()or the??operator before using them. - Mind the flow difference: If a handler needs the coupon code or status, remember the legacy flow nests those inside the
others_dataJSON string while the modern flow exposes them at the top level. - Pro required: The hook never fires on a free-only install, so test with Ultimate Spin Wheel Pro active.
Related Documentation
- uspw_after_entry_saved: Fires after the entry row is saved, with the database entry ID — ideal for CRM sync.
- uspw_before_save_entry: Filter the entry data before it is written, for enrichment or UTM tracking.
- uspw_after_prize_selected: Runs right after the server picks the winning slice.
- uspw_before_send_winner_email: Customize the winner email before it is sent.
Conclusion
The uspw_after_coupon_won action is a Pro-only extension point that runs your code as soon as a spin is saved, making it a clean way to push winners to SMS gateways, webhooks, or role changes. Just account for the two spin flows — the legacy flow nests coupon fields inside others_data, while the modern flow exposes them at the top level — and keep outbound calls non-blocking. If you need help, visit the wowDevs support center.