=== ShopBooster — Bundle Pricing, Stories & Upsell ===
Contributors: jdaproai
Tags: woocommerce, upsell, woocommerce bundle, video stories, quantity discount
Requires at least: 6.0
Tested up to: 6.7
Requires PHP: 7.4
Stable tag: 2.9.17
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Boost your WooCommerce conversions with dynamic bundle pricing tiers, a video stories carousel, and smart one-click upsell — no ACF or WPCode needed.

== Description ==

**ShopBooster** is an all-in-one conversion plugin for WooCommerce product pages. It replaces complex multi-plugin setups with a single, lightweight solution configured directly from the product editor.

= Features =

**📦 Dynamic Bundle Pricing Widget**
* Unlimited pricing tiers (buy 1, buy 3, buy 6… any quantity)
* Per-tier custom badge with color picker
* Optional quantity selector (+/-) that automatically jumps to the next tier
* Stock-aware: tiers exceeding available stock are hidden automatically
* Real-time price update as quantity changes
* Drag & drop to reorder tiers

**🎬 Video Stories Carousel**
* TikTok/Reels-style vertical video carousel below product images
* Supports direct .mp4 files and YouTube/Shorts links
* Progress bar, autoplay, loop
* Navigation dots

**🧴 Smart Upsell**
* One-click toggle to add a complementary product at a discounted price
* Product search with autocomplete (no ID needed)
* Image picker from media library

**⭐ Dynamic Trust Badge**
* Star rating badge (0–5, decimals supported)
* Stars fill automatically based on the rating value

**⚡ Stock Urgency Text**
* Replaces the default "X in stock" text with a customizable urgency message
* Fully configurable from global settings

= No dependencies =
ShopBooster works without ACF, WPCode, or any third-party plugin. Everything is configured from the native WooCommerce product editor under the **🚀 ShopBooster** tab.

= Global Settings =
Configure accent color, shipping text, blocked coupon (incompatible with bundle offers), and stock urgency text once — applies to all activated products.

== Installation ==

1. Upload the `shopbooster` folder to `/wp-content/plugins/`
2. Activate the plugin through the **Plugins** menu in WordPress
3. Go to **WooCommerce → 🚀 ShopBooster** to configure global settings
4. On any product page, open the **🚀 ShopBooster** tab and activate the plugin for that product

== Frequently Asked Questions ==

= Does this work with any WooCommerce theme? =
Yes. ShopBooster injects its widget using standard WooCommerce hooks and is compatible with most themes. Minor CSS adjustments may be needed for highly customized themes.

= Do I need ACF or WPCode? =
No. ShopBooster stores all data using native WordPress post meta. No third-party plugins required.

= Can I use YouTube Shorts links for the Stories carousel? =
Yes. Paste any YouTube, YouTube Shorts, or youtu.be link and ShopBooster will automatically embed it as an iframe.

= Does the bundle pricing affect actual cart prices? =
Yes. ShopBooster hooks into WooCommerce's cart totals calculation and applies the correct per-unit price based on the quantity tier selected.

= Can I block a coupon from being used with bundle offers? =
Yes. Enter the coupon code in the global settings under "Blocked coupon on bundles". The coupon will be rejected if the customer has a bundle quantity in their cart.

= Is the plugin translation-ready? =
Yes. ShopBooster is fully internationalized using the `shopbooster` text domain. A French translation is included.

== Screenshots ==

1. Bundle pricing widget with 3 tiers, trust badge, and stock urgency text
2. Video Stories carousel below product images
3. Upsell toggle with discounted price
4. ShopBooster tab in the WooCommerce product editor
5. Global settings page

== Changelog ==

= 2.9.17 =
* Fix: upsell special price was overridden in cart totals when the upsell product has its own ShopBooster tiers (e.g. a "1 unit" tier at full price). The tier price read-filter now skips upsell cart lines, so the configured upsell price (e.g. 15€ instead of 25€) is correctly charged.
* Fix: upsell cart line now displays the special price (crossed-out regular + reduced) in cart and mini-cart instead of the full catalog price.

