Recover abandoned WooCommerce carts with secure links, optional emails, configurable tracking, and accurate revenue attribution.
Cart Rebound is a free, open-source WooCommerce abandoned cart recovery plugin for WordPress. It records logged-in carts and, when enabled, guest carts; flips inactive carts to abandoned after a configurable idle window; lets shoppers restore their cart through an unguessable tokenized recovery link; and attributes recovered revenue to the real order. Guest tracking and automatic recovery emails are disabled by default. A clean do_action event surface and REST API let automation tools react to abandonment and recovery without coupling to plugin internals.
📖 Full usage & developer guide → docs/USAGE.md — step-by-step installation, every setting, how tracking & recovery work end to end, the admin dashboard, and the events + REST API reference.
- Reliable cart capture — logged-in carts plus opt-in guest carts, including the email a guest types at checkout before submitting. Works on both classic checkout (AJAX beacon + server-side hooks) and block / Store API checkout.
- Configurable abandonment detection — driven by Action Scheduler (WooCommerce's bundled, self-healing scheduler) with a wp-cron fallback. The idle threshold lives in the query, so changing it takes effect on the next scan.
- Tokenized recovery links — rebuild the cart (items, variations, and coupons) and send the shopper straight to checkout. No raw session key in the URL.
- Accurate revenue attribution — orders are linked to carts by explicit order meta, never fuzzy total matching, so coupons, shipping, and tax never break the link. Carts resolve to recovered or completed only on real payment, with separate timestamps and a dedicated recovered-amount field.
- Optional built-in recovery email — disabled by default and scheduled a configurable delay after abandonment, with merge tags for the shopper, the cart contents and value, the recovery and checkout links, the coupon, and your store details.
- Developer event & REST API —
cart_rebound_abandoned/cart_rebound_recoveredactions, and a read API for carts, stats, and recovered revenue. - Admin dashboard — active / abandoned / recovered counts, recovered revenue, recovery rate, and a filterable list of cart sessions with row actions.
- HPOS-compatible — built for WooCommerce High-Performance Order Storage.
- WordPress 6.2+
- WooCommerce (active)
- PHP 7.4+
- Install and activate WooCommerce.
- Download the latest
cart-rebound.zipfrom Releases (or build it — see below). - In WordPress: Plugins → Add New → Upload Plugin, choose the zip, install, activate.
- Visit Cart Rebound in the admin sidebar to configure tracking, retention, abandonment detection, and optional recovery emails.
add_to_cart / cart_updated / checkout-email ──▶ active
│ idle > threshold (scan)
▼
completed ◀── order paid (was active) abandoned ──▶ lost ──▶ purged
▲ │ (cleanup window, no order)
└────────── order paid & linked to ──────────┘
this cart ⇒ recovered (revenue attributed)
Status only transitions to completed / recovered when the order is actually paid, so a pending or never-paid order never prematurely removes a cart from recovery.
React to recovery events from your own plugin or an automation tool:
add_action( 'cart_rebound_abandoned', function ( array $payload ) {
// $payload: cart_id, customer_email, first_name, cart_total, currency,
// products[], recovery_url, last_activity, …
} );
add_action( 'cart_rebound_recovered', function ( array $payload ) {
// adds: order_id, recovered_amount, recovered_at, recovery_method
} );REST (namespace cart-rebound/v1, capability manage_woocommerce, nonce-protected): GET carts, GET carts/{id}, GET stats, GET/POST settings, POST carts/{id}/mark-recovered, DELETE carts/{id}.
Built on a Laravel-style, container-driven OOP framework (service providers, REST routing with middleware, form requests, a query builder, dbDelta migrations) with a React + TypeScript + Vite admin.
- A local WordPress 6.2+ installation with WP-CLI available
- PHP 7.4+ and Composer (
phpdbgis needed only for coverage) - Node.js 24+ and pnpm 11.5.0
- This repository installed or linked at
wp-content/plugins/cart-rebound
The complete, human-readable source is maintained in this public repository. Production archives contain compiled assets; their uncompressed TypeScript, React, and CSS sources are under resources/.
After cloning the repository into wp-content/plugins/cart-rebound, run the
complete development setup:
composer setupThis invokes scripts/setup-development.sh.
The script may also be run directly with
bash scripts/setup-development.sh.
The command:
- Installs the PHP and locked pnpm dependencies.
- Builds the admin assets.
- Enables WordPress debug logging, sets the environment to
local, and opts Cart Rebound into HMR. - Installs WooCommerce when missing and activates it.
- Activates Cart Rebound and runs its database migrations.
It assumes the standard plugin path shown above, so the WordPress root resolves
to ../../... After setup, run pnpm dev whenever you want the long-running
Vite HMR server.
The dependency and build steps can also be run individually:
composer install
pnpm install --frozen-lockfile
pnpm build
composer qa # phpcs (WP-Extra), PHPStan L8, PHP 7.4 compat, Rector, PHPUnit
composer test:coverage # PHPUnit HTML report → coverage/
pnpm qa # tsc strict, prettier, eslint, stylelint
pnpm dev # live Vite source assets + HMR on the plugin admin pages
bash scripts/build-zip.sh # build assets/POT → build/cart-rebound.zipDependency cleanup and fresh installation are kept separate for each package manager:
pnpm run clean # remove node_modules and the project-local pnpm store
pnpm install # install from pnpm-lock.yaml
pnpm run fresh-install # clean pnpm dependencies, then install them
composer clean # remove vendor and composer.lock
composer install # install from composer.lock
composer fresh-install # clean, resolve dependencies, and generate a new lockfileHMR means Hot Module Replacement: while pnpm dev is running, React,
TypeScript, and CSS changes appear on Cart Rebound admin pages without a full
page reload whenever Vite can replace the changed module.
HMR is deliberately opt-in. Add the following to the local WordPress
wp-config.php before it loads wp-settings.php. If WP_DEBUG is already
defined, update the existing declaration instead of defining it twice.
define( 'WP_DEBUG', true );
define( 'WP_ENVIRONMENT_TYPE', 'local' );
define( 'CART_REBOUND_ENABLE_HMR', true );WP_ENVIRONMENT_TYPE may also be set to development. Then start Vite from
the plugin root and keep that process running:
pnpm devVite listens on the fixed origin http://localhost:5173, writes its origin to
public/hot, and WordPress loads @vite/client plus
resources/js/admin/main.tsx from that server. Because the development origin
uses HTTP, access the local WordPress site over HTTP as well; an HTTPS admin
page will block the scripts as mixed content.
A normal Vite shutdown removes public/hot. If Vite was terminated abruptly
and the admin app tries to load from an unavailable development server, restart
pnpm dev or run pnpm build to remove the stale marker and regenerate the
compiled assets.
Leave CART_REBOUND_ENABLE_HMR undefined or set it to false, then compile the
admin app whenever its source changes:
pnpm buildWordPress will load the hashed assets in public/build. Production
environments always use compiled assets and ignore public/hot.
The archive command also requires WP-CLI with wp i18n make-pot available. pnpm production-zip runs the full PHP and JavaScript quality gates and writes the submission archive to build/cart-rebound.zip.
The release workflow runs the complete QA suite and WordPress Plugin Check,
builds the production-only plugin directory, deploys it to the cart-rebound
WordPress.org SVN repository, copies .wordpress-org artwork to the SVN assets
directory, and publishes the same zip on GitHub. Build, SVN deployment, and
GitHub publishing run as separate jobs so build tooling never receives SVN
credentials or a write-capable GitHub token, and the GitHub release can be
retried without repeating a successful SVN deployment.
Add these encrypted repository secrets under Settings → Secrets and variables → Actions before the first release:
SVN_USERNAME— the case-sensitive WordPress.org username.SVN_PASSWORD— the SVN-specific password generated in the WordPress.org Account & Security settings. Do not use the normal account password.
For an optional approval gate, create a GitHub environment named
wordpress-org and configure required reviewers for it. The production job is
already assigned to that environment.
Before using production credentials, run WordPress.org Deployment Dry Run from the repository's Actions page. It accepts a branch, tag, or commit, uses a read-only GitHub token, receives no SVN credentials, simulates the SVN changes, and uploads the resulting zip as a seven-day workflow artifact.
The WordPress Playground definition is maintained at
.wordpress-org/blueprints/blueprint.json. Deployment places it at
assets/blueprints/blueprint.json in SVN, where WordPress.org uses it to
install WooCommerce and open Cart Rebound's dashboard. After the first deploy,
test the preview and enable public previews from the plugin's Advanced View.
For each release:
- Run
composer bump-version X.Y.Z. This synchronizespackage.json,composer.json, the plugin header,CART_REBOUND_VERSION, and thereadme.txtStable tag, then refreshescomposer.lock. Add the matching= X.Y.Z =changelog entry inreadme.txt; the command deliberately does not invent release notes. Preview the changes withcomposer bump-version -- X.Y.Z --dry-run. - Run
bash scripts/check-release-version.sh X.Y.Zandpnpm production-zip. - Commit and push the release to
main. On GitHub, create a release with aX.Y.Ztag targeting that exact commit, then publish the release. A leadingvis also accepted, but the unprefixed tag matches the WordPress.org SVN version directly.
The production build regenerates the POT metadata from the plugin header, so the translation template does not need manual version maintenance.
Publishing a stable GitHub release starts .github/workflows/release.yml.
Drafts and prereleases do not deploy. Deployment stops before SVN is changed if
the release tag commit is not contained in main history, versions disagree,
QA fails, or the production build fails. This allows main to advance after a
release tag is created without allowing releases from unmerged branches.
Reusable actions are pinned to full commit hashes so their executed code cannot
change when a moving tag changes.
Guest tracking and automatic recovery emails are disabled by default. The plugin stores tracked cart and checkout identity data locally in the WordPress database and uses a first-party, HTTP-only cart_rebound_ref cookie for approximately 30 days. It does not send telemetry or tracked-cart data to the plugin author.
The default retention windows are 30 days for stale active/unrecovered carts and 365 days for recovered/completed carts; both are configurable. Cart Rebound registers WordPress personal-data exporters and erasers for matching cart and activity-log data. Recovery emails use the site's configured WordPress mail transport. See readme.txt for the full disclosure.
GPL-2.0-or-later. Bundled JavaScript library notices are in THIRD-PARTY-LICENSES.txt. Contributions welcome.