@roottale/cms-mcp
Version:
RootTale CMS integration MCP server — bundled integration docs, Next.js example code, and public API lookup tools. Run with: npx @roottale/cms-mcp
101 lines (84 loc) • 3.04 kB
Markdown
---
title: 메뉴 (네비게이션) 연동
description: 어드민 "디자인 > 메뉴"에서 관리하는 네비게이션을 헤더/푸터에 렌더
---
# 메뉴 (네비게이션) 연동
어드민(mysite.roottale.com)의 **디자인 > 메뉴**에서 저장한 네비게이션 트리를
사이트의 헤더·푸터에 렌더합니다. 고객이 직접 메뉴 항목(이름·주소·순서·하위
항목)을 바꿀 수 있어 코드 수정 없이 네비가 갱신됩니다.
- 메뉴는 **위치 핸들(slug)** 로 구분합니다 — 관례: `primary`(헤더), `footer`(푸터).
- 항목은 깊이 2 트리 (상위 + 드롭다운 1단).
- `url` 은 상대 경로(`/about`) 또는 절대 `http(s)` URL — 서버가 위험 스킴을
제거한 안전한 값만 내려줍니다.
- 메뉴 저장 시 발행 웹훅(`post.updated`, paths: `["/"]`)이 발송되므로
웹훅 수신 라우트(`revalidation-webhooks.md`)를 설정했다면 몇 초 내 반영됩니다.
## 서버 컴포넌트에서 메뉴 가져오기
```tsx
// components/site-nav.tsx (Server Component)
import Link from "next/link";
import { fetchMenu } from "@roottale/cms-client/server";
export async function SiteNav() {
const menu = await fetchMenu({
apiKey: process.env.ROOTTALE_API_KEY!,
slug: "primary",
});
// 메뉴 미설정(null)이면 자체 fallback 네비를 렌더하세요.
if (!menu) {
return (
<nav>
<Link href="/blog">블로그</Link>
</nav>
);
}
return (
<nav>
{menu.items.map((item) => (
<div key={item.id}>
<Link
href={item.url}
{...(item.newTab
? { target: "_blank", rel: "noopener" }
: {})}
>
{item.label}
</Link>
{item.children?.length ? (
<div>
{item.children.map((child) => (
<Link key={child.id} href={child.url}>
{child.label}
</Link>
))}
</div>
) : null}
</div>
))}
</nav>
);
}
```
`fetchMenu` 는 미존재/구 서버의 404 를 `null` 로 돌려주므로(fail-soft) 항상
fallback 분기를 두세요. 전체 메뉴 목록이 필요하면 `fetchMenus({ apiKey })`.
## 타입
```ts
interface RootTaleMenu {
id: string;
name: string; // "헤더 메뉴"
slug: string; // "primary" | "footer" | ...
items: RootTaleMenuItem[];
updatedAt: string | null;
}
interface RootTaleMenuItem {
id: string;
label: string;
url: string; // "/about" 또는 "https://..."
newTab?: boolean; // target="_blank" rel="noopener" 로 렌더
children?: RootTaleMenuItem[];
}
```
## 캐싱
메뉴 응답은 5분 캐시(+SWR)로 내려갑니다. 페이지가 ISR 이라면 발행 웹훅이
`/` 를 revalidate 할 때 함께 갱신되므로 별도 처리 없이 near-real-time 입니다.
## raw HTTP
JS 외 스택은 `GET /v1/cms/public/menus/{slug}` 를 직접 호출하세요 —
`api-reference.md` 참고.