SSD Nodes Learn Hosting plans →
راهنماها Matt Connorتوسط Matt Connor · به‌روزرسانی شده 2026-08-27

غیرفعال کردن WP-Cron و تنظیم System Cron در وردپرس

با غیرفعال کردن WP-Cron و استفاده از system cron در وردپرس، از اجرای نامنظم وظایف جلوگیری کنید. با استفاده از WP-CLI و تنظیم دقیق crontab، زمان‌بندی دقیق را تضمین کنید.

WP-Cron چیست و چرا system cron جایگزین آن می‌شود

WP-Cron زمان‌بند وظایف داخلی در WordPress است که تنها زمانی اجرا می‌شود که شخصی درخواستی برای یک صفحه ارسال کند. هیچ فرآیندی در داخل WordPress به‌صورت خودکار بیدار نمی‌شود. در هر درخواستی که از حافظه کش (cache) پاسخ داده نشود، WordPress فهرستی از وظایف زمان‌بندی‌شده را می‌خواند و اگر موعد یکی از آن‌ها فرا رسیده باشد، یک درخواست HTTP دوم به آدرس /wp-cron.php برای خود ارسال می‌کند تا آن کار را انجام دهد. انتقال این وظیفه به system cron باعث می‌شود که کار مورد نظر در یک زمان‌بندی ثابت و قابل پیش‌بینی اجرا شود، فارغ از اینکه سایت در آن لحظه هزار بازدیدکننده داشته باشد یا هیچ بازدیدی نداشته باشد.

دو خط کد، کار اصلی را انجام می‌دهند: یک ثابت (constant) در wp-config.php و یک ورودی در crontab. هر چیز دیگری که در این راهنما آمده، جزئیاتی است که آن دو خط به شما نمی‌گویند. اینکه وظیفه باید با چه کاربری اجرا شود، چگونه ثابت کنید که رویدادهای زمان‌بندی‌شده واقعاً اجرا شده‌اند، و سه روشی که این تنظیمات بدون نمایش هیچ خطایی در سایت، با شکست مواجه می‌شوند.

مثال‌ها از /srv/www/example.com به عنوان دایرکتوری WordPress و از www-data به عنوان کاربر وب‌سرور استفاده می‌کنند. در همه جا، مسیرها و کاربر مخصوص به خود را جایگزین کنید.

کدام بازدیدکننده باعث اجرای cron در یک سایت پربازدید می‌شود

هر درخواست بدون کش (uncached)، هزینه بررسی cron را پرداخت می‌کند. وردپرس گزینه cron را بارگذاری کرده، زمان‌بندی‌ها را مقایسه می‌کند و در صورت رسیدن موعد، spawn_cron() را فراخوانی می‌کند که یک درخواست loopback غیرمسدودکننده به /wp-cron.php می‌فرستد. بازدیدکننده منتظر نتیجه نمی‌ماند، اما یک worker در PHP منتظر می‌ماند. در یک VPS کوچک که از PHP-FPM با pm.max_children = 5 استفاده می‌کند، یک job زمان‌بندی‌شدهٔ کند می‌تواند یک‌پنجم ظرفیت PHP شما را برای مدتی طولانی اشغال کند؛ این اتفاق معمولاً در شلوغ‌ترین دقیقه سایت رخ می‌دهد، زیرا در آن زمان بیشترین بارگذاری صفحه انجام می‌شود.

وردپرس تعداد تکرارها را محدود می‌کند. این سیستم یک قفل با طول عمر WP_CRON_LOCK_TIMEOUT (به‌طور پیش‌فرض 60 ثانیه) ایجاد می‌کند تا بازدیدکنندگان همزمان، هر کدام یک اجرای جداگانه را آغاز نکنند. این قفل از تکرار جلوگیری می‌کند، اما کار را از مسیر اصلی درخواست خارج نمی‌کند.

پیش از آنکه تصمیم بگیرید آیا این موضوع اهمیت دارد یا خیر، بررسی کنید که این فرایند چند بار روی سرور شما اجرا می‌شود. هر درخواست loopback در لاگ دسترسی وب‌سرور ظاهر می‌شود:

