CMS Hooks
Read-only · SDK 1.8TanStack Query hooks for fetching CMS posts, groups, and tags. Authoring (create / update / delete) lives in Reopt Studio.
usePostList
Fetch and cache posts with optional status, group, search, and pagination filters. Returns CmsPaginatedResponse<Post>.
components/post-list.tsx
import { usePostList } from "@reopt-ai/brandapp-sdk/react/hooks";
import type { ReoptSDK } from "@reopt-ai/brandapp-sdk";
function PostList({ sdk }: { sdk: ReoptSDK }) {
const { data, isLoading, error } = usePostList(sdk, {
status: "published",
limit: 20,
});
if (isLoading) return <p>Loading posts...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data?.records.map((post) => (
<li key={post.id}>
<a href={`/blog/${post.slug}`}>{post.title}</a>
<span>{post.status}</span>
</li>
))}
</ul>
);
}usePost
Fetch a single post by id (returns PostDetail with document.contentRich).
components/post-detail.tsx
import { usePost } from "@reopt-ai/brandapp-sdk/react/hooks";
import type { ReoptSDK } from "@reopt-ai/brandapp-sdk";
function PostDetail({ sdk, postId }: { sdk: ReoptSDK; postId: string }) {
const { data: post } = usePost(sdk, postId);
if (!post) return null;
return <article>{post.title}</article>;
}usePostBySlug
Resolve a post by its slug without an id mapping — ideal for a /blog/[slug] route. Server components can call sdk.cms.posts.getBySlug directly to avoid an extra HTTP hop.
components/blog-article.tsx
import { usePostBySlug } from "@reopt-ai/brandapp-sdk/react/hooks";
import type { ReoptSDK } from "@reopt-ai/brandapp-sdk";
// Resolve a post by its slug (e.g. for a /blog/[slug] route on your own site).
// The 3rd arg scopes the lookup to a post group; the 4th passes React Query options.
function BlogArticle({ sdk, slug }: { sdk: ReoptSDK; slug: string }) {
const { data: post, isLoading } = usePostBySlug(sdk, slug);
if (isLoading) return <p>Loading...</p>;
if (!post) return <p>Not found</p>;
return <article>{post.title}</article>;
}usePostGroupList
List post groups (categories). Returns CmsPaginatedResponse<PostGroup> with postCount per group.
components/group-nav.tsx
import { usePostGroupList } from "@reopt-ai/brandapp-sdk/react/hooks";
import type { ReoptSDK } from "@reopt-ai/brandapp-sdk";
// Returns CmsPaginatedResponse<PostGroup> (records, total, page, ...).
function GroupNav({ sdk }: { sdk: ReoptSDK }) {
const { data } = usePostGroupList(sdk, { sortBy: "name" });
return (
<nav>
{data?.records.map((group) => (
<a key={group.id} href={`/blog/${group.slug ?? group.id}`}>
{group.name} ({group.postCount})
</a>
))}
</nav>
);
}usePostGroup
Fetch a single post group by id (returns PostGroup).
components/group-header.tsx
import { usePostGroup } from "@reopt-ai/brandapp-sdk/react/hooks";
import type { ReoptSDK } from "@reopt-ai/brandapp-sdk";
function GroupHeader({ sdk, groupId }: { sdk: ReoptSDK; groupId: string }) {
const { data: group } = usePostGroup(sdk, groupId);
if (!group) return null;
return (
<header>
<h1>{group.name}</h1>
<p>{group.postCount} posts</p>
</header>
);
}useCmsTags
List the tags used across the brand scope. Returns Tag[] where each entry is { id, text, postCount }.
components/tag-cloud.tsx
import { useCmsTags } from "@reopt-ai/brandapp-sdk/react/hooks";
import type { ReoptSDK } from "@reopt-ai/brandapp-sdk";
// Tag[] — each entry is { id, text, postCount }. Optionally scope by groupId.
function TagCloud({ sdk, groupId }: { sdk: ReoptSDK; groupId?: string }) {
const { data: tags } = useCmsTags(sdk, groupId ? { groupId } : undefined);
return (
<div>
{tags?.map((tag) => (
<span key={tag.id}>
{tag.text} ({tag.postCount})
</span>
))}
</div>
);
}