How to Preview WordPress Drafts in Astro Before Publishing

Disclaimer: Content may contain affiliate links, WPThink.com may earn a commission from qualifying purchases.

Why preview breaks

A WordPress preview can be perfectly valid while Astro still looks dead.

The editor clicks Preview, WordPress opens a URL, and Astro answers with a 404 or yesterday’s version. That usually feels like a content error, but it is not. WordPress can preview unpublished revisions inside its own authenticated world; a static Astro site only knows whatever content was fetched during the last build.

Until Astro is given a preview-aware path—typically SSR, on-demand rendering, or a signed draft endpoint—it has nothing to render for that draft. In other words, the failure is structural, not editorial: WordPress is showing future data, while Astro is serving frozen data.

The mismatch

Why ordinary Astro fetching misses previews

Published pages and preview content come from different lifecycles.

Astro’s default model assumes content is known at build time. A page is generated from a stable URL, using a query that returns only publicly visible records, and that HTML is then frozen until the next build. That works perfectly for posts whose WordPress status is publish.

Preview content lives somewhere else. A draft, scheduled entry, or in-progress edit is often stored as a draft plus revision or autosave, not as the public version attached to the site’s normal content path. In WordPress, the preview a logged-in editor sees is usually the latest revision, while the public slug may still point to an older published post—or to nothing at all.

That creates two different retrieval patterns:

  • Published pages: fetch by slug through ordinary REST or GraphQL queries during the Astro build.
  • Preview pages: fetch by post ID or preview token at request time, usually with authentication.
  • Scheduled and draft content: may be excluded from public queries entirely.

So the problem is not rendering. It is addressing and access: previews are private, mutable, and revision-based, while static routes are public, fixed, and build-based.

Practical default

Choose the preview model with the smallest blast radius

Three patterns usually appear, but only one fits most editorial teams cleanly.

  • Full-site SSR: simplest mental model, because every request can ask WordPress for draft-aware data. The cost is permanent runtime hosting, more caching complexity, and weaker static guarantees. That trade-off matters, especially when comparing Astro’s static and SSR behavior for frequently updated sites.
  • Separate preview builds or staging deploys: useful for reviewing branches, layout changes, or near-final content. It is much less reliable for individual draft revisions, autosaves, and last-minute editorial checks.
  • A dedicated SSR preview route: the usual sweet spot. Public pages stay fully static, while /preview/... runs server-side, validates a WordPress preview token, and fetches the correct draft or revision at request time.

This route isolates risk instead of turning the whole site dynamic. It also keeps preview logic where it belongs: authenticated, uncached, and explicit.

In practice, that means static for visitors, SSR for editors—a narrow dynamic surface that solves previews without rewriting the delivery model.

WordPress side

Define the preview contract in WordPress

Reliable preview begins before Astro fetches anything. WordPress must turn its Preview action into a custom URL that points at Astro’s preview route, not the default frontend. In practice, that URL should carry only the context Astro needs: content type, a stable record key, and—when revision fidelity matters—a revision or autosave reference. This is the part many guides skip, even in a broader Astro and WordPress integration walkthrough.

The most important rule is simple: never key preview by slug. Slugs change during editing, may not exist on drafts, and can point to the wrong version after a rename. Use an immutable identifier instead, such as database ID or another permanent internal key exposed by the API.

A dependable contract usually includes:

  • a custom preview URL like /preview?type=post&id=123
  • a stable identifier that survives title and slug edits
  • an auth mechanism that can read drafts, autosaves, or revisions

Authentication deserves special care. Browser cookies and wp-admin nonces often break across domains, so server-to-server access is usually safer: Application Passwords, JWT, or a signed token exchange handled only on the Astro server. If WordPress cannot package trustworthy preview context, Astro cannot produce trustworthy previews.

Revision accuracy depends on what WordPress sends

If editors must preview the exact autosave rather than the latest draft record, include a revision identifier in the preview URL and fetch that version explicitly.

Implementation

