npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

fluent-wp-client

v3.0.1

Published

Runtime-agnostic TypeScript WordPress REST API client with typed CRUD, auth, abilities, relation helpers, and an optional Gutenberg block add-on

Readme

fluent-wp-client

Runtime-agnostic TypeScript client for the WordPress REST API.

Works on Node.js, Deno, Bun, and in the browser — using only web-standard APIs (fetch, URL, Blob).

Install

npm install fluent-wp-client

Quick start

import { WordPressClient } from 'fluent-wp-client';

const wp = new WordPressClient({
  baseUrl: 'https://your-wordpress-site.com',
});

const posts = wp.content('posts');

// Read a list of posts
const recentPosts = await posts.list({ perPage: 10 });

// First-class resources use the same fluent style
const comments = await wp.comments().list({ post: 42 });

// Read a single post
const post = await posts.item('hello-world');

// Create a draft post (requires auth)
const draft = await posts.create({ title: 'Hello', status: 'draft' });

Design principles

  • WordPress is the source of truth for validation. Request and mutation helpers defer validation to the REST API. When you want local validation, use .describe(), .explore(), or CLI-generated artifacts in application code.
  • Schemas are discoverable at runtime. Every resource and ability exposes its live JSON Schema through .describe() and wp.explore(), making the client adaptive to custom post types, taxonomies, plugin endpoints, and ACF fields.
  • Strict defaults for built-ins, flexible defaults for everything else. Native posts and pages get strict typing; generic CPTs default to a post-like shape that tolerates WordPress supports removing fields like title, content, or author.
  • Extension by composition, not hard-coding. content(resource), terms(resource), ACF relation extraction, and ability builders stay generic so projects can layer in custom fields, meta, relations, and plugin data without fighting the client.
  • Runtime-agnostic and serialization-safe. Terminal reads return plain DTOs that survive structuredClone(), JSON.stringify(), and cross-boundary transport (SSR, RSC, postMessage).

Features

  • Unified typed content builderscontent('posts'), content('pages'), content('books'), and terms('genre') share one API shape, with stricter typing for built-in resources
  • First-class fluent resource clientsmedia(), comments(), users(), and settings() expose consistent list/item/create/update/delete/describe APIs, with upload() for media and me() for users
  • Cross-resource searchsearchContent() queries across posts, pages, and CPTs via the /wp/v2/search endpoint
  • Parallel bulk fetchinglistAll() fetches all pages in parallel batches for dramatic speed improvements on large datasets
  • Rate limiting supportonRequest callback lets you implement custom rate limiting or request logging
  • Extensible collection filters — built-in list helpers and generic resource builders accept typed core filters plus extra endpoint-specific query params
  • Lean embedded payloads — post-like DTO reads skip _embed by default; opt in with embed: true or selective embed: ['author', 'wp:term'] and use typed extraction helpers
  • Flexible CPT defaults — generic content reads tolerate post types that omit title, content, excerpt, or author
  • Portable Gutenberg block add-onfluent-wp-client/blocks adds block type discovery, generated block JSON Schemas, parse/serialize/validate helpers, and explicit .blocks().get() / .blocks().set() content workflows
  • Framework-neutral agent helpers — root package APIs expose JSON Schema selectors, fields, and query argument helpers for Flue, MCP, LangChain, and custom agents
  • AI SDK tool factoriesfluent-wp-client/ai-sdk exposes manually composable Vercel AI SDK tools
  • CLI schema/code generationfluent-wp-client ships a CLI for discovering resource schemas and generating TypeScript, JSON Schema, and Zod outputs
  • Auth flexibility — Basic auth (application passwords), JWT, cookie+nonce, prebuilt headers, and per-request signing
  • WordPress Abilities API — discover and execute registered abilities with the same upstream-validated model as the rest of WordPress
  • Schema discovery and custom validation — validator-agnostic root exports plus .describe(), .explore(), and CLI schema generation for app-level Zod, Valibot, or custom validation
  • Embed extraction helpersgetEmbeddedAuthor(), getEmbeddedTerms(), getEmbeddedFeaturedMedia(), getEmbeddedParent(), plus ACF helpers like getAcfFieldPosts() and getAcfFieldTerms()

Gutenberg block workflows

Use the dedicated block add-on when you need block parsing, validation, or block type discovery:

import { WordPressClient } from 'fluent-wp-client';
import { withBlocks } from 'fluent-wp-client/blocks';

const wp = new WordPressClient({
  baseUrl: 'https://example.com',
  auth: { username: 'admin', password: 'app-password' },
});

const wpBlocks = withBlocks(wp);
const blockSchemas = await wpBlocks.blocks().schemas();
const postQuery = wpBlocks.content('posts').item('hello-world');
const blocks = await postQuery.blocks().get({
  schemas: blockSchemas,
  validate: true,
});

blocks[0].innerHTML = '<p>Updated paragraph body.</p>';
blocks[0].innerContent = ['<p>Updated paragraph body.</p>'];

await postQuery.blocks().set(blocks, blockSchemas);

Standalone helpers are also available when you already have raw content.raw:

import {
  createWordPressBlockJsonSchemas,
  parseWordPressBlocks,
  serializeWordPressBlocks,
  validateWordPressBlocks,
} from 'fluent-wp-client/blocks';

const blockTypes = await wpBlocks.blocks().list();
const blockSchemas = createWordPressBlockJsonSchemas(blockTypes);
const blocks = await parseWordPressBlocks(content.raw);
const result = await validateWordPressBlocks(blocks, {
  schemas: blockSchemas,
});

if (result.valid) {
  const nextContent = await serializeWordPressBlocks(blocks);
}

blocks().set() does not implicitly fetch block types. Pass the schemas you want to allow when you need whitelist validation.

If you want native Zod schemas for AI-produced block trees, import them from fluent-wp-client/blocks/zod.

AI SDK Integration

Use the optional fluent-wp-client/ai-sdk entrypoint when you want manually composable Vercel AI SDK tools built on top of your WordPress client instance.

import { WordPressClient } from 'fluent-wp-client';
import {
  getContentCollectionTool,
  getContentTool,
  saveContentTool,
} from 'fluent-wp-client/ai-sdk';

const wp = new WordPressClient({
  baseUrl: 'https://example.com',
  auth: { username: 'editor', password: 'app-password' },
});

await wp.explore();

const tools = {
  searchPosts: getContentCollectionTool(wp, {
    contentType: 'posts',
    fixedArgs: { perPage: 5, status: 'publish' },
  }),
  readContent: getContentTool(wp),
  writePost: saveContentTool(wp, {
    contentType: 'posts',
    fixedInput: { status: 'draft' },
  }),
};

saveContentTool handles both create and update — call it without id to create, or with id to update. One tool surface, one mental model.

Every tool factory accepts an optional fetch callback that replaces the default WordPress client call with a custom implementation — useful for caches, live loaders, proxies, or custom request pipelines. Works for reads and writes alike.

Use toolOptions to pass additional AI SDK tool settings such as title, inputExamples, lifecycle callbacks, outputSchema, or toModelOutput without replacing the generated WordPress execution and schema behavior.

See docs/ai-sdk.mdx for the full tool catalog and configuration model.

Framework-Neutral Agent Tools

Use root package helpers when your agent framework needs JSON Schema, selectors, fields, or query arguments to register its own tools.

await wp.explore();

const selectors = await wp.getCatalogSelectors();
const inputSchema = await wp.content('posts').getJsonSchema('create');
const queryParams = await wp.content('posts').getQueryParams();

Define framework-specific tool names, descriptions, defaults, fixed arguments, and mutation guardrails in your adapter. The package provides the catalog-derived building blocks.

CLI

Use the built-in CLI to discover WordPress REST schemas and generate code artifacts:

npx fluent-wp-client schemas --url https://example.com
npx fluent-wp-client schemas --url https://example.com --types-out wp-types.d.ts
npx fluent-wp-client schemas --url https://example.com --zod-out wp-schemas.mjs --types-out wp-types.d.ts
npx fluent-wp-client schemas --url https://example.com --zod-out wp-schemas.ts --json-out wp-schemas.json --types-out wp-types.d.ts

The schemas command discovers WordPress JSON Schema, then emits the artifacts requested by output paths. Omit output paths to write wp-schemas.ts, or pass paths such as --zod-out wp-schemas.mjs, --json-out wp-schemas.json, and --types-out wp-types.d.ts. Zod output is intentionally limited to .ts or .mjs; JSON Schema uses .json; standalone types use .d.ts.

Generated schemas relax WordPress-specific response quirks centrally: optional scalar ACF fields can validate as "", and registered meta fields accept WordPress' declared empty defaults. Authenticated runtime catalogs include catalog.site.timezone, keep strict date-time schemas for WordPress date fields, and automatically normalize subsequent DTO date values to offset ISO datetime strings. Without timezone metadata, schemas and DTOs fall back to WordPress' raw local datetime strings.

Rate limiting and request control

Use the onRequest callback to implement rate limiting, request logging, or other custom logic:

// Simple delay between requests
const wp = new WordPressClient({
  baseUrl: 'https://example.com',
  onRequest: async (url, init) => {
    await new Promise(resolve => setTimeout(resolve, 100));
  },
});
// Token bucket rate limiter
const rateLimiter = new TokenBucketLimiter({ tokensPerSecond: 10, maxTokens: 20 });
const wpWithRateLimit = new WordPressClient({
  baseUrl: 'https://example.com',
  onRequest: async (url, init) => {
    await rateLimiter.acquireToken();
  },
});

Parallel bulk fetching

listAll() automatically fetches pages in parallel for maximum performance. It fetches the first page to get the total count, then spawns parallel requests for remaining pages in configurable batches:

// Fetch all posts with default concurrency (5 pages at a time)
const allPosts = await wp.content('posts').listAll();

// Higher concurrency for faster fetching (use with caution)
const allUsers = await wp.users().listAll({}, {}, { concurrency: 10 });

// Lower concurrency to be gentler on the server
const allComments = await wp.comments().listAll({}, {}, { concurrency: 2 });

The explore() API also makes parallel requests when discovering all resources, dramatically speeding up schema discovery.

Flexible collection filters

Collection helpers keep typed core filters like search, include, exclude, and slug, and they also forward extra endpoint-specific params for plugin or project-specific REST extensions.

const posts = await wp.content('posts').list({
  search: 'hello world',
  include: [4, 8],
  titleSearch: 'Hello',
});

const books = await wp.content('books').list({
  include: [164, 165],
  titleSearch: 'Test Book',
});

Array params are serialized as repeated param[] entries instead of comma-joined strings.

Embedded data

Post-like DTO reads stay lean by default. Pass embed: true or a selective embed array to include related data, then use typed extraction helpers to pull it out:

import { getEmbeddedAuthor, getEmbeddedTerms } from 'fluent-wp-client';

const post = await wp.content('posts').item('hello-world', { embed: true });
const author = getEmbeddedAuthor(post);
const categories = getEmbeddedTerms(post, 'category');

// Selective embed reduces server-side work
const post2 = await wp.content('posts').item('hello-world', {
  embed: ['author', 'wp:term'],
});

// Embed on lists
const posts = await wp.content('posts').list({ perPage: 10, embed: true });

Auth examples

// Basic auth (WordPress application passwords)
const wp = new WordPressClient({
  baseUrl: 'https://example.com',
  auth: { username: 'admin', password: 'app-password' },
});

// JWT auth
const wp = new WordPressClient({
  baseUrl: 'https://example.com',
  auth: { token: 'jwt-token' },
});

// Cookie + nonce (browser sessions)
const wp = new WordPressClient({
  baseUrl: 'https://example.com',
  auth: { nonce: window.wpApiSettings.nonce, credentials: 'include' },
});

Documentation

Full documentation lives in the docs/ folder:

  • Overview — feature overview and quick start
  • Usage guide — all client methods, CRUD patterns, pagination, and error handling
  • Authentication — auth strategies and resolver helpers
  • Gutenberg content — the fluent-wp-client/blocks add-on for block type discovery, parsing, validation, and writes
  • Custom endpoints — custom post types, taxonomies, and plugin namespaces
  • Abilities — WordPress Abilities API
  • Validation — Standard Schema, Zod, and custom validators
  • Embed extraction — embed parameters, typed extraction helpers, and ACF relation extraction
  • Schema discovery.describe(), .explore(), and runtime Zod conversion
  • CLI — generate JSON Schema and Zod artifacts from live WordPress instances
  • AI SDK integration — compose WordPress tools for the Vercel AI SDK

Development

# Start the local WordPress environment
npm run wp:start

# Run the integration test suite
npm test

# Stop the environment
npm run wp:stop

Core transport, mutation helpers, query primitives, and base resource classes live under src/core/, while query builders live under src/builders/. Package consumers continue to import the public API from src/index.ts.

Tests run against a real WordPress Docker container managed by @wordpress/env. See tests/ for setup details.

License

GPL-2.0-or-later