<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Adriaan De Kaey</title>
    <description>The latest articles on DEV Community by Adriaan De Kaey (@dekaeyman).</description>
    <link>https://dev.to/dekaeyman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4199219%2F1f56f7c9-5c75-438f-8159-6bbe9ec5a699.png</url>
      <title>DEV Community: Adriaan De Kaey</title>
      <link>https://dev.to/dekaeyman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dekaeyman"/>
    <language>en</language>
    <item>
      <title>How to replace WP-Cron with a real cron job</title>
      <dc:creator>Adriaan De Kaey</dc:creator>
      <pubDate>Wed, 21 Oct 2026 21:59:04 +0000</pubDate>
      <link>https://dev.to/dekaeyman/how-to-replace-wp-cron-with-a-real-cron-job-1g43</link>
      <guid>https://dev.to/dekaeyman/how-to-replace-wp-cron-with-a-real-cron-job-1g43</guid>
      <description>&lt;p&gt;WP-Cron is how WordPress runs scheduled work: publishing a post at 09:00, sending a newsletter, taking a backup. It has one big catch: &lt;strong&gt;it only runs when someone visits your site.&lt;/strong&gt; On a quiet site, or behind a cache, tasks run late or not at all, and WordPress does not tell you.&lt;/p&gt;

&lt;p&gt;The fix is old and simple: let a real scheduler start those tasks instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  In short
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Have a real scheduler call &lt;code&gt;https://yoursite.com/wp-cron.php&lt;/code&gt; every 5 minutes.&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;define( 'DISABLE_WP_CRON', true );&lt;/code&gt; to &lt;code&gt;wp-config.php&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Check that tasks run on time and nothing is overdue.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What WP-Cron actually does
&lt;/h2&gt;

&lt;p&gt;On every page load, WordPress checks a list of scheduled tasks. If one is due, it sends a request to &lt;code&gt;wp-cron.php&lt;/code&gt; on its own site in the background, and that request runs the task. So WP-Cron is not a clock, it is a check that rides along on visitor traffic. That fails in predictable ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No visitors, no tasks.&lt;/strong&gt; A post due at 09:00 goes out when the first visitor arrives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching hides the visits.&lt;/strong&gt; With full page caching or a CDN, most visits never reach PHP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The background request can fail.&lt;/strong&gt; Some hosts, firewalls and password protection block it, and then nothing runs at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Signs you have this problem: posts saying &lt;strong&gt;Missed schedule&lt;/strong&gt;, pending WooCommerce scheduled actions piling up, late emails, or Site Health warning that &lt;em&gt;a scheduled event is late&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Set up a real trigger
&lt;/h2&gt;

&lt;p&gt;Do this first, before touching &lt;code&gt;wp-config.php&lt;/code&gt;, so there is never a gap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A, a crontab on your own server:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# With WP-CLI: run every task that is due, every 5 minutes&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt;/5 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; /var/www/yoursite &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; wp cron event run &lt;span class="nt"&gt;--due-now&lt;/span&gt; &lt;span class="nt"&gt;--quiet&lt;/span&gt;

&lt;span class="c"&gt;# Without WP-CLI: call wp-cron.php over HTTP&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt;/5 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; curl &lt;span class="nt"&gt;-fsS&lt;/span&gt; &lt;span class="nt"&gt;--max-time&lt;/span&gt; 60 &lt;span class="s2"&gt;"https://yoursite.com/wp-cron.php?doing_wp_cron"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Option B, your hosting control panel:&lt;/strong&gt; cPanel and Plesk have a cron or scheduled tasks screen. Use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-O&lt;/span&gt; - &lt;span class="s2"&gt;"https://yoursite.com/wp-cron.php?doing_wp_cron"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Option C, an external cron service:&lt;/strong&gt; the easiest choice on managed hosting or for many sites, because it works on any host and a good one tells you when a call fails. Point it at &lt;code&gt;https://yoursite.com/wp-cron.php?doing_wp_cron&lt;/code&gt; every 5 minutes. (I build &lt;a href="https://cronengine.com/wordpress-cron?utm_source=devto&amp;amp;utm_medium=article" rel="noopener noreferrer"&gt;CronEngine&lt;/a&gt;, which does exactly this, with a free plan.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Switch off the built-in WP-Cron
&lt;/h2&gt;

&lt;p&gt;Add this to &lt;code&gt;wp-config.php&lt;/code&gt;, above &lt;code&gt;/* That's all, stop editing! */&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Scheduled tasks are now started by a real cron job.&lt;/span&gt;
&lt;span class="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'DISABLE_WP_CRON'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing is deleted. Every task stays scheduled, and &lt;code&gt;wp-cron.php&lt;/code&gt; still runs them whenever it is called.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Check that it works
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;In the free &lt;strong&gt;WP Crontrol&lt;/strong&gt; plugin, no event should be more than one interval overdue.&lt;/li&gt;
&lt;li&gt;Schedule a test post a few minutes ahead and see it go live without visiting the site.&lt;/li&gt;
&lt;li&gt;A 401 or 403 from &lt;code&gt;wp-cron.php&lt;/code&gt; usually means a firewall or password protection blocks the call; a 500 means a plugin's task hit an error.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How often?
&lt;/h2&gt;

&lt;p&gt;Calling &lt;code&gt;wp-cron.php&lt;/code&gt; when nothing is due costs almost nothing. Every 15 minutes is fine for a blog, every 5 minutes for most sites, every 1 to 5 minutes for WooCommerce.&lt;/p&gt;




&lt;p&gt;The full guide, with multisite, Cloudflare and managed hosting notes, is on &lt;a href="https://cronengine.com/guides/replace-wp-cron?utm_source=devto&amp;amp;utm_medium=article" rel="noopener noreferrer"&gt;cronengine.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>php</category>
      <category>cron</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