= 2.9.16 =
* New: rating source mode per product. "Auto (real customer reviews) with threshold" pulls the live WooCommerce/CusRev review average and count; below the configured review threshold it automatically falls back to the manual rating/label. "Manual" keeps the fixed value as before.
* New per-product field "Seuil d'avis" (default 5) controlling when auto rating activates.
* The auto label shows the real verified review count (e.g. "83 avis vérifiés") and updates on its own.

= 2.9.15 =
* New: optional clickable rating badge. When enabled in WooCommerce → ShopBooster, the trust rating ("4.8/5") becomes a link that smooth-scrolls to the reviews section.
* New setting "Reviews section ID" (default: sb-avis-clients) — set this same ID on the Elementor reviews container (Advanced → CSS ID) so the badge knows where to scroll.

= 2.9.14 =
* Tweak: upsell note ("Note sous le prix" / .sb-upsell-tag) font size increased from 12px to 14px for better emphasis under the price.

= 2.9.13 =
* Fix: Stories cards HTML is now rendered in a native <template> element and cloned by JS, instead of being embedded inside an inline JavaScript string. Prevents fatal page-wide SyntaxError when HTML-rewriting optimizers (Smush lazy-load, WP Rocket, etc.) modify the video markup inside the script.
* Hardening: stories init wrapped in try/catch — any unexpected failure now only skips the stories module instead of breaking the whole product page.
* Hardening: stories script tagged data-no-optimize / data-cfasync to be excluded from LiteSpeed/Cloudflare JS combine & minify.
* Fix: carousel scroll handler no longer throws if no story card is found.

= 2.9.10 =
* Fix: The styled quantity selector on simple products now appears whenever ShopBooster is active (without tiers), regardless of whether the upsell or shipping banner is enabled. Previously, disabling both left the product with no quantity selector at all (native hidden, styled one not shown).

= 2.9.9 =
* Fix / New: On a simple product with ShopBooster active but no pricing tiers (e.g. upsell only), the theme's native quantity field could overlap the upsell box and looked unstyled. It is now replaced by a styled − 1 + selector placed above the upsell, consistent with the tier selector. Only applies when an upsell or shipping banner is shown; tiered and variable products are unaffected.

= 2.9.8 =
* Fix: The "Shipping banner" feature toggle could not be turned off — unchecking it and updating brought it back checked. Its checkbox was displayed and read everywhere but was missing from the save loop, so the meta was never written. It now saves correctly like the other toggles.

= 2.9.7 =
* Fix: On themes whose WooCommerce price format uses a non-breaking space entity (e.g. Astra), tier prices displayed the raw "&nbsp;" text (e.g. "33,80&nbsp;€") because the JS re-rendered prices via textContent. The price format is now HTML-decoded before use, so a proper space is shown.

= 2.9.6 =
* Fix: The tier editor's "Sale price" and "Final price" fields rejected decimal values (e.g. 16.9) because the number inputs had no step attribute — only whole numbers were accepted. They now accept decimals (step="any"). The quantity field stays integer-only. Existing tiers are unaffected.

= 2.9.5 =
* New: An illustrated user guide (docs/mode-demploi.html) ships with the plugin, linked from the top of the settings page.

= 2.9.4 =
* New: The coupon blocked on bundles setting now accepts multiple coupon codes, separated by commas. Each listed coupon is rejected when the cart contains a bundle quantity. Existing single-code configurations keep working unchanged.

= 2.9.3 =
* Tweak: The "Linked product" field in the tier editor is now a live product search (type a few letters, pick the product) instead of a raw ID input, matching the upsell field. Existing linked products are preloaded with their names.

= 2.9.2 =
* New: Product tiers — a tier card can now link to another product via the new "Linked product ID" field in the tier editor (pid: token). Selecting that card adds the linked product to the cart instead of the parent. Price, sale price, image and GTIN are read live from the linked product, and the card is hidden if it is out of stock. Designed for component kits: tier 1 = Kit Duo, tier 2 = Kit Trio, each kit keeping its own recipe, computed stock and component decrement.
* Fix: The upsell now follows correctly when a product tier swaps the added product (config read from the storefront product, orphan purge keyed to the product actually in the cart).
* Security: The posted linked product ID is validated against the tiers configured on the product.

