You scheduled the article, closed the editor, and expected it to appear while you were doing something else. Now the publication time has passed, the homepage hasn't changed, and WordPress says Missed schedule. Or the editor says Published, but your readers still can't find it.

A WordPress scheduled post not publishing isn't always a cron problem. Start by separating a late trigger from a failed publishing event, a timezone mismatch, and a cached page. That distinction determines which fix is worth making.

Table of Contents

Match Your Symptom to Its Cause

Use this symptom table to choose your first check before changing settings.

Scheduled post symptoms, likely causes and first checks

SymptomMost likely causeFirst check
Missed schedule that clears only after a visitor loads the siteWP-Cron ran late, with no requests near the scheduled timeCompare the scheduled time with the first page load after it in your access logs
Missed schedule that persists after a manual cron runStuck or failed publish event, or a post-state problemRun wp cron event list and confirm the publish event is still queued
Post is live but readers see the old versionPage, host or CDN cache serving stale HTMLOpen the post in a private window, then purge all cache layers
Post publishes two hours off, or one hour off after a clock changeFixed UTC offset or timezone mismatchCompare Settings > General time with the post's scheduled timestamp
Post stays in Scheduled after a plugin or theme updatePlugin conflict or a hook that alters publishingOn staging, switch to a default theme and check whether the post publishes
Cron output shows HTTP errors or timeoutsLoopback request blocked by firewall, SSL or host rulesRun Site Health and check the loopback test result
Post is published but missing from the feedCached feed URL, or publication after the last feed refreshLoad /feed/ in a private window after purging cache

Treat the middle column as a working diagnosis, not a verdict. A matching symptom tells you where to inspect first, but you still need evidence before changing the server configuration.

Record the failure before fixing it

Write down the scheduled timestamp, including the timezone, and when the post really became publicly available. If it never appeared, record when you checked and what status WordPress displayed.

Also note the last relevant change: a plugin update, theme switch, hosting move, security rule, or cache adjustment. Keep the post ID with those notes so you don't accidentally compare a draft with a different published article.

Practical rule: Change one thing, run a controlled publishing test, and record the result before changing something else.

WordPress's explanation of its request-triggered scheduling mechanism helps explain why an overdue post doesn't necessarily indicate defective content. Missed schedule is a timing signal, not proof that the article needs rewriting.

If an announcement must be live immediately, publish it manually after recording the evidence. Then troubleshoot with a disposable test post rather than repeatedly changing the date on important content.

How WP-Cron Decides When Your Post Goes Live

WordPress doesn't have an always-running scheduler checking your post every moment. Its native WP-Cron mechanism checks for due work when a page request reaches WordPress.

The process is easier to understand as a sequence.

An infographic showing the five-step process of how WP-Cron triggers a scheduled WordPress post publication.

Consider the example in the WordPress Cron documentation: a post scheduled for 2:00 p.m. may not be processed until 5:00 p.m. if no page loads occur between those times. That's 180 minutes of lateness in that example, not a universal maximum.

Follow the publishing event

  1. The editor saves a future publication time. WordPress stores the post as scheduled and queues its publishing event.
  2. The scheduled instant arrives. Without a request that triggers WP-Cron, the event remains waiting.
  3. A visitor reaches WordPress afterward. WP-Cron checks the queue and identifies overdue work.
  4. The publishing task executes. The publish_future_post event attempts to publish the associated post.
  5. The post becomes public. Its status changes to Published, making it eligible to appear in the site's public listings and feed.

This is why quiet sites and overnight publishing windows are vulnerable to late triggers. The selected timestamp tells WordPress when the task becomes due; it doesn't independently wake the server.

A system scheduler works differently. It initiates a command on its own clock rather than waiting for visitors, but it doesn't automatically replay a missed invocation. WP-Cron retains due events for a later opportunity.

Separate lateness from failure

Lateness is the gap between the intended publication time and the successful cron trigger. Failure means the event doesn't complete, potentially because execution is disabled, a request is blocked, resources are exhausted, or code interrupts publishing.

The interval between successful triggers governs trigger-related lateness. It doesn't guarantee that the publishing operation itself will succeed once invoked.

For a visual walkthrough, the accompanying video provides another way to follow the scheduling workflow.

If your evidence points to a late trigger, editing the article or switching themes won't address that mechanism. You need a dependable way to invoke scheduled work.

How to Set Up a Server Cron Job Step by Step

A server cron job is useful when publication shouldn't depend on visitors. It replaces the trigger, not WordPress's publishing logic, so it won't repair every stuck post.

Before editing configuration, save a backup and confirm the correct WordPress directory and hosting account. If you're still establishing the site, the WordPress blog setup guide provides the broader setup context.