sudo grep -c 'wp-cron.php' /var/log/nginx/access.log

آپاچی در عوض در /var/log/apache2/access.log می‌نویسد. تعداد هزاران درخواست در روز یک هزینه واقعی است؛ این عددی است که باید روی سرور خودتان اندازه‌گیری کنید، نه اینکه در یک مقاله بخوانید؛ درست همان‌طور که پیش و پس از هر تغییر دیگری، یک VPS را بنچمارک می‌کنید.

کش کردن، وضعیت را تغییر می‌دهد. اگر یک کش صفحه، اکثر درخواست‌ها را به صورت HTML ایستا پاسخ دهد، PHP برای آن درخواست‌ها اجرا نمی‌شود و در نتیجه بررسی cron هرگز اتفاق نمی‌افتد. یک سایت پربازدید که به‌شدت کش شده باشد، رفتاری مشابه سایت‌های کم‌ترافیک (که در ادامه آمده) خواهد داشت.

چرا بازدیدکنندگان باعث اختلال در cron در سایت‌های کم‌بازدید می‌شوند

وقتی بازدیدکننده‌ای وجود نداشته باشد، cron هم اجرا نمی‌شود. سایتی که در روز تنها چند بازدید دارد، کارهای زمان‌بندی‌شده‌اش را هم فقط چند بار در روز و در لحظات تصادفی که بازدیدها انجام می‌شوند، اجرا می‌کند.

علائم این مشکل همگی مشابه هستند. پستی که برای ساعت 09:00 زمان‌بندی شده است، در لیست پست‌ها با وضعیت Missed schedule باقی می‌ماند تا زمانی که شخصی صفحه‌ای را بارگذاری کند. افزونه‌های پشتیبان‌گیری، کارهای شبانه را نادیده می‌گیرند. بررسی‌های به‌روزرسانی با تأخیر انجام می‌شوند، بنابراین داشبورد چیزی برای به‌روزرسانی نشان نمی‌دهد، در حالی که یک نسخه امنیتی جدید منتشر شده است. ایمیل‌های سفارش، اعلان‌های تمدید و هشدارهای انقضا با تأخیر ارسال می‌شوند.

هیچ‌کدام از این موارد خطایی را در لاگ ثبت نمی‌کنند. از دیدگاه WordPress، کار موردنظر هرگز دیر نشده است، زیرا اصلاً شروع نشده بود.

گام 1: غیرفعال کردن محرک بازدیدکننده در wp-config.php

فایل /srv/www/example.com/wp-config.php را باز کنید و ثابت زیر را به آن اضافه کنید:

define( 'DISABLE_WP_CRON', true );

این ثابت را بالای خطی که شامل /* That's all, stop editing! Happy publishing. */ است قرار دهید؛ زیرا خط بلافاصله بعد از آن کامنت، نیازمند wp-settings.php است و wp-settings.php جایی است که وردپرس بررسی cron را به init متصل می‌کند. اگر ثابت پس از آن require تعریف شود، خیلی دیر اعمال شده و هیچ تغییری ایجاد نمی‌کند؛ در نتیجه فایل از نظر ظاهری درست به نظر می‌رسد اما محرک همچنان به اجرا ادامه می‌دهد.

تأیید کنید که این خط در جای درستی قرار دارد:

grep -n "DISABLE_WP_CRON\|stop editing" /srv/www/example.com/wp-config.php

این ثابت مانع از زمان‌بندی رویدادها نمی‌شود. افزونه‌ها همچنان وظایف را دقیقاً مانند قبل به صف اضافه می‌کنند. این دستور فقط مانع از اجرای صف توسط بارگذاری صفحات می‌شود؛ به این معنی که صف تا زمانی که گام 3 را به پایان نرسانید، هرگز اجرا نخواهد شد.

این کار همچنین مانع از درخواست‌های مستقیم به /wp-cron.php نمی‌شود. هر کسی همچنان می‌تواند آن URL را درخواست کند و این معمولاً بی‌خطر است، زیرا فایل فقط کارهایی را اجرا می‌کند که موعدشان فرا رسیده باشد. مسدود کردن آن در پیکربندی وب‌سرور اختیاری است. اگر آن را مسدود کنید، مکانیزم جایگزین curl که در انتهای این راهنما آمده است نیز از کار می‌افتد.

