Scheduled publishing sounds simple: write the article now, choose a date, and let the system publish it later. On a static website there is no WordPress scheduler waiting behind the scenes, so you have to create that publishing system yourself.
WordRanger was where I learned the difference between having a scheduled workflow and having a reliable publishing process.
What GitHub Actions is doing in this setup
GitHub Actions runs workflows defined in YAML files inside .github/workflows. A workflow can run after a repository event, on a manual command, or on a schedule.
For a small static blog, the publishing job can be very simple conceptually:
- Check today's date.
- Look for a matching dated folder.
- Move or copy the due article into the live blog directory.
- Remove the scheduled copy.
- Commit the change.
- Regenerate the sitemap or blog index if needed.
- Deploy the current production files.
A simple folder model
One understandable approach is to keep scheduled posts outside the public blog folder:
scheduled/
2026-09-22/
blog/
automate-blog-publishing-github-actions.html
blog/
already-published-article.htmlThe production build should exclude scheduled/. Otherwise the unpublished file may still be publicly accessible even though it is not linked from the blog page.
The schedule itself is only one part
A GitHub Actions schedule uses cron syntax. GitHub currently allows scheduled workflows on the default branch, and scheduled runs use the latest commit on that branch. GitHub also supports an IANA timezone field for timezone-aware scheduling.
A schedule might look conceptually like this:
on:
workflow_dispatch:
schedule:
- cron: '15 9,10,11,12 * * *'
timezone: "America/New_York"The repeated hours can give a publishing job more than one opportunity to catch a due folder. The manual workflow_dispatch trigger is equally important because it gives you a way to test or recover without editing the article itself.
Why a scheduled run may not happen exactly when expected
This was one of the confusing WordRanger moments. A scheduled job did not appear when expected, even though the workflow could run manually.
GitHub's documentation says scheduled Actions can be delayed during periods of high load, especially near the start of an hour. If load is sufficiently high, some queued jobs can be dropped. GitHub specifically recommends scheduling at a different minute of the hour to reduce this risk.
That means a missed run does not automatically tell you what failed. You need to separate trigger problems from workflow-logic problems.
Use manual dispatch as your first test
Before trusting the scheduler:
- Create a harmless test article or dated folder.
- Run the workflow manually from the Actions tab.
- Confirm the article reaches the correct live path.
- Check the generated sitemap and blog index.
- Confirm the deployment completes.
- Open the live page.
If the manual run fails, fix the publishing logic first. If the manual run succeeds but the scheduled run does not appear, investigate the trigger and GitHub's scheduling behavior separately.
Do not let a scheduled folder overwrite the current site
One mistake that can hide inside a working scheduler is copying an entire dated folder over production. If the folder contains an old copy of blog.html or sitemap.xml, the scheduled release can quietly restore stale versions of those files.
A safer pattern is to store only the new article in the scheduled folder. On publish day, let the workflow update the current blog index and regenerate the sitemap from the current production content.
| Risky pattern | Safer pattern |
|---|---|
| Store article + old blog index + old sitemap in each dated folder | Store only the article and generate shared files at publish time |
| Copy the entire scheduled folder into production | Copy only approved article files |
| Assume a scheduled run will be exact | Allow multiple check windows and retain manual dispatch |
| Publish before testing the workflow | Run the full logic manually first |
Protect the production branch
Scheduled workflows only run from the default branch, so the workflow file needs to exist there. For a small personal project, main often acts as production.
The workflow also needs only the permissions required for its job. If it commits published files back to the repository, it needs appropriate contents write permission. Deployment credentials such as Cloudflare API tokens should live in repository secrets rather than inside the YAML or public code.
Update dates when the article actually publishes
If an article was drafted weeks earlier, decide whether the visible publication date and structured-data datePublished should reflect the scheduled release. A workflow can normalize those fields when it publishes.
The important thing is consistency. The visible date, structured data, sitemap, and blog card should not contradict one another.
Regenerate the sitemap after publishing
A scheduled article should become discoverable through normal internal links and the sitemap once it is public. Generating the sitemap during deployment is safer than maintaining a series of future sitemap snapshots.
That also prevents unpublished URLs from being submitted to search engines before the article is live.
What to inspect when the workflow fails
- Did a workflow run exist? If no, investigate the trigger and schedule.
- Which job failed? Open the run and identify the first failed job.
- Which step failed? Read the step logs rather than guessing from the red X.
- Was the dated folder found? Check timezone and folder naming.
- Did Git have permission to commit? Review workflow permissions.
- Did deployment fail after publishing? The repository may have updated correctly even if hosting did not.
Do you still need a test scheduler?
Not forever. A dedicated test workflow is useful while you are proving that scheduled events and publishing logic behave as expected. Once the production workflow has run successfully on schedule several times and you have a manual fallback, a permanent test scheduler may only create noise.
The better long-term safeguard is observable production: clear workflow names, useful logs, manual dispatch, sensible commit messages, and notifications for failures.
A beginner-friendly scheduled publishing checklist
- The workflow file exists on the default branch.
- The scheduled folder is excluded from production deployment.
- The date folder format is consistent.
- The workflow publishes article files only.
- The blog index is updated from the current version.
- The sitemap is regenerated after publication.
- The workflow has been tested manually.
- The schedule uses a non-zero minute where practical.
- There is more than one daily check if missing the exact first run would matter.
- A manual fallback remains available.
- Secrets are stored in GitHub Secrets, not the repository.
- Workflow logs are checked when anything behaves unexpectedly.
What WordRanger changed about how I think about automation
Before building the scheduler, automation sounded like a way to avoid work. After debugging it, I think of automation differently: it moves repeated work into a system, but that system becomes something you have to understand well enough to verify.
That is still a good trade. Once the process works, scheduling a post means creating the article and placing it in the right dated folder instead of remembering to publish manually. But the useful automation is the version with a clear fallback and no mystery about what happens when it fails.
References
- GitHub. Events that trigger workflows. GitHub Docs.
- GitHub. Workflow syntax for GitHub Actions. GitHub Docs.
- GitHub. Troubleshooting workflows. GitHub Docs.