WordPress wp-cron.php with Systemd Timer

The wp-cron.php script for WordPress handles various scheduled events (such as checking for updates, publishing scheduled posts and more). By default this will be executed at each page load (to check if anything needs to be done). A common recommendation is to disable this and instead run it as a cron job.

We deal with a lot of high-traffic and demanding sites at Kinsta. Because of this, we’ve seen a lot of performance issues with the WordPress built-in Cron handler: WP-Cron. First off, it’s important to understand that WP-Cron is not a real cron job, it’s simply what WordPress has created to mimic what a system cron does.

https://kinsta.com/knowledgebase/disable-wp-cron/

wp-cron.php is the WordPress task scheduler, that takes care of things like checking for updates and publishing scheduled posts.
It runs on every single page load.
If your website has not been visited in a while, it will have a lot of missed tasks to catch up which can greatly increase the loading time and could cause additional resource usage issues.

https://my.kualo.com/knowledgebase/65_wordpress/1295_why-and-how-to-disable-the-wordpress-wp-cron.php-and-set-it-as-a-real-cron-job-within-cpanel.html

Rather than running this on a cron, I prefer to use a systemd timer.

Configuration Files

A timer and service unit need to be added to systemd. I prefer to run these as a user service so the service and timer files need to be located in ~/.config/systemd/user. That folder will most likely not exist, so first create it:

mkdir -p ~/.config/systemd/user

Service File

Create the service next; the service is what will be executed by the timer. I name this service wp-cron so it should be located in the file ~/.config/systemd/user/wp-cron.service. The content of the service file:

[Unit]
Description=Run WordPress cron
After=network.target

[Service]
Type=simple
WorkingDirectory=/home/mywebsite/public_html
ExecStart=/usr/bin/php /home/mywebsite/public_html/wp-cron.php

[Install]
WantedBy=default.target

The WorkingDirectory and ExecStart lines will need to be adjusted for your specific environment.

Timer File

The timer which calls the service needs to be created. This should be located in the file ~/.config/systemd/user/wp-cron.timer:

[Unit]
Description=Run WordPress cron
After=network.target

[Timer]
Persistent=false
OnCalendar=minutely
Unit=wp-cron.service

[Install]
WantedBy=timers.target

With the above OnCalendar setting the WordPress cron will be executed every minute.

Enabling Timer

The timer now needs to be enabled and started:

systemctl --user enable wp-cron.timer
systemctl --user start wp-cron.timer

To verify the timer is enabled and to see the next run time use the status command:

systemctl --user status wp-cron.timer

To verify the service actually ran, use the status command for the service:

systemctl --user status wp-cron.service

Once you have confirmed it is working, the WordPress configuration file (wp-config.php) needs to be adjusted to disable the cron. Edit the file and set the DISABLE_WP_CRON flag:

// Disable the WordPress cron
// This is instead being executed as a systemd timer/service
define('DISABLE_WP_CRON', true);

Common Problems

These are fixes for common problems.

Service not being executed if user is not logged in

By default (at least for Debian) users cannot have lingering processes. If the user is not logged in no user services/timers will run. To fix this use loginctl:

loginctl enable-linger mywebsite

Leave a Reply

Your email address will not be published.