گام 2: نصب WP-CLI

ابزار WP-CLI رابط خط فرمان رسمی برای WordPress است. این ابزار به باینری خط فرمان PHP نیاز دارد که بسته‌ای مجزا از ماژول PHP وب‌سرور است.

php -v
sudo apt install -y php-cli

ابزار WP-CLI را از طریق فایل phar نصب کنید؛ این روشی است که راهنمای نصب رسمی توصیه می‌کند:

cd /tmp
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
php wp-cli.phar --info
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
wp --info

دستور php wp-cli.phar --info مسیر باینری PHP، نسخه PHP و نسخه WP-CLI را چاپ می‌کند. اگر هر سه مورد نمایش داده شوند، فایل phar به‌درستی کار می‌کند. تا اوت 2026، راهنمای نصب، نسخه PHP 7.2.24 را به عنوان حداقل نیاز اعلام کرده است و از آنجا که Ubuntu 24.04 با PHP 8.3 عرضه می‌شود، سرورهای امروزی به‌راحتی از این محدودیت عبور می‌کنند. برای به‌روزرسانی در آینده از sudo wp cli update استفاده کنید.

ابزار WP-CLI را همیشه با کاربر سایت اجرا کنید و هرگز از کاربر root استفاده نکنید:

sudo -u www-data /usr/local/bin/wp --path=/srv/www/example.com core version

ابزار WP-CLI در صورت اجرا با کاربر root از شروع کار خودداری می‌کند:

Error: YIKES! It looks like you're running this as root.

این ابزار دستور --allow-root را پیشنهاد می‌دهد. در اینجا از آن استفاده نکنید. دلیل این موضوع در اولین حالت خطا در ادامه توضیح داده شده است.

همچنین توجه داشته باشید که sudo -u www-data -i کار نمی‌کند، زیرا shell ورود آن حساب کاربری /usr/sbin/nologin است و شما با خطای This account is currently not available. مواجه می‌شوید. ارسال مستقیم دستور به sudo -u باعث نادیده گرفتن shell ورود می‌شود و در نتیجه دستور به‌درستی اجرا می‌گردد.

اکنون تأیید کنید که WordPress ثابت (constant) تعریف‌شده در گام 1 را شناسایی می‌کند:

sudo -u www-data /usr/local/bin/wp --path=/srv/www/example.com eval 'var_dump( DISABLE_WP_CRON );'

این دستور مقدار bool(true) را چاپ می‌کند. بروز خطای مهلک (fatal error) در مورد ثابت تعریف‌نشده به این معناست که خط define() اجرا نمی‌شود، که معمولاً به این دلیل است که آن خط پس از دستور require قرار گرفته است.

گام 3: افزودن ورودی cron با کاربر صحیح

کاربر صحیح، همان کاربری است که مالک فایل‌هایی است که PHP می‌نویسد. هر دو سمت را بررسی کنید:

stat -c '%U %G' /srv/www/example.com/wp-content/uploads
grep -E '^(user|group) = ' /etc/php/8.3/fpm/pool.d/www.conf

در نصب پیش‌فرض Ubuntu، پاسخ هر دو www-data است. اگر برای سایت خود یک pool اختصاصی PHP-FPM با کاربر مخصوص به آن تعریف کرده‌اید—که در تنظیمات هر سایت روی پشته LAMP در Ubuntu 24.04 معمولاً به همین صورت انجام می‌شود—از همان کاربر برای تمام مراحل زیر استفاده کنید.

یک دایرکتوری لاگ بسازید که آن کاربر اجازه نوشتن در آن را داشته باشد:

sudo install -d -o www-data -g www-data -m 750 /var/log/wp-cron

crontab همان کاربر را ویرایش کنید:

sudo crontab -u www-data -e

این خط را اضافه کنید:

*/5 * * * * /usr/bin/flock -n /run/lock/wp-cron-example.lock /usr/local/bin/wp --path=/srv/www/example.com cron event run --due-now >> /var/log/wp-cron/example.log 2>&1

بخش به بخش بررسی می‌کنیم: */5 دستور را هر 5 دقیقه اجرا می‌کند. flock -n از یک فایل قفل (lock file) استفاده می‌کند و اگر اجرای قبلی هنوز در حال پردازش باشد، بلافاصله متوقف می‌شود. /usr/local/bin/wp مسیر مطلق (absolute path) است که cron به آن نیاز دارد. --path اجازه می‌دهد دستور از هر دایرکتوری کاری اجرا شود. --due-now فقط رویدادهایی را اجرا می‌کند که زمانشان فرا رسیده است، نه تمام رویدادهای موجود در صف. تغییر مسیر (redirect) خروجی‌های عادی و خطاها را به فایلی می‌فرستد که می‌توانید آن را بخوانید.

این تغییر مسیر در عمل اختیاری نیست. cron خروجی دستورات را به کاربر مربوطه ایمیل می‌کند؛ اکثر ایمیج‌های VPS فاقد یک عامل انتقال ایمیل (MTA) هستند، بنابراین cron عبارت (CRON) info (No MTA installed, discarding output) را لاگ کرده و خروجی را حذف می‌کند. وجود یک فایل، مستندات را حفظ می‌کند.

فایل ذخیره‌شده را بررسی کنید:

sudo crontab -u www-data -l

برای چندین سایت، برای هر کدام یک خط با دقایق متفاوت بنویسید تا همگی همزمان شروع نشوند:

*/5 * * * * /usr/bin/flock -n /run/lock/wp-cron-one.lock /usr/local/bin/wp --path=/srv/www/one.example.com cron event run --due-now >> /var/log/wp-cron/one.log 2>&1
2-59/5 * * * * /usr/bin/flock -n /run/lock/wp-cron-two.lock /usr/local/bin/wp --path=/srv/www/two.example.com cron event run --due-now >> /var/log/wp-cron/two.log 2>&1

این لاگ تا ابد رشد می‌کند مگر اینکه آن را چرخش (rotate) دهید. فایل /etc/logrotate.d/wp-cron را بنویسید:

