
ถ้าคุณสังเกตว่าเว็บ WordPress ช้าเป็นครั้งคราวโดยไม่มีสาเหตุชัดเจน หรือ Server Load พุ่งสูงในช่วงสั้นๆ สาเหตุหนึ่งที่มักถูกมองข้ามคือ WP-Cron — ระบบ Scheduled Task ของ WordPress ที่ทำงานในลักษณะที่ไม่มีประสิทธิภาพ
บทความนี้อธิบายว่า WP-Cron ทำงานอย่างไร ทำไมถึงก่อปัญหา และวิธีแก้ไขที่ถูกต้องด้วยการตั้ง Server Cron Job จริงบน DirectAdmin
WP-Cron คืออะไร?
WP-Cron คือระบบ Task Scheduling ใน WordPress ใช้สำหรับงานอัตโนมัติต่างๆ เช่น:
- ตรวจสอบและแจ้งเตือน Plugin/Theme Update ใหม่
- ส่ง Email สรุปรายงาน (WordPress Site Health)
- ลบ Post Revisions เก่า, Expired Transients
- รัน Task จาก Backup Plugin (เช่น UpdraftPlus)
- เผยแพร่ Scheduled Post ที่ตั้งเวลาไว้
ปัญหาหลักของ WP-Cron: ต่างจาก Cron Job จริง WP-Cron จะทำงานเฉพาะเมื่อ มีคนเยี่ยมชมเว็บ — ทุกครั้งที่มี Request เข้ามา WordPress จะเช็คว่ามีงานที่ค้างอยู่หรือไม่ และถ้ามีก็จะรันทันที ทำให้ Response Time ของ Request นั้นช้าลง
ปัญหาที่เกิดจาก WP-Cron
1. เว็บช้าแบบไม่สม่ำเสมอ
เมื่อ WP-Cron เริ่มทำงาน จะทำให้ PHP Process ที่ handle Request ของผู้เข้าชมต้องรองานอัตโนมัติเหล่านั้นด้วย ผลคือ Response Time เพิ่มขึ้นแบบกระทันหัน โดยไม่มีสัญญาณเตือนล่วงหน้า
2. งานไม่ทำงานตรงเวลา
ถ้าเว็บมีผู้เข้าชมน้อย (เช่น เว็บธุรกิจที่มี Traffic ต่ำในช่วงกลางคืน) Scheduled Post ที่ตั้งเวลา 02:00 น. อาจไม่ถูกเผยแพร่จนกว่าจะมีคนแรกเข้าเว็บในตอนเช้า
3. CPU Spike บน Shared Hosting
บนเว็บที่มี Traffic สูง หลาย Request มาพร้อมกันทำให้ WP-Cron ถูก Trigger หลายครั้งพร้อมกัน ก่อให้เกิด CPU Spike ที่ไม่จำเป็น
วิธีแก้: ปิด WP-Cron + ตั้ง Server Cron จริง
วิธีที่ถูกต้องคือปิด WP-Cron ที่ทำงานแบบ Pseudo-cron ออก แล้วใช้ Cron Job ของ Server ที่ทำงานตรงเวลาจริงๆ แทน
ขั้นที่ 1: ปิด WP-Cron ใน wp-config.php
เปิดไฟล์ wp-config.php ที่ root ของเว็บ WordPress แล้วเพิ่มบรรทัดนี้ ก่อน บรรทัด /* That's all, stop editing! */:
define('DISABLE_WP_CRON', true);
หมายเหตุ: การตั้ง DISABLE_WP_CRON จะหยุดเฉพาะการ Trigger อัตโนมัติผ่าน HTTP Request — ไม่ได้ลบ Queue งานที่ค้างอยู่ Cron Job จาก Server ยังรันงานเหล่านั้นได้ตามปกติ
ขั้นที่ 2: ตั้ง Cron Job บน DirectAdmin
หลังจากปิด WP-Cron แล้ว ต้องตั้ง Cron Job จริงบน Server เพื่อให้ WordPress ยังทำงานอัตโนมัติได้:
- Login เข้า DirectAdmin
- ไปที่ Advanced Features → Cronjobs
- คลิก Create New Cronjob
- กำหนด Schedule เป็น ทุก 5 นาที (แนะนำ)
- ใส่คำสั่งดังนี้:
php /home/[username]/domains/[yourdomain.com]/public_html/wp-cron.php > /dev/null 2>&1
แทนที่ [username] ด้วยชื่อ User ของ DirectAdmin และ [yourdomain.com] ด้วยโดเมนของคุณ
การตั้งค่า Schedule บน DirectAdmin
ใน Cron Job ของ DirectAdmin จะมีฟิลด์ให้กรอก:
| ฟิลด์ | ค่า (ทุก 5 นาที) | ความหมาย |
|---|---|---|
| Minute | */5 | ทุก 5 นาที |
| Hour | * | ทุกชั่วโมง |
| Day | * | ทุกวัน |
| Month | * | ทุกเดือน |
| Weekday | * | ทุกวัน |
ทำความเข้าใจ Cron Expression ก่อนตั้งค่า
ก่อนที่จะตั้ง Cron Job บน DirectAdmin หรือ Server ใด ๆ ควรเข้าใจ Syntax ของ Cron Expression ก่อน เพราะการกรอกผิดช่องจะทำให้งานทำงานผิดเวลาหรือไม่ทำงานเลย Cron Expression ประกอบด้วย 5 ช่อง ได้แก่ Minute, Hour, Day, Month, Weekday
| Expression | ความหมาย | เหมาะสำหรับ |
|---|---|---|
*/5 * * * * | ทุก 5 นาที | WordPress ทั่วไป (แนะนำ) |
*/1 * * * * | ทุก 1 นาที | เว็บที่มี Traffic สูงมาก |
0 * * * * | ทุก 1 ชั่วโมง | เว็บที่มี Traffic ต่ำ |
0 2 * * * | ทุกวัน เวลา 02:00 น. | งาน Backup รายวัน |
0 0 * * 0 | ทุกวันอาทิตย์ เวลาเที่ยงคืน | งานรายสัปดาห์ |
ถ้าไม่แน่ใจว่า Expression ที่เขียนถูกต้องหรือไม่ ให้ใช้ Cron Expression Generator ของ AsiaGB ที่ช่วยสร้างและตรวจสอบ Expression ได้ฟรีโดยไม่ต้องจำ Syntax เอง
ข้อผิดพลาดที่พบบ่อยหลังปิด WP-Cron
หลังจากปิด WP-Cron และตั้ง Server Cron แล้ว อาจพบปัญหาต่อไปนี้หากตั้งค่าไม่ถูกต้อง
1. Scheduled Post ไม่ถูกเผยแพร่
สาเหตุ: Server Cron ไม่ได้ทำงานเนื่องจาก Path ของ PHP ผิด ให้ตรวจสอบด้วยคำสั่ง which php บน SSH เพื่อหา Path ที่ถูกต้อง บน Server บางตัวต้องใช้ php8.1 หรือ php8.2 แทน php เฉย ๆ
2. Cron Email น่ารำคาญส่งมาทุก 5 นาที
เพิ่ม > /dev/null 2>&1 ต่อท้ายคำสั่ง Cron เพื่อ redirect output ทิ้ง หรือตั้งค่า MAILTO="" เป็นบรรทัดแรกของ Crontab
# ตัวอย่าง Crontab ที่ไม่ส่ง Email
MAILTO=""
*/5 * * * * php /home/username/domains/example.com/public_html/wp-cron.php > /dev/null 2>&1
3. Plugin Backup ไม่ทำงานตามเวลา
Plugin อย่าง UpdraftPlus หรือ All-in-One WP Migration ที่ใช้ WordPress Cron เป็นตัวกำหนดเวลา Backup จะยังทำงานได้ผ่าน Server Cron ที่ตั้งไว้ใน Step ก่อนหน้า เพราะงานเหล่านั้นอยู่ใน WordPress Cron Queue อยู่แล้ว Server Cron แค่รัน wp-cron.php ให้ตรงเวลากว่าเดิมเท่านั้น
เคล็ดลับ: ถ้าใช้ Plugin Backup ที่มี Cron Schedule เป็นของตัวเอง เช่น WP-CLI หรือ BackWPup ให้ตั้ง Schedule ให้ตรงกันเพื่อหลีกเลี่ยงการทำงานซ้ำซ้อน และแนะนำให้ Backup ช่วงที่ Traffic ต่ำที่สุด เช่น 01:00–04:00 น.
WP-Cron บน WordPress Multisite
สำหรับเว็บที่ใช้ WordPress Multisite การปิด WP-Cron ทำงานในลักษณะเดียวกัน แต่มีจุดแตกต่างสำคัญที่ควรทราบ
- ต้องเพิ่ม
define('DISABLE_WP_CRON', true);ในwp-config.phpของ Main Site เท่านั้น จะมีผลกับทุก Sub-site ในระบบ - Server Cron จะต้องรัน
wp-cron.phpของ Main Site เท่านั้น เพราะ WordPress จะจัดการ Cron Queue ของทุก Sub-site ให้เอง - ถ้าแต่ละ Sub-site มี Domain ต่างกัน (Domain Mapping) ให้ตรวจสอบว่า wp-cron.php สามารถเข้าถึงได้ผ่าน Domain หลัก
- ใช้ Plugin WP Crontrol บน Network Admin เพื่อดู Cron Event ของทุก Sub-site รวมกัน
สรุปสำหรับ Multisite: แก้ wp-config.php ครั้งเดียว ตั้ง Cron Job บน Server ครั้งเดียว ทุก Sub-site ได้รับประโยชน์พร้อมกัน ไม่ต้องตั้งค่าแยกต่างหากสำหรับแต่ละ Sub-site
ทางเลือก: Trigger ผ่าน wget หรือ curl
ถ้าใช้ PHP CLI ไม่ได้หรือต้องการวิธีอื่น สามารถใช้ wget หรือ curl เรียก wp-cron.php ผ่าน HTTP แทนได้:
# ใช้ wget
wget -q -O - https://yourdomain.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1
# หรือใช้ curl
curl -s https://yourdomain.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1
แนะนำ PHP CLI มากกว่า HTTP: การใช้ PHP CLI ตรงๆ เร็วกว่าและไม่ผ่าน Web Server ทำให้ไม่กินทรัพยากร Network และไม่มีค่าใช้จ่ายด้าน HTTP Overhead เหมาะสำหรับ Server ที่มี Load สูง
ตรวจสอบว่า Cron Job ทำงานถูกต้อง
หลังตั้งค่าแล้ว ให้ตรวจสอบด้วย Plugin WP Crontrol (ฟรี) ที่ช่วย:
- ดู Queue ของ Scheduled Tasks ทั้งหมดใน WordPress
- รัน Task แบบ Manual เพื่อทดสอบ
- แก้ไข Schedule และเพิ่ม Custom Event ได้
ติดตั้งแล้วไปที่ Tools → Cron Events จะเห็นรายการงานทั้งหมดพร้อมเวลาที่จะรันครั้งต่อไป ถ้า Cron Job Server ทำงานสม่ำเสมอ ค่า "Next Run" จะอัพเดทตามที่กำหนด
สรุป: WP-Cron vs Server Cron
| ด้าน | WP-Cron (ค่าเริ่มต้น) | Server Cron (แนะนำ) |
|---|---|---|
| ทริกเกอร์ | ทุก HTTP Request | ตรงเวลาที่กำหนด |
| ความแม่นยำ | ขึ้นกับ Traffic | แม่นยำสม่ำเสมอ |
| ผลต่อ UX | ทำให้เว็บช้าเป็นครั้งคราว | ไม่กระทบ Response Time |
| เว็บ Traffic ต่ำ | งานอาจล่าช้า/ไม่ทำงาน | ทำงานตามเวลาเสมอ |
| การตั้งค่า | ไม่ต้องตั้งอะไร (ใช้ได้เลย) | ตั้งครั้งเดียว ใช้ได้ตลอด |
ความปลอดภัยของ wp-cron.php — ควรป้องกันอย่างไร?
เมื่อตั้ง Server Cron แล้ว ไฟล์ wp-cron.php ยังคงเข้าถึงได้ผ่าน HTTP สาธารณะ ซึ่งอาจถูก Abuse เพื่อทำ DoS (โจมตีโดยสร้าง Request จำนวนมาก) หรือ Trigger งานโดยไม่ได้รับอนุญาต แนะนำให้ป้องกันเพิ่มเติมดังนี้
วิธีที่ 1: Block ด้วย .htaccess (Apache)
เพิ่มบรรทัดต่อไปนี้ใน .htaccess ที่ root ของ WordPress เพื่อปิดการเข้าถึงจากภายนอก แต่ยังอนุญาต Cron Job ของ Server ที่รันจาก Localhost
# ปิดการเข้าถึง wp-cron.php จากภายนอก
<Files wp-cron.php>
Order allow,deny
Deny from all
Allow from 127.0.0.1
</Files>
วิธีที่ 2: Block ด้วย Nginx
# ใน Server Block ของ Nginx
location = /wp-cron.php {
allow 127.0.0.1;
deny all;
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
เมื่อ Block จาก Public แล้ว Cron Job ของ Server ที่รันด้วย PHP CLI โดยตรงยังทำงานได้ตามปกติ เพราะไม่ผ่าน HTTP เลย
หมายเหตุสำคัญ: ถ้าใช้วิธี HTTP (wget/curl) ใน Cron Job ให้แก้เป็น Localhost IP แทน เช่น curl -s http://127.0.0.1/wp-cron.php?doing_wp_cron -H "Host: yourdomain.com" เพื่อหลีกเลี่ยงการถูก Block โดย Firewall ตัวเองด้วย
WP-CLI: อีกทางเลือกสำหรับ Cron Job บน Server
ถ้า Hosting รองรับ WP-CLI (WordPress Command Line Interface) สามารถใช้คำสั่ง wp cron event run --due-now แทน wp-cron.php ได้ ซึ่งให้ข้อดีหลายอย่างกว่า
- รันเฉพาะงานที่ถึงกำหนดเวลา ไม่ใช่รัน wp-cron.php ทั้งไฟล์
- ดู Log ได้ชัดเจนว่าแต่ละ Event ทำงานสำเร็จหรือล้มเหลว
- สามารถรัน Single Event เพื่อ Debug ได้
- ไม่ต้องใช้ HTTP Request เลย ปลอดภัยกว่า
# Cron Job ด้วย WP-CLI (แทนที่ php wp-cron.php)
*/5 * * * * /usr/local/bin/wp cron event run --due-now \
--path=/home/username/domains/example.com/public_html \
--quiet > /dev/null 2>&1
| วิธีรัน Cron | ข้อดี | ข้อจำกัด |
|---|---|---|
| PHP CLI (wp-cron.php) | ใช้ได้ทุก Hosting, ตั้งง่าย | ต้องระบุ PHP Path ให้ถูกต้อง |
| WP-CLI | Log ละเอียด, Debug ง่าย | ต้องติดตั้ง WP-CLI บน Server ก่อน |
| curl/wget (HTTP) | ไม่ต้องใช้ Shell Access | ผ่าน HTTP Overhead, IP ต้องอนุญาต |
แก้ปัญหา Cron Job ที่ไม่ทำงานด้วย Log
หาก Cron Job ตั้งค่าแล้วแต่งานไม่ทำงานตามเวลา ให้ตรวจสอบ Log ของ Cron Daemon บน Server ก่อนเป็นอันดับแรก เพราะ Error ส่วนใหญ่มาจาก Path ผิด, Permission ไม่เพียงพอ หรือ Environment Variable ขาดหาย
# ดู Cron Log บน CentOS/AlmaLinux
tail -f /var/log/cron
# ดู Cron Log บน Ubuntu/Debian
grep CRON /var/log/syslog | tail -50
# ทดสอบ Cron Command ด้วยตัวเอง
php /home/username/domains/example.com/public_html/wp-cron.php
echo $? # ควรได้ 0 (success)
ถ้า Cron ทำงานได้ใน Shell แต่ไม่ทำงานใน Cron Job ปัญหามักมาจาก Environment Variable เช่น PATH ที่ใน Cron Environment แคบกว่า Shell ปกติ แก้โดยใส่ Full Path ทุกที่
# ตัวอย่าง Cron ที่ใช้ Full Path ทั้งหมด
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
*/5 * * * * /usr/bin/php8.2 /home/username/domains/example.com/public_html/wp-cron.php > /dev/null 2>&1
Tip สุดท้าย: หลังตั้งค่าทุกอย่างเสร็จแล้ว รอ 10–15 นาที แล้วตรวจสอบ Plugin WP Crontrol อีกครั้ง ถ้า "Next Run" ของ Event ต่างๆ เปลี่ยนไปตาม Schedule ที่กำหนด แสดงว่า Server Cron ทำงานถูกต้องสมบูรณ์แล้ว
Hosting WordPress รองรับ Cron Job แบบ Server-side
AsiaGB Hosting พร้อม DirectAdmin ที่มี Cronjobs ในตัว ตั้ง Schedule ได้ทุกรูปแบบ รองรับ PHP CLI และ curl เริ่มต้น 500 บาท/ปี
ดูแพ็กเกจ Hosting →