=== RewardCrate – Cart Goals & Rewards Booster for WooCommerce ===
Contributors: wpmilan
Tags: free shipping bar, cart goals, free gift, cart upsell, average order value
Requires at least: 6.4
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.3.3
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Free shipping bar, free gifts and automatic discounts in one cart goal bar, with product suggestions that close the gap.

== Description ==

**RewardCrate is a free cart goal bar for WooCommerce.** It shows shoppers
how far they are from the next reward, such as free shipping, a free gift or a
discount, and suggests the products that close that exact gap, with a
one-click add button right inside the bar. When a goal is reached, the reward
applies by itself.

Everything runs on your own WordPress site. There is no SaaS, no account to
create, no API key and no per-order fee.

= Why store owners choose RewardCrate =

* **More than a free shipping bar.** Set as many goals as you like, each with
  its own reward: free shipping, a free gift product, or a percentage or fixed
  discount. One progress bar shows every goal as a marker.
* **Suggestions that fit the gap.** A shopper $16 away from free shipping sees
  in-stock products priced to get them there, not random best sellers, and
  adds one without leaving the cart.
* **Rewards that apply themselves.** The gift drops into the cart at $0, the
  discount applies with no coupon code to share, and shipping turns free at
  checkout.
* **Works with your cart.** Classic and block cart and checkout, the
  Mini-Cart block, a sticky bar, a shortcode and a block.
* **Shows what it earned.** A Stats tab counts orders per goal, revenue from
  suggested products and what the rewards cost you.

= Perfect for =

* Stores that want shoppers to reach the free shipping minimum.
* Raising average order value without a blanket sitewide discount.
* Gift-with-purchase promotions: "Spend $75, get a free sampler".
* Tiered offers: free shipping at $50, a gift at $75, 10% off at $120.
* Moving accessories and add-ons that complete a bigger purchase.

= How it works =

1. Open **WooCommerce > RewardCrate** and add your goals: the cart amount
   that unlocks each one, its label and its reward.
2. Choose where the bar shows: cart, checkout, Mini-Cart, a sticky bar on
   every page, or anywhere you place the block or the `[rewardcrate_goal]`
   shortcode.
3. Shoppers see their progress, the next reward and the products that close
   the gap. The bar updates live as the cart changes.
4. A reached goal pays out by itself: free shipping at checkout, the gift line
   at $0, or the discount, labelled with your goal's name.
5. Check the Stats tab to see orders per goal, suggestion revenue, reward cost
   and average order value.

= Goals and rewards =

* Unlimited goals, each unlocking free shipping, a free gift or a discount.
* Pause a goal without deleting it, or duplicate one to build the next rung.
* **Free shipping:** make the cheapest paid rate free, or follow the minimum
  of your shipping zone's own Free shipping method.
* **Free gift:** any simple product or variation, added automatically at $0
  with its quantity locked. A shopper who removes the gift is not given it
  again for that goal.
* **Discount:** a percentage or fixed amount, applied automatically and shown
  under your goal's name. Nothing to type, nothing to leak.
* Goals are measured on the cart subtotal before discounts, so an unlocked
  discount never pushes the cart back below its own goal.
* Decide whether goal discounts combine with coupons marked "Individual use
  only".

= Gap-filler suggestions =

* Products priced from the gap up to a ceiling you set, so suggestions
  actually unlock the next goal.
* Your pinned products first, then cross-sells and products from the same
  categories as the cart, then best sellers.
* Exclude products or whole categories. Out-of-stock, hidden and
  already-in-cart products are never suggested.
* One-click add from the bar in classic and block carts; variable products
  link to their page unless exactly one variation fits.
* Fast on large catalogues: it reads WooCommerce's product lookup table and
  caches the results.

= Display =

* Cart and checkout (classic and block), the Mini-Cart block drawer, product
  pages (shown even before anything is in the cart), a dismissible sticky bar
  at the top or bottom of the screen, a block for any page, and a shortcode.
* Three bar styles (Card, Minimal and Bold), an optional striped fill, and a
  reward icon on each goal's marker: truck, gift, tag, percent, star, heart,
  crown or bolt.
* Eight ready-made colour palettes, or your own colours, including a fill for
  when every goal is reached and the border, with a contrast check so the
  message stays readable.
* Corner roundness, bar thickness, text size, rounded or square bar ends,
  left or centred text, full or narrow width, and whether goal labels and
  amounts show under the bar.
* Sticky bar on every screen size, desktop only or phones only, after a delay
  you choose, and kept off the pages you pick.
* Your own suggestions heading and Add button text, and a Custom CSS box for
  anything else.
* A celebration when a goal unlocks: confetti or a badge, never animated for
  visitors who prefer reduced motion.
* Your own messages for an empty cart, progress, each unlock and the end,
  with a live preview of the real bar. Messages can name the amount still
  needed, the goal's own amount and its reward.
* Keyboard and screen reader friendly, and translation ready.

= Built for modern WooCommerce =