Build one preview route, then keep the rest of the stack familiar

  1. Create a single server-rendered preview page

    Add an Astro route such as /preview/[id] or /preview?post=123 that runs on the server. This route is the only part of the site that needs runtime draft access; published post pages can remain static.

  2. Fetch by immutable WordPress ID, never by slug

    Preview links should carry the database ID because titles and slugs often change during editing. The server route can then perform an authenticated request to WordPress and ask for the current draft, autosave, or latest revision for that exact post ID.

  3. Authenticate the fetch and request non-public states

    Use the same credentials strategy chosen earlier—cookies, JWT, Application Passwords, or a preview proxy—but make sure the query can see unpublished content. In practice that means requesting draft, pending, private, and revision-like sources instead of the normal public publish-only query.

  4. Normalize preview data to the published post shape

    Convert the draft or revision response into the same fields used by the public page: title, content, excerpt, author, date, featured image, SEO metadata, and taxonomy terms. This translation layer is where preview logic belongs, not inside templates.

  5. Render with the exact same presentation components

    Pass the normalized preview payload into the same PostLayout, rich-text renderer, blocks, and SEO components used for live posts. Usually the only preview-specific UI needed is a small banner and noindex plus Cache-Control: private, no-store headers.

A shared renderer prevents the common failure mode where preview looks correct but the published page breaks—or the reverse.

Most preview bugs are data bugs wearing a template costume

When teams build a separate preview template, drift starts immediately: one path handles featured images differently, another skips block transforms, another misses SEO fields.

A safer pattern is simple: special loading, shared rendering. Let the preview route do unusual work—authentication, revision lookup, autosave fallback, cache bypassing—but hand the result to the same components that render production content. That keeps preview honest because it exercises the real page, not a lookalike.

Security first

Lock down the preview path

Rendering a draft is not enough; the preview route is a private delivery channel. If a CDN, browser, or reverse proxy treats it like ordinary content, stale responses can survive edits, or one editor’s draft can leak into another request. That is why the route used to preview a draft before deployment should opt out of caching at every layer.

  • Send Cache-Control: private, no-store, max-age=0 and disable platform edge caching.
  • Add Vary: Cookie or the exact auth header used for preview access.
  • Return X-Robots-Tag: noindex, nofollow, noarchive so crawlers do not retain the URL.

WordPress credentials must stay on the server. The browser should receive only a signed, short-lived preview token or an HttpOnly session cookie, while Astro performs the authenticated WordPress fetch server-side. Avoid exposing application passwords, bearer tokens, or draft identifiers in client JavaScript, public env vars, or shareable query strings that end up in logs and analytics.

Private by default

A preview that can be indexed, cached, or replayed is a publication bug, not a successful preview implementation.

FAQ

When previews still refuse to behave

Why does the preview show the published post instead of the draft?

The route is usually resolving by slug when WordPress issued a post ID. Drafts, autosaves, and revisions can point to different records, so the fetch must follow the immutable content ID first.

Why does stale content keep appearing after the logic looks correct?

A static page, browser cache, edge cache, or host CDN may still be serving an older response. Preview endpoints should send no-store headers, and hosts that cache authenticated GET requests need special attention.

Why does preview work locally but fail in staging or production?

Environment drift is common: wrong secrets, mismatched site URLs, stripped auth headers, or proxy rules that drop cookies. HTTPS-only callbacks and CORS differences also break otherwise correct code.

Why are featured images or embeds missing only in preview?

Draft content often exposes media URLs or domains not allowed in the Astro image pipeline. Relative URLs, private media, and environment-specific asset hosts should be normalized and explicitly permitted.

When is the preview system not the real problem?

If the base Astro-to-WordPress connection is shaky, preview debugging becomes misleading. In that case, starter setup and workflow choices should be fixed first.

Checklist

Preview Readiness Check

  • Wrong content never appears

    Opening a preview URL shows the latest draft, autosave, or revision for that post ID—not the published slug page or another entry.

  • Access is private

    Preview requires valid WordPress auth or a signed token. Responses send no-store and noindex, and credentials never reach the browser.

  • Rendering matches production

    The preview route uses the same Astro components, serializers, and asset handling as published pages. Differences stay limited to preview-only fetch logic.

  • Links and media stay consistent

    Canonical URLs remain public URLs, while internal links, embeds, and image domains resolve correctly inside preview sessions.

  • Failure modes are obvious

    Expired auth, missing revisions, and fetch errors return explicit diagnostics to editors and logs to developers instead of silently falling back to published content.

If every item passes, draft preview is dependable enough for editorial sign-off.