/var/log/wp-cron/*.log {
    weekly
    rotate 4
    missingok
    notifempty
    compress
    create 640 www-data www-data
}

بررسی کنید که فایل بدون اعمال تغییرات، پارس شود: sudo logrotate --debug /etc/logrotate.d/wp-cron.

گام 4: تأیید اجرای واقعی رویدادهای زمان‌بندی‌شده

ذخیره شدن موفقیت‌آمیز یک خط در crontab به معنای اجرای آن نیست. از ارزان‌ترین بررسی شروع کنید و به سراغ روشی بروید که وضعیت را به‌طور قطعی مشخص می‌کند.

ابتدا، آیا cron دستور را اجرا کرده است؟ Cron لاگ‌های خود را در journal و تحت unit اختصاصی خود ثبت می‌کند:

journalctl -u cron.service --since "15 min ago" | grep wp

یک ورودی سالم به این شکل است (برچسب زمانی و نام میزبان از ابتدای آن حذف شده است):

CRON[24913]: (www-data) CMD (/usr/bin/flock -n /run/lock/wp-cron-example.lock /usr/local/bin/wp --path=/srv/www/example.com cron event run --due-now >> /var/log/wp-cron/example.log 2>&1)

این خط نشان می‌دهد که cron دستور شما را با کاربر www-data اجرا کرده است. این خروجی هیچ اطلاعاتی درباره موفقیت‌آمیز بودن اجرای دستور نمی‌دهد.

دوم، آیا WordPress چیزی اجرا کرده است؟ فایل لاگ را بخوانید:

sudo tail -n 20 /var/log/wp-cron/example.log

ابزار WP-CLI برای هر رویداد یک خط و در نهایت یک جمع‌بندی چاپ می‌کند:

Executed the cron event 'wp_version_check' in 0.418s.
Success: Executed a total of 2 cron events.

خطاها نیز در همین فایل ثبت می‌شوند که هدف اصلی استفاده از 2>&1 است. در بیشتر دفعات اجرا، رویداد معوقه‌ای وجود ندارد و خروجی بسیار کم خواهد بود؛ بنابراین فایل را پس از زمانی بخوانید که می‌دانید رویدادی در انتظار اجرا بوده است.

سوم، اجرای کامل (end-to-end) را اثبات کنید. یک رویداد نشانگر (marker event) زمان‌بندی کنید و ناپدید شدن آن را مشاهده کنید:

sudo -u www-data /usr/local/bin/wp --path=/srv/www/example.com cron event schedule wp_cli_cron_check now
sudo -u www-data /usr/local/bin/wp --path=/srv/www/example.com cron event list --fields=hook,next_run_relative --format=csv | grep wp_cli_cron_check

یک بازه زمانی صبر کنید و سپس دستور لیست کردن را دوباره اجرا کنید. آن hook حذف شده است، زیرا یک رویداد یک‌بارمصرف پس از اجرا از صف پاک می‌شود. هیچ افزونه‌ای callback برای آن نام hook ثبت نکرده است، بنابراین اجرای آن تأثیر دیگری بر سایت ندارد. اگر پس از دو بازه زمانی، hook همچنان در لیست باشد، یعنی صف پردازش نمی‌شود. دو بررسی اول به شما می‌گویند که مشکل از cron است یا WP-CLI.

برای این کار از wp cron test استفاده نکنید. این دستور بررسی می‌کند که آیا قابلیت spawning با بازدیدکننده کار می‌کند یا خیر، و زمانی که DISABLE_WP_CRON فعال باشد، خطا می‌دهد. در سروری که به‌درستی پیکربندی شده باشد، این خطا خروجی مورد انتظار است، نه یک نقص فنی.

جایگزین systemd timer

اگر سایر وظایف زمان‌بندی‌شدهٔ سرور شما در حال حاضر به صورت systemd services and timers اجرا می‌شوند، وردپرس را نیز به همان‌جا منتقل کنید. در این صورت، هر اجرا در systemctl list-timers نمایش داده می‌شود و خروجی به‌جای فایلی که نیاز به چرخش (rotate) دارد، مستقیماً به journal ارسال می‌گردد.

فایل /etc/systemd/system/wp-cron-example.service را بنویسید:

[Unit]
Description=Run due WordPress cron events for example.com

[Service]
Type=oneshot
User=www-data
Group=www-data
ExecStart=/usr/local/bin/wp --path=/srv/www/example.com cron event run --due-now

سپس /etc/systemd/system/wp-cron-example.timer را ایجاد کنید:

[Unit]
Description=Run WordPress cron for example.com every 5 minutes

[Timer]
OnCalendar=*:0/5
AccuracySec=30s
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now wp-cron-example.timer
systemctl list-timers wp-cron-example.timer
journalctl -u wp-cron-example.service -n 20

Systemd به‌طور هم‌زمان دو نسخه از یک سرویس مشابه را اجرا نمی‌کند، بنابراین این نسخه نیازی به flock ندارد. گزینه Persistent=true باعث می‌شود اگر در زمان خاموش بودن دستگاه اجرایی از دست رفته باشد، سیستم آن را جبران کند؛ کاری که یک ورودی crontab قادر به انجام آن نیست.

یکی از دو روش crontab یا timer را انتخاب کنید. اجرای هم‌زمان هر دو روی یک سایت به این معناست که صف وظایف دو بار تخلیه می‌شود و اجرای تکراری کارهایی مانند ارسال ایمیل یا پردازش سفارش برای مشتریان شما قابل مشاهده خواهد بود.

چرا cron job نباید با کاربر root اجرا شود

این اولین مورد از سه روشی است که پیکربندی در آن شکست می‌خورد. اگر job را در crontab کاربر root قرار دهید، WP-CLI پیش از انجام هر کاری متوقف می‌شود:

Error: YIKES! It looks like you're running this as root.

صف پردازش (queue) هرگز اجرا نمی‌شود و اگر خروجی را redirect نکرده باشید، هرگز پیام خطا را نخواهید دید. راه‌حل خطرناک، افزودن --allow-root است، زیرا در این صورت هر فایلی که یک افزونه در طول آن اجرا می‌نویسد، متعلق به root خواهد بود. درخواست وب بعدی که با کاربر www-data اجرا می‌شود، نمی‌تواند در آن دایرکتوری‌ها بنویسد و سایت شروع به نمایش خطاهایی مانند این می‌کند:

Unable to create directory wp-content/uploads/2026/08. Is its parent directory writable by the server?

مالکیت فایل‌ها را اصلاح کنید و سپس job را منتقل نمایید:

sudo chown -R www-data:www-data /srv/www/example.com/wp-content

فایل crontab کاربر root و crontab کاربر www-data دو فایل مجزا هستند، بنابراین حذف خط از یکی، دیگری را تغییر نمی‌دهد. هر دو را بررسی کنید:

sudo crontab -u root -l
sudo crontab -u www-data -l

چرا cron گزارش wp: not found می‌دهد

این دومین خرابی است. Cron به کارهای کاربر یک PATH بسیار کوتاه می‌دهد، /usr/bin:/bin. ابزار WP-CLI در /usr/local/bin نصب می‌شود که در آن لیست نیست. کار شروع می‌شود، در کسری از ثانیه شکست می‌خورد و لاگ فقط یک خط را نشان می‌دهد:

/bin/sh: 1: wp: not found

به‌جای حدس‌زدن، محیط اجرای cron را خودتان ببینید. یک خط موقت اضافه کنید:

*/5 * * * * env > /tmp/cron-env.txt 2>&1

