# etechflow/module-abandoned-cart

> Abandoned Cart Email + Exit-Intent Popup extension for Magento 2 — recovers lost sales via automated email reminders and on-site discount popups. Fully compatible with Luma, Hyva, and Adobe Commerce.

`composer require etechflow/module-abandoned-cart`

Canonical URL: https://packagento.com/etechflow/module-abandoned-cart

## At a glance

- **Vendor**: etechflow (https://packagento.com/etechflow.md)
- **Latest version**: 1.0.4 — released 2026-06-22
- **Pricing**: Free
- **Package type**: Magento 2 module
- **Status**: active, accepting new buyers

## Installation

Packagento is licence-gated, so even free packages need a licence on a project before Composer can resolve them.

1. **Sign in or create an account** at https://packagento.com/customer/account/.

2. **Add the package to your account.** Open https://packagento.com/etechflow/module-abandoned-cart and complete the free checkout. A licence is minted automatically.

3. **Create or pick a project, then activate the licence on it.**
   - Projects represent the Magento installs you deploy to. Manage them at https://packagento.com/projects/.
   - Activate the new licence on the project you'll deploy this package to. Activation is what generates the Composer credentials scoped to that project.

4. **Add the project credentials to your Magento codebase.**

   Grab the project's public + private key from https://packagento.com/projects/ (open the project, then its Credentials tab), and add them to `auth.json`:

   ```json
   {
     "http-basic": {
       "packagento.com": {
         "username": "ppk_live_...",
         "password": "psk_live_..."
       }
     }
   }
   ```

   Add the Packagento Composer repository to `composer.json`:

   ```json
   {
     "repositories": [
       { "type": "composer", "url": "https://packagento.com" }
     ]
   }
   ```

5. **Install and apply.**

   ```bash
   composer require etechflow/module-abandoned-cart:*
   bin/magento setup:upgrade
   bin/magento setup:di:compile
   bin/magento cache:flush
   ```

## What it does

Abandoned Cart Email + Exit-Intent Popup extension for Magento 2 — recovers lost sales via automated email reminders and on-site discount popups. Fully compatible with Luma, Hyva, and Adobe Commerce.

## README

Recover lost sales with automated, personalised abandoned-cart email reminders. Fully compatible with Luma, Hyvä, and Adobe Commerce.

---

### Features

- **Configurable email sequences** — send up to 9 reminders per cart at custom intervals (e.g., 1 hour, 24 hours, 72 hours)
- **One-click cart restore** — customers click the link in the email and their cart is back exactly as they left it, optionally with auto-login
- **Auto-generated discount coupons** — incentivise recovery with unique single-use coupon codes per email
- **Open & click tracking** — measure exactly which emails are working and which carts they recovered
- **Rich targeting** — per-store, per-customer-group, by cart subtotal range, by item count, by Magento price-rule conditions
- **Guest cart support** — track and email visitors who reached checkout but never logged in
- **Test mode** — preview emails by redirecting to a dev inbox before going live
- **Unsubscribe link** — built into every email, with confirmation page
- **Recovery dashboard** — total abandoned, total recovered, recovery rate, revenue recovered, by date range
- **Per-rule analytics** — at-a-glance recovery rate per rule in the rules grid

---

### Compatibility

| | Open Source 2.4.6 | Open Source 2.4.7 | Adobe Commerce 2.4.6 | Adobe Commerce 2.4.7 |
|---|---|---|---|---|
| Luma theme | ✅ | ✅ | ✅ | ✅ |
| Hyvä theme 1.3+ | ✅ | ✅ | ✅ | ✅ |
| PHP | 8.1 / 8.2 | 8.2 / 8.3 | 8.1 / 8.2 | 8.2 / 8.3 |

---

### Installation

#### Via Composer (recommended)

```bash
composer require etechflow/module-abandoned-cart
bin/magento module:enable Etechflow_AbandonedCart
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush
```

#### Manual (upload zip)

1. Upload the `ETechFlow/AbandonedCart` folder to `app/code/ETechFlow/AbandonedCart/` on your server
2. SSH in and run:

```bash
cd /path/to/magento
bin/magento module:enable Etechflow_AbandonedCart
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush
```

#### Verify the install

```bash
bin/magento module:status Etechflow_AbandonedCart
## Expected: Module is enabled
bin/magento etechflow:abc:verify
## Expected: ALL CHECKS PASSED
```

#### Cron must be running

The module's emails are sent by Magento cron. If you haven't already set up Linux cron:

```bash
bin/magento cron:install
crontab -l   # verify it was added
```

---

### Configuration

Go to **Stores → Configuration → ETechFlow → Abandoned Cart Email**.

Key settings to review on first install:

- **General → Enable Module**: Yes
- **General → Cart Abandonment Threshold**: 30 minutes (default — adjust to your store's checkout flow)
- **License → License Key**: Paste the key from your purchase email (development hosts skip this)
- **Email Sending → Sender Identity**: Pick which "Store Email Address" sends the recovery emails
- **Cart Restore → Restore Token Expiry**: 30 days default

Then create your first rule under **Marketing → ETechFlow Abandoned Cart → Email Rules → Add New Rule**.

A typical sequence:
1. Rule 1: send 1 hour after abandonment, friendly reminder, no coupon
2. Rule 2: send 24 hours later, includes 5% coupon
3. Rule 3: send 72 hours later, "last chance" with 10% coupon

---

### CLI commands

| Command | Purpose |
|---|---|
| `bin/magento etechflow:abc:verify` | End-to-end smoke test. Run after install and after upgrade. |
| `bin/magento etechflow:abc:perf` | Micro-benchmark of hot paths. Add `--iterations=N` and `--json=path`. |
| `bin/magento etechflow:abc:send` | Force a cron tick now (don't wait for the schedule). |
| `bin/magento etechflow:abc:cleanup` | Force the cleanup cron now. |

---

### Performance

This module is built for high-traffic stores. Performance characteristics on warm cache:

| Hot path | p95 target |
|---|---|
| Frontend cart-save observer | < 0.5 ms |
| Per-cron-tick batch (50 carts) | < 1.5 s |
| 1-click restore controller | < 50 ms |
| Tracking pixel | < 20 ms |

Storefront pages take ZERO additional work from this module — all heavy lifting happens in cron.

---

### Hyvä theme

Hyvä compatibility ships in the same package. The module detects the active theme automatically and:

- Sends Hyvä-styled email templates (Tailwind classes) on Hyvä storefronts
- Sends Luma-styled templates on Luma storefronts
- Restore + Unsubscribe pages render with both Block (Luma) and ViewModel (Hyvä) paths — no Knockout on Hyvä

---

### Adobe Commerce

The module works fully on Adobe Commerce 2.4.6 / 2.4.7 and adds:

- Future v1.1.0: B2B company-account abandoned-cart support
- Future v1.1.0: Customer Segments integration
- Future v1.1.0: GraphQL endpoints for headless

v1.0.0 already handles multi-website / multi-store and AC's customer-group targeting.

---

### Uninstall

```bash
bin/magento module:disable Etechflow_AbandonedCart
composer remove etechflow/module-abandoned-cart
bin/magento setup:upgrade
```

Database tables (`etechflow_abandoned_cart`, `etechflow_abandoned_cart_rule`, `etechflow_abandoned_cart_email_log`) are dropped by the schema patch on uninstall.

---

### Support

- Email: etechflow0@gmail.com
- Website: https://etechflow.com
- Bug reports: include the output of `bin/magento etechflow:abc:verify`

---

### License

Proprietary. See `LICENSE.txt` for terms. A per-installation license is required for production use.

## Changelog

All notable changes to Etechflow_AbandonedCart are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) per ETechFlow Module Development Standards §3.

---

### v1.0.1 — 2026-06-05

Security + bundle-consistency fix.

- Rotated per-module SECRET_FRAGMENTS (closes accidental plaintext-secret exposure in v1.0.0)
- Replaced plain BUNDLE_SECRET constant with BUNDLE_SECRET_FRAGMENTS array (aligned with other ETechFlow modules)
- BUNDLE_ID changed from 'ETECHFLOW_MAGENTO_BUNDLE_V1' to 'etechflow-bundle' (matches the rest of the suite — bundle keys interoperate)
- MODULE_ID changed from 'abandoned-cart-popup' to 'abandoned-cart' (matches composer package name)
- Dropped backward-compat for legacy v1.0–v1.2 'host|hmac' key format (no merchants on those versions)

⚠️ v1.0.0 keys (per-module or bundle) no longer validate. Re-issue keys via tools/generate-license.php.

### [Unreleased]

_Nothing pending — see v1.0.0 below for the initial release._

### [1.0.0] — 2026-05-21

_Released after the 22-phase build + bulk re-deploy + end-to-end verification on the magento-dev.etechflow.com Docker stack._

#### Initial release — production-ready abandoned-cart recovery for Luma, Hyvä, and Adobe Commerce

Etechflow_AbandonedCart ships with a complete cart-recovery email system that detects abandoned carts via cron (no per-request scanning), sends configurable email sequences with 1-click restore links and optional auto-generated discount coupons, and attributes recovered revenue back to the originating emails for reporting. Built to match Amasty's feature surface with five concrete UX improvements (plain-English tooltips, inline rule preview, specific CSV-error messages, per-rule recovery rate in the rules grid, multi-recipient test mode).

##### Added
- **Cart abandonment tracking** — `CartSaveObserver` records every cart save into `etechflow_abandoned_cart`, with all four mandatory observer guards (enabled / bulk-importer / indexer-processing / relevant-change).
- **Configurable email sequences** — up to 9 rules per cart, ordered by priority, with per-rule store / customer-group / cart-subtotal / Magento-price-rule conditions.
- **One-click cart restore** — `Controller/Restore/Index` with HMAC-signed single-use tokens, configurable token expiry, optional auto-login for logged-in customers, optional merge with the customer's current cart.
- **Auto-generated discount coupons** — `Model/CouponGenerator` issues per-email single-use coupon codes tied to a Magento sales rule the merchant chooses.
- **Email open & click tracking** — 1×1 pixel + URL wrapping via `Controller/Track/Open` and `Controller/Track/Click`. UTM parameters auto-appended (configurable).
- **Unsubscribe flow** — every email carries an unsubscribe link; the confirmation page is Luma + Hyvä compatible.
- **Recovery attribution** — `OrderPlaceAfterObserver` + `Quote\SubmitPlugin` mark carts as RECOVERED and link them back to the email that drove the conversion.
- **Test Mode** — redirect all outbound emails to a comma-separated list of dev inboxes for safe pre-launch testing.
- **Hyvä compatibility** — `view/frontend/templates/hyva/` + `ViewModel/` + `hyva_default.xml` deliver Alpine-powered restore + unsubscribe pages with no Knockout dependencies.
- **Admin Rules grid + form** — full CRUD UI Component at Marketing → ETechFlow Abandoned Cart → Email Rules, with inline per-rule recovery rate.
- **Admin Carts grid + view** — list every tracked cart with filters by status / customer / store / date, plus per-cart "Send Now" manual trigger.
- **Admin Reports dashboard** — total abandoned, total recovered, recovery rate, open rate, click rate, revenue recovered, by date range.
- **CLI commands** — `etechflow:abc:verify` (end-to-end smoke), `etechflow:abc:perf` (micro-benchmark with `--iterations` and `--json`), `etechf

_(Changelog truncated for .md surface. Full history on https://packagento.com/etechflow/module-abandoned-cart.)_

## Recent Versions

| Version | Released |
|---|---|
| 1.0.4 | 2026-06-22 |
| 1.0.1 | 2026-06-05 |

## Dependencies

### Require

| Package | Constraint |
|---|---|
| magento/framework | >=103.0.0 |
| magento/module-backend | >=102.0.0 |
| magento/module-checkout | >=100.0.0 |
| magento/module-config | >=101.0.0 |
| magento/module-cron | >=100.0.0 |
| magento/module-customer | >=103.0.0 |
| magento/module-email | >=101.0.0 |
| magento/module-quote | >=101.0.0 |
| magento/module-sales | >=103.0.0 |
| magento/module-sales-rule | >=101.0.0 |
| magento/module-store | >=101.0.0 |
| magento/module-ui | >=101.0.0 |
| php | ~8.1.0\|\|~8.2.0\|\|~8.3.0\|\|~8.4.0 |

### Suggest

| Package | Constraint |
|---|---|
| magento/module-company | Required only on Adobe Commerce B2B for company-level abandoned-cart tracking |
| magento/module-graph-ql | Required only when exposing abandoned-cart data to headless / PWA storefronts |

## Quality

Latest release (1.0.4) fails the Packagento QA pipeline. Verdicts below are per-cell (Magento line × PHP version) for the matrixed tools, and run-once for the static / security tiers.


### Compatibility

Each Magento line is installed on its supported PHP versions, then the module is built (DI compile + static-content deploy). Cells show passed / failed / untested; staircase gaps render as `–`.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | Pass | Pass | – | – |
| 2.4.8 | – | Pass | Pass | – |
| 2.4.9 | – | – | Pass | not tested |


### Code Quality

Advisory checks against the module's source. Never affect the Compatibility verdict — a phpcs finding can't make a module incompatible.

#### Static Analysis

Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| PHPCS | Fail | 378 | 32 errors, 346 warnings (ruleset: Magento2) — 146 auto-fixable with phpcbf |
| PHPMD | Error | 0 | phpmd reported an analysis error: Unexpected token: [, line: 82, col: 19, file: tools/generate-license.php. #0 /opt/composer-global/vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/AbstractPHPParser.php(8056): PDepend\Source\Parser\UnexpectedTokenException->__construct(Object(PDepend\Source\Tokenizer\Token), Object(PDepend\Source\AST\ASTCompilationUnit)) #1 /opt/composer-global/vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/AbstractPHPParser.php(8041): PDepend\Source\Language\PHP\AbstractPHPParser->getUnexpectedTokenException(Object(PDepend\Source\Tokenizer\Token)) #2 /opt/composer-global/vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/AbstractPHPParser.php(8006): PDepend\Source\Language\PHP\AbstractPHPParser->getUnexpectedNextTokenException() #3 /opt/composer-global/vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/AbstractPHPParser.php(2495): PDepend\Source\Language\PHP\AbstractPHPParser->consumeToken(7) #4 /opt/composer-global/vendor/pdepend/pde |
| Cpd | Warning | 6 | 6 duplicated chunks spanning 233 total lines (min-lines=5, min-tokens=70) |
| Composer validate | Info | 13 | valid; 13 advisory notes (composer validate --strict) |

#### PHPStan

Type-checks the module against a real Magento install. Re-runs per Magento + PHP version because resolvable symbols differ between releases.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | 88 | 88 | – | – |
| 2.4.8 | – | 88 | 88 | – |
| 2.4.9 | – | – | 88 | N/A |


### Tests

Unit and integration suites run per Magento + PHP cell. Test failures speak to the module's behaviour, not its compatibility with a line, so they're reported here separately.

#### Unit Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |

#### Integration Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |


### Security

Dependency-advisory audit (composer audit) plus a source malware scan. A malware detection fails the version outright.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| Composer audit | Pass | 0 |  |
| Malware scan | Pass | 0 |  |

## Licence and pricing

Free. A licence is still minted on checkout and bound to your project for Composer access — no payment step.

Refundable within 14 days of first purchase via https://packagento.com/account/refunds/.

## Install via Claude Code or any MCP client

The Packagento MCP server can run the licence + project + Composer steps above in one tool call:

```
purchase_and_install_packages(
  composer_names=["etechflow/module-abandoned-cart"],
  project_id="proj_xxx"
)
```

This handles cart, checkout, licence minting, project activation, and writes auth.json credentials. Connect a client with `claude mcp add packagento https://mcp.packagento.com`. Full setup at https://packagento.com/docs/mcp-setup.

## Vendor

etechflow is a Magento 2 vendor on Packagento. See https://packagento.com/etechflow.md for their full catalogue.

