=== Limeboom Spin Wheel ===
Contributors: osmankarakus
Tags: spin wheel, prize wheel, lucky wheel, coupon, discount
Requires at least: 6.2
Tested up to: 7.1
Requires PHP: 8.1
Stable tag: 1.0.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
WC requires at least: 8.2
WC tested up to: 9.4

A prize wheel for WooCommerce stores: server-side prizes, real gift products, and one prize per customer enforced at checkout.

== Description ==

Limeboom Spin Wheel puts a prize wheel on your WooCommerce store. A shopper spins, wins a discount or a free product, and the prize lands in their basket straight away — no code to copy out, no email address required.

Most wheel plugins decide the prize in the browser and hand over a coupon. This one decides on the server, gives real products as real order lines, and checks at the till that nobody uses the campaign twice.

= Prizes that actually arrive =

* **Percentage off**, with a maximum discount cap — something a WooCommerce coupon cannot do on its own, so "20% off" can never cost more than you planned.
* **Amount off** the order.
* **Free shipping.**
* **A free product**, added as a genuine order line priced at zero. Stock comes down, the item appears on the order, and your reports, invoices and ERP all still see it. Not a "100% off coupon" that hides the product from everything downstream.

= Built so the campaign cannot leak =

* **The server picks the prize.** Weights, quotas and odds never reach the browser, so nobody can read them or steer the outcome.
* **The same person always wins the same prize**, optionally. Clearing cookies and spinning again gets you the same slice, which makes fishing for a better prize pointless.
* **One prize per customer, checked at checkout** against the customer account and the billing email — details a shopper cannot fake without also faking a deliverable address. Spinning is free; the lock is where the money is.
* **Quotas are reserved atomically.** Two people spinning at the same instant cannot both take the last one.
* **A budget ceiling** pauses the campaign once the prizes handed out have cost what you budgeted.
* **A simulator** runs ten thousand synthetic spins against your weights and shows the expected spread and cost before you go live. Nothing is issued and no quota moves.

= Works on a real shop =

* **Full page caching is fine.** LiteSpeed, WP Rocket, Cloudflare: the wheel fetches what it needs at runtime instead of baking a token into cached HTML that goes stale and returns 403.
* **No coupon bloat.** Winning codes are not written as WordPress posts, so your Coupons screen does not fill with thousands of single-use rows.
* **Classic and block checkout**, and High-Performance Order Storage.
* **A prize won on an empty basket is kept**, and applies itself once the basket qualifies.
* **Cancelled or refunded orders** hand the quota and the budget back.
* **Prices are formatted by WooCommerce**, using your store's currency settings rather than a hard-coded symbol.

= Honest reporting =

A funnel from shown through opened, spun, in basket and ordered, plus how many prizes were turned away at checkout. Revenue counted from the orders that actually used a prize, next to what those prizes cost, so you can see whether the campaign paid for itself rather than guessing.

= Accessible =

Keyboard operable throughout, focus trapped inside the dialog, Escape closes it, the result announced to screen readers through a live region, and reduced motion respected. Text colours are derived from your chosen background by contrast ratio, so a light theme does not leave half the labels unreadable.

= Campaigns =

Create as many campaigns as you like, each with optional start and end dates. The storefront shows one wheel at a time: the most recently created campaign that is running and inside its date window. Scheduling a campaign ahead of time therefore lets it take over automatically when it starts.

== Installation ==

1. Install and activate the plugin, with WooCommerce already active.
2. Go to WooCommerce → Spin Wheel and create a campaign.
3. Set your slices, their prizes and their weights. The real odds are shown next to each weight as you type.
4. Run the simulator to see the expected spread and cost.
5. Set the campaign to Running.

== Frequently Asked Questions ==

= Do shoppers have to give an email address? =

No. By default they spin straight away and the prize applies itself to the basket. Email is offered afterwards as a convenience — "send it to me so you don't lose it". You can require an address before the spin instead, or limit the wheel to logged-in customers.

= What stops someone spinning over and over? =

Three layers, in increasing order of friction. Deterministic prize assignment makes re-spinning pointless because the same person lands on the same slice. A session lock and rate limiting stop reflex retries. And the checkout gate stops the only thing that actually costs money: using the campaign a second time.

= Will it work with my caching plugin? =

Yes. The wheel's configuration is cacheable and holds no per-visitor data, and the token that authorises a spin is fetched separately and never cached. A stale token baked into cached HTML is the usual reason a wheel plugin returns 403 for logged-out visitors; this one avoids it by design.

= Can shoppers see the odds? =

No. Weights and quotas stay on the server. The browser is told which slice to stop on and nothing more.

= Does a free product come out of stock? =

Yes. The gift is a real order line, so stock moves exactly as it would for a bought item, and the product shows up in your sales reports.

= What happens if an order is cancelled or refunded? =

The prize is released. The quota goes back, the budget figure is corrected, and that customer can win again.

= Does it work with the block checkout? =

Yes. The one-prize-per-customer check runs on both the classic and the Store API checkout paths. A gate installed only on the classic hook is silently skipped on block-based stores, which is worth asking any wheel plugin about.

= Can I translate it? =

Yes. The plugin ships with a .pot file and all strings are translatable. Translations are welcome through translate.wordpress.org.

== Screenshots ==

1. The wheel, mid-spin, on a storefront.
2. The result screen: the won product with photo, price and code, and a button that puts it in the basket.
3. The campaign editor, with live odds beside every weight.
4. The simulator, showing the expected prize spread and what it will cost.
5. The funnel and revenue panel.
6. The cart banner that invites a qualifying shopper to spin before they check out.

== Changelog ==

= 1.0.0 =
* First public release.

== Upgrade Notice ==

= 1.0.0 =
First public release.

== Legal ==

Rules for prize promotions differ by country and are the store owner's responsibility. The plugin provides a terms link, an optional consent checkbox and a per-person entry limit; it does not interpret any jurisdiction's requirements.
