ปิด WP-Cron ใช้ Server Cron แทน

ถ้าคุณสังเกตว่าเว็บ WordPress ช้าเป็นครั้งคราวโดยไม่มีสาเหตุชัดเจน หรือ Server Load พุ่งสูงในช่วงสั้นๆ สาเหตุหนึ่งที่มักถูกมองข้ามคือ WP-Cron — ระบบ Scheduled Task ของ WordPress ที่ทำงานในลักษณะที่ไม่มีประสิทธิภาพ

บทความนี้อธิบายว่า WP-Cron ทำงานอย่างไร ทำไมถึงก่อปัญหา และวิธีแก้ไขที่ถูกต้องด้วยการตั้ง Server Cron Job จริงบน DirectAdmin

WP-Cron คืออะไร?

WP-Cron คือระบบ Task Scheduling ใน WordPress ใช้สำหรับงานอัตโนมัติต่างๆ เช่น:

ปัญหาหลักของ 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 ยังทำงานอัตโนมัติได้:

  1. Login เข้า DirectAdmin
  2. ไปที่ Advanced Features → Cronjobs
  3. คลิก Create New Cronjob
  4. กำหนด Schedule เป็น ทุก 5 นาที (แนะนำ)
  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 ทำงานในลักษณะเดียวกัน แต่มีจุดแตกต่างสำคัญที่ควรทราบ

สรุปสำหรับ 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 (ฟรี) ที่ช่วย:

ติดตั้งแล้วไปที่ 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 ได้ ซึ่งให้ข้อดีหลายอย่างกว่า

# 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-CLILog ละเอียด, 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 →