پس از یک بازه زمانی، /tmp/cron-env.txt را بخوانید و سپس آن خط را حذف کنید. مقدار PATH= در آن فایل دقیقاً همان چیزی است که کار شما دریافت می‌کند.

دو راه برای رفع این مشکل وجود دارد. از مسیر مطلق /usr/local/bin/wp استفاده کنید، همان‌طور که در مرحله 3 گفته شد. یا PATH را یک‌بار در بالای crontab، قبل از تمام خطوط مربوط به کارها تنظیم کنید:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

همین تله یک سطح پایین‌تر هم وجود دارد. فایل wp phar با #!/usr/bin/env php شروع می‌شود، بنابراین shell باید بتواند php را نیز پیدا کند. اگر PHP خارج از /usr/bin قرار داشته باشد (که در بیلد‌های سفارشی و بیلد‌های کنترل پنل اتفاق می‌افتد)، با این خطا مواجه می‌شوید:

/usr/bin/env: 'php': No such file or directory

در این حالت، مفسر را به‌صورت صریح فراخوانی کنید، برای مثال /usr/local/bin/php /usr/local/bin/wp --path=/srv/www/example.com cron event run --due-now.

چرا بازهٔ زمانی یک‌دقیقه‌ای مشکل اصلی را بازتولید می‌کند

این سومین شکست است. * * * * * نسبت به پنج دقیقه امن‌تر به نظر می‌رسد، اما در یک سایت پربازدید، شما را به نقطهٔ شروع بازمی‌گرداند. اگر اجرای یک پردازش طولانی‌تر از بازهٔ زمانی باشد، اجرای بعدی در حالی آغاز می‌شود که اولی هنوز در حال انجام است. ده دقیقه بعد، ده پردازش PHP وجود خواهد داشت که هر کدام حافظه و اتصال دیتابیس اختصاصی خود را اشغال کرده‌اند.

برای مشاهدهٔ مستقیم انباشتگی پردازش‌ها:

ps -eo etimes,user,args | grep '[c]ron event run'

etimes سن پردازش به ثانیه است. یک خط نشان‌دهنده وضعیت سالم است. چندین خط با سن بسیار بیشتر از بازهٔ زمانی شما، به این معنی است که اجراها در حال انباشته‌شدن هستند و در یک VPS کوچک، این وضعیت به خطای Too many connections در MySQL یا کشته‌شدن PHP توسط هسته (kernel) برای بازپس‌گیری حافظه منجر می‌شود که می‌توانید آن را با sudo dmesg -T | grep -i 'killed process' تأیید کنید.

