How to disable wp_cron and use real cron with WP-CLI in WordPress

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)

  1. 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
  2. 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

  1. Check that wp-config.php contains the constant (WP-CLI verification shown above).
  2. 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
  3. 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.

  1. Open the crontab for the web user:
    sudo crontab -u www-data -e
  2. 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
  3. 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)

  1. Set DISABLE_WP_CRON:
    /usr/local/bin/wp --path=/var/www/example.com/public_html config set DISABLE_WP_CRON true --raw
  2. 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
  3. 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
  4. 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

  1. To revert to wp_cron, remove or comment out the constant in wp-config.php:
    // define(DISABLE_WP_CRON, true)
  2. Alternatively, with WP-CLI:
    /usr/local/bin/wp --path=/var/www/example.com/public_html config delete DISABLE_WP_CRON
  3. 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 🙂



Leave a Reply

Your email address will not be published. Required fields are marked *