Skip to content

How to fix "Missed schedule" on a scheduled WordPress post

The post's time passed and WordPress did not publish it. The post is intact. Publish it now, then find the reason. WordPress only runs scheduled tasks when a page is loaded and the site can send a request to itself, and one line in wp-config.php switches that off.

By
WP Ministry
Published
Tested on
WordPress 7.1.3, PHP 8.3.35

In short

  • "Missed schedule" means the post's time has passed and it is still scheduled. Nothing is lost.
  • WordPress publishes a scheduled post only when a page is loaded after its time and the site can request its own wp-cron.php.
  • `wp cron event run --due-now` publishes what is waiting. A post it leaves behind can be published by its ID.
  • A DISABLE_WP_CRON line in wp-config.php stops scheduled publishing unless a cron job on the server runs the tasks instead.
  • `wp cron test`, or Tools then Site Health, shows whether the site can reach itself.
  • A cron job on the server puts publishing on a real clock.

"Missed schedule" appears on the Posts screen, in the Date column, where a scheduled post said "Scheduled". It means the time you set has passed and the post is still waiting. The task that should have published it did not run.

Nothing is lost. The post is as you left it, and it keeps the date you gave it when it is published late.

How a scheduled post gets published

When you schedule a post, WordPress adds a one-off task for it, named publish_future_post, to its own scheduler, WP-Cron. WP-Cron is not a clock. WordPress's handbook says it "is only triggered on page load": when a page is requested, WordPress looks for tasks that are due and, if it finds one, sends a request to its own wp-cron.php file, which runs them.

So a post goes out on time only when three things hold. A page is loaded after the post's time. WP-Cron has not been switched off. The site can send that request to itself. The first fix publishes what is waiting, whatever the cause. The others each deal with one of the three.

The commands are WP-CLI, run over SSH from the folder WordPress is installed in. How to use WP-CLI covers connecting and installing it, and in the WP-CLI command builder you choose a job, fill in what it needs, and copy the command with its flags in place.

Where it goes wrong

A page request passes through each of these in turn. This one comes from WordPress itself.

  1. Browser
  2. DNS
  3. HTTPS
  4. CDN or firewall
  5. Web server
  6. PHP
  7. WordPress (this error comes from here)
  8. Database and files

What causes it

How to fix it

Publish the missed posts now

  • Easy
  • No risk
  • About 5 minutes
  • Steps tested on WordPress 7.1.3

Without WP-CLI, go to Posts, choose "Quick Edit" under the post's title, set "Status" to "Published" and press "Update". Do the same for each post marked "Missed schedule".

  1. Step 1: List the posts that are still scheduled

    The dates are in the site's own timezone. A date in the past is a missed post.

    bash
    wp post list --post_status=future --fields=ID,post_title,post_date
  2. Step 2: Run every task that is due

    This runs each task whose time has passed, not only posts, and prints a line for each, such as "Executed the cron event 'publish_future_post'". It works while WP-Cron is switched off. Newer versions of WP-CLI answer "A cron event run is already in progress; skipping." when WordPress tried to start its tasks within the last minute. If yours does, go on to the next step.

    bash
    wp cron event run --due-now
  3. Step 3: Publish what is still listed

    Run the list again. A post still there with a past date has no task left to publish it. Publish it by its ID, here 123. Several IDs can follow one another.

    WordPress answers "Success: Updated post 123." A post whose date is still ahead stays scheduled, even if you name it.

    bash
    wp post update 123 --post_status=publish

Turn WP-Cron back on

  • Easy
  • Back up first
  • About 10 minutes
  • Steps tested on WordPress 7.1.3
  1. Step 1: Read the setting

    true means WordPress has been told not to start scheduled tasks on page loads. An error saying the constant is not defined means it is not set, and this fix is not yours. Without WP-CLI, open wp-config.php and look for define( 'DISABLE_WP_CRON', true );.

    bash
    wp config get DISABLE_WP_CRON --format=json
  2. Step 2: Find out whether anything runs the tasks instead

    The line is meant to be paired with a cron job on the server. crontab -l over SSH lists yours. One can also be set in a hosting control panel, so look there or ask the host. If there is one and posts are still missed, the job is failing: see the last fix. If there is none, go on.

  3. Step 3: Remove the line

    bash
    wp config delete DISABLE_WP_CRON
  4. Step 4: Load any page of the site

    The missed posts are published within a few seconds. Reload the Posts screen and the Date column says "Published".

To undo it: Put the line back in wp-config.php.

Test whether the site can reach itself

  • Takes care
  • Back up first
  • About 15 minutes
  • Steps tested on WordPress 7.1.3

Without WP-CLI, go to Tools, then Site Health. "Your site could not complete a loopback request" means the request WordPress sends to itself failed, and the text under it gives the error. Site Health also reports "A scheduled event is late" when tasks are not running on time, which is one reason the maintenance checklist has you read it every month.

  1. Step 1: Run the test

    "Success: WP-Cron spawning is working as expected." means the request got through, and this is not your cause.

    bash
    wp cron test
  2. Step 2: Read the error

    • "The DISABLE_WP_CRON constant is set to true. WP-Cron spawning is disabled." Use the fix above.
    • "WP-Cron spawn returned HTTP status code: 403 Forbidden". Something understood the request and refused it.
    • The same line with 401. The site is behind a password, as a staging copy may be. WordPress sends no password with this request.
    • "WP-Cron spawn failed with error:" and a cURL error. The request never arrived. Error 6 means the server could not find the site's own domain name, 7 that it could not connect, and 28 that no answer came in time. These are for the host.
  3. Step 3: For a 403 on Apache, look for a rule that names the file

    Each line it prints names wp-cron.php. Copy .htaccess somewhere safe, then remove the rule that denies access to the file, together with any <Files> lines that open and close it. If nothing is printed, the refusal comes from a firewall or from the host: ask for the server's own requests to wp-cron.php to be let through.

    bash
    grep -n -i "wp-cron" .htaccess
  4. Step 4: Test again, then wait a minute and load a page

    When wp cron test reports success, wait a minute before loading a page. WordPress does not start its tasks more than once in 60 seconds, and a failed attempt counts. The missed posts are then published.

To undo it: Put back the lines you removed from .htaccess.

Start the tasks without that request

  • Easy
  • Back up first
  • About 10 minutes
  • Steps tested on WordPress 7.1.3

If you cannot remove what refuses the request, WordPress has a second way to start its tasks. Its documentation gives it for scheduled posts that are not being published. WordPress sends the visitor's browser a redirect to the same page and runs the tasks in the connection the browser has just left.

  1. Step 1: Add the line above "That's all, stop editing"

    wp-config.php
    define( 'ALTERNATE_WP_CRON', true );
  2. Step 2: Wait a minute, then load a page

    The address gains ?doing_wp_cron= and a number for that one request. The missed posts are published.

A visitor sees that address whenever a task is due, and WordPress's documentation says the method carries some risk. Use it where a cron job is not open to you.

To undo it: Remove the line from wp-config.php.

Put the scheduler on the server's clock

  • Advanced
  • Low risk
  • About 20 minutes

The handbook's answer for tasks that must run on time is to have the server's scheduler, cron, run them at a fixed interval, whether or not anyone visits. This crontab line runs the command from the first fix every five minutes, so a post is at most five minutes late. Change both paths to yours.

text
*/5 * * * * /usr/local/bin/wp cron event run --due-now --path=/home/example/public_html --quiet

The command makes no web request, so whatever refuses wp-cron.php is not in its way. Once the job is in place, set DISABLE_WP_CRON to true so that page loads stop trying to start the same tasks.

The guide to automatic backups has the whole procedure under "Put WP-Cron on a real clock": opening the crontab, a line for servers without WP-CLI, the order to do it in and how to check that it works.

To undo it: Remove the line from wp-config.php first, then the line from the crontab.

When to get help

If posts are still missed after `wp cron test` reports success, or it reports a connection error on a server you do not run yourself, what is left is the server's own logs and firewall. Past that point, more changes inside WordPress are guesses.

Common questions

Does a post published late keep the date I scheduled?

Yes. Publishing changes the post's status and leaves its date alone, so it carries the day and time you set, not the moment it went out.

Can the Timezone setting cause it?

Not by being wrong. A post scheduled under the wrong timezone is published at the wrong hour, and until then the Posts screen says "Scheduled". Changing the timezone afterwards is different. The label is worked out from the post's local time and the timezone the site has now, while the publishing task keeps the moment it was given when the post was saved. After a change under Settings, General, "Timezone", a post can say "Missed schedule" hours before its task is due. Open the post, set its date again and save it.

Why was the post published as soon as I looked?

Opening the Posts screen is a page load like any other. On a quiet site, WordPress finds the task due as you look at the list and publishes the post a moment later. Posts on such a site go out late, not never, and a cron job on the server puts them on time.

More on this subject

Would you rather we fixed it?

Quick Fix is $49. One issue, one site, up to about an hour. No fix, no fee. 30-day warranty. It starts with a free diagnosis.