WooCommerce plugin
A WordPress plugin that fills the E-commerce (RFM) dashboard from your store — orders, carts, product views and history — without touching your theme or slowing checkout.
Install the plugin, paste one connect code, import your order history. Every component of the E-commerce (RFM) template is fed, and past orders are imported so the scores mean something on day one rather than in ninety days.
Requires WordPress 6.0+, WooCommerce 7.1+, PHP 7.4+. Works with High-Performance Order Storage and the cart/checkout blocks.
Set up
The connect code carries the ingest URL and the key together, and your project is resolved from the key itself — so there is no URL to mistype and no project id to look up.
- Settings → Integrations → WooCommerce in ChurnWarn — create a key for the store and copy the connect code.
- In WordPress: Plugins → Add New → Upload Plugin, upload the zip, activate.
- WooCommerce → Settings → Integrations → ChurnWarn — paste the code, save. The screen turns green and names the project it connected to.
- Click Import order history.
What it sends
| Signal | When | Component it feeds |
|---|---|---|
order_placed | Order reaches Processing or Completed | Recency, Frequency, Monetary — 62% of the score |
order_returned | Refund recorded, full or partial | Return rate |
cart_created | First item added to a known customer's cart | Cart abandonment (denominator) |
cart_abandoned | Cart untouched for the configured window | Cart abandonment |
product_viewed | Known customer opens a product page | Purchase conversion |
referral | Order uses a coupon matching your referral prefixes | Referrals (opt-in) |
Account facts are written too — kind: person, valueBasis: ltv, lifetime spend, order count,
first and last order — which is what makes the dashboard read LTV at risk. Account silence, the
eighth component, needs no signal of its own.
Cart and view history do not exist in WooCommerce, so those three components start empty and fill forward. Everything else backfills.
Privacy
Pseudonymous by default, matching the other SDKs:
- A registered customer becomes
wc_{user_id}. - A guest becomes
wcg_{HMAC-SHA256(email, site salt)}— one account across repeat guest orders, and an id nobody can turn back into an email. The salt is generated on the merchant's site and never transmitted. - Payloads carry numbers, ids and booleans. Never addresses, phone numbers or free text, and everything is scrubbed with the same masking the other SDKs use before it leaves.
Switching Customer identity to Identified sends names and emails, for merchants who run win-back campaigns from the dashboard. It is the only setting that sends personal data, and switching it re-keys accounts — re-run the import afterwards.
Behavioural signals honour the WP Consent API (statistics) when a consent plugin is installed.
Order records are treated as business records; the churnwarn_should_track filter overrides either.
Settings worth a second look
Cart abandoned after — 240 minutes (4 hours) by default, adjustable from 15 minutes to 7 days. It feeds a scored component directly, so set it to your own repurchase rhythm: a grocery cart is stale in an hour, a furniture cart is still live after two days.
Browser tracking — on by default. Cached product pages never reach PHP, so server-side view tracking under-counts on any store running a page cache, and a conversion rate with a missing denominator is worse than none. With this on, views are reported from the storefront and server-side view tracking switches itself off so nothing is counted twice.
Report values in — base currency by default. A multi-currency store reporting in order currency would have 100 EUR and 100 JPY summed as "200".
Count an order when it becomes — leave it on the default. Both transitions are wired and the shared idempotency key means the second one is ignored, not double-counted.
Re-running anything is free
Every event carries a deterministic idempotency key — wc:{install}:order:{id}:placed — and
ChurnWarn keeps the first event it sees for a key and ignores the rest. So a re-run of the
importer, a retry after a timeout, and a WooCommerce hook that fires twice all converge on exactly
one event.
It cannot break the store
A ChurnWarn failure — API down, key revoked, table missing — must cost the merchant nothing. Our code runs inside their checkout, so this gets more attention here than in any other SDK.
- No network I/O on any request a shopper waits for. Producing an event is one
INSERT. Delivery happens in Action Scheduler jobs, plus an opportunistic flush onshutdownthat only runs afterfastcgi_finish_request()has already handed the page over. - One fault barrier. Every callback is registered through a wrapper that swallows
Throwableand, for filters, returns the input untouched. - A kill switch. Twenty consecutive failures, or any 401/403, pauses sending and raises an admin notice — no retry storm against a dead endpoint.
- Bounded everything. 50k queued rows max (oldest shed and counted), 200 events per request, 200 enqueues per page load.
- Staging clones are detected by site-URL fingerprint and paused, so a copy of production cannot post test orders into the live dashboard.
Filters
| Filter | Purpose |
|---|---|
churnwarn_should_track( bool $allowed, string $context ) | Veto any signal. $context is transactional or behavioural. |
churnwarn_order_exchange_rate( float $rate, WC_Order $order, string $base ) | Supply a rate when your multi-currency plugin is not one of the ones read automatically. |
Next
- E-commerce (RFM) template — what each component scores and how to tune it.
- Security & data masking — what the masking pass covers.