Configure the replacement safely

  1. Prepare the configuration change. Open wp-config.php and locate the line telling you to stop editing. The setting to add above it is define('DISABLE_WP_CRON', true);, but don't activate it until the replacement job works.

  2. Create the server job. In cPanel's cron interface or your account's crontab, use an every-minute schedule with the command cd /path/to/wordpress && wp cron event run --due-now. Replace the directory with the actual installation path, and use the full WP-CLI executable path if your host requires it. In crontab format, the schedule fields are * * * * *.

  3. Run the command manually. Execute it as the same account that will run the scheduled job. Check for PHP errors, permission failures, and an incorrect working directory. A successful shell session under a different user doesn't prove the hosting scheduler has the same access.

  4. Inspect the pending event. Run wp cron event list while your test post is still scheduled. Look for publish_future_post, check its arguments against the post ID, and compare its next run with the intended publication time.

  5. Confirm unattended execution, then disable visitor-triggered cron. Verify that the host actually invokes the job, activate the prepared DISABLE_WP_CRON setting, and observe a scheduled post without loading the public site. Use the scheduler's logs and the editor to check the result.

If WP-CLI isn't available, configure the host scheduler to request wp-cron.php using curl on a five-minute interval. With SITE_URL set to your site's real base address, the command can use curl --fail --silent --show-error "$SITE_URL/wp-cron.php". This introduces a wider trigger window and still depends on a successful HTTP request.

Check the result, not just the configuration

Diagnostic commands and healthy results

CheckCommand or locationHealthy result
List pending eventswp cron event listThe matching publish_future_post event appears with a next run near its scheduled time
Run due events nowwp cron event run --due-nowNo PHP errors, and a due test post changes to Published
Test cron spawningwp cron testCron spawning and loopback succeed when testing native WP-Cron
Confirm WP-Cron is disabledwp-config.php, DISABLE_WP_CRONSet to true only after the replacement job is confirmed
Confirm loopback worksTools > Site HealthNo unexplained loopback or REST errors
Confirm host job existsHost cron panel or crontab -lThe every-minute job has the correct WordPress and executable paths

wp cron test can warn when native WP-Cron is intentionally disabled. That warning alone doesn't invalidate a working direct WP-CLI job.

If shell access is blocked, send hosting support the exact command and ask them to configure and verify it. Never disable the existing trigger without a working replacement.

Fix Stuck Events and Missed-Schedule Loops

A real cron job isn't the end of the fix. A WordPress Trac report documents posts remaining in Missed schedule despite an every-minute system job running wp cron event run --due-now.

That report supports a narrower conclusion than “cron is broken”: successful invocation doesn't prove a specific post completed its publishing transition.

Use the checklist as a reminder, while keeping the distinction between native WP-Cron and a verified replacement job clear.

A step-by-step infographic titled Fix Stuck Events and Missed-Schedule Loops for troubleshooting WordPress scheduling issues.

Inspect the event before changing the interval

Start with the queue. Run wp cron event list and locate the event associated with the affected post. If it's missing while the post remains scheduled, re-save the intended date and time, then inspect the queue again.

A missing event is evidence of a scheduling or state inconsistency, not proof of a particular plugin's guilt. Avoid deleting unrelated events while investigating.

Next, execute due work. Run wp cron event run --due-now, preserve the output, and check the post's status immediately afterward. If the command runs but the post remains overdue, inspect PHP and server logs covering that execution.

Look for a fatal error, timeout, or interrupted request rather than assuming a shorter interval will help. A command's overall success message isn't a substitute for checking the affected post.

Distinguish HTTP restrictions from post-state problems

Then check loopback behavior. Review Tools > Site Health and investigate firewall, SSL, authentication, or hosting restrictions when HTTP requests fail. An HTTP-based cron job can be invoked successfully by the scheduler yet fail to reach WordPress.

Direct WP-CLI execution is different: it doesn't require that same HTTP loopback path to invoke due events. Don't diagnose a CLI publishing failure solely from a loopback warning.

Finally, inspect the post itself. Confirm you're looking at the intended post ID, not a second draft or a similarly named article. Check for a confusing slug, unexpected status changes, or publishing customizations before re-saving or manually publishing.

Keep cron output, server logs, Site Health results, and the post's status together. None tells the whole story alone.

If the same post fails after two controlled manual runs, escalate with the exact command, timestamps, post ID, and relevant log lines. Repeatedly installing cron plugins or changing intervals can obscure the original fault without resolving it.

Timezone and Daylight Saving Traps to Check

Before treating a post as overdue, compare WordPress's displayed current time, its configured timezone, the audience's local time, and the post's scheduled timestamp. Write those values together so you're comparing actual instants rather than clock labels.

Open Settings > General and check both the timezone selector and the displayed time. The timezone troubleshooting explanation distinguishes named regional zones from fixed UTC offsets, which don't adjust for daylight saving.

Timezone setting types and how they behave

Setting typeExampleDaylight saving behaviorRisk for scheduled posts
Named city zoneEurope/BerlinAdjusts automatically at regional seasonal transitionsLowest risk for single-region publishers
Fixed UTC offsetUTC+1Doesn't adjust; local expectations can shift by an hour in summerOften a hidden cause after manual setup
UTCUTC+0Never shiftsUseful for global embargoes, but readers must convert time
Server or PHP timeHost-definedCan differ from WordPress time after custom codeInvestigate when displayed time looks wrong

