etechflow / module-back-in-stock-notification
etechflow/module-back-in-stock-notification
Back-in-stock notification for Magento 2. Customer subscribes on out-of-stock product pages, gets emailed when stock returns. Anonymous + customer-linked subscriptions, multi-store aware, one-click unsubscribe, queued/rate-limited delivery. Standalone — works without any other ETechFlow module — and integrates richer when paired with NDE / BED / ISP.
ETechFlow Back-in-Stock Notification
Customers subscribe to out-of-stock products. When stock returns, they get an email.
Standalone-first — works on any Magento 2.4.4+ install without other ETechFlow modules. Integrates richer when paired with NDE / BED / ISP.
Install
composer require etechflow/module-back-in-stock-notification:^1.0
bin/magento module:enable ETechFlow_BackInStockNotification
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush
# Restart php-fpm to clear OPcache (mandatory on prod with opcache.validate_timestamps=0)
Activate the licence
php tools/generate-license.php --module=back-in-stock-notification --host=<your-domain>
Paste the key into Stores → Configuration → eTechFlow → Back-in-Stock Notification → License Key.
For multi-module customers, paste the bundle key into the Bundle License Key field instead. One key activates every ETechFlow module installed on the host.
Verify
bin/magento etechflow:bisn:verify
Twelve PASS lines means you're good to go.
How it works
- Customer hits an out-of-stock PDP → a "Notify me when back in stock" form replaces the disabled Add-to-Cart button.
- Form submit →
etechflow_bisn_subscriptionrow created. Anonymous (email only) or customer-linked. - Merchant saves stock with qty > 0 →
StockSaveObserverenqueues a notification for every subscription matching that product + store. - Cron runs every 5 min →
QueueConsumersends batched, rate-limited emails. Default 60 emails/minute. - Customer clicks the email → one-click unsubscribe (RFC 8058 compliant) OR goes to the PDP to purchase.
Configuration
Stores → Configuration → eTechFlow → Back-in-Stock Notification:
- License Key — per-module key (or use Bundle License Key for the suite)
- Module Enabled — toggle the whole feature
- Email Rate Limit — emails/minute (default 60). Adjust to your SMTP capacity.
- Subscription Lifetime — auto-expire unredeemed subscriptions after N days (default 180, 0 = never)
- eTechFlow Suite Integrations — NDE / BED / ISP opt-in toggles (hidden if the sibling module isn't installed)
- Notifications — sender email, sender name, email subject template
Compatibility
- Magento Open Source 2.4.4 – 2.4.8
- Adobe Commerce 2.4.4 – 2.4.8
- PHP 8.1 / 8.2 / 8.3 / 8.4
- Hyvä Theme + Hyvä Checkout (PDP form renders via Hyvä-safe block)
Support
[email protected] — please include your license key + Magento version when reporting issues.
Changelog — ETechFlow Back-in-Stock Notification
All notable changes to this module. Adheres to Semantic Versioning.
[1.0.3] — 2026-05-22 — Move admin menu under eTechFlow top-level sidebar
Changed
- BISN admin pages relocated to a dedicated "eTechFlow" sidebar entry. Previously the Subscriptions list lived under
Sales → Operations. Now it sits in aBack-in-Stockcolumn inside a new top-leveleTechFlowsidebar entry (clusters with other paid-extension vendors above Magento's Stores). Matches the pattern Amasty / Magefan / MageWorx use so merchants can spot paid extensions at a glance. - Each eTechFlow module declares the same
eTechFlow::root+eTechFlow::settings+eTechFlow::configurationentries — Magento merges by id, so installing N modules still produces exactly oneeTechFlowsidebar group. No inter-module dependency added; BISN remains standalone.
Migration
composer update etechflow/module-back-in-stock-notification
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f
bin/magento cache:flush
Admin URL routes unchanged (etechflow_bisn/subscription/index still works). No schema or behaviour changes — pure menu-layout adjustment.
[1.0.2] — 2026-05-20 — Inline-AJAX subscribe (progressive enhancement)
Removes the full-page reload on subscribe. Customer types email, clicks Notify me, the form swaps inline to a "You're on the list" success card. No spinner, no flash-message round-trip.
Added
- Inline-AJAX submit via vanilla
fetch()— no jQuery, no Alpine, no Magewire dependency. Works on every browser Magento officially supports (Safari 11+, Chrome / Edge / Firefox last 2 versions). - Form
data-elementhooks on the wrapper + form so the script binds reliably without conflicting with anything else on the page. - Inline-error rendering — invalid email / form-key expired / dedupe message all render inline next to the form, not as a flash message.
Changed
Controller/Subscription/Create.phpis now dual-mode: when the request includesX-Requested-With: XMLHttpRequestorAccept: application/json, returns a JSON envelope ({success, message}). Otherwise falls back to the v1.0.1 flash-message + redirect-to-referrer flow. Same persistence + dedupe + double-opt-in logic, only the response shape differs.
Backwards compatibility
- JavaScript disabled → plain HTML POST + redirect still works (the
<form>still hasaction+method="post"). - AJAX endpoint is the same URL — no new routes, no extra controllers, no breaking changes for anyone who built integrations against v1.0.0/1.0.1's URL.
- No new DB schema, no new admin config, no new dependencies. Drop-in replacement.
Theme compatibility
- Luma: native browser
fetch()available — works. - Hyvä Theme:
fetch()available — works. Inline JS doesn't conflict with Alpine or Hyvä's own scripts. - Hyvä Checkout: BISN's form is on the PDP, not the checkout, so this is irrelevant — but the same form works if a Hyvä Checkout merchant decides to display it inside the checkout for any reason.
Migration
composer update etechflow/module-back-in-stock-notification
bin/magento cache:flush
No setup:upgrade, no setup:di:compile needed — only template + controller changed, no schema or DI tree changes. Customers upgrading from v1.0.1 just need to flush cache.
[1.0.1] — 2026-05-20 — Real-install hotfix (3 bugs caught by live Magento 2.4.8 test)
Caught the moment we ran this module against a real Magento install for the first time. None of these would have shown up in php -l / composer-resolution / XSD-validation — only setup:upgrade and a full end-to-end run surface them.
Fixed
etc/db_schema.xml: invalidcomment="..."attributes on<index>elements. Magento's declarative-schema XSD only permitscommenton<table>and<column>, not on<index>or<constraint>.setup:upgradefailed with: "Element 'index', attribute 'comment': The attribute 'comment' is not allowed. Line: 96 / Line: 170", and the two BISN tables never got created. Five invalid attributes stripped; XML stays well-formed. Subsystem-by-subsystem table comments (on<table>and<column>) are unaffected.Observer/StockSaveObserver::getStoreIdsForProduct()was a stub that returned only[0]. Any store-scoped subscription (the normal case —store_id=1for the default store view) was missed, so even when stock came back, the queue stayed empty. Replaced withgetStoreIdsWithActiveSubs(productId)which queries DISTINCT store_id from the subscription table for active subs on this product. Hot-path-indexed on(product_id, store_id, status). Adds one constructor arg (CollectionFactory) — requiressetup:di:compileafter upgrade.- Test/Unit/Model/LicenseValidatorTest.php added. 15 PHPUnit tests, 37 assertions, covering: HMAC determinism, www-stripping, case-insensitive canonicalisation, key uniqueness per host, per-module vs bundle key differentiation, whitespace trimming, 18 dev-host patterns recognised, 5 production-host patterns NOT mistakenly recognised as dev, isValid() on dev/prod hosts, tamper-detection. All 15 pass.
Migration
composer update etechflow/module-back-in-stock-notification
bin/magento setup:upgrade
bin/magento setup:di:compile
# Restart php-fpm to clear OPcache (mandatory on prod with opcache.validate_timestamps=0)
If you were on v1.0.0 and setup:upgrade failed (you would have seen the index/comment XSD error), the v1.0.1 upgrade applies cleanly — the failed v1.0.0 install didn't create the tables, so re-running setup:upgrade after composer update will create them now.
[1.0.0] — 2026-05-20 — Customer subscribes, gets emailed when stock returns
First commercial release. Solves the universal "customer wanted the product, you were OOS, you lost the sale" problem.
The differentiator vs every existing M2 back-in-stock module
Every existing module on the marketplace shares one or more of these footguns:
- No queue / no rate limit — popular SKU restocks, module synchronously sends 5,000 emails inside one stock-save observer, breaks the stock-import job. Ours queues and rate-limits.
- Per-website only, not per-store — multi-store stores send notifications across all stores indiscriminately. Ours is store-scoped.
- No anonymous subscriptions OR no logged-in linking — either guests can't subscribe (limits lead capture) or logged-in customer subs aren't linked to their account (UX regression). Ours does both, with auto-linking on customer creation.
- No one-click unsubscribe — required by CAN-SPAM / RFC 8058. Many modules ship without it. Ours has signed-token one-click unsubscribe.
- No suite integration — pure standalone, so a customer whose drop-ship rules (NDE) say "not eligible" still gets a "back in stock!" email. Ours respects NDE eligibility when installed.
Added
Foundation
registration.php,composer.json(proprietary licence, soft-deps on NDE / BED / ISP)etc/module.xmlsetup_version1.0.0- DB schema: 2 tables.
etechflow_bisn_subscription— customer_id (nullable), email, product_id, store_id, subscribed_at, notified_at, unsubscribe_token, status.etechflow_bisn_notification_queue— subscription_id, scheduled_at, attempts, status. Decouples "stock came back" from "email was sent".
- Admin config (
etc/adminhtml/system.xml) — License section + General Settings + eTechFlow Suite Integrations + Notifications. Standard 4-section layout.
Licensing + Infrastructure
Model/LicenseValidator— per-domain HMAC + bundle key.MODULE_ID = back-in-stock-notification. SharesBUNDLE_SECRET_FRAGMENTSwith every eTechFlow module.Model/Config— license-awareisEnabled(). Soft-detection of optional integrations (NDE, BED, ISP) viaclass_exists.Model/Performance/Profiler— Tideways span helper, tagsETechFlow_BISN_*.
Entities + Service Contracts
- Full Api/Data + Api/Repository contracts for the Subscription entity.
- Model + ResourceModel + Collection + Repository implementations.
Frontend
Block/Product/NotifyMeForm+ template — renders on PDP when product is out of stock. Replaces the disabled Add-to-Cart with a "Notify me when back in stock" form (email + optional first-name).Block/Customer/SubscriptionList+ template — customer account "My Subscriptions" page. Lists active subscriptions with unsubscribe-from-here button.- One-click unsubscribe controller —
etechflow_bisn/subscription/unsubscribe?token=<signed>validates the signed token, removes the subscription, shows a confirmation page.
Detection + Notification
Observer/StockSaveObserver— fires oncataloginventory_stock_item_save_after. Cheap: bails immediately if no subscriptions exist for the product. Whenqtygoes from 0 → positive, enqueues notifications.Cron/QueueConsumer— runs every 5 min via cron. Pulls due notifications from queue, rate-limited (default 60/min), sends transactional email per subscription, marks as sent. Retries on transient failure up to 3 attempts.Model/Notification/BackInStockSender— composes + sends the email. Customisable template via Magento's standard email-template system.etc/email_templates.xml— registersetechflow_bisn_back_in_stocktemplate. Default template atview/frontend/email/back_in_stock.html.
Admin
- Magento UI Component listing grid at Sales → Operations → Back-in-Stock Subscriptions: ID, Email, First Name, Product ID, Customer ID, Store View, Status (filterable), Subscribed At, Notified At, per-row Actions (Delete / Cancel).
- Mass actions: Delete (removes audit row), Cancel (keeps audit row, blocks future notifications), Notify Now (force-queues notification — bypasses the qty 0→positive trigger).
- Two ACL resources:
subscriptions_delete(Delete + Cancel) andsubscriptions_notify_now(force-queue) so you can grant view-only access to most admin roles. - Source model for the Status column dropdown.
Auto-Link Anonymous Subscriptions
Plugin/Customer/AutoLinkSubscriptionsPlugin—after-plugin onMagento\Customer\Api\AccountManagementInterface::createAccount. When a guest who previously subscribed by email later registers with the same email, their pending subscriptions auto-link to the new customer (so they appear in My Account → Subscriptions immediately).- Defensive: never blocks customer creation. Logs failures and continues.
Lifetime Expiry
Cron/LifetimeExpiryCron— runs daily at 03:00. Updatesstatusfrompending|confirmed→expiredfor rows older than the admin-configurable lifetime (default 180 days, 0 = never expire). Single UPDATE query — index-only on(status, subscribed_at). Logs the affected row count when nonzero.
Double Opt-In Confirmation Email
Model/Notification/ConfirmSender— sends the confirmation email when the admin "Require Double Opt-In" toggle is on. Best-effort — if SMTP fails, the pending subscription stays in DB so the customer can re-trigger from the PDP form.- Default template at
view/frontend/email/confirm.html(configurable via Marketing → Email Templates).
Optional eTechFlow Suite Adapters
Model/Adapter/NdeEligibilityAdapter— when NDE is installed + admin opted in, "in stock" is determined by NDE'sIneligibilityChecker::isEligible()instead of rawqty > 0. Falls back to direct stock check when NDE isn't present.Model/Adapter/BedEtaAdapter— when BED is installed, restock notifications include BED's per-product ETA in the email if the restock is itself a future backorder.Model/Adapter/IspStoreAdapter— when ISP is installed, customers can opt to subscribe to a specific pickup-store's stock (not just the global stock).
Verify CLI
bin/magento etechflow:bisn:verify— 12 checks covering license, config, all 2 DB tables, repository via DI, observer registration, cron registration, email-template registration. Exit 0 on full pass, 1 on any failure.
Standalone-first architecture
Same pattern as ISP. This module works fully standalone — no other ETechFlow module required. The integrations with NDE / BED / ISP are opt-in enhancements soft-detected via class_exists. If the sibling module isn't installed, BISN falls back to its own self-contained logic.
| Optional pairing | Standalone | With pairing |
|---|---|---|
| + NDE | "In stock" = qty > 0 |
"In stock" = NDE eligibility rules (respects drop-ship + supplier mode) |
| + BED | Generic "Back in stock!" | "Back on Jun 12!" (uses BED's ETA) |
| + ISP | Global stock check | Optional per-store subscription |
Compatibility
- Magento Open Source 2.4.4 – 2.4.8
- Adobe Commerce 2.4.4 – 2.4.8
- PHP 8.1 / 8.2 / 8.3 / 8.4
- Hyvä Theme + Hyvä Checkout (PDP form renders via Hyvä-safe block)
| Version | Stability | QA Status | Compatibility | Released |
|---|---|---|---|---|
| 1.3.1 | stable | Fail | Magento 2.4.7-2.4.8 Details | 2026-06-22 15:12:46 |
| 1.3.0 | stable | Not tested | Not yet tested Details | 2026-06-20 14:46:31 |
| 1.2.0 | stable | Not tested | Not yet tested Details | 2026-06-06 13:56:18 |
| 1.1.0 | stable | Not tested | Not yet tested Details | 2026-06-01 10:51:24 |
| 1.0.3 | stable | Not tested | Not yet tested Details | 2026-05-22 06:41:35 |
| 1.0.2 | stable | Not tested | Not yet tested Details | 2026-05-20 18:49:33 |
| 1.0.1 | stable | Not tested | Not yet tested Details | 2026-05-20 18:24:33 |
| 1.0.0 | stable | Not tested | Not yet tested Details | 2026-05-20 17:13:02 |
Requires 11
| Package | Constraint |
|---|---|
| magento/framework | ^103.0||^104.0 |
| magento/module-backend | ^102.0||^103.0 |
| magento/module-catalog | ^104.0||^105.0 |
| magento/module-catalog-inventory | ^100.4||^101.0 |
| magento/module-config | ^101.2||^102.0 |
| magento/module-cron | ^100.4||^101.0 |
| magento/module-customer | ^103.0||^104.0 |
| magento/module-email | ^101.1||^102.0 |
| magento/module-store | ^101.1||^102.0 |
| magento/module-ui | ^101.2||^102.0 |
| php | ~8.1.0||~8.2.0||~8.3.0||~8.4.0 |
Suggests 3
| Package | Reason |
|---|---|
| etechflow/module-backorder-eta-display | Optional. When installed, restock-on-backorder notifications include BED's per-product ETA. |
| etechflow/module-in-store-pickup | Optional. When installed, customers can subscribe to a specific pickup-store's stock. |
| etechflow/module-next-day-eligibility | Optional. When installed, 'back in stock' uses NDE's eligibility rules engine. |
No QA results yet
QA pipelines haven't run for this version. Compatibility and quality results appear here once the vendor publishes a tagged release that gets ingested.
More from etechflow
View vendorDynamic 'View Other Options/Finishes/Sizes' PDP buttons driven by per-product link attributes; replaces hardcoded in-description buttons and strips the old ones at render time.
Theme-agnostic mega menu for Magento 2. Renders on Hyvä, Luma, Adobe Commerce default and custom themes via automatic runtime detection. Provides a JSON endpoint for lazy-loaded subcategory + featured-product data.
EtechFlow Store Locator — admin-managed store/branch finder for Magento 2 with a Leaflet + OpenStreetMap map and postcode proximity search (postcodes.io). Hyva and Luma compatible. No paid map API key required.
Universal Product Fitment Finder for Magento 2 — Make/Model/Year/Part filtering on any fitment domain (automotive, motorcycle, marine, RV, phone cases, watches, appliance parts, anywhere a customer asks "will this fit my X?"). Admin-configurable labels + URL prefix so the same module rebrands to any merchant domain. Includes PDP fitment badge, SEO URLs, customer garage with cross-device sync, OEM/part-number search, and admin tooltips throughout. Theme-agnostic — Hyvä, Luma, custom themes. Renamed from "module-vehicle-compat" in v2.0.0.
Turn an existing module into recurring revenue.
If you already maintain a Magento 2 module on GitHub or GitLab, listing it on Packagento takes about five minutes. We mirror your tags, handle distribution signing, and route paid licenses through Stripe Connect, so you can keep shipping the way you already do.