* High-Performance Order Storage (HPOS) and the Cart and Checkout blocks.
* No custom database tables and no external requests.
* Loads its scripts only on pages that show the bar.

= Source code and build =

The JavaScript in the `build/` folder is compiled from the plugin's own
human-readable source, which ships inside the plugin:

* `build/admin.js` from `resources/js/admin/index.tsx` (the settings screen)
* `build/widget.js` from `resources/js/widget.ts` (the bar in classic carts, the mini-cart widget and the sticky bar)
* `build/blocks.js` from `resources/js/blocks/cart-goal.tsx` (the bar in the Cart and Checkout blocks)
* `build/blocks-editor.js` from `resources/js/blocks/editor.tsx` (the Cart goal block in the editor)
* `build/goal-bar-editor.js` from `resources/js/blocks/goal-bar-editor.tsx` (the standalone goal bar block in the editor)
* `build/coupon-labels.js` from `resources/js/blocks/coupon-labels.ts` (goal discount labels in the Cart and Checkout blocks)

Block metadata lives in `resources/blocks/` and styles in `resources/css/`.
No third-party library is bundled: WordPress and WooCommerce packages are
loaded from the site at runtime.

To rebuild the files, install Node.js 20 or newer, then run `npm install`
and `npm run build` in the plugin folder. The build uses `@wordpress/scripts`
(webpack) with the included `webpack.config.js`.

== Installation ==

1. In your WordPress admin, go to **Plugins > Add New**, search for
   *RewardCrate*, then install and activate it. WooCommerce must be active.
2. Open **WooCommerce > RewardCrate**.
3. On the **Goals** tab, add a goal: the cart amount, a label and the reward.
   Add as many as you like.
4. On the **Display** tab, choose where the bar shows and set its colours and
   messages.
5. Save, add a product to your cart and watch the bar.

== Frequently Asked Questions ==

= Is RewardCrate free? =

Yes. Every feature described here is in the free plugin, with no limits on
goals, products or orders.

= Does it work with the block cart and checkout? =

Yes. The bar appears in the Cart and Checkout blocks, where you can also move
it with the "Cart goal" block, and in the classic shortcode cart and
checkout.

= Can I show the bar in the Mini-Cart? =

Yes. With a block theme, open the Mini-Cart template part in the Site Editor
and add the "Cart goal" block to the drawer. Classic themes show it in the
WooCommerce mini-cart widget automatically.

= How do I turn off the sticky bar? =

Untick **Sticky bar on every page** on the **Display** tab, where you can
also move it to the bottom of the screen. Shoppers can also close it
themselves for the rest of their visit.

= Can the bar show on product pages? =

Yes. Tick **Product pages, above Add to cart** on the **Display** tab. It
shows even while the cart is empty, so shoppers see the first goal, such as
"Spend $50.00 to unlock Free Shipping!", before they add anything. It works
in classic and block themes.

= Does the discount push the cart back below its own goal? =

No. Goals are measured on the cart subtotal before discounts, so an unlocked
discount stays unlocked.

= What happens if the gift product goes out of stock? =

The gift is skipped and the goal still shows as reached. The event is written
to the WooCommerce log under the source `rewardcrate`, once an hour per
product.

= Can a shopper remove the free gift? =

Yes. A removed gift is remembered for that visit and not added again for the
same goal. If the cart drops below the goal and reaches it again, the gift is
offered again.

= Can shoppers type a goal's discount code? =

No. Goal discounts are virtual coupons that only exist while their goal is
reached. Typed in by hand below the goal, they are rejected like any unknown
code.

= Does it work with multi-currency plugins? =

Goal amounts are saved in your store currency. When a currency plugin shows
the cart in another currency, convert each goal with the
`smcc_threshold_amount` filter, which receives the amount and the goal. Amounts
on the bar are formatted with WooCommerce's own price format, so they follow
the shopper's currency.

WPML with WooCommerce Multilingual:

    add_filter( 'smcc_threshold_amount', function ( $amount ) {
        return apply_filters( 'wcml_raw_price_amount', $amount );
    } );

Aelia Currency Switcher:

    add_filter( 'smcc_threshold_amount', function ( $amount ) {
        return apply_filters( 'wc_aelia_cs_convert', $amount, get_option( 'woocommerce_currency' ), get_woocommerce_currency() );
    } );

CURCY – Multi Currency for WooCommerce:

    add_filter( 'smcc_threshold_amount', function ( $amount ) {
        return function_exists( 'wmc_get_price' ) ? wmc_get_price( $amount ) : $amount;
    } );

Suggested products follow the shopper's currency on their own: the exchange
rate is measured from your products' converted prices. To set it yourself,
return the price of one store-currency unit in the shopper's currency from the
`smcc_gap_filler_currency_rate` filter.

= How are the stats counted? =

Each order placed while goals are on records the goals it reached, the cart
amount, the reward cost and the revenue from suggested products, in the
order's own data. The Stats tab totals paid orders from the last 30 days,
refreshed once a day or on demand.

= Is the higher average order value proof that the goals work? =