ابزار WP-CLI فراخوانی‌های رویداد (event callbacks) را مستقیماً اجرا می‌کند و به جای درخواست wp-cron.php، از آن استفاده نمی‌کند؛ بنابراین قفل 60 ثانیه‌ای که وردپرس برای جلوگیری از اجرای همزمان استفاده می‌کند، در اینجا اعمال نمی‌شود. flock -n در ورودی مرحله 3 همان چیزی است که اکنون از هم‌پوشانی جلوگیری می‌کند. یک اجرای نادیده‌گرفته‌شده (skipped run) طبق طراحی، بلافاصله و بدون خروجی متوقف می‌شود. هم‌پوشانی مشکلی است که باید در crontab حل کنید، نه مشکلی که هستهٔ سیستم‌عامل برای شما حل کند: حتی جای‌گذاری وظایف با آگاهی از کش که در هسته لینوکس 7.2 اضافه شد فقط تصمیم می‌گیرد که پردازش روی کدام هسته قرار بگیرد، نه اینکه چند نمونه از آن را شروع کرده‌اید.

بازهٔ زمانی را بر اساس کوتاه‌ترین زمان‌بندی که واقعاً به آن وابسته‌اید انتخاب کنید و ابتدا مدت زمان یک اجرا را اندازه بگیرید:

time sudo -u www-data /usr/local/bin/wp --path=/srv/www/example.com cron event run --due-now

پنج دقیقه یک پیش‌فرض معقول است: پستی که برای ساعت 09:00 زمان‌بندی شده، تا ساعت 09:05 منتشر می‌شود. پانزده دقیقه برای سایتی که هیچ مورد حساس به زمانی ندارد، مناسب است. یک دقیقه مختص فروشگاه‌ها و افزونه‌های مبتنی بر صف است که واقعاً به آن نیاز دارند، و تنها زمانی از آن استفاده کنید که مطمئن باشید یک اجرا در عرض چند ثانیه به پایان می‌رسد.

اگر نمی‌توانید WP-CLI را نصب کنید

برخی از میزبان‌ها ابزارهای shell را مسدود می‌کنند. یک درخواست HTTP ساده به wp-cron.php همان صف را اجرا می‌کند، با این تفاوت که از کل پشته وب عبور می‌کند:

*/5 * * * * /usr/bin/curl -sS --max-time 120 "https://example.com/wp-cron.php?doing_wp_cron" > /dev/null

آنچه به‌طور مشخص از دست می‌دهید:

  • اجرای عملیات توسط زمان‌های پایان (timeouts) وب‌سرور و PHP-FPM محدود می‌شود، بنابراین ممکن است یک کار طولانی در میانه راه قطع شود.
  • گواهی باید معتبر باشد، در غیر این صورت curl با خطای SSL certificate problem متوقف می‌شود؛ بنابراین تمدید گواهی‌ها را با Certbot روی nginx فعال نگه دارید.
  • کش صفحه نباید wp-cron.php را کش کند، در غیر این صورت درخواست‌های cron یک پاسخ کش‌شده دریافت می‌کنند و هیچ کاری انجام نمی‌شود.
  • شما هیچ خروجی به ازای هر رویداد دریافت نمی‌کنید، بنابراین تنها مدرک اجرای یک کار، تأثیری است که بر جای گذاشته است.

-sS باعث می‌شود curl در صورت موفقیت ساکت بماند اما همچنان خطاها را چاپ کند، که این دقیقاً همان چیزی است که در یک cron job به آن نیاز دارید.

چه موارد دیگری در زمان‌بندی سرور قرار می‌گیرند

هنگامی که cron سیستم مدیریت صف WordPress را بر عهده گرفت، سایر کارهای روتین سرور را نیز در همان‌جا متمرکز کنید تا دید کاملی نسبت به آن‌ها داشته باشید. وصله‌های امنیتی سیستم‌عامل باید توسط unattended upgrades مدیریت شوند، نه با یک خط دستور cron که به‌صورت دستی نگهداری می‌کنید. به‌روزرسانی افزونه‌ها و پوسته‌های WordPress تصمیم متفاوتی است: اجرای wp plugin update --all در crontab ممکن است باعث از کار افتادن سایت در ساعت 3 بامداد شود، بدون آنکه کسی متوجه آن باشد. بنابراین، این کار را به‌صورت آگاهانه یا پس از طی مراحل تست در محیط staging و تهیه نسخه پشتیبان انجام دهید.

