To make WordPress scheduled tasks run on time, disable WP-Cron and replace it with a real cron job in cPanel. WP-Cron isn't a scheduler. It only checks for due tasks when PHP handles a page load, and on WP Aligned hosting most page loads are served from the LiteSpeed cache without PHP running at all. A cPanel cron job runs wp-cron.php on a fixed schedule, whether or not anyone visits. WP Aligned doesn't add this cron job for you, so we recommend setting it up on every production site. It takes about five minutes.
WordPress uses WP-Cron for anything that happens on a schedule: publishing scheduled posts, plugin and theme update checks, WooCommerce cleanup, backup plugins, email digests, and the LiteSpeed Cache crawler.
On each request that PHP handles, WordPress checks whether a task is due and, if one is, fires off a request to wp-cron.php. That causes two problems:
Typical symptoms:
A scheduled event is late or A scheduled event has failed.You need the site's document root: the folder WordPress is installed in. In cPanel, go to Domains > Domains and read the Document Root column. For the account's main domain it's usually public_html, so the full path is /home/exampleuser/public_html, with your cPanel username in place of exampleuser.
The command for that site is:
/usr/local/bin/php /home/exampleuser/public_html/wp-cron.php >/dev/null 2>&1
What each part does:
/usr/local/bin/php is cPanel's PHP command. When you give it a script inside a site's folder, it runs that script with the PHP version the domain uses in MultiPHP Manager, so the command keeps working when you change the site's PHP version. Use the full path. Cron doesn't search /usr/local/bin, and a bare php there is a different build that won't run scripts this way./home/exampleuser/public_html/wp-cron.php is the site's WP-Cron script. Use the full path.>/dev/null 2>&1 discards the output, so cPanel doesn't email you every five minutes.Prefer WP-CLI? See Using WP-CLI instead below. Both do the same job.
Add the cron job first, and disable WP-Cron second, so scheduled tasks never go without a trigger.
The new job appears under Current Cron Jobs. The PHP command examples box at the top of the form shows the same /usr/local/bin/php pattern. You don't need its domain-specific ea-php99 form, because /usr/local/bin/php already picks the domain's version.
If the account has several WordPress sites (production, staging, a second domain), add one cron job per site, each with its own document root. A cron job only runs the WordPress install whose wp-cron.php it points to.
Now stop WordPress from triggering WP-Cron on page loads.
wp-config.php and choose Edit.php
/* That's all, stop editing! Happy publishing. */
php
define( 'DISABLE_WP_CRON', true );
If DISABLE_WP_CRON is already in the file, change its value to true rather than adding a second line. If you can't find the "stop editing" comment, add the line above require_once ABSPATH . 'wp-settings.php';.
Give it 10 to 15 minutes, then:
A scheduled event is late and A scheduled event has failed should be gone. Site Health only rechecks when you load the page, so reload it.To see exactly what the cron job does, temporarily change the end of the command from >/dev/null 2>&1 to:
>> /home/exampleuser/wp-cron.log 2>&1
After a few runs, open wp-cron.log in File Manager. An empty file means every run succeeded, because wp-cron.php prints nothing when it works. Any text in it is an error to fix. Change the command back and delete the log when you're done.
cron treats % as a line break, so a command containing % (for example, a date +%Y in a file name) is cut off at that point and fails silently. The commands in this guide don't use %. If you need one, escape it as \%.
cron runs with a short search path that doesn't include /usr/local/bin. A command that starts with plain php or wp either isn't found or runs the wrong PHP build, and because the output goes to /dev/null, you won't see the error. Always start the command with /usr/local/bin/php.
With DISABLE_WP_CRON set to true and no cron job, nothing runs at all: no scheduled posts, no update checks, no crawler. If you remove the cron job, remove the define line too.
A staging copy or a migrated site copies wp-config.php, including DISABLE_WP_CRON, but not the cron job. Add a cron job for the new copy, or remove the line from its wp-config.php. See How to create Development Sites.
WP-CLI is installed on WP Aligned servers at /usr/local/bin/wp. To run due events with it, use this command in place of the one above:
cd /home/exampleuser/public_html && /usr/local/bin/php /usr/local/bin/wp cron event run --due-now >/dev/null 2>&1
Keep /usr/local/bin/php in front of /usr/local/bin/wp. Without it, cron runs WP-CLI with the wrong PHP build and it fails with Only CLI access.
One difference from the wp-cron.php command: WP-CLI runs on the server's default PHP version, not the version the domain uses in MultiPHP Manager. That's fine for running scheduled events on most sites. If you need WP-CLI to use the site's exact version, replace /usr/local/bin/php with that version's PHP, for example /opt/cpanel/ea-php83/root/usr/bin/php for PHP 8.3.
On a multisite network, running wp-cron.php only processes the main site. Scheduled events on the other sites stay pending. Use WP-CLI to run every site's events in one cron job:
cd /home/exampleuser/public_html && /usr/local/bin/php /usr/local/bin/wp site list --field=url | xargs -I {} /usr/local/bin/php /usr/local/bin/wp cron event run --due-now --url={} >/dev/null 2>&1
New sites added to the network are picked up automatically, because the command lists the sites each time it runs.
Open a ticket if:
wp-cron.log shows an error you can't trace to a plugin, and Site Health still reports late events.Include the site's domain and the cron command you used. See Need Help? for how to reach us.
Not if the cron job is set up. The cron job runs the same wp-cron.php that WordPress would have triggered, just on a fixed schedule. Disabling WP-Cron without the cron job does stop them.
No. When nothing is due, wp-cron.php checks the schedule and exits. If an account has many WordPress sites, you can use every 15 minutes instead: leave Common Settings alone and type */15 in the Minute field.
A little, on uncached requests. WordPress no longer checks the schedule and fires a background request during a visitor's page load. The bigger gain is that scheduled work happens on time.