Not on its own. The Stats tab compares orders that reached a goal or bought a
suggestion with orders that did neither, and shoppers who reach a goal may
have spent more anyway. It is a correlation, and the tab says so. Measuring
the real lift needs a holdout group that never sees the goals.

= Can I change how the bar looks in my theme? =

Yes. Set colours and messages on the **Display** tab, or copy
`templates/goal-widget.php` to `yourtheme/rewardcrate/goal-widget.php`
and edit it there.

= Does it send data to an external service? =

No. Everything runs on your own server and the plugin makes no remote
requests.

= What happens if I uninstall it? =

Its settings and cached data are removed from every site. The goal details
recorded on past orders are kept, because they are part of those orders'
history.

= Is there a hook for developers? =

Yes. Among others: `smcc_goal_rules` to change the goals per request,
`smcc_should_display` to hide the bar for a request while rewards still apply,
`smcc_threshold_amount` to convert amounts, `smcc_tier_is_unlocked` to veto
a goal, `smcc_gap_filler_candidates` and `smcc_gap_filler_ranked` to shape
suggestions, `smcc_state_data` to change what the bar receives, and the
`smcc_order_recorded` action after an order's goals are stored.

= Can I copy my goals to another store? =

Yes. On the **Tools** tab, export the settings to a file and import it on the
other store, then save. Gift and pinned products are matched by ID, so check
them afterwards. The same tab resets everything to the defaults.

== Screenshots ==

1. The goal bar in the block cart: progress to the next reward and products that close the gap.
2. A one-click add in the classic cart unlocks free shipping and celebrates.
3. The free gift added at $0, with the next goal still ahead.
4. Every goal reached: free gift, free shipping and the labelled discount.
5. The bar in the block checkout's order summary, with shipping already free.
6. The goal bar inside the Mini-Cart drawer.
7. The sticky bar follows shoppers around the store.
8. Goals: a goal ladder, and as many goals as you like, each with its own reward and icon.
9. Display: a live preview of the real bar, three styles, and layout and text controls.
10. Stats: orders per goal, suggestion revenue, reward cost and average order value.
11. The bar on a product page, showing the first goal before anything is in the cart.
12. Display: colour palettes, placements and the sticky bar's position, devices, delay and excluded pages.

== Changelog ==

= 1.3.3 =
* Fix: suggested products now match the gap when a currency plugin shows the cart in another currency.
* Fix: with "Hide the bar while the cart is empty" off, the bar now shows on the empty cart page too, classic and block.

= 1.3.2 =
* Tweak: back to the original cart-and-gift icon, now also in the settings header.

= 1.3.1 =
* Tweak: a new icon and banner, with the same mark in the settings header.

= 1.3.0 =
* Add: corner roundness, bar thickness and text size controls.
* Add: rounded or square bar ends, left or centred text, and a narrow width.
* Add: hide the goal labels or amounts under the bar.
* Add: a fill colour for when every goal is reached, and a border colour.
* Add: show the sticky bar on desktop or phones only, after a delay, and keep it off chosen pages.
* Add: your own suggestions heading and Add button text.
* Add: a Custom CSS box on the Display tab.
* Tweak: new listing screenshots of the redesigned bar and settings.

= 1.2.0 =
* Add: reward icons on the bar, with an icon to choose per goal.
* Add: Card, Minimal and Bold bar styles, and an optional striped fill.
* Add: eight colour palettes and a contrast check on the Display tab.
* Add: the goal bar on product pages, shown even with an empty cart.
* Add: a message for the empty cart, with the `{goal}` placeholder.
* Add: the sticky bar can sit at the bottom of the screen.
* Enhance: the Display tab previews the real bar for an empty cart, a cart on its way and a finished cart.
* Enhance: a new brand mark in the settings header.

= 1.1.0 =
* Add: pause a goal without deleting it; paused goals keep their stats.
* Add: duplicate a goal, and start from a ready-made goal set.
* Add: Tools tab to export, import and reset the settings, and copy the shortcode.
* Add: `{goal}` message placeholder for the cart amount that unlocks a goal.
* Add: `smcc_should_display` filter to hide the bar for a request.
* Add: Settings link on the Plugins screen.
* Enhance: redesigned settings screen with a sticky header, live status, a goal ladder, inline checks on each goal and Ctrl+S to save.
* Enhance: the settings screen reopens on the tab you last used.
* Fix: the message preview replaced only the first copy of a placeholder.

= 1.0.0 =
* Initial release.

== Upgrade Notice ==

= 1.3.3 =
Suggested products follow the shopper's currency, and the empty cart page can show the first goal.

= 1.3.2 =
The original icon returns, in the listing and the settings header.

= 1.3.1 =
A refreshed icon and banner, matching the settings screen.

= 1.3.0 =
More ways to style the bar: sizes, shapes, alignment, completion colour, sticky bar targeting and custom CSS.

= 1.2.0 =
Reward icons, bar styles, colour palettes, a product page bar and a bottom sticky bar.

= 1.1.0 =
A redesigned settings screen, pausable goals, and settings export and import.

= 1.0.0 =
Initial release.