FAQ

آیا غیرفعال کردن WP-Cron مانع از انتشار پست‌های زمان‌بندی‌شده می‌شود؟

خیر، تا زمانی که مکانیزم دیگری صف را اجرا کند. DISABLE_WP_CRON فقط مانع از این می‌شود که بارگذاری صفحات، صف را فعال کند. رویدادها دقیقاً مانند قبل زمان‌بندی می‌شوند. پستی که برای ساعت 09:00 تنظیم شده است، در اولین اجرای cron پس از ساعت 09:00 منتشر می‌شود؛ بنابراین با بازه زمانی پنج دقیقه، پست تا ساعت 09:05 منتشر خواهد شد. اگر این ثابت (constant) را تنظیم کنید و هرگز ورودی cron را اضافه نکنید، پست در لیست با وضعیت Missed schedule باقی می‌ماند تا زمانی که چیزی صف را اجرا کند.

کدام کاربر باید job مربوط به cron وردپرس را اجرا کند؟

کاربری که مالک فایل‌هایی است که PHP می‌نویسد؛ در نصب پیش‌فرض Ubuntu این کاربر www-data است. با استفاده از stat -c '%U %G' /srv/www/example.com/wp-content/uploads بررسی کنید و آن را با خط user = در پیکربندی pool مربوط به PHP-FPM مقایسه کنید. اجرای job با کاربر root باعث می‌شود WP-CLI با خطای YIKES متوقف شود و اجبار به اجرای آن با --allow-root، فایل‌هایی با مالکیت root در wp-content باقی می‌گذارد که وب‌سرور پس از آن قادر به نوشتن در آن‌ها نخواهد بود.

سیستم cron هر چند وقت یک‌بار باید cron وردپرس را اجرا کند؟

بازه زمانی پنج دقیقه برای اکثر سایت‌ها مناسب است. این بازه را با کوتاه‌ترین زمان‌بندی که واقعاً به آن نیاز دارید هماهنگ کنید و آن را به‌طور مطمئنی بیشتر از زمانی که یک اجرای واحد طول می‌کشد نگه دارید؛ این زمان را می‌توانید با قرار دادن time قبل از دستور WP-CLI اندازه‌گیری کنید. در سایت‌های شلوغ، بازه‌های یک‌دقیقه‌ای باعث انباشته شدن اجراها روی یکدیگر می‌شود، مگر اینکه flock از آن‌ها محافظت کند.

چرا پس از غیرفعال کردن WP-Cron، دستور wp cron test با شکست مواجه می‌شود؟

زیرا آن دستور، فعال‌سازی (spawning) توسط بازدیدکننده را تست می‌کند و زمانی که DISABLE_WP_CRON روی true تنظیم شده باشد، خطا گزارش می‌دهد. این نتیجه در سروری که به این شکل پیکربندی شده، صحیح است. در عوض، مسیر system cron را بررسی کنید: /var/log/wp-cron/example.log را بخوانید یا یک رویداد نشانگر (marker event) با wp cron event schedule زمان‌بندی کنید و تأیید کنید که پس از اجرای بعدی، از wp cron event list حذف شده است.

آیا به WP-CLI نیاز دارم یا استفاده از curl برای wp-cron.php کافی است؟

استفاده از curl کار می‌کند و زمانی که امکان نصب WP-CLI را ندارید، پاسخ مناسبی است. این روش کندتر است، زیرا وردپرس را از طریق وب‌سرور بارگذاری می‌کند و محدود به timeout درخواست است. WP-CLI رویدادها را در یک پردازش PHP خط فرمان بدون timeout وب اجرا می‌کند و برای هر رویداد، یک خط شامل مدت زمان اجرا چاپ می‌کند؛ بنابراین لاگ به شما دقیقاً می‌گوید چه چیزی اجرا شده و چقدر طول کشیده است.