Retention on most stores is a post-mortem. The subscription cancels, or the unsubscribe event fires, and the marketing team scrambles out a “We Miss You” coupon. That customer left weeks earlier. The usual advice is to wait for hard data, but in 14 years of building WooCommerce stores the thing that has quietly cost my clients the most money is silent churn: the customers who never cancel anything and just spend less every month.
Customer Churn Prediction does not need a data science team behind it. Transaction dates and order totals are already sitting in your database, and that is enough to measure buying momentum. The useful question is not whether a customer counts as active or inactive, it is which direction they are moving. Someone who spent $500 three months ago, $200 last month and $50 this month is technically still active. They are also on their way out.
The math behind buying momentum
Churn rarely happens overnight. Most customers taper off, ordering less often for a while before they stop entirely. Linear regression measures that taper. The number you want is the slope: positive means the customer is buying more over time, negative means they are heading toward buying nothing.
This is not a neural network, it is a trend line through a handful of points. If you want the wider picture of how your customers behave first, my guide to RFM Analysis for WooCommerce Segmentation covers the baseline this sits on top of.
Calculating the trend line in WooCommerce
Customer Churn Prediction here means aggregating monthly spending and taking the slope of the resulting line. Pulling straight from wp_wc_order_stats keeps the query cheap enough to run on a busy store.
/**
* Calculate buying momentum (slope) for a WooCommerce customer.
*
* @param int $customer_id
* @return float Slope of the spending trend. Negative = Churn Risk.
*/
function bbioon_calculate_customer_trend( $customer_id ) {
global $wpdb;
// Get last 6 months of revenue aggregated by month
$query = $wpdb->prepare( "
SELECT
MONTH(date_created) as mth,
SUM(total_amount) as monthly_spend
FROM {$wpdb->prefix}wc_order_stats
WHERE customer_id = %d
AND date_created >= DATE_SUB(NOW(), INTERVAL 6 MONTH)
GROUP BY MONTH(date_created)
ORDER BY date_created ASC
", $customer_id );
$data = $wpdb->get_results( $query, ARRAY_A );
if ( count( $data ) < 2 ) {
return 0; // Not enough data to determine a trend
}
$n = count( $data );
$sum_x = 0; $sum_y = 0; $sum_xy = 0; $sum_xx = 0;
foreach ( $data as $index => $row ) {
$x = $index + 1; // Time index (1, 2, 3...)
$y = (float) $row['monthly_spend'];
$sum_x += $x;
$sum_y += $y;
$sum_xy += ( $x * $y );
$sum_xx += ( $x * $x );
}
// Linear Regression Slope Formula: (nΣxy - ΣxΣy) / (nΣx² - (Σx)²)
$denominator = ( $n * $sum_xx ) - ( $sum_x * $sum_x );
if ( $denominator == 0 ) return 0;
$slope = ( ( $n * $sum_xy ) - ( $sum_x * $sum_y ) ) / $denominator;
return $slope;
}
Why the slope beats last order date
Plenty of stores judge this on last order date alone. It is a useful number, but it says nothing about volume decay. A customer might keep ordering every week and spend $10 less each time. Recency still marks them active, while the Customer Churn Prediction slope is already falling. Seeing that early is what lets a win-back workflow fire while the customer is still buying something.
Running this calculation on every request will hurt. Cache the result in a transient, or in a meta field you refresh only when an order completes. If you want to see how a much larger operation handles the same problem, Stripe’s guide on churn models covers their approach to predictive billing data.
If churn prediction work is eating your dev hours, I have been doing this since the 4.x days and I am happy to take it off your plate.
The practical version
By the time someone clicks cancel, the decision is old news. Calculating the slope and flagging the negative ones gives you a warning while the customer is still spending, which is the only point where a retention offer has anything to work with. It is an afternoon of work in your reporting code.