Caching – astrojs-wp-integration
Caching
Section titled “Caching”This package integrates with Astro route caching through live-loader cacheHint values and one invalidation action:
createWpCacheInvalidateAction()for posts, terms, and users
Astro owns the cache runtime and configuration. Use the Astro docs as the source of truth for setup and provider behavior:
What The Integration Adds
Section titled “What The Integration Adds”- Live loaders return
cacheHint.lastModifiedwhen the WordPress payload exposes a trustworthy timestamp. - Live loaders return tags for entry identity and useful relationships such as authors and terms.
- The cache invalidation action fetches the latest WordPress entity, derives the entry tag, and calls
context.cache.invalidate()for you.
flowchart LR A[App route or API endpoint] --> B[getLiveEntry() or getLiveCollection()] B --> C[wp-astrojs-integration live loader] C --> D[WordPressClient] D --> E[WordPress REST API] C --> F[cacheHint with tags and lastModified] F --> A A --> G[Route applies Astro.cache.set(...) or context.cache.set(...)] H[createWpCacheInvalidateAction] --> I[Read changed WordPress entity] I --> J[Derive narrow entry tag] J --> K[context.cache.invalidate(...)]The invalidation action is intentionally narrower than the full live-loader tag set:
- post invalidation targets only the changed entry tag
- term invalidation targets only the changed entry tag
- user invalidation targets only the changed entry tag
That keeps cached listing strategies effective when only one changed item needs to be refreshed.
Live Collection Usage
Section titled “Live Collection Usage”Pass the live-loader cache hint straight into Astro.cache.set() and then add your route freshness settings.
---import { getLiveEntry } from 'astro:content';
const { entry, error, cacheHint } = await getLiveEntry('books', { slug: Astro.params.slug });
if (error || !entry) { return Astro.redirect('/404');}
if (cacheHint) { Astro.cache.set(cacheHint);}
Astro.cache.set({ maxAge: 300 });---
<h1>{entry.data.title.rendered}</h1>Fluent AI Tool Reads
Section titled “Fluent AI Tool Reads”For public/shared AI endpoints, fluent-wp-client/ai-sdk tool factories can use a fetch override that delegates reads to a live collection. This keeps AI tooling owned by fluent-wp-client while still letting the Astro endpoint consume live-loader cache hints.
import { getLiveEntry } from 'astro:content';import type { APIRoute } from 'astro';import { getContentTool } from 'fluent-wp-client/ai-sdk';import { wp } from '../../lib/wp';
export const GET: APIRoute = async (context) => { const tool = getContentTool(wp, { contentType: 'posts', fetch: async (input) => { if (!input.id && !input.slug) { throw new Error('Provide either id or slug to read a post.'); }
const lookup = input.id ? { id: input.id } : { slug: input.slug }; const { entry, error, cacheHint } = await getLiveEntry('posts', lookup);
if (error) throw error; if (cacheHint) context.cache.set(cacheHint);
return { item: entry?.data }; }, });
if (!tool.execute) throw new Error('Content tool is not executable.');
const result = await tool.execute({ slug: 'hello-world' }, { toolCallId: 'read-post', messages: [], });
context.cache.set({ maxAge: 300, swr: 60 });
return Response.json(result);};Do not use this pattern for per-user reads. Live collections do not receive request, cookies, or locals; use a request-scoped WordPressClient and context.cache.set(false) for user-specific content.
Filtered Collections
Section titled “Filtered Collections”Filtered live collections can use collection-level cache hints when the result set has stable membership, such as include, exclude, taxonomy filters, author filters, or explicit ordering.
Free-text search filters do not receive a collection-level cache hint. A search result can change when any matching or formerly matching WordPress entity changes, so caching the whole result set under one route hint is not safe. Entries returned from the search still include per-entry cache hints, so routes can cache individual entity pages or compose their own narrower strategy.
---import { getLiveCollection } from 'astro:content';
const { entries, cacheHint } = await getLiveCollection('posts', { search: Astro.url.searchParams.get('q') ?? '',});
// `cacheHint` is undefined for free-text search results.if (cacheHint) { Astro.cache.set(cacheHint);}---
<ul> {entries.map((entry) => <li>{entry.data.title.rendered}</li>)}</ul>Invalidation Actions
Section titled “Invalidation Actions”Create the action next to your existing WordPress write actions:
import { createWpCacheInvalidateAction,} from 'wp-astrojs-integration';import { wordPressAuthBridge } from '../lib/auth/bridge';
export const server = { wpCacheInvalidate: createWpCacheInvalidateAction(wordPressAuthBridge.getClient),};Call it with id and entity. Add post_type for posts, taxonomy for terms, and nothing extra for users:
import { z } from 'zod';
const baseSchema = z.object({ id: z.number(),}).passthrough();
export const postSchema = baseSchema.extend({ entity: z.literal('post'), post_type: z.string(),});
export const taxonomySchema = baseSchema.extend({ entity: z.literal('term'), taxonomy: z.string(),});
export const userSchema = baseSchema.extend({ entity: z.literal('user'),});Examples:
await actions.wpCacheInvalidate({ id: 42, entity: 'post', post_type: 'book',});
await actions.wpCacheInvalidate({ id: 8, entity: 'term', taxonomy: 'genre',});
await actions.wpCacheInvalidate({ id: 3, entity: 'user',});User-Specific Routes
Section titled “User-Specific Routes”For user-specific pages, use a request-scoped fluent-wp-client instance from middleware or the auth bridge and opt out per route instead of caching everything globally:
That is the right default for dashboards, account pages, or any route where request cookies or user identity affect the HTML. Do not route per-user reads through live loaders; live loaders do not receive request, cookies, or locals.