Title: Oli Abandoned Cart Recovery
Author: Olivier Bigras
Published: <strong>October 2, 2026</strong>
Last modified: October 2, 2026

---

Search plugins

![](https://ps.w.org/oli-abandoned-cart-recovery/assets/banner-772x250.png?rev=3725611)

![](https://ps.w.org/oli-abandoned-cart-recovery/assets/icon.svg?rev=3725611)

# Oli Abandoned Cart Recovery

 By [Olivier Bigras](https://profiles.wordpress.org/bigrat95/)

[Download](https://downloads.wordpress.org/plugin/oli-abandoned-cart-recovery.1.1.1.zip)

 * [Details](https://wordpress.org/plugins/oli-abandoned-cart-recovery/#description)
 * [Reviews](https://wordpress.org/plugins/oli-abandoned-cart-recovery/#reviews)
 *  [Installation](https://wordpress.org/plugins/oli-abandoned-cart-recovery/#installation)
 * [Development](https://wordpress.org/plugins/oli-abandoned-cart-recovery/#developers)

 [Support](https://wordpress.org/support/plugin/oli-abandoned-cart-recovery/)

## Description

**Oli Abandoned Cart Recovery** asks for the customer’s consent on the checkout 
page and, once the consent box is ticked, saves the email and the cart — even for
guests who never place an order — and sends a sequence of reminder emails when the
cart is abandoned. Consent is on by default for guests and logged-in customers (
Quebec Law 25, GDPR). Every email has a secure recovery link that refills the cart,
pre-fills the email and sends the customer straight to checkout. Reminders stop 
automatically as soon as an order is placed.

It works with the **classic checkout** and the **block checkout**, is compatible
with **HPOS** (High-Performance Order Storage), and does all the heavy work in the
background with **Action Scheduler** (WP-Cron fallback). Nothing runs on the front
end except one tiny script on the checkout page.

#### Capture

 * **Email captured on the fly, with consent** — once the consent box is ticked,
   the email is sent on blur/change with a debounce, a nonce and server-side `is_email`
   validation
 * **Classic and block checkout** — one delegated listener works with both, through
   the lightweight `wc-ajax` endpoint
 * **Phone, first and last name** captured with the email
 * **Guests and registered customers** — logged-in carts are updated every time 
   the cart changes, once the customer has consented
 * **Consent first (default)** — with the **Require consent** switch on (default),
   nothing is saved for guests or logged-in customers (no email, phone or cart) 
   until they tick the consent checkbox under the email field (classic and block
   checkout). A logged-in customer’s consent is remembered in their account and 
   can be withdrawn by unticking the box. The switch can be turned off by the site
   owner, under their own responsibility: a permanent warning (Law 25, GDPR) is 
   then shown in the admin
 * **Consent text with links** — edited per language with a small editor (links,
   bold, italic, saved with `wp_kses`), for example to link your privacy policy.
   Left empty, the default text is translated in each visitor’s language
 * **Abuse protection** — rate limits on the capture endpoint (per IP and per session,`
   oli_acr_capture_rate_limits` filter) and a honeypot field
 * **Cache-proof** — checkout pages send no-cache headers and `DONOTCACHEPAGE`; 
   an expired nonce from a cached page is refreshed automatically
 * **Tracked roles** — all users or only the roles you choose
 * **Cart snapshot** — products, quantities, variations, total, currency and language,
   linked to the WooCommerce session and a secure token

#### Multilingual

 * **Templates per language** — each template has its own texts (name, subject, 
   heading, content, button) for every active language, edited in language tabs;
   delay, coupon and status are shared
 * **Consent text per language**
 * **Works with** TranslatePress, Polylang (with _Polylang for WooCommerce_, or 
   the short snippet in the FAQ), WPML and Weglot (and a single-language site); 
   other plugins can be added with the `oli_acr_lang_adapters` filter
 * **Sent in the cart’s language** — the language of the checkout page is saved 
   with the cart; recovery and unsubscribe links point to the URL of that language,
   and the recovery link opens the checkout page of that language
 * **Adjustable fallback language** for carts in an unknown or deactivated language
 * **WPML String Translation and Polylang strings** — texts of the fallback language
   are registered, so they can also be translated there

#### Reminders

 * **Sent in the customer’s language** — each reminder is sent in the language saved
   with the cart (`switch_to_locale`). Default templates stay translatable until
   you edit them
 * **Several email templates**, each with its own delay, subject, heading, reply-
   to address, content, recovery button label and active/inactive status
 * **Sent in sequence** — reminder #1, then #2, and so on, counted from the moment
   the cart was abandoned
 * **Placeholders** — `{first_name}`, `{last_name}`, `{full_name}`, `{email}`, `{
   cart_items}`, `{cart_total}`, `{recovery_link}`, `{recovery_button}`, `{coupon}`,`{
   coupon_code}`, `{unsubscribe_link}`, `{site_name}`, `{site_url}`, `{order_number}`,`{
   order_date}`
 * **WooCommerce email look** — messages are wrapped in the WooCommerce email template(
   colors, header, footer), with a plain-text part (multipart/alternative)
 * **Retries after a failed send** — a failed reminder gets the _Send failed_ status
   and is retried after 5 minutes, 30 minutes and 2 hours (`oli_acr_retry_delays`
   filter); the cause is shown in the admin and logged in WooCommerce > Status >
   Logs, even without `WP_DEBUG`
 * **Unique coupons** — optional single-use coupon per reminder (prefix, percentage
   or fixed amount, validity), restricted to the customer’s email and applied automatically
   when the recovery link is clicked; created only when the email shows it (`{coupon}`
   or `{coupon_code}`)
 * **Coupon clean-up** — used and expired generated coupons are moved to the trash
   daily
 * **Pending orders** — reminders for unpaid orders with their own delay and templates,
   with a secure “pay for order” link
 * **Send a test** — send any template to the address of your choice
 * **Send now** — send the next reminder of a cart or pending order manually
 * **Admin notification** — a WooCommerce email is sent to the admin when a cart
   or pending order is recovered

#### Stop, unsubscribe and privacy

 * **Automatic stop** — as soon as an order is placed with the same session or email,
   the cart is marked _Recovered_ and linked to the order
 * **Unsubscribe link** in every email (with `List-Unsubscribe` and `List-Unsubscribe-
   Post` one-click headers, RFC 8058) and an **exclusion list** you can edit
 * **No email ever sent** to unsubscribed addresses
 * **Personal data exporter and eraser** for the WordPress privacy tools
 * **Suggested privacy policy text**
 * **Automatic clean-up** — old unrecovered carts are deleted, old reminded pending
   orders can be cancelled, and all data is kept only for the retention period you
   choose

#### Dashboard and reports

 * **Abandoned carts** list (WP_List_Table) with status filters, search, bulk delete
   and row actions
 * **Pending orders**, **Recovered** orders and **Email log** (sent, clicked, recovered,
   coupon)
 * **Reports** — abandoned carts, emails sent, clicks, recovered carts and pending
   orders, recovery rate and recovered revenue, by period (7, 30, 90 days, 12 months,
   all time), by day and by template
 * **Shop manager access** — optional, through the dedicated `oli_acr_manage` capability

#### Lightweight by design

 * Two custom tables with indexes, created with `dbDelta` and a schema version
 * One indexed `UPDATE` marks carts as abandoned; reminders are processed in batches(`
   oli_acr_batch_size` filter), under an atomic lock with a time budget so two runs
   never send the same reminder
 * No work on the front end besides the checkout script (about 3 KB, no jQuery);
   settings are autoloaded, so no extra query on other pages
 * Works with HPOS and with the legacy order storage
 * No external service, no tracking pixel

### Privacy

The plugin stores, in the store’s own database: the email, phone, first and last
name typed on the checkout page, the cart content, and the reminder email history.
No data is sent to a third party. A suggested text is added to **Settings > Privacy**,
and the data can be exported or erased with the WordPress privacy tools.

## Screenshots

[⌊Dashboard: recovery stats (abandoned carts, emails sent, clicks, recovery rate,
recovered revenue), report by day and report by template⌉⌊Dashboard: recovery stats(
abandoned carts, emails sent, clicks, recovery rate, recovered revenue), report 
by day and report by template⌉[

Dashboard: recovery stats (abandoned carts, emails sent, clicks, recovery rate, 
recovered revenue), report by day and report by template

[⌊Abandoned carts list with status filters (active, abandoned, reminded, recovered,
unsubscribed, send failed), including the error of a failed send⌉⌊Abandoned carts
list with status filters (active, abandoned, reminded, recovered, unsubscribed, 
send failed), including the error of a failed send⌉[

Abandoned carts list with status filters (active, abandoned, reminded, recovered,
unsubscribed, send failed), including the error of a failed send

[⌊Email template editor: language tabs, placeholders, unique coupon and "Send a 
test"⌉⌊Email template editor: language tabs, placeholders, unique coupon and "Send
a test"⌉[

Email template editor: language tabs, placeholders, unique coupon and “Send a test”

[⌊Settings: the "Require consent" switch turned off, with the Quebec Law 25 / GDPR
warning (consent is on by default)⌉⌊Settings: the "Require consent" switch turned
off, with the Quebec Law 25 / GDPR warning (consent is on by default)⌉[

Settings: the “Require consent” switch turned off, with the Quebec Law 25 / GDPR
warning (consent is on by default)

[⌊Cart reminder email received by the customer, with the cart items and the recovery
button⌉⌊Cart reminder email received by the customer, with the cart items and the
recovery button⌉[

Cart reminder email received by the customer, with the cart items and the recovery
button

## Installation

 1. Upload the `oli-abandoned-cart-recovery` folder to `/wp-content/plugins/`, or install
    the zip from **Plugins > Add New > Upload Plugin**
 2. Activate the plugin through the **Plugins** menu in WordPress (WooCommerce must
    be active)
 3. Go to **WooCommerce > Abandoned Carts > Settings** and choose the abandonment delay
 4. Go to the **Email templates** tab, review the templates and activate the ones you
    want
 5. Click **Send a test** to check the email

## FAQ

### Is it compatible with multilingual plugins?

Yes: TranslatePress, Polylang, WPML and Weglot are detected automatically (in that
order of priority: WPML, Polylang, TranslatePress, Weglot, then WordPress itself).
The language of the checkout page is saved with the cart, the reminder is sent in
that language, and its links open the store in that language. Under Abandoned Carts
> Email templates, each template has one tab per active language. Polylang needs
_Polylang for WooCommerce_ or a short snippet: see “Polylang: what do I need?” below.

### Polylang: what do I need?

Free Polylang alone translates the pages, but WooCommerce does not recognize the
translated cart and checkout pages: on those pages the capture script is not loaded
and **no cart is saved** in the other languages. Install **Polylang for WooCommerce**,
or link the translated pages to WooCommerce with this snippet (in a small plugin
or your theme’s `functions.php`):

    ```
    add_filter( 'woocommerce_get_checkout_page_id', function ( $id ) { return function_exists( 'pll_get_post' ) && pll_get_post( $id ) ? pll_get_post( $id ) : $id; } );
    add_filter( 'woocommerce_get_cart_page_id', function ( $id ) { return function_exists( 'pll_get_post' ) && pll_get_post( $id ) ? pll_get_post( $id ) : $id; } );
    ```

Until one of them is in place, the plugin shows a dismissible notice on its own 
screens.

### Which text is used for a language?

For each field, in this order: the text written in that language’s tab; the WPML
String Translation or Polylang string translation of the fallback language text;
the default text translated in that language (if the fallback text is still the 
default one); then the fallback language text. The same order applies to the consent
text.

### What is the fallback language?

The language used when a cart’s language is unknown or no longer active, and for
texts missing in a language. By default it is the site’s default language (or the
multilingual plugin’s default language); you can change it in Settings.

### How do I add another multilingual plugin?

Extend the `OLI_ACR_Lang_Adapter` class (languages, current language, URL conversion,
optional string translation) and add an instance with the `oli_acr_lang_adapters`
filter.

### Does it capture guests who never place an order?

Yes, once they consent. With the default settings, the email and the cart are saved
only after the guest ticks the consent box on the checkout page; the email is then
sent on blur or change, with the cart content. No account or order is needed. If
you turn consent off (your responsibility), the email is saved as soon as it is 
typed.

### Does it work with the block checkout?

Yes. The same script listens to the email field of the classic checkout and of the
block checkout.

### When is a cart considered abandoned?

When it has had no activity for the delay set in Settings (60 minutes by default).
Each template is then sent after its own delay, counted from that moment.

### What happens when the customer comes back?

The recovery link refills the cart, pre-fills the email, applies the coupon of the
email (if any) and redirects to the checkout. As soon as the order is placed, the
cart is marked _Recovered_ and no other reminder is sent.

### Is it compatible with HPOS?

Yes. Orders are only accessed through the WooCommerce CRUD API and compatibility
is declared for custom order tables and the cart/checkout blocks.

### Does it slow down my store?

No. The capture request only runs on the checkout page. Detection and sending run
in the background with Action Scheduler, in batches, on indexed queries.

### Are customers tracked without consent?

No, not by default. The **Require consent** switch is on by default and applies 
to guests and to logged-in customers: until the box is ticked, nothing is sent to
the server or saved (no email, phone or cart), and no reminder is sent. A logged-
in customer who ticked the box once is remembered (the box is shown ticked and can
be unticked to withdraw consent). This follows Quebec’s Law 25 and the GDPR, which
require express consent before collecting personal information for marketing reminders.
You can turn the switch off in Settings — guests and logged-in customers are then
tracked without the box — but you become responsible for having another legal basis,
and a warning stays in the admin. Carts saved while the switch is off are marked
as captured without consent: if you turn the switch back on, they are not reminded(
unless the customer ticks the box later). You can also choose to never track guests.
Reminders for pending (unpaid) orders do not depend on this switch.

### I upgraded from 1.0.x and my store was in “Always” mode. What changed?

Version 1.1.0 turns consent on for these stores (the switch is on) and shows a notice
on the plugin’s screens until you dismiss it. You can turn consent off again in 
Settings, under your own responsibility.

### Are carts saved by 1.0.x still reminded after the update?

No. Version 1.0.x did not record whether a cart was saved with the consent box ticked
or in “Always” mode (a store may also have switched modes before updating). To be
safe, every cart saved by 1.0.x — guests and logged-in customers — is marked as 
captured without consent and is not reminded until the customer ticks the box again
in 1.1.0. Pending order reminders are not affected.

### What happens when an email cannot be sent?

The cart gets the _Send failed_ status with the error message, a dismissible notice
is shown on the plugin’s screens and the error is logged in WooCommerce > Status
> Logs (source `oli-abandoned-cart-recovery`), even without `WP_DEBUG`. The reminder
is retried after 5 minutes, 30 minutes and 2 hours, then the cart stays _Send failed_;
use **Send next reminder now** once your mail settings are fixed.

### In which language are reminders sent?

In the language saved with the cart (site language, or WPML / Polylang language).
Default templates and the default consent text are translated in that language as
long as you did not edit them. An edited template is sent as written, in a single
language.

### How do I remove all data?

Deleting the plugin from the Plugins screen removes its tables (carts and email 
log), options, capability, scheduled actions with their Action Scheduler logs and
group, WP-Cron events, the plugin’s WooCommerce log files, order, user and coupon
metadata (including the block checkout consent field), the plugin’s keys in WooCommerce
sessions, and generated coupons that were never used. Generated coupons that were
used stay in WooCommerce, because they are linked to orders; only the plugin’s marker
is removed. To keep everything, tick **Keep the data when the plugin is deleted**
in Settings (off by default).

### Which languages are supported?

The plugin is written in English and fully translatable (text domain `oli-abandoned-
cart-recovery`). Translations are managed on translate.wordpress.org and installed
automatically by WordPress; French (Canada) and French (France) translations will
be contributed there.

## Reviews

There are no reviews for this plugin.

## Contributors & Developers

“Oli Abandoned Cart Recovery” is open source software. The following people have
contributed to this plugin.

Contributors

 *   [ Olivier Bigras ](https://profiles.wordpress.org/bigrat95/)

[Translate “Oli Abandoned Cart Recovery” into your language.](https://translate.wordpress.org/projects/wp-plugins/oli-abandoned-cart-recovery)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/oli-abandoned-cart-recovery/),
check out the [SVN repository](https://plugins.svn.wordpress.org/oli-abandoned-cart-recovery/),
or subscribe to the [development log](https://plugins.trac.wordpress.org/log/oli-abandoned-cart-recovery/)
by [RSS](https://plugins.trac.wordpress.org/log/oli-abandoned-cart-recovery/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 1.1.1

 * Admin notices are shown only on the plugin’s own screens (WooCommerce > Abandoned
   Carts), and all of them can be dismissed; the WooCommerce requirement notice 
   is shown only on the Plugins screen
 * Admin script and styles are enqueued only on the plugin’s screens; CSS selectors
   are scoped to the plugin’s page; no more inline scripts, inline event handlers
   or inline style attributes in the admin and on the checkout page
 * Bulk delete of carts is handled before the page is displayed (capability and 
   nonce checks, then a clean redirect)
 * Activation works on every supported WordPress version (autoload helper with a
   fallback when `wp_set_option_autoload_values()` is not available), and PHP / 
   WordPress versions are checked with a clear message instead of an error
 * Translations are no longer bundled with the plugin: WordPress loads them automatically
   from translate.wordpress.org
 * Security hardening: the unsubscribe confirmation page output is filtered with`
   wp_kses()`

#### 1.1.0

 * New: consent switch (on by default) that applies to guests and logged-in customers;
   when off, a permanent Law 25 / GDPR warning is shown in the admin
 * New: consent text edited per language with links, bold and italic (`wp_kses`)
 * Privacy: logged-in customers must also tick the consent box (consent remembered
   in their account, withdrawable); 1.0.x logged-in carts without consent are no
   longer reminded
 * Privacy: stores upgraded from 1.0.x in “Always” mode switch to consent, with 
   an admin notice; carts saved by 1.0.x (which did not record how consent was given)
   and carts captured in 1.1.0 while the switch is off are never reminded once consent
   is required, until the customer ticks the box
 * New: retries after a failed send (5 min, 30 min, 2 h) with the _Send failed_ 
   status, the error in the carts list, an admin notice and an error log entry, 
   even without `WP_DEBUG`
 * New: plain-text part in reminder emails (multipart/alternative)
 * New: rate limits and honeypot on the capture endpoint
 * Fix: legacy order storage (HPOS off) — no more `meta_query` notice; already processed
   pending orders no longer block newer ones
 * Fix: atomic lock with renewal and time budget, and each cart is claimed before
   sending, so slow SMTP runs never overlap
 * Fix: checkout pages are never cached (no-cache headers, `DONOTCACHEPAGE`), and
   an expired capture nonce is refreshed automatically
 * Performance: settings and version options are autoloaded (2 fewer queries per
   page)
 * New: templates and consent text per language, edited in language tabs; default
   templates are created in every active language
 * New: language adapters for TranslatePress, Polylang, WPML, Weglot and WordPress
   core, with the `oli_acr_lang_adapters` filter to add others
 * New: reminders sent in the cart’s language (language of the checkout page); recovery
   and unsubscribe links use the URL of that language, the recovery link opens the
   checkout page of that language, and the unsubscribe page is shown in that language
 * New: adjustable fallback language
 * New: fallback language texts registered in WPML String Translation and Polylang;
   documented priority order
 * Fix: no coupon is created when the email does not show it (no `{coupon}` or `{
   coupon_code}`), with a warning in the template list and editor
 * New: notice when Polylang is active without Polylang for WooCommerce (translated
   checkout pages not recognized)
 * Fix: “1 hour” / “1 hours” plurals and the date of the failure notice in the site’s
   date and time format
 * New: `{coupon_amount}` placeholder and a translatable coupon introduction sentence
   in the default templates (removed when there is no coupon)
 * New: `oli_acr_translate_url` filter
 * Fix: with the site in English, the admin showed template names, subjects and 
   content in French (list, editor, log, “Send a test”); the admin now shows templates
   in the admin language or in the selected language tab, and “Send a test” uses
   that language
 * Fix: uninstall also removes the block checkout consent value (`_wc_other/oli-
   acr/consent`) stored in the customer data of WooCommerce sessions
 * Upgrade: 1.0.x templates and consent text become the fallback language texts;
   unchanged default templates get their texts in every active language

#### 1.0.1

 * Privacy: guests are now captured only with explicit consent by default (Quebec
   Law 25, GDPR); without consent, no email, phone or cart is sent or saved
 * Fix: “Send next reminder now” refuses recovered, unsubscribed or finished carts;
   nonces are tied to each cart and order, and the sequence continues after a manual
   send
 * Fix: uninstall removes Action Scheduler logs and group, the plugin’s WooCommerce
   log files, consent metadata, session keys and unused generated coupons
 * New: “Keep the data when the plugin is deleted” option (off by default)
 * Fix: reminders are sent in the language saved with the cart; default templates
   and the default consent text follow that language until edited
 * Fix: the default consent text is no longer frozen in one language when settings
   are saved
 * Fix: one-click unsubscribe header (List-Unsubscribe-Post)
 * Fix: the empty image column is removed from the email items table, and the coupon
   border uses the WooCommerce email base color
 * Fix: email addresses no longer break mid-address in the admin Customer column
 * Fix: test emails contain a dummy unsubscribe link with no effect
 * Code quality: WordPress Coding Standards (Extra, Docs), PHPCompatibility 7.4+,
   PHPStan level 6 and Plugin Check

#### 1.0.0

 * Initial release
 * Email and phone capture on the classic and block checkout, guests and registered
   customers
 * Consent mode and tracked roles
 * Multiple email templates sent in sequence, unique coupons, coupon clean-up
 * Pending order recovery and automatic cancellation of old reminded pending orders
 * Secure recovery link, unsubscribe link and exclusion list, automatic stop on 
   order
 * Admin notification for recovered carts and orders
 * Dashboard, reports, carts, pending orders, recovered and email log tabs
 * Shop manager access with a dedicated capability
 * Privacy exporter, eraser and policy text
 * HPOS and cart/checkout blocks compatibility
 * French (Canada) and French (France) translations

## Meta

 *  Version **1.1.1**
 *  Last updated **21 hours ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 6.4 or higher **
 *  Tested up to **7.1.2**
 *  PHP version ** 7.4 or higher **
 * Tags
 * [abandoned cart](https://wordpress.org/plugins/tags/abandoned-cart/)[cart recovery](https://wordpress.org/plugins/tags/cart-recovery/)
   [multilingual](https://wordpress.org/plugins/tags/multilingual/)[woocommerce](https://wordpress.org/plugins/tags/woocommerce/)
 *  [Advanced View](https://wordpress.org/plugins/oli-abandoned-cart-recovery/advanced/)

## Ratings

No reviews have been submitted yet.

[Your review](https://wordpress.org/support/plugin/oli-abandoned-cart-recovery/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/oli-abandoned-cart-recovery/reviews/)

## Contributors

 *   [ Olivier Bigras ](https://profiles.wordpress.org/bigrat95/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/oli-abandoned-cart-recovery/)