告別資料庫蚊子館:50 行代碼自動催生現金流
您的資料庫裡是否躺著數萬名「沈睡客群」?資深工程師 Eric 揭露,手動篩選名單進行再行銷的效率極差。本文教您利用 WordPress 原生 Cron Job 與一段精簡 PHP 代碼,全自動偵測超過 90 天未消費的用戶,並即時發送專屬優惠券。告別浪費時間的重複性勞動,現在就實施這套自動化喚醒引擎,將那 95% 的沉寂會員,轉變為持續且穩定的營收來源!
「資料庫不是拿來養蚊子的!」資深工程師教你用 50 行代碼自動偵測並喚醒 90 天未消費的『沈睡客群』
嗨,我是 Eric,浪花科技的資深工程師。今天不談什麼高大上的 AI 預測模型,我們來聊聊一個更實際、甚至有點「銅臭味」的話題:把躺在資料庫裡的死魚,變成活跳跳的現金。
我看過太多客戶的 WooCommerce 後台,會員數動輒好幾萬,看起來很風光,但仔細一撈 SQL,真正活躍的可能連 5% 都不到。剩下的 95% 呢?就像你家過年買的糖果盒一樣,擺在角落長灰塵。這些「沈睡客戶」其實比新客戶更有價值——他們認識你、買過你的東西,只是忘了你的存在。
行銷部門通常會說:「那我們每個月手動發電子報!」別鬧了,手動篩選名單、匯出 Excel、匯入 MailChimp,這流程跑兩次就沒人想做了。身為工程師,我們的職責就是「消滅重複性勞動」。
今天這篇文章,我要教你如何用 WordPress 原生的 Cron Job 和一段精簡的 PHP 代碼,自動偵測「超過 90 天未消費」的用戶,並自動生成一張專屬優惠券寄給他。全自動、零手動。
為什麼是 90 天?技術與人性的黃金交叉點
在寫 Code 之前,先講邏輯。為什麼設定 90 天?
- 記憶曲線:三個月是大部分消費者對品牌記憶模糊的臨界點。
- 資料庫效能:如果每天都掃描「昨天未消費」的用戶,你的伺服器 CPU 會哭出來。90 天是一個既能篩出足夠樣本,又不至於讓 Query 爆炸的時間區間。
- 避免騷擾:太頻繁的「想念你」郵件,只會讓人覺得你是恐怖情人。
技術難點:如何在 WordPress 中高效撈取「最後消費日」?
這是一個坑。WooCommerce 預設的 wp_users 表裡面,並沒有直接欄位紀錄「最後一次下單時間」。
如果你每次 Cron Job 執行時,都要用 wc_get_orders() 去遍歷所有訂單來反查用戶,這就是標準的「N+1 查詢災難」。當你的訂單數破萬時,網站會直接卡死。
Step 1:埋點——在用戶 Meta 紀錄最後消費時間
最優雅的做法,是在用戶下單完成時,順手更新一個 _last_purchase_date 到 usermeta 表。這樣我們之後撈資料時,只需要簡單的 Meta Query,速度快上 100 倍。
把這段加到你的 functions.php 或自製外掛中:
// 當訂單狀態變更為「完成」或「處理中」時,更新用戶的最後購買時間
add_action('woocommerce_order_status_completed', 'roamer_update_last_purchase_date', 10, 1);
add_action('woocommerce_order_status_processing', 'roamer_update_last_purchase_date', 10, 1);
function roamer_update_last_purchase_date($order_id) {
$order = wc_get_order($order_id);
$user_id = $order->get_user_id();
if ($user_id) {
// 儲存 Unix Timestamp,方便後續比對
update_user_meta($user_id, '_roamer_last_buy', current_time('timestamp'));
// 順便清除「已喚醒」標記(如果有的話),因為他買了!
delete_user_meta($user_id, '_roamer_dormant_alert_sent');
}
}
Step 2:打造自動喚醒引擎 (Cron Job)
有了數據,接下來就是自動化引擎。我們需要註冊一個 WordPress 排程,每天跑一次,找出符合以下條件的人:
_roamer_last_buy小於 90 天前。_roamer_dormant_alert_sent不存在(避免重複發送)。
核心程式碼邏輯
// 1. 註冊排程時間間隔(這裡示範每天一次,測試時可改為每小時)
add_filter('cron_schedules', function ($schedules) {
$schedules['daily_check'] = array(
'interval' => 86400,
'display' => __('Every Day')
);
return $schedules;
});
// 2. 註冊 Action Hook
add_action('roamer_daily_dormant_check', 'roamer_process_dormant_users');
// 3. 確保排程已啟用(通常放在外掛啟用時,這裡簡化處理)
if (!wp_next_scheduled('roamer_daily_dormant_check')) {
wp_schedule_event(time(), 'daily_check', 'roamer_daily_dormant_check');
}
// 4. 主邏輯:撈人、發信
function roamer_process_dormant_users() {
// 設定 90 天前的時間戳
$cutoff_date = strtotime('-90 days');
// 查詢條件
$args = array(
'role' => 'customer',
'number' => 50, // 為了效能,每次只處理 50 人
'meta_query' => array(
'relation' => 'AND',
array(
'key' => '_roamer_last_buy',
'value' => $cutoff_date,
'compare' => '<', // 早於 90 天前
'type' => 'NUMERIC'
),
array(
'key' => '_roamer_dormant_alert_sent',
'compare' => 'NOT EXISTS' // 沒發過通知的
)
)
);
$user_query = new WP_User_Query($args);
$users = $user_query->get_results();
if (!empty($users)) {
foreach ($users as $user) {
// 產生專屬優惠碼 (例如:COMEBACK-123)
$coupon_code = roamer_create_dynamic_coupon($user->ID);
// 發送郵件
$subject = '好久不見!這是您的專屬回歸禮物';
$message = "嗨 {$user->display_name},
我們發現您有一陣子沒來逛逛了。為了表示想念,我們為您準備了 9 折優惠券:{$coupon_code}。
期待您的光臨!";
$headers = array('Content-Type: text/html; charset=UTF-8');
wp_mail($user->user_email, $subject, $message, $headers);
// 標記已發送,避免明天重複發
update_user_meta($user->ID, '_roamer_dormant_alert_sent', current_time('timestamp'));
}
}
}
Step 3:動態生成專屬優惠券 (Bonus)
別再發那種全網通用的 WELCOME2025 了,那種代碼很容易流出被濫用。我們要生成的是「限制該用戶Email使用」且「限時」的專屬優惠券。
function roamer_create_dynamic_coupon($user_id) {
$coupon_code = 'COMEBACK-' . $user_id . '-' . wp_rand(100, 999);
$coupon = new WC_Coupon();
$coupon->set_code($coupon_code);
$coupon->set_discount_type('percent'); // 百分比折扣
$coupon->set_amount(10); // 10% OFF
$coupon->set_individual_use(true); // 單獨使用
$coupon->set_usage_limit(1); // 只能用一次
$coupon->set_email_restrictions(array(get_userdata($user_id)->user_email)); // 限制該用戶 Email
$coupon->set_date_expires(strtotime('+7 days')); // 7天後過期,製造急迫感
$coupon->save();
return $coupon_code;
}
工程師的碎碎念:關於效能與優化
這套系統上線後,我有幾個建議要給你,這也是很多新手開發者容易忽略的坑:
1. 批次處理 (Batch Processing)
如果你有 10 萬個沈睡會員,千萬不要嘗試一次全部發完。我在代碼中設定了 'number' => 50,這意味著每次 Cron 執行只處理 50 人。如果你的量很大,可以將 Cron 頻率調高(例如每小時一次),這樣既能消化名單,又不會讓伺服器因為 PHP Timeout 而掛掉。
2. 郵件發送服務 (SMTP)
千萬不要依賴 WordPress 預設的 wp_mail() 直接用主機發信。當你短時間發送大量郵件時,主機 IP 很容易被 Gmail 或 Outlook 判定為垃圾郵件。請務必搭配 SendGrid、Mailgun 或 Amazon SES 等專業的 Transactional Email 服務,並設定好 SMTP 外掛。
3. 資料庫索引 (Indexing)
當 wp_usermeta 表變得非常巨大時,Meta Query 的效能會下降。雖然這個功能是在背景執行,不會直接影響前台使用者體驗,但如果可以,定期清理孤兒 Meta Data (Orphan Meta) 是保持網站健康的好習慣。
總結
透過這段不到 100 行的代碼,你建立了一個 24 小時不休息的業務員。它會自動觀察誰快要忘記你們品牌,然後在他遺忘的前一刻,遞上一張有誠意的優惠券。這比投 Facebook 廣告找新客便宜太多了。
技術是為了服務商業目標而存在的。別讓你的資料庫只是一堆冷冰冰的 0 與 1,讓它們動起來,為你創造價值。
常見問題 (FAQ)
Q1: 如果用戶沒登入就購買,這樣偵測得到嗎?
這套邏輯是基於 user_id 的。如果是「訪客結帳 (Guest Checkout)」,WooCommerce 預設不會建立使用者帳號,因此無法記錄到 User Meta。建議開啟 WooCommerce 的「結帳時自動建立帳戶」功能,才能最大化數據價值。
Q2: 這會不會跟我的電子報系統 (如 MailChimp) 衝突?
不會衝突,但要小心「訊息轟炸」。建議在你的 CRM 策略中區隔開來。這個功能屬於「系統級通知」,針對性極強。如果 MailChimp 也有類似的 Automation,請擇一使用,避免客戶同一天收到兩封喚醒信。
Q3: 代碼放哪裡?一定要寫成外掛嗎?
對於初學者,放在子主題 (Child Theme) 的 functions.php 是最快的方法。但為了管理方便,我強烈建議將這些功能封裝成一個獨立的「網站專屬功能外掛 (Site Specific Plugin)」,這樣就算你換了佈景主題,功能依然存在。
延伸閱讀
- 拒絕盲目行銷!資深工程師教你用 WordPress 打造「使用者行為偵測」自動標籤系統
- 訂單自動化實戰:用 n8n 串接 WooCommerce,打造 24 小時不休息的「數位店長」
- 註冊後的黃金 5 分鐘!工程師教你設計「自動化迎賓旅程」,讓新會員從路人變鐵粉
如果你覺得要在 PHP 裡面寫這些邏輯太頭痛,或者你的資料量已經大到需要企業級的 CRM 架構規劃,歡迎隨時找我們聊聊。我們擅長處理這種「稍微有點複雜」的技術難題。
不想手動撈名單?需要客製化您的 WooCommerce 自動化行銷引擎?






