ブログ
アプリにブログを追加します。
インストール
npx @fumadocs/cli@latest add blogコンポーネントは components/blog に、投稿用のユーティリティは lib/blog.ts にインストールされます。
blogPageSchema を使って投稿用のコレクションを定義し、著者を登録します。
import { defineCollections } from 'fumadocs-mdx/macro';
import { loader } from 'fumadocs-core/source';
import { type BlogAuthor, blogPageSchema } from './blog';
export const blog = defineCollections({
type: 'doc',
dir: 'content/blog',
schema: blogPageSchema,
});
export const blogSource = loader({
baseUrl: '/blog',
source: blog.toFumadocsSource(),
});
export const blogAuthors: Record<string, BlogAuthor> = {
fuma: {
name: 'Fuma Nama',
title: 'Maintainer',
url: 'https://fuma-nama.dev',
image: 'https://avatars.githubusercontent.com/u/76240755',
},
};投稿は content/blog 配下に作成します。
---
title: Hello World
description: My first post.
date: 2026-10-12
tags: [Announcement]
authors: [fuma]
image: /blog/hello-world.png
---| フィールド | 説明 |
|---|---|
date | 公開日です。投稿はこの日付順に並べ替えられます |
tags | タグごとに /blog/tags 配下にページが作成されます |
authors | 著者のキーです。未登録のキーは著者名として扱われます |
image | カバー画像の URL です。投稿のカードに表示されます |
リモート画像
カバー画像とアバターは next/image でレンダリングされます。images.remotePatterns で画像のホストを許可してください。
ページ
getPosts() は、ページの著者とタグを解決したうえで、新しい順に返します。返されたページは、Home Layout 配下のルートでレンダリングしてください。
投稿
import { blogAuthors, blogSource } from '@/lib/source';
import { getPosts } from '@/lib/blog';
import { BlogCards } from '@/components/blog';
export default function Page() {
return (
<div className="mx-auto w-full max-w-(--fd-layout-width) px-4 py-12">
<BlogCards posts={getPosts(blogSource.getPages(), blogAuthors)} />
</div>
);
}投稿
findPost() は、投稿とその前後の投稿 (新しい投稿と古い投稿) をまとめて取得します。toc を指定すると、目次と共有ボタンを含むフローティングパネルが表示されます。
import { notFound } from 'next/navigation';
import { blogAuthors, blogSource } from '@/lib/source';
import { findPost, getPosts } from '@/lib/blog';
import { getMDXComponents } from '@/components/mdx';
import {
BlogAuthors,
BlogBackLink,
BlogBody,
BlogDate,
BlogDescription,
BlogHeader,
BlogPage,
BlogPostNav,
BlogTags,
BlogTitle,
} from '@/components/blog';
export default async function Page(props: PageProps<'/blog/[slug]'>) {
const { slug } = await props.params;
const page = blogSource.getPage([slug]);
const found = page && findPost(getPosts(blogSource.getPages(), blogAuthors), page.url);
if (!page || !found) notFound();
const { post, newer, older } = found;
const MDX = page.data.body;
return (
<BlogPage toc={page.data.toc}>
<BlogHeader>
<BlogBackLink href="/blog" />
<BlogTitle>{post.title}</BlogTitle>
<BlogDescription>{post.description}</BlogDescription>
<BlogAuthors authors={post.authors} />
<BlogTags tags={post.tags} />
{post.date && <BlogDate date={post.date} />}
</BlogHeader>
<BlogBody>
<MDX components={getMDXComponents()} />
</BlogBody>
<BlogPostNav newer={newer} older={older} />
</BlogPage>
);
}タグ
getTags() を使うと、すべてのタグを一覧表示できます。
import { blogSource } from '@/lib/source';
import { getPosts, getTags } from '@/lib/blog';
import { BlogHeader, BlogTagCards, BlogTitle } from '@/components/blog';
export default function Page() {
const tags = getTags(getPosts(blogSource.getPages()));
return (
<div className="mx-auto flex w-full max-w-(--fd-layout-width) flex-col gap-4 px-4 py-12">
<BlogHeader>
<BlogTitle>All Tags</BlogTitle>
</BlogHeader>
<BlogTagCards tags={tags} />
</div>
);
}また、特定のタグが付いた投稿は getTagPosts() で表示できます。存在しないタグの場合、この関数は undefined を返します。
import { notFound } from 'next/navigation';
import { blogAuthors, blogSource } from '@/lib/source';
import { getPosts, getTagPosts, getTags } from '@/lib/blog';
import { BlogCards, BlogHeader, BlogTitle } from '@/components/blog';
export default async function Page(props: PageProps<'/blog/tags/[tag]'>) {
const { tag } = await props.params;
const result = getTagPosts(getPosts(blogSource.getPages(), blogAuthors), tag);
if (!result) notFound();
return (
<div className="mx-auto flex w-full max-w-(--fd-layout-width) flex-col gap-4 px-4 py-12">
<BlogHeader>
<BlogTitle>{result.tag.name}</BlogTitle>
</BlogHeader>
<BlogCards posts={result.posts} />
</div>
);
}
export function generateStaticParams() {
return getTags(getPosts(blogSource.getPages())).map((tag) => ({ tag: tag.slug }));
}国際化
getPosts() には、blogSource.getPages(lang) のように特定のロケールのページを渡してください。
タグページのURLは lib/blog.ts の getBlogUrl によって生成されます。ローダーのURLと一致させるには、getBlogUrl に i18n の設定を渡してください。
import { i18n } from '@/lib/i18n';
export const getBlogUrl = createGetUrl('/blog', i18n);投稿のフィードを公開する方法については、RSS フィードを参照してください。
How is this guide?
最終更新日