= 2.9.1 =
* Tweak: The packs editor now shows a warning when the "Bundle Pricing Tiers" feature toggle is unchecked on the product, since that toggle is the master switch for both tiers and packs.

= 2.9.0 =
* New: "Quantity packs" mode for variable products. The customer picks attributes with the theme's native selectors/swatches, then a quantity pack with a percentage discount (e.g. x3 -21%, x6 -28%). Pack prices are computed live from the selected variation and update when the variation changes. Packs exceeding the variation's stock are disabled automatically.
* New: Packs are defined per product in a simple one-line-per-pack field (quantity|discount %|label|badge|#color) shown only on variable products. The historical "one card per variation" mode remains the default.
* Security: the pack discount is re-read server-side from product meta (only the pack index is posted) and applied only when the cart quantity reaches the pack quantity. The pack label and discount are shown on the cart line.

= 2.8.5 =
* Tweak: Unselected tier cards get a slightly darker border (#c9c9c9 instead of #e0e0e0) for better definition, plus a hover state (#9e9e9e) hinting they are clickable. The selected state (accent border + tinted background) remains the strongest visual signal.

= 2.8.4 =
* Tweak: Upsell box restyle refined — white background (the accent tint could be mistaken for a selected tier), bolder 2px dashed accent border, and an automatic discount pill (e.g. -20%) computed from the upsell price vs the crossed-out price, matching the tier badges visual language.

= 2.8.3 =
* Tweak: The upsell box is now visually differentiated from the tier cards — dashed border in the accent color and a subtle accent-tinted background (with a plain white fallback for older browsers). Reads as an optional add-on instead of a third tier.

= 2.8.2 =
* Tweak: The "top" shipping banner position is now accurately labeled "Between the tiers and the upsell box" — this is where it has always rendered inside the widget. Label fix only, no behavior change.

= 2.8.1 =
* Tweak: Position labels rephrased around visible landmarks (tiers, upsell box, Add to cart button) instead of the quantity selector, which is hidden when pricing tiers are active. No behavior change.

= 2.8.0 =
* Change: The recommended positions are now the defaults — upsell box between the quantity selector and the Add to cart button, shipping banner just above the button. Sites that explicitly saved a position (globally or per product) keep their choice.

= 2.7.9 =
* New: Global default positions for the upsell box and the shipping banner (WooCommerce → ShopBooster settings). Product-level position selects now default to "Global settings" and can force a specific position per product. Existing per-product choices are preserved. Fully translated (7 languages).

= 2.7.8 =
* Fix: The upsell toggle and the stock urgency badge stopped working when the inline widget was not rendered (e.g. upsell and shipping banner both deported, no tiers). Their initialization is now independent of the widget container.

= 2.7.7 =
* New: Shipping banner position is now configurable per product — top of the widget (default) or just above the "Add to cart" button (reassurance at the point of decision, renders after the upsell box when both are deported).

= 2.7.6 =
* i18n: The 4 strings introduced in 2.7.1–2.7.4 (banner icon setting, upsell stock/removal notices) are now translated in all 7 languages (fr, es, de, it, nl, pt, ar).

= 2.7.5 =
* Fix: Orphan upsell items are now also purged when the cart is loaded from the session, covering carts that became orphaned before the update or through removal paths that bypass the standard hooks.

= 2.7.4 =
* Fix: When the main product is removed from the cart (or its quantity drops to zero), the linked upsell item is now removed automatically with an explanatory notice. Previously the upsell stayed in the cart at its discounted price without the main product.

= 2.7.3 =
* New: Third upsell position — "Between the quantity selector and the Add to cart button" (recommended): the box is seen before the purchase decision without breaking the payment buttons block.
* Tweak: Top margin added to the upsell box so it doesn't stick to the quantity field or button in deported positions.

= 2.7.2 =
* New: Upsell box position is now configurable per product — inline in the widget (default) or below the "Add to cart" button, to avoid confusion between the product quantity selector and the upsell.
* New: The upsell box is automatically hidden when the upsell product is out of stock or not purchasable.
* Fix: Server-side stock validation when the upsell is added to the cart (a soft notice is shown if it became unavailable).
* Fix: The upsell was never added to the cart on products without pricing tiers (the server-side guard required active tiers).
* Security: The posted upsell product ID is now validated against the one configured on the product (prevents price manipulation).

= 2.7.1 =
* New: The shipping banner icon (previously hardcoded 📦) is now configurable. Set a global icon in Settings (any emoji, empty = no icon) and override it per product in the ShopBooster tab (empty = global icon, "none" = no icon on that product).

= 2.7.0 =
* New: Shipping banner is now a per-product feature toggle (5th switch in the Activation box) and its text can be customized per product (empty = global settings text). The banner can also display on its own, without tiers or upsell.

= 2.6.2 =
* Fix: A second quantity-hiding CSS rule (clip technique used to keep the field in the DOM for tier sync) was still applied globally. Both hiding rules are now injected only when tiers or variation cards actually control the quantity. The native quantity selector is fully restored on products using only upsell/badge/urgency/kit features.

= 2.6.1 =
* Fix: The native quantity selector on the product page is no longer hidden when ShopBooster is active but the tiers feature is disabled or no tiers are defined (it is only hidden when tiers or variation cards actually control the quantity).

= 2.6.0 =
* New: Per-feature toggles on each product (tiers, trust badge, upsell, stock urgency) under the Activation section. Existing products keep everything enabled (backward compatible).
* Fix: Cart quantity is no longer locked when ShopBooster is active but no tiers are defined (price override, cart count, tier label and quantity lock now only apply when tiers are actually in play).
* Fix: Upsell and trust badge now render even when no tiers are defined (the widget previously required tiers to display anything).
* Clarified: video stories are independent and display whenever videos are added, regardless of the activation checkbox.

= 2.5.3 =
* Improvement: Lightbox arrows are desktop-only (mobile relies on swipe + dots, avoiding overlap with the video content) and their style is hardened against theme CSS overrides (fixed 44px circles).

= 2.5.2 =
* New: Navigation dots below the lightbox video (clickable, active dot in accent color) so it is immediately clear that several stories can be browsed.

= 2.5.1 =
* Fix: Lightbox arrows are now anchored to the video frame edges (they were spread across the whole screen on wide monitors) and are shown as compact overlay buttons on mobile instead of being hidden.

= 2.5.0 =
* New: Story lightbox navigation — swipe left/right on mobile (swipe down to close), arrow buttons and keyboard arrows on desktop, "2 / 3" counter, and auto-advance to the next story when an MP4 ends. Loops through the carousel.

= 2.4.0 =
* New: Story thumbnails can be clicked to play the video fullscreen with sound (vertical 9:16 lightbox, close button, click-outside and Escape to close, thumbnails paused during playback). Works for both MP4 and YouTube Shorts.
* New: Global setting "Stories: play on click" to enable/disable the lightbox (enabled by default).

= 2.3.1 =
* New: Per-tier image picker in the tier editor (media library). The engine already displayed tier images, but the visual editor had no way to set them — legacy images are preserved, and clicking an existing thumbnail lets you remove or replace it.

= 2.3.0 =
* New (Pro preview): In mixed mode, secondary attributes are now rendered as clickable pill buttons (unavailable combinations grayed out) instead of native dropdowns.
* New: Quantity +/- stepper on the selected variation card, synced with the native quantity field and capped at the variation's available stock.

= 2.2.0 =
* New (Pro preview): Multi-attribute variable products. Choose which attribute is displayed as ShopBooster cards (setting at the top of the Variations tab); the other attributes keep their native selectors. Cards show the minimum price ("From ...") when it varies across the other attributes, and update to the exact price once a full variation is resolved.

= 2.1.3 =
* Improvement: Structured data now keeps the native WooCommerce offer first (its price matches the Google Merchant Center feed for automatic price checks) and appends multi-unit tier offers after it, instead of replacing it. Prevents potential price-mismatch warnings in Merchant Center.

= 2.1.2 =
* Fix: The "Enable component kit mode" checkbox was invisible in the product admin (hidden by WooCommerce options-panel CSS floats). It is now displayed in a highlighted box at the top of the Kit tab.

= 2.1.1 =
* Fix: Kit component stock reduction/restock now also hooks directly into order status changes (processing/completed and cancelled/refunded/failed), so it works even when third-party plugins bypass the standard WooCommerce stock reduction signal. Anti-double-decrement guard kept.

= 2.1.0 =
* New (Pro preview): Component kits. A kit product is assembled from other products: its stock is computed from component stocks, each sale decreases every component's real stock, and cancellations/refunds restock them. Kit contents are saved on the order line.
* New: Kit tab in the product admin with a component picker (product search + quantity per component).

= 2.0.0 =
* New (Pro preview): Variable products support. Each variation is displayed as a ShopBooster card (price, sale discount, per-unit price, stock, image via the native WooCommerce form).
* New: Per-variation admin fields — card label, units per pack, badge text and badge color.
* New: Order line items of variable products now carry the GTIN from the variation's native "unique identifier" field.
* Note: this build is for private use; the public WordPress.org build remains 1.2.0.

= 1.2.0 =
* New: Per-tier EAN/GTIN field in the tier editor (optional).
* New: Tier label and GTIN are now saved as order line item meta (visible in admin orders, emails, invoices and exports).
* New: schema.org structured data now includes one Offer per pricing tier (price, quantity, GTIN) for better SEO / rich results.

= 1.1.6 =
* Fix: Upsell image picker in the product admin was not saving the selected image (hidden field ID mismatch). Selecting an image from the media library now updates the preview and saves correctly.

= 1.1.5 =
* Fix: Live price updates in the bundle widget now follow the WooCommerce price format settings (decimal/thousand separators, decimals, currency position) instead of a hardcoded French format. Prices are now consistent across the widget, cart and theme.

= 1.1.4 =
* Fix: Cart count badge now counts each bundle-tier line as 1 item instead of its real quantity (e.g. a "100 gr" tier no longer shows 100 in the header cart icon). Real quantity is kept for stock and pricing.

= 1.1.3 =
* Fix: Mini-cart line total now respects tax display settings (was showing excl. tax amount)

= 1.1.2 =
* New: Tier label shown instead of raw quantity in cart page (quantity locked for tier products)
* New: Mini-cart shows line total instead of ambiguous unit price breakdown

= 1.1.1 =
* Fix: Tier pricing now applied with maximum priority (compatibility with discount plugins)
* Fix: Native quantity selector hidden on Shoptimizer and standard themes
* New: Tier label displayed next to product name in cart

= 1.1.0 =
* New: Stories carousel position selector (below gallery, title, price, above/below cart button)
* New: Option to swap main product image when a tier is selected
* New: Option to hide native variation selectors (avoid duplicates with tiers)
* New: Fallback rendering hook for themes that bypass the cart button hook (e.g. Shoptimizer)
* Fix: Currency symbol displayed as HTML entity in tier prices

= 1.0.0 =
* Initial release
* Dynamic bundle pricing with unlimited tiers
* Video Stories carousel (mp4 + YouTube/Shorts)
* Smart upsell with one-click toggle
* Dynamic trust badge (auto star fill)
* Stock urgency text
* Drag & drop tier reordering
* Media library picker for upsell image
* Product autocomplete search for upsell
* Global settings (accent color, shipping text, blocked coupon, stock urgency)

== Upgrade Notice ==

= 1.1.0 =
New positioning options, image swap, better theme compatibility, currency fix.

= 1.0.0 =
Initial release.
