Skip to content

Catalog Integration – astrojs-wp-integration

The catalog integration discovers your WordPress REST API during Astro setup and stores the result in Astro’s cache directory. Catalog-aware helpers can then use the stored metadata without repeating expensive discovery requests. When a WordPress URL is available, the integration also generates typed Zod schema artifacts in Astro’s cache using the fluent-wp-client schema CLI.

Use it when you want:

  • schema and resource metadata available during builds
  • generated Zod schemas and TypeScript resource types for your WordPress instance
  • discovery-aware helpers such as describe() to avoid extra network requests
  • direct fluent-wp-client tools and mapping code to share one build-time catalog
  • authenticated discovery for private resources, ACF fields, users, or abilities

The catalog contains metadata. Normal content reads such as client.content('posts').list() still fetch live WordPress data.

The virtual module is always importable when the integration is installed. When the catalog is disabled or optional discovery fails, catalog is undefined and hasCatalog is false.

[!CAUTION] The catalog can contain a large amount of schema metadata. Import virtual:wp-astrojs/catalog, virtual:wp-astrojs/schemas, and virtual:wp-astrojs/collections from server-only Astro files such as content.config.ts, actions/index.ts, pages, endpoints, or server utilities. Avoid importing them from client-side islands or browser bundles.

Add the integration to astro.config.mjs.

astro.config.mjs
import { defineConfig } from 'astro/config';
import wordpress from 'wp-astrojs-integration/integration';
export default defineConfig({
integrations: [
wordpress({
catalog: {
enabled: true,
refresh: 'build',
required: true,
},
}),
],
});

Set at least WP_CATALOG_URL in .env or in the environment that runs astro sync or astro build.

.env
WP_CATALOG_URL=https://cms.example.com

The integration uses Vite’s supported loadEnv() helper during Astro setup, so .env files and shell or CI variables are available. Shell and CI variables take precedence over .env values, matching Vite’s behavior.

Authenticated discovery supports JWT username/password login, application passwords, or a prebuilt Authorization header.

JWT login or application password
WP_CATALOG_USERNAME=admin
WP_CATALOG_PASSWORD="your-password"

When WP_CATALOG_USERNAME and WP_CATALOG_PASSWORD are present, the integration checks the WordPress REST index for the /jwt-auth/v1/token route key. If the route exists, it exchanges the credentials through the /wp-json/jwt-auth/v1/token endpoint. If the route does not exist, it uses application-password basic auth with the same values.

Prebuilt Authorization header
WP_CATALOG_AUTH_HEADER="Basic base64-value"

Use WP_CATALOG_AUTH_HEADER for custom auth flows such as CI-generated Bearer tokens, OAuth, or reverse proxies.

If your project already uses a shared public URL variable, pass it explicitly from astro.config.mjs or set catalog.envPrefix to match your variable prefix.

astro.config.mjs
wordpress({
catalog: {
envPrefix: 'PUBLIC_WORDPRESS_BASE_',
},
});

With that prefix, the integration reads PUBLIC_WORDPRESS_BASE_URL as the catalog URL.

The integration exposes virtual:wp-astrojs/catalog. Create your shared client from this module so it is seeded with the stored catalog.

src/lib/wp.ts
import { createWordPressClient } from 'virtual:wp-astrojs/catalog';
export const wp = createWordPressClient({
baseUrl: import.meta.env.WP_CATALOG_URL,
});

defineWordPressClient() is available as an alias if you prefer Astro-style naming.

Use the client with loaders and actions as usual.

src/content.config.ts
import { defineCollection } from 'astro:content';
import { postSchema } from 'fluent-wp-client/zod';
import { wordPressPostStaticLoader } from 'wp-astrojs-integration';
import { wp } from './lib/wp';
export const collections = {
posts: defineCollection({
loader: wordPressPostStaticLoader(wp),
schema: postSchema,
}),
};

The integration also exposes virtual:wp-astrojs/collections. Use defineWordPressCollection() when you want the loader and schema to come from the catalog together. For post types and taxonomies discovered by the schema CLI, the helper uses the generated typed Zod schema before falling back to runtime catalog conversion.

src/content.config.ts
import { defineWordPressCollection } from 'virtual:wp-astrojs/collections';
import { wp } from './lib/wp';
export const collections = {
posts: defineWordPressCollection('posts', { client: wp }),
books: defineWordPressCollection('books', { client: wp }),
livePosts: defineWordPressCollection('posts', {
mode: 'live',
client: wp,
}),
};