Test the intended instant

A fixed offset can produce a post that appears late even though WordPress has correctly queued it for the configured instant. For example, an intended local morning publication can appear an hour later during summer when the site remains on a winter offset.

Don't assume the direction of the discrepancy. Compare the actual regional offset on the publication date, especially around a clock change.

Choose the convention that matches your editorial operation:

  • Regional publication: Use a named city zone when editors and readers expect a consistent local publication hour.
  • Global announcement: Consider UTC when an embargo or coordinated release must refer to the same instant worldwide.
  • Distributed editorial team: Document whether schedule entries mean publisher-local time, audience-local time, or UTC.

Check custom time handling

Server or PHP time can diverge from WordPress display time when custom code or plugins change timezone handling. If the values disagree, inspect that customization rather than repeatedly correcting individual post dates.

During the week of a daylight-saving transition, schedule a disposable post five minutes ahead and confirm the expected local publication time. Record the zone and date with the result so another editor can reproduce the test.

Caching and Plugin Conflicts That Hide Published Posts

Start with the cheaper question: Did publishing fail, or are you looking at an old response? A Published status next to stale public pages calls for a cache check before any scheduler change. I've watched posts go live on time and stay invisible to visitors because the homepage cache kept serving the pre-publish version.

Compare the editor and public view rather than trusting either alone.

A laptop open on a wooden desk showing a WordPress dashboard with a published post and website view.

Check each public surface

Open a private browser window and inspect the homepage, the post's own URL, and /feed/. Private browsing clears local browser state; it does nothing about a host cache or CDN sitting between you and the server.

Purge the plugin cache, host cache, and CDN separately, checking after each action. If object caching is configured, include it in the investigation rather than assuming a page-cache purge clears everything.

A feed deserves its own check because feed readers poll it independently of the homepage. Use the RSS feed format example to identify the article entry rather than relying on how your browser renders XML.

Isolate conflicts on staging

On a staging copy, disable plugins except the cache and cron components needed to reproduce the setup, switch to a default theme, and schedule a test five minutes ahead. If it publishes, restore plugins in batches of three, then isolate the last batch when failure returns.

If it still fails, test the retained cache and cron components too. Leaving them enabled during the first pass doesn't prove they're innocent.

Prioritize these areas:

  • Caching plugins: Check stale public output and purge behavior.
  • Security plugins: Inspect blocked loopback or cron requests.
  • SEO customizations: Investigate code that alters publishing hooks.
  • Backup and scheduling plugins: Compare their events and execution times with the failure.

Change one variable at a time during isolation. Swapping two plugins, or adjusting a hook and a setting together, leaves you unable to say which change restored publishing. Note which component alters the result so another editor can repeat the test.

Record which update preceded the failure. Run disruptive isolation on staging, because disabling live-site plugins can interrupt readers and site functions.

Confirm the Publish Time and Keep Schedules Reliable

After any repair, schedule a clearly named test post ten minutes ahead. Confirm its appearance on the homepage where your layout normally lists new posts, at its own URL, and in /feed/.

Record when each surface updates instead of checking only the editor's status. For our publication, the feed check matters because Read More Info offers both a posts feed and a comments feed that readers can subscribe to in an RSS reader.

Use this final verification checklist after changing the setup.

An infographic listing four steps to verify that WordPress scheduled posts are publishing correctly.

Keep a small maintenance routine

  1. Verify the replacement scheduler monthly. Check crontab -l or the hosting panel and confirm the every-minute job still points to the right installation. Recheck paths after a migration rather than assuming the old command remains valid.

  2. Try an off-hour publication slot. Scheduling five to ten minutes away from the hour is a reasonable operational precaution if other jobs cluster on the hour. Treat it as a scheduling preference, not a cure for broken execution.

  3. Keep caching understandable. Prefer a clear caching setup over stacking overlapping cache plugins. Purge the relevant layers after a publishing test and keep a note of which layer affected the result.

  4. Retest after platform changes. Repeat the controlled test after WordPress, plugin, theme, or hosting upgrades. Retain the documented timezone convention so a later editor doesn't change what publication times mean without anyone noticing.

These are maintenance recommendations, not guarantees of exact-minute delivery. A working trigger, a valid publishing event, and fresh public output still need separate confirmation.

Keep the evidence useful

Save a short operational note with the working command, WordPress path, timezone, cache locations, and the latest successful test. That gives the next person something concrete to compare when scheduling fails again.

If you also use update alerts, check their behavior separately from publication. The site update notification guide provides a related workflow, but an alert should never replace checking the actual public post and feed.

Decision rule: Decide whether the problem is timing, state, cache, or conflict before changing a setting, because each has a different first check.

A dependable setup is one you can verify, not merely one with a cron plugin installed. Keep the test small, preserve the evidence, and stop making changes once the scheduled post completes the full public publishing path.


Read More Info publishes general-interest WordPress articles and provides open feeds for posts and comments. Visit Read More Info for related publishing guidance, then add its posts feed to your RSS reader to follow new articles without repeatedly checking the homepage.