排程好晚上八點上線的促銷文章,到了九點還躺在「排程中」;設定每天凌晨備份,隔天打開卻發現備份根本沒跑。這種狀況在 WordPress 站長之間天天發生,而幕後的元凶幾乎都是同一個——WP-Cron。
問題的根源在於,WordPress 內建的 WP-Cron 並不是真正的排程,它得靠訪客流量才會被觸發。把排程交給主機 cron job,由作業系統層級在固定時間執行,才是讓任務準時又穩定的正解。這篇會帶你拆解兩者的差異,讀懂 crontab 語法,並依你的主機環境(cPanel 虛擬主機或有 SSH 的 VPS)一步步把真實系統排程設定起來。
WP-Cron 跟主機 cron job 到底差在哪
最關鍵的差別只有一句話:主機 cron job 是作業系統層級的真排程,WP-Cron 只是 WordPress 用 PHP 模擬出來的「偽排程」,必須靠網頁被瀏覽才會啟動。
WordPress 是一支 PHP 應用程式,通常沒有權限直接操作伺服器的系統服務,於是開發者用了一個變通做法:每當有人(包含搜尋引擎爬蟲)載入網站任何一個頁面,WordPress 就會在背景觸發 wp-cron.php,去檢查資料庫裡有沒有過期未執行的排程,有的話就趁這次請求一併跑掉。
這個「看臉色」的設計帶來兩個方向相反的麻煩。流量低的網站排程會嚴重延遲,你設在凌晨三點的備份,可能要等到早上第一個訪客上門才被觸發,延誤從幾分鐘到好幾個小時都有。流量高的網站則是另一種浪費,每一次頁面載入都去檢查排程,在已經上了快取的環境裡反而拖慢整體速度。更別說很多主機層級快取為了效能會擋掉對 wp-cron.php 的重複請求,直接讓排程失靈。
還有一個常被忽略的點是安全面。wp-cron.php 是對外公開、任何人都能直接請求的檔案,惡意者可以反覆呼叫它來拉高伺服器負載,形成一種低成本的攻擊手法。改用主機 cron job 並把公開觸發關掉,等於順手把這道門關上。
真實系統排程的好處對應地很清楚:時間到了就一定執行,不看流量臉色;網站不必在每次載入時檢查排程,減輕 PHP 與資料庫負擔;所有任務集中在單一介面(cPanel 或 SSH)管理,一目了然。WordPress 官方外掛手冊本身也建議正式站點改用伺服器層級的 cron。
改用主機 cron job 前,wp-config.php 要先改什麼
核心動作是在 wp-config.php 加一行常數,告訴 WordPress 不要再用頁面載入觸發 WP-Cron。順序很重要——先把主機 cron job 設好,再回頭關閉 WP-Cron,絕對不要反過來。
如果你先關掉 WP-Cron、卻還沒設定替代的系統排程,所有排程任務(文章定時發佈、自動備份、外掛更新檢查、觸發式郵件)會在沒有任何錯誤訊息的情況下靜悄悄全部停擺,問題很難第一時間被發現。
要關閉內建觸發,請用 FTP 或主機控制台的檔案管理員打開網站根目錄的 wp-config.php,在 /* That's all, stop editing! Happy publishing. */ 這行之前加入:
define('DISABLE_WP_CRON', true);
wp-config.php 帶有大量敏感設定,改錯會讓整站打不開,動手前先備份一份原始檔。
要特別釐清一個常見誤解:這行常數只是阻止 WP-Cron 在「頁面載入時」自動觸發,它不會封鎖 wp-cron.php 被直接呼叫。你在下一步設定的主機 cron job,依然能正常呼叫它來執行排程,兩者並不衝突。
crontab 的五個欄位怎麼讀
設定主機 cron job 一定會碰到 crontab 語法。一條排程規則由五個時間欄位加上要執行的指令組成,五個欄位由左到右分別是分、時、日、月、星期。
| 欄位 | 意義 | 可填範圍 |
|---|---|---|
| 第 1 欄 | 分鐘 | 0–59 |
| 第 2 欄 | 小時 | 0–23 |
| 第 3 欄 | 日 | 1–31 |
| 第 4 欄 | 月 | 1–12 |
| 第 5 欄 | 星期 | 0–7(0 與 7 都代表星期日) |
搭配幾個特殊符號就能組出各種頻率。星號「*」代表「每一個」這個單位;斜線「/n」代表每隔 n 個單位執行一次;逗號「,」用來列舉多個時間點;減號「-」表示一段連續範圍。
幾組對照看完就懂:
* * * * *:每分鐘執行一次*/5 * * * *:每隔 5 分鐘執行一次*/15 * * * *:每隔 15 分鐘執行一次0 * * * *:每小時整點執行30 3 * * *:每天凌晨三點半執行
對多數 WordPress 網站來說,*/15(每 15 分鐘)是穩妥的起手值。需要更密集或更寬鬆的設定,看你的站對排程的依賴程度,後面選擇頻率時會再細談。
wget、PHP CLI、WP-CLI 三種觸發方式怎麼選
設定主機 cron job 時,指令欄位有三種主流寫法可以呼叫 WordPress 排程,差別在於「繞不繞過網路層」。先給結論:能用 WP-CLI 就用 WP-CLI,其次是 PHP CLI,HTTP 請求式(wget/curl)放最後考慮。
WP-CLI(最推薦):WP-CLI 內建的 cron 指令只會跑「真正到期」的事件,比直接呼叫 wp-cron.php 更有效率,而且完全在本機執行,繞過 DNS、SSL 與防火牆。crontab 寫法:
*/15 * * * * cd /path/to/wordpress && wp cron event run --due-now >/dev/null 2>&1
PHP CLI:直接用 PHP 命令列執行 wp-cron.php,同樣不經過 HTTP,速度比 wget/curl 快。寫法:
*/15 * * * * php /path/to/wordpress/wp-cron.php >/dev/null 2>&1
HTTP 請求式(wget/curl):透過網址請求 wp-cron.php,相容性最廣,cPanel 教學最常見的就是這種:
*/15 * * * * wget -q -O - https://yourdomain.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1
指令尾巴的 >/dev/null 2>&1 的作用是把輸出與錯誤訊息都丟棄,不然 cPanel 預設每跑一次就寄一封執行結果通知信給你,很快就會塞爆信箱。
為什麼 HTTP 請求式要放最後?因為它把一個本來在本機就能完成的工作,硬繞了一圈網路。這條路上的每一個環節都可能讓排程失敗:DNS 解析延遲或異常、SSL 憑證到期、Cloudflare 或 Wordfence 這類防火牆攔截、以及網路請求本身的逾時限制。任務一旦在執行到一半時被逾時切斷,那次排程就不完整,若它是每日任務,就得等到隔天才有下一次機會。相對地,WP-CLI 與 PHP CLI 在本機直接執行,這些網路風險全部不存在。
如果環境因素讓你非得用 HTTP 請求不可,curl 比 wget 安全一些,而且可以改打本機位址、用 Host 標頭指定網域,避免走出公網再繞回來:
*/15 * * * * curl -L -k --header "Host: yourdomain.com" https://127.0.0.1/wp-cron.php?doing_wp_cron >/dev/null 2>&1
這裡 -L 是跟隨轉址,-k 則因為憑證的網域名稱(yourdomain.com)和你實際請求的位址(127.0.0.1)對不起來、需要略過憑證驗證。搭配在防火牆只允許本機請求 wp-cron.php,就能同時擋掉外部惡意觸發。
至於該設多密集,可以依站台類型抓:
| 站台類型 | 建議頻率 |
|---|---|
| 低流量部落格、形象官網 | 每 15–30 分鐘 |
| 中流量站、一般電商 | 每 5–10 分鐘 |
| 高流量站或排程吃重(WooCommerce、線上課程) | 每 1–5 分鐘 |
頻率不是愈高愈好。在沒有待辦任務時還頻繁觸發,只會徒增伺服器負載,先用建議值起跑,再依實際排程活動量微調。多數虛擬主機也會限制最小間隔(常見是每小時一次或每 15 分鐘一次),設定前先確認你的方案上限。
在 cPanel 主機上設定主機 cron job 的步驟
虛擬主機通常只給你 cPanel、沒有 SSH,這時就在控制台的圖形介面裡新增排程。整個流程不需要懂 Linux,只要貼對一條指令。
第一步、登入 cPanel,在「進階(Advanced)」分類裡找到並點進「Cron Jobs」。不同主機商的位置略有差異,找不到時用控制台搜尋框打「Cron」最快。
第二步、在「Add New Cron Job(新增排程)」區塊,先決定執行頻率。介面通常有「Common Settings(常用設定)」下拉選單,裡面有「Twice Per Hour(每半小時)」「Once Per Hour(每小時)」這類預設值;想自訂就直接在分、時、日、月、星期五個欄位填數字。不確定的話,每半小時是適合大多數網站的安全選擇。
第三步、在「Command(指令)」欄位貼上觸發指令。虛擬主機多半沒開放 WP-CLI,最穩妥的是 HTTP 請求式:
wget -q -O - https://yourdomain.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1
記得把 yourdomain.com 換成你自己的網域。若主機支援 PHP 命令列,也可以改用效率更好的 PHP CLI 寫法,路徑要填主機上的絕對路徑:
php -q /home/你的帳號/public_html/wp-cron.php >/dev/null 2>&1
第四步、按下「Add New Cron Job」,新排程就會出現在下方清單。如果你想收到執行通知,把上方的 Email 欄位填好;不想被通知信轟炸,就保留指令尾端的 >/dev/null 2>&1。
別忘了回到上一節,把 wp-config.php 的 DISABLE_WP_CRON 設為 true,這個 cPanel 排程才會真正取代原本的 WP-Cron。
用 SSH crontab 在 VPS 上設定排程
如果你的主機是 VPS 或有 SSH 權限,直接編輯系統的 crontab 會比走控制台更乾淨,而且不受主機商的圖形介面功能限制,任何 Linux 主機都適用。
用 SSH 連上伺服器後,執行:
crontab -e
這會打開目前使用者的 crontab 編輯畫面,在最後一行加上你的排程規則(三選一)。最推薦的 WP-CLI 寫法:
*/15 * * * * cd /path/to/wordpress && wp cron event run --due-now >/dev/null 2>&1
把 /path/to/wordpress 換成你 WordPress 安裝的實際路徑。存檔離開後,系統每 15 分鐘就會替你跑一次到期排程。若你不確定 WP-CLI 或 PHP 執行檔的完整路徑,用 which wp、which php 查出絕對路徑填進去,會比只寫 wp、php 更不容易因環境變數問題而失敗。
WordPress 多站台網路(Multisite)要留意:每個子站的排程需要各自觸發,單純對主網域的 wp-cron.php 設一條排程,子站排程可能跑不起來。WP-CLI 原生支援多站台,用 --url 指定要跑的站台即可:
*/15 * * * * cd /path/to/wordpress && wp cron event run --due-now --url=https://yourdomain.com >/dev/null 2>&1
需要把整個網路的所有子站都跑過一輪,可以串接 wp site list 逐站處理。DISABLE_WP_CRON 常數在多站台環境只要設一次,就會套用到整個網路。
順帶一提,若你的主機是 Windows 環境,對應的工具不是 crontab,而是內建的「工作排程器(Task Scheduler)」,原理一致,只是改用圖形介面或 schtasks 指令來建立定時任務。
WooCommerce 站為什麼更需要真實主機 cron job
如果你跑的是 WooCommerce 商店,把排程交給主機 cron job 不只是優化,而是接近必要。原因是 WooCommerce 大量倚賴排程在背景處理時間敏感的工作,而這些工作一旦延遲,影響的是實際營運。
WooCommerce 的核心排程引擎 Action Scheduler 會處理一連串需要準時的任務:訂單狀態的自動轉換、會員或訂閱制商品的續訂與到期、發送訂單與通知信、清理過期的暫存資料、以及與外部系統的資料同步。這些動作底層都掛在 WordPress 的 cron 機制上。
把這串任務交給看流量臉色的 WP-Cron,後果很具體。低流量時段下單,訂單狀態可能卡著不動;訂閱制商品到了續訂時間卻沒被觸發;該寄的通知信遲遲不發。對一般部落格來說,排程晚跑十分鐘無傷大雅;對商店來說,這直接關係到客戶體驗的順暢。這裡只是客觀點出排程與訂單流程的連動,實際的收款與金流設定仍以各金流服務的文件為準。
正因為電商站的排程又多又密,前面的頻率建議裡,WooCommerce 這類「排程吃重」的站台才會落在每 1 到 5 分鐘的區間。把 WP-Cron 換成穩定的主機 cron job,等於替整個訂單流程裝上一個守時的引擎。
設好之後怎麼確認排程真的在跑
設定完不要直接收工,務必驗證 WP-Cron 確實已停用、而且主機 cron job 真的有在觸發。漏掉這一步,是排程明明設了卻還是漏跑的常見原因。
最直覺的做法是裝免費外掛 WP Crontrol。啟用後進到後台「工具 → Cron 事件」,會列出系統所有排程事件、各自的執行頻率、下一次預計執行時間與對應的掛鉤(hook)。如果 WP-Cron 已正確停用,你就不會再看到事件被每次頁面載入觸發,而是按照你主機排程的間隔清空。這個列表平時也是排查哪個外掛排程出狀況的好工具。
有 WP-CLI 的環境,在伺服器上跑這行就能檢查待執行事件:
wp cron event list
它會列出每個待跑事件與下次執行時間。若清單正常、事件在兩次執行之間有被清掉,代表排程運作正常。
想確認 crontab 那條規則有沒有真的觸發,可以暫時把輸出改寫進記錄檔:
*/15 * * * * wget -q -O - https://yourdomain.com/wp-cron.php?doing_wp_cron >> /tmp/wpcron.log 2>&1
等過了 15 分鐘再去看 /tmp/wpcron.log 有沒有內容,確認跑過之後再把記錄改回 >/dev/null 2>&1,避免記錄檔無限長大。
如果設好仍不運作,先檢查幾個高頻地雷:指令裡的網域或安裝路徑是否填對、PHP 或 WP-CLI 是否用了完整絕對路徑、虛擬主機是否限制了你設定的最小間隔、以及 DISABLE_WP_CRON 是不是其實還沒生效。逐項排掉,多半就能找到卡點。
把 WP-Cron 換成主機 cron job,本質上是用一個守時可靠的系統服務,取代一個要靠人潮才肯動工的臨時機制。設定步驟不長:先依你的環境(cPanel 或 SSH crontab)建好排程,挑對觸發方式(優先 WP-CLI),再回頭把 DISABLE_WP_CRON 打開,最後用 WP Crontrol 或記錄檔確認真的在跑。
現在就打開你的主機控制台,照著上面對應你環境的那一節走一遍。排程準時了,你那些定時文章、每日備份、訂單處理才能真正擺脫「看流量臉色」的不確定,乖乖在該執行的時間執行。