mhinspeya / lucky-spin-hyva
Inspeya Lucky Spin Extension lets you engage with your store visitors through interactive game experience and offer winnings to boost purchases.
Package info
git.modehaus.de/hyvae/inspeya-lucky-spin/
Type:magento2-module
pkg:composer/mhinspeya/lucky-spin-hyva
Requires
- php: >=8.1 <8.5
- mhinspeya/backend-mod: ^1.0.2
Requires (Dev)
None
Suggests
- mhinspeya/backend-mod: Support Configuration
Provides
None
Conflicts
None
Replaces
None
README
mhinspeya/lucky-spin-hyva
Module Information
| Item | Value |
|---|---|
| Module | MHinspeya_Spinwheel |
| Composer package | mhinspeya/lucky-spin-hyva |
| Version | 1.0.3 |
| License | OSL-3.0 |
| Author | MHinspeya / Inspeya |
| Path (manual install) | app/code/MHinspeya/Spinwheel |
| Admin route | inspeyaspinwheel |
| Dependency | mhinspeya/backend-mod ^1.0 |
Overview
The Inspeya Hyva Lucky Spin module adds an interactive gamification experience to Magento 2. A customizable lucky-spin popup lets customers win discounts, coupon codes, free shipping, or other promotional rewards.
The module is built for Hyvä Themes (lightweight JS, Tailwind-friendly markup) and is configured from Magento Admin without code changes.
Key benefits
- Increase visitor engagement with an interactive spin wheel.
- Encourage newsletter sign-up / lead capture before the spin.
- Improve conversion by rewarding visitors with exclusive offers.
- Reduce cart abandonment with personalized discount incentives.
- Create a fun shopping experience that supports retention.
Features
- Fully compatible with Hyvä Themes.
- Responsive design for desktop, tablet, and mobile.
- Dynamic AJAX architecture: 100% Full Page Cache (FPC) independent. Enabling/disabling the module or specific page popups reflects instantly without flushing page caches.
- Campaign-based popups (homepage, CMS, category, product, cart).
- Read-only schedule inputs: Admin "Valid From" and "Valid To" fields feature read-only text inputs with dual-click triggers (input click or calendar button) to prevent manual typing errors.
- Weighted wheel slices (gravity %) mapped to Magento cart price rules.
- Restrict display by store, customer group, device, date/time, and frequency.
- Optional email / name / address fields before spinning.
- Automatic coupon assignment from the selected cart price rule.
- Global popup design (colors, radii, padding) in Stores → Configuration.
- Duplicate campaigns (clone + slices, copy is disabled).
- Audit log for campaign and configuration changes.
- Spin user list with CSV / Excel export.
- Full translation synchronization: 312 phrases synchronized across
en_US,de_DE,de_AT, andde_CHdictionaries covering PHP, PHTML, JS, XML, and transactional emails.
Requirements
- Magento Open Source / Adobe Commerce 2.4.x
- PHP 8.1 – 8.4 (
>=8.1 <8.5) - Hyvä Theme (storefront)
- Composer (if using Composer install)
- Dependency:
mhinspeya/backend-mod^1.0(Inspeya admin menu tab) - Writable Magento dirs:
var/,generated/,pub/static/
Installation
Run all commands from the Magento root.
In production mode, run setup:di:compile and static-content deploy after enable/upgrade.
Option 1: Composer (recommended)
# 1) Install the Inspeya backend menu dependency (if not already present)
composer require mhinspeya/backend-mod:^1.0
# 2) Install Lucky Spin
composer require mhinspeya/lucky-spin-hyva
# 3) Enable and upgrade
bin/magento module:enable MHinspeya_BackendMod MHinspeya_Spinwheel
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f
bin/magento cache:flush
If your Composer repository is private, add it first (example):
composer config repositories.mhinspeya composer https://repo.example.com
Use the repository URL provided by Inspeya for your license.
Option 2: Manual (app/code)
Ensure
MHinspeya_BackendModis installed and enabled (vendorvia Composer, orapp/code/MHinspeya/BackendMod).Copy this module to:
app/code/MHinspeya/SpinwheelRun:
bin/magento module:enable MHinspeya_Spinwheel bin/magento setup:upgrade bin/magento setup:di:compile bin/magento setup:static-content:deploy -f bin/magento cache:flushConfirm status:
bin/magento module:status MHinspeya_SpinwheelExpected: Module is enabled.
Do not install the same package in both vendor and app/code. Magento will throw a duplicate-module error.
File / cache permissions
If bin/magento cache:flush cannot clear files owned by the web server, flush as that user, for example:
sudo -u www-data bin/magento cache:flush
Or use Admin → System → Cache Management.
Hyvä Tailwind compilation
If the store theme compiles the module's Tailwind CSS, run the build from the theme's web/tailwind directory:
cd app/design/frontend/<Vendor>/<theme>/web/tailwind
npm install
npm run build
# Or for production:
npm run build-prod
[!TIP] Troubleshooting
Error: Cannot find module './cli/index':
Ifnode_modules/.bin/tailwindcssbecomes a flat file instead of a symbolic link (e.g., after copying directories or extracting archives without preserving symlinks), rebuild the binaries:rm -rf node_modules/.bin && npm rebuild npm run build
Uninstall / Disable
bin/magento module:disable MHinspeya_Spinwheel
bin/magento setup:upgrade
bin/magento cache:flush
Composer uninstall (only if installed via Composer):
composer remove mhinspeya/lucky-spin-hyva
bin/magento setup:upgrade
bin/magento cache:flush
Database tables from db_schema.xml are not removed automatically on disable. Remove them only if you intentionally want data purged:
mhinspeya_spincampaignslistmhinspeya_spinwheel_slicesmhinspeya_spinwheel_userlistmhinspeya_spinwheel_freqmhinspeya_spinwheel_audit_log
Admin menu & ACL
Parent menu: Inspeya (MHinspeya_BackendMod::mhinspeya)
| Menu | Path | ACL |
|---|---|---|
| Lucky Spin | Inspeya → Lucky Spin | MHinspeya_Spinwheel::spinwheel |
| Spin Settings | Inspeya → Lucky Spin → Spin Settings | MHinspeya_Spinwheel::config_spin |
| Spin User List | Inspeya → Lucky Spin → Spin User List | MHinspeya_Spinwheel::postuser |
| Spin Campaigns List | Inspeya → Lucky Spin → Spin Campaigns List | MHinspeya_Spinwheel::campaign |
| Audit Log | Inspeya → Lucky Spin → Audit Log | MHinspeya_Spinwheel::auditlog |
Stores configuration is also available at:
Stores → Configuration → Inspeya → Lucky Spin (spinwheel)
Configuration
1. Stores → Configuration → Inspeya → Lucky Spin
The module is disabled by default (spinwheel/general/enable = 0). Enable it here, then create at least one campaign.
General Settings (spinwheel/general)
| Field | Config path | Default | Description |
|---|---|---|---|
| Module Enable | spinwheel/general/enable | No (0) | Master switch. Dynamically evaluated via AJAX on every request. Enabling/disabling applies instantly on storefront pages without requiring Full Page Cache (FPC) flushes. |
| Homepage Popup Enable | spinwheel/general/home_popup_status | Yes (after setup patch) | Allow campaigns with Display = Homepage. |
| CMS Page Popup Enable | spinwheel/general/cms_popup_status | Yes | Allow campaigns with Display = CMS Pages. |
| Category Popup Enable | spinwheel/general/catgory_popup_status | Yes | Allow campaigns with Display = Category pages. |
| Product Page Popup Enable | spinwheel/general/product_popup_status | Yes | Allow campaigns with Display = Product Pages. |
| Cart Page Popup Enable | spinwheel/general/cart_popup_status | Yes | Allow campaigns with Display = Cart Page. |
| Enable Wheel Sound | spinwheel/general/enable_wheel_sound | — | Play spin sound on the wheel. |
| Show Fireworks | spinwheel/general/show_fireworks | — | Show fireworks on a winning spin. |
Page-type toggles also control which Display options appear on the campaign form. If a page type is No, that Display option is hidden.
Checkout popup exists in code but is not exposed in the current configuration UI.
Popup Design (spinwheel/design)
Global look-and-feel for all storefront popups. Use Use system value / Use Default to restore config.xml defaults. Color fields use a color picker.
| Field | Config path | Default |
|---|---|---|
| Heading Color | spinwheel/design/heading_color | #000000 |
| Text Color | spinwheel/design/text_color | #000000 |
| Text Field Color | spinwheel/design/field_text_color | #000000 |
| Placeholder Color | spinwheel/design/placeholder_color | #64748b |
| Button Color | spinwheel/design/button_color | #000000 |
| Button Text Color | spinwheel/design/button_text_color | #ffffff |
| Button Hover Color | spinwheel/design/button_hover_color | #333333 |
| Wheel Circle Line Color | spinwheel/design/circle_line_color | #be8686 |
| Slice Text Color | spinwheel/design/slice_text_color | #000000 |
| Text Field Border Color | spinwheel/design/field_border_color | #000000 |
| Button Border Radius (px) | spinwheel/design/button_border_radius | 0 |
| Popup Border Radius (px) | spinwheel/design/popup_border_radius | 0 |
| Form Card Border Radius (px) | spinwheel/design/form_card_border_radius | 0 |
| Text Field Border Radius (px) | spinwheel/design/field_border_radius | 0 |
| Text Field Border Width (px) | spinwheel/design/field_border_width | 1 |
| Text Line Height | spinwheel/design/line_height | 1.5 |
| Form Padding (px) | spinwheel/design/form_padding | 20 |
Saving this section is recorded in the Audit Log.
2. Spin Campaigns List
Inspeya → Lucky Spin → Spin Campaigns List
Create one campaign per popup placement (or more, using sort order when several match).
Grid columns: Campaign Id, Name, Is Active, Image, Display on, Sort Order, Valid From, Valid To, Identifier, Store Info.
Grid actions
- Add New Lucky Spin Campaign
- Row: Edit, Duplicate
- Mass: Enable, Disable, Delete
Campaign form buttons: Back, Duplicate, Delete, Save and Continue, Save.
Duplicate clones the campaign and all slices. The copy name is {original} (Copy), identifier is unique, and status is disabled.
Lucky Spin Popup Detail
| Field | Required | Notes |
|---|---|---|
| Name | Yes | Admin label. |
| Identifier | Yes | Letters only, no spaces or special characters. |
| Campaign Image | Yes | jpg / jpeg / png, max 2 MB. Shown on the wheel popup. |
| Status | Yes | Enabled / Disabled toggle. Default enabled. |
| Select Stores | Yes | Multi-select store views. |
| Valid From | Yes | Read-only date + time (dd.MM.y HH:mm), Magento store timezone. Dual trigger: click input or calendar button to open picker. |
| Valid To | Yes | Read-only date + time, Magento store timezone. Dual trigger: click input or calendar button to open picker. |
| Sort Order | No | Lower number wins when several campaigns match. Digits only. Default 0. |
Lucky Spin Popup Settings
| Field | Required | Options / notes |
|---|---|---|
| Display | Yes | Homepage, CMS Pages, Category pages, Product Pages, Cart Page (Checkout exists in code but is hidden unless enabled in config). Options appear only when the matching page popup setting is Yes. |
| Select cms pages | No | Shown for CMS Display. Multi-select CMS pages. |
| Category | No | Shown for Category Display. Multi-select catalog categories. |
| Display on device | Yes | All Devices, Desktop, I-pad, Mobile. |
| Show Customer Name | Yes | Email only; First Name + Email; Last Name + Email; First & Last Name + Email; First, Last, Postcode & City + Email. |
| Display Frequency | Yes | Every Visit; One Visit per hour; One visit per day; One visit per week; One visit per month. |
| Lucky Spin Hide Popup | Yes | Always Display; 10 / 20 / 30 / 40 Seconds. |
| User Group | No | Multi-select Magento customer groups (including NOT LOGGED IN). |
| When to show | Yes | Immediately; Exit-Intent; After Time (seconds); When scroll down (%). |
| Time | If When to show = After Time | Seconds to wait. |
| Scroll | If When to show = When scroll down | Scroll percentage. |
| Lucky Spin Popup position | No | Center; Top Bar; Bottom Bar; Left Sidebar; Right Sidebar. |
| Range | No | Default 20. |
| Title Text | Yes | 3–30 characters. Default: Play and win exciting discounts. |
| Subtitle Text | Yes | 3–50 characters. |
| Rules Text | No | Max 120 characters. |
| Result title | Yes | 3–50 characters. Default: Hooray! You have the discount voucher. |
| Result Sub title | Yes | 3–50 characters. Default: Today is your lucky day!. |
| Result title last line | No | 3–50 characters. Default: You can enter your discount code at checkout!. |
Wheel slices
On the campaign form, select 3, 6, or 9 slices. For each slice:
| Field | Description |
|---|---|
| Select Cart price Rule | Magento cart price rule used as the prize (coupon / discount). |
| Gravity (%) | Win weight. Higher gravity = more likely. Weights are used together (weighted random). |
| Color | Slice color on the wheel. |
Create cart price rules before assigning them to slices.
3. Spin User List
Inspeya → Lucky Spin → Spin User List
Customers who submitted the spin form. Columns: Id, First Name, Last Name, Post Code, City, Campaign Name, Coupon label, Store View, Created At.
- Mass delete
- Export CSV / Excel XML
4. Audit Log
Inspeya → Lucky Spin → Audit Log
Read-only history of admin changes. Columns: ID, Date, Admin User, Action, Entity Type, Entity, Entity ID, IP Address, Details.
Typical actions: campaign create / update / delete / duplicate, mass enable / disable / delete, and Stores → Configuration saves for Lucky Spin.
Customer experience
- Visitor opens a page where a matching campaign is allowed (module + page-type + campaign status, dates, store, group, device, frequency).
- Popup appears according to When to show (immediately, delay, scroll, or exit intent).
- Customer fills the fields required by Show Customer Name.
- Customer spins the wheel.
- A slice is selected using gravity weights.
- The linked cart price rule coupon / reward is shown (and emailed when configured).
Winning emails use template Spin To Win (spin_template → spinwheel.html). Sender is Magento Custom Email 1 (trans_email/ident_custom1).
Storefront pages
The popup container blocks are embedded into the page layout without layout-level ifconfig gating. This ensures that the Full Page Cache (FPC) does not lock the display state. When the page loads, Alpine.js dynamically queries the respective AJAX endpoint (spinwin/ajax/*). If the module or page popup is enabled in admin, the campaign data is delivered and rendered in real time. If disabled, an empty payload is returned immediately without executing heavy database queries.
| Page | Layout | Template | Page-type config | AJAX Endpoint |
|---|---|---|---|---|
| Homepage | cms_index_index.xml | spinpop.phtml | home_popup_status | spinwin/ajax/getpopup |
| CMS page | cms_page_view.xml | cms-popup.phtml | cms_popup_status | spinwin/ajax/cmspopup |
| Category | catalog_category_view.xml | cat-popup.phtml | catgory_popup_status | spinwin/ajax/catpopup |
| Product | catalog_product_view.xml | prod-popup.phtml | product_popup_status | spinwin/ajax/productpopup |
| Cart | checkout_cart_index.xml | cart-popup.phtml | cart_popup_status | spinwin/ajax/cartpopup |
Database tables
| Table | Purpose |
|---|---|
mhinspeya_spincampaignslist | Campaigns (schedule, targeting, copy, design leftovers). |
mhinspeya_spinwheel_slices | Wheel slices (rule, gravity, color) per campaign. |
mhinspeya_spinwheel_userlist | Customers who spun. |
mhinspeya_spinwheel_freq | Display frequency tracking (IP / user / popup). |
mhinspeya_spinwheel_audit_log | Admin audit trail. |
Compatibility
- Magento Open Source 2.4.x
- Adobe Commerce 2.4.x
- Hyvä Theme
- PHP 8.1 – 8.4
Use cases
- Promotional campaigns
- Seasonal sales
- Black Friday / newsletter capture
- Cart-page last-chance offers
Test cases
Manual QA scenarios (admin, storefront, gravity, frequency, ACL, audit log, image URLs, and more) are in TESTCASES.md.
Support
For issues or questions, contact support@inspeya.com or visit https://inspeya.com.