Publishing and Custom Domains
Publishing is two distinct steps: a build turns your content into static files, and a deploy uploads those files to Cloudflare Pages. This page covers what the build produces, how the deploy works, and how to put your own domain in front of it.
The build
Settings, Generation has the Build Site button. A build is a full production build: it cleans the output directory first and minifies the HTML it writes.
Every build produces:
- one directory per post at
posts/{slug}/index.html - one directory per page at
{slug}/index.html - the homepage at
index.html, either the post listing or a page you promoted - paginated archives at
posts/index.htmlandposts/page/{n}/index.html - a tag index at
tags/index.htmland a page per tag attags/{slug}/index.html - a
404.html, which static hosts serve for unknown routes - member pages (login, signup, verify, portal)
rss.xmlandatom.xml, plus/rss,/feed, and/atomdirectories that redirect to themsitemap.xmlandrobots.txt(whoseSitemap:line uses your Site URL)llms.txtandllms-full.txt- your theme’s static assets, your site’s own static files (which override theme files of the same name), and the site’s media library
Drafts are excluded unless you turn on “Include draft posts in build”. Paid-tier gated posts are redacted before anything is rendered, so a gated body never reaches the static output, the feeds, the sitemap, or llms.txt.
After a build the page shows a “Last built” timestamp and a Download button that gives you the entire output as a zip. That zip is a complete static site: you can host it anywhere, WordPuppi included or not.
Previewing before you deploy
Three things let you look at the site without publishing it.
- Preview site, in the site sidebar, builds your saved content and opens a preview in a new tab. On a phone-width screen it is the arrow icon in the top bar. It always builds first, so a page you added a minute ago is in it. In the desktop app it opens in your system browser.
- The Preview link card in Settings, General is a stable address for the last build, of the form
/preview/{slug}/{key}/. Send it to a reviewer, make separate revocable share links, or rotate the key to cancel every link at once. See Sites and Settings. A preview link shows the last build, so it does not change until you build again. - The Preview button in a post or page editor renders that one item through your real theme without saving it. It is a quick check, not a build.
Published versus draft
A post or page only reaches a build when its status is published. In the Posts and Pages lists, the Published switch in each row flips a post or page between published and draft without opening it, and the label beside it says which state it is in (posts can also read Scheduled or Archived). Publishing here still only marks the item publishable: nothing changes on the public web until you build and deploy.
The not deployed badge
When you have saved changes that the live site has not seen yet, a round count badge appears beside Preview site in the sidebar. Its tooltip reads “Changes not deployed”. Press it to open Not deployed yet, which shows when the site was last deployed (or “Never deployed”) and lists each unpublished change with its kind: Post, Page, Settings, or Theme, and when it changed. Long lists end with “and N more”.
If Cloudflare Pages is connected, the popover has a Deploy button that runs the same build and deploy as the Generation page. If it is not, it tells you to connect a Cloudflare Pages project. The badge disappears when nothing is pending, and after a deploy it refreshes.
Deploying to Cloudflare Pages
Connect Cloudflare Pages under Site platforms, on the Deploy tab, first (see Getting Started for the token permissions). Then Build & Deploy on the generation page does the whole thing in one press. On the Deploy tab, a Cloudflare Pages assignment also has its own Deploy button, which asks you to confirm before it publishes.
Build
The site is rebuilt from current content and the resolved theme, so a deploy never ships a stale build.
Ensure the project
WordPuppi looks up the Pages project by name, and creates it (production branch main) if it does not exist. The name defaults to your site slug, unless the connection or the request names one.
Upload
Every output file is hashed, and Cloudflare is asked which hashes it is missing. Only missing files are uploaded, in batches, with retries and automatic token refresh. _redirects and _headers travel as their own parts rather than as static assets.
Create the deployment
A manifest of path to hash is posted, and Cloudflare publishes the deployment. The URL comes back in the toast and stays linked on the card.
Unchanged files are not re-uploaded, so a second deploy of a mostly unchanged site is quick.
The generated _redirects
The build writes a Cloudflare Pages _redirects file with:
200rewrites for/member/verify/*and/member/unsubscribe/*, so member magic links resolve to the member pages while keeping the token in the URL for the page’s own JavaScript to read- a
301from your homepage page’s own slug URL to/, when you promoted a page to homepage, so you do not serve two copies of the same content
Custom domains
Type a hostname into Custom Domain on the deploy card and press Save. Two things happen:
- The domain is registered on the Cloudflare Pages project. A domain that is already registered is treated as success, not as an error.
- If your API token carries zone permissions, WordPuppi finds the zone, then updates or creates a proxied
CNAMErecord for that hostname pointing at<project>.pages.dev. A record that already points there is left alone.
If the DNS step fails, the domain is still added to the project and the toast tells you to check your DNS zone yourself.
The card then polls Cloudflare for verification status and shows it: “Verifying on Cloudflare Pages” while it is pending, and “Active on Cloudflare Pages” once it goes live.
Also set Site URL in generation settings to the domain you are serving from. That is what canonical links, the sitemap, and robots.txt are built against, and it is not derived from the domain field automatically.
Deployment history
GET /api/v1/cloudflare/deployments lists deployments for the project, and GET /api/v1/cloudflare/deployments/{id} returns one, each with its environment, URL, status, and creation time. The deploy card surfaces the latest one as a link.