Pass schema when you need to override the generated schema, or loaderOptions to forward options such as mapEntry or embed to the underlying WordPress loader.

Override collection behavior
export const collections = {
mappedBooks: defineWordPressCollection('books', {
client: wp,
loaderOptions: {
mapEntry: (book) => ({
...book,
title: { ...book.title, rendered: book.title.rendered.trim() },
}),
},
}),
};

virtual:wp-astrojs/generated-schemas exposes the generated Zod schemas and TypeScript resource types produced from the same WordPress instance. This is useful when you want to reuse a validator outside defineWordPressCollection().

src/actions/index.ts
import { wpBookSchema, type WPBook } from 'virtual:wp-astrojs/generated-schemas';
export function normalizeBook(book: WPBook) {
return wpBookSchema.parse(book);
}

The integration writes these artifacts to Astro’s cache with the rc.5 CLI output flags:

Generated internally
fluent-wp-client schemas \
--url https://cms.example.com \
--zod-out .astro/wp-astrojs/generated-schemas.mjs \
--types-out .astro/wp-astrojs/generated-schemas.d.ts

JSON Schema files are not generated by the integration because Astro consumes the Zod validators and TypeScript declaration output.

Use virtual:wp-astrojs/schemas to apply catalog-derived create and response schemas to action factories.

src/actions/index.ts
import { createCreatePostAction, createUpdatePostAction } from 'wp-astrojs-integration';
import { withWordPressActionSchemas } from 'virtual:wp-astrojs/schemas';
import { wp } from '../lib/wp';
export const server = {
createBook: createCreatePostAction(
wp,
withWordPressActionSchemas('books', { resource: 'books' }),
),
updateBook: createUpdatePostAction(
wp,
withWordPressActionSchemas('books', { resource: 'books' }),
),
};

withWordPressActionSchemas() only fills missing schema and responseSchema values. Explicit schemas still win.

Override one action schema
export const server = {
createBook: createCreatePostAction(
wp,
withWordPressActionSchemas('books', {
resource: 'books',
schema: customCreateBookSchema,
}),
),
};
wordpress({
catalog: {
enabled: true,
refresh: 'build',
required: true,
envPrefix: 'WP_CATALOG_',
include: ['content', 'terms', 'resources', 'abilities'],
cacheFile: 'wp-astrojs/catalog.json',
},
});
OptionDefaultDescription
enabledtrueEnables catalog discovery.
refresh'build'Controls when discovery fetches from WordPress. Use 'build', 'dev', 'always', or 'manual'. manual never fetches and requires a stored catalog unless required is false.
requiredtrueThrows when the catalog cannot be loaded or fetched. Set to false to warn and continue with catalog as undefined.
envPrefix'WP_CATALOG_'Prefix for URL and auth env vars.
urlWP_CATALOG_URLWordPress base URL. Prefer env vars for deploy portability.
includeall kindsLimits discovery to content, terms, resources, or abilities.
cacheFilewp-astrojs/catalog.jsonRelative file inside Astro’s cache directory.
import {
catalog,
catalogPath,
createWordPressClient,
defineWordPressClient,
hasCatalog,
seedWordPressClient,
} from 'virtual:wp-astrojs/catalog';
ExportDescription
catalogThe stored WordPressDiscoveryCatalog, or undefined when disabled.
catalogPathAbsolute path to the cached catalog file.
hasCatalogBoolean convenience flag.
seedWordPressClient(client)Calls client.useCatalog(catalog) when a catalog exists.
createWordPressClient(config)Creates a WordPressClient and seeds it with the catalog.
defineWordPressClient(config)Alias for createWordPressClient(config).
import {
getWordPressContentSchemas,
getWordPressResourceSchemas,
getWordPressTermSchemas,
withWordPressActionSchemas,
} from 'virtual:wp-astrojs/schemas';
ExportDescription
getWordPressResourceSchemas(resource, options)Returns catalog-derived Zod schemas for any discovered resource.
getWordPressContentSchemas(resource)Returns schemas for one content resource such as posts, pages, or books.
getWordPressTermSchemas(resource)Returns schemas for one term resource such as categories, tags, or genres.
withWordPressActionSchemas(resource, options)Adds missing schema and responseSchema options for action factories.
import { defineWordPressCollection } from 'virtual:wp-astrojs/collections';
ExportDescription
defineWordPressCollection(resource, options)Defines a static or live Astro collection using a WordPress loader and catalog-derived item schema.
  • TypeScript88%
  • PHP11%
  • Astro1%