Contents
Overview
This article explains, in exhaustive detail, how to disable WordPresss built-in pseudo-cron (wp_cron) and run scheduled tasks using a real system cron (or systemd timer) while managing and testing schedules with WP-CLI. It covers reasons to switch, exact commands and file edits, multiple example setups (cron, cron.d, crontab for a specific user, systemd timer), WP-CLI commands for listing and running events, testing and troubleshooting, permissions and environment considerations, multisite specifics, rollback instructions, and security/performance notes. All examples use absolute paths and explicit PHP and WP-CLI usage recommended for production reliability.
Why disable wp_cron?
- wp_cron is pseudo-cron: It runs only when a page loads, by performing an HTTP loopback to the site to trigger scheduled events. It is not a system cron and is dependent on site traffic and reliable loopback requests.
- Problems with wp_cron:
- Missed or delayed events on low-traffic sites.
- High-traffic sites get wp_cron triggered on many requests, adding overhead.
- Loopback requests can fail due to firewalls, hosting restrictions, or incorrect DNS.
- Benefits of using a real cron:
- Precise scheduling and predictable memory/cpu provisioning.
- Centralized logging and easier debugging.
- Reduced web request overhead and more control over execution environment (specific PHP binary, user, limits).
Before you begin
- Back up your WordPress files and database.
- Ensure WP-CLI is installed and working for the target site. Test with a simple command like:
/usr/local/bin/wp --info
- Know the absolute path to your WordPress installation (example: /var/www/example.com/public_html).
- Know the correct PHP binary to use on the CLI (example: /usr/bin/php or /usr/local/bin/php74). The PHP binary used by cron must have required extensions and access to the same PHP-FPM pools if needed.
- Decide which system user will run the cron (recommended: the system user that owns the WordPress files, commonly www-data, apache, or a dedicated deploy user). Avoid running WP-CLI as root if possible if running as root, add –allow-root to WP-CLI commands but understand the risk.
- Have access to the servers crontab (crontab -e) or ability to create /etc/cron.d files or systemd units.
Step 1 — Disable wp_cron in wp-config.php
Set the DISABLE_WP_CRON constant to true in your wp-config.php. Two safe ways are shown: using WP-CLI or editing the file directly.
Method A — Use WP-CLI (recommended when you have wp-cli)
- Run this command from any directory specify –path if necessary:
/usr/local/bin/wp --path=/var/www/example.com/public_html config set DISABLE_WP_CRON true --raw
- Confirm the constant is set:
/usr/local/bin/wp --path=/var/www/example.com/public_html config get DISABLE_WP_CRON
Method B — Edit wp-config.php manually
Add the following line above the / Thats all, stop editing / comment in wp-config.php:
define(DISABLE_WP_CRON, true)
Step 2 — Verify wp_cron is disabled and inspect scheduled events
- Check that wp-config.php contains the constant (WP-CLI verification shown above).
- List scheduled events via WP-CLI:
/usr/local/bin/wp --path=/var/www/example.com/public_html cron event list --fields=hook,recurrence,next_run --format=table
- Optionally list only overdue/due events:
/usr/local/bin/wp --path=/var/www/example.com/public_html cron event list --fields=hook,next_run,status --format=csv
Step 3 — Run WP-Cron via system cron (several approaches)
Choose one of the following methods to run scheduled events consistently and reliably.
Option A — Per-site crontab (run as the site file owner user)
Edit the crontab for the site owner (example uses user www-data). This is the recommended approach because it uses the same user as the file owner, avoiding permission issues.
- Open the crontab for the web user:
sudo crontab -u www-data -e
- Add this line to run the WP-CLI cron runner every minute (adjust paths to match your installation):
/usr/local/bin/wp --path=/var/www/example.com/public_html cron event run --due-now --quiet >> /var/log/wp-cron.log 2>1
- Notes:
- Use –quiet to minimize output. Remove it when debugging to get more information in the log.
- Do not use –allow-root unless you are running as root. Its safer to run as the site owner.
Option B — System-wide /etc/cron.d file
Create a file such as /etc/cron.d/wp-cron-example-com and set the user explicitly. This is useful for multiple sites or when you want system-managed crons.
# /etc/cron.d/wp-cron-example-com # Run WP Cron for example.com every minute as www-data www-data /usr/local/bin/wp --path=/var/www/example.com/public_html cron event run --due-now --quiet >> /var/log/wp-cron-example-com.log 2>1
Option C — Invoke wp-cron.php directly via PHP (less recommended)
You can call wp-cron.php with PHP. This is lower-level and bypasses WP-CLI it works but offers fewer testing tools and no WP-CLI logging ease.
www-data /usr/bin/php -f /var/www/example.com/public_html/wp-cron.php > /dev/null 2>1
Important: When calling wp-cron.php directly, be sure PHP CLI settings (memory_limit, max_execution_time) are sufficient.
Option D — systemd timer (recommended on systemd hosts for centralized control)
Systemd timers offer precise scheduling and better logging integration. Create a service unit and timer unit.
# /etc/systemd/system/wp-cron-example-com.service [Unit] Description=Run WP-Cron events for example.com [Service] Type=oneshot User=www-data WorkingDirectory=/var/www/example.com/public_html ExecStart=/usr/local/bin/wp --path=/var/www/example.com/public_html cron event run --due-now --quiet
# /etc/systemd/system/wp-cron-example-com.timer [Unit] Description=Timer for WP-Cron events for example.com [Timer] OnCalendar=-- ::00 Unit=wp-cron-example-com.service Persistent=true [Install] WantedBy=timers.target
Enable and start the timer:
sudo systemctl daemon-reload sudo systemctl enable --now wp-cron-example-com.timer # View status and next run sudo systemctl list-timers --all grep wp-cron-example-com
Step 4 — Using WP-CLI to manage and test cron events
WP-CLI provides commands to list, run, test, and manipulate scheduled events. These commands are invaluable for debugging and ensuring tasks run as expected.
List scheduled events
/usr/local/bin/wp --path=/var/www/example.com/public_html cron event list --format=table --fields=hook,recurrence,next_run
Run due events manually (useful for testing)
/usr/local/bin/wp --path=/var/www/example.com/public_html cron event run --due-now
Run a specific event hook
/usr/local/bin/wp --path=/var/www/example.com/public_html cron event run my_custom_hook
Delete an event (if needed)
/usr/local/bin/wp --path=/var/www/example.com/public_html cron event delete my_broken_hook
Show full event details
/usr/local/bin/wp --path=/var/www/example.com/public_html cron event list --format=json jq .
Use jq or –format=csv to parse results if you want programmatic inspection.
Full end-to-end example (recommended production approach)
- Set DISABLE_WP_CRON:
/usr/local/bin/wp --path=/var/www/example.com/public_html config set DISABLE_WP_CRON true --raw
- Create a dedicated systemd service and timer (as shown above) or add a crontab entry for the site owner:
sudo crontab -u www-data -l # Add: /usr/local/bin/wp --path=/var/www/example.com/public_html cron event run --due-now --quiet >> /var/log/wp-cron-example-com.log 2>1
- Verify scheduled events and run due ones manually to test:
/usr/local/bin/wp --path=/var/www/example.com/public_html cron event list /usr/local/bin/wp --path=/var/www/example.com/public_html cron event run --due-now
- Check logs (/var/log/wp-cron-example-com.log) and system logs for any errors.
Testing tips
- Temporarily increase logging verbosity: remove –quiet in cron line and write output to a log file so you can see errors and warnings.
- Use run-once testing:
/usr/local/bin/wp --path=/var/www/example.com/public_html cron event run --due-now --allow-root
(Use –allow-root only in controlled environments better to run under the site user.)
- When events fail, run them interactively to see PHP errors or stack traces.
- Use WP-CLI to inspect hook callbacks by searching the codebase for the hook name to find the source of the scheduled callback.
Troubleshooting — common issues and fixes
- Nothing runs: Confirm DISABLE_WP_CRON is set. Confirm cron lines are present and active (crontab -l, /etc/cron.d listing, or systemctl list-timers).
- Permissions errors: Cron running as wrong user cannot read wp-config.php or plugin files. Run cron as the owner of the WordPress files (chown -R or run crontab -u owner).
- Wrong PHP binary or missing extensions: Use the same PHP version you use in production or one that has required extensions. Test with: /usr/bin/php -v and ensure it matches.
- WP-CLI not found in PATH when cron runs: Use absolute path to WP-CLI in cron entries (e.g., /usr/local/bin/wp). Confirm permissions on the wp binary are executable by the cron user.
- Loopback-dependent code fails: Some plugins rely on external HTTP requests or the WP HTTP API ensure network connectivity or adapt plugins to use direct function calls where needed.
- ALTERNATE_WP_CRON interfering: ALTERNATE_WP_CRON is a fallback for loopback failures. If defined and used, remove it when using real cron to avoid conflicts. Its less commonly used but check wp-config.php for it.
- SELinux or AppArmor preventing execution: Check audit logs and adjust policies or put cron jobs under allowed contexts.
- High runtimes and memory limits: If scheduled tasks are heavy, increase PHP CLI memory_limit and max_execution_time for the PHP binary your cron uses (edit /etc/php/
/cli/php.ini or use wrapper script that sets environment variables).
Advanced Notes and Best Practices
- Use absolute paths everywhere — cron runs with a limited environment never rely on PATH or relative paths.
- Log output separately per site so you can track issues quickly, eg. /var/log/wp-cron-example-com.log.
- Schedule frequency: Running every minute is common to match wp_crons typical behavior. Less frequent schedules (every 5 minutes) may be acceptable depending on requirements.
- Throttle long jobs: If scheduled jobs take a long time, consider batching logic or dedicated worker queues (Redis, Gearman, background queue libraries).
- WP-CLI environment: If you have multiple PHP versions, create wrapper scripts that set the required PHP binary and environment variables and call WP-CLI, then call the wrapper from cron.
- Monitoring: Add alerts if cron hasnt run or if some jobs remain overdue for a long time (use monitoring tools to check /var/log outputs or cron exit codes).
Multisite considerations
- DISABLE_WP_CRON is global and should be placed in wp-config.php as usual for multisite.
- System cron or systemd timer should run the same WP-CLI commands with the –path pointing to the multisite installation root. WP-CLI will run scheduled tasks across the entire network.
- When running specific site-level tasks, use WP-CLIs –url flag to scope actions to a particular site.
Rollback and restoring original behavior
- To revert to wp_cron, remove or comment out the constant in wp-config.php:
// define(DISABLE_WP_CRON, true)
- Alternatively, with WP-CLI:
/usr/local/bin/wp --path=/var/www/example.com/public_html config delete DISABLE_WP_CRON
- After re-enabling wp_cron, remove or disable your system cron or systemd timer to avoid duplicate runs.
Security considerations
- Do not run WP-CLI as root unless strictly necessary. If you must, use –allow-root but be aware of file ownership implications for generated files.
- Restrict access to log files and cron.d files so only appropriate users can read them.
- Audit scheduled tasks to ensure no untrusted or unsanitized callbacks are scheduled.
Quick reference table
Task | Recommended command/config |
---|---|
Disable wp_cron |
wp --path=/var/www/example.com/public_html config set DISABLE_WP_CRON true --raw |
List scheduled events |
wp --path=/var/www/example.com/public_html cron event list |
Run due events via WP-CLI (cron) |
/usr/local/bin/wp --path=/var/www/example.com/public_html cron event run --due-now --quiet |
Systemd timer | Create a service that runs WP-CLI and a timer that runs it every minute enable with systemctl. |
Helpful links
Summary
Disabling wp_cron and using a real system cron or systemd timer gives you reliable, controllable scheduling for WordPress. Use WP-CLI for easy inspection, manual runs, and programmatic control. Always run cron jobs as the site owner where possible, use absolute paths, test thoroughly with logs and WP-CLI commands, and ensure PHP CLI has correct configuration and permissions. The instructions above provide ready-to-use examples for crontab, /etc/cron.d, and systemd, plus exhaustive troubleshooting and best practices to run WordPress scheduled events in production safely and predictably.
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |