タクソノミーはコンテンツを整理するための分類システムです。EmDash にはカテゴリとタグが組み込まれており、専門的な分類ニーズに対応するカスタムタクソノミーもサポートしています。
組み込みタクソノミー
| タクソノミー | タイプ | 説明 |
|---|---|---|
| カテゴリ | 階層型 | 親子関係を持つネストされた分類 |
| タグ | フラット | 階層のないシンプルなラベル |
どちらもデフォルトで投稿コレクションに利用可能です。
用語の管理
用語を作成
管理ダッシュボード
- タクソノミーページに移動(例:
/_emdash/admin/taxonomies/category) - 新規追加フォームに用語名を入力
- オプションで設定:スラッグ、親、説明
- 追加をクリック
コンテンツエディター
- エディターでコンテンツエントリを開く
- サイドバーのタクソノミーパネルを探す
- カテゴリの場合、チェックボックスを選択するか + 新規追加 をクリック
- タグの場合、カンマ区切りでタグ名を入力
- コンテンツを保存
API
POST /_emdash/api/taxonomies/category/terms
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN
{
"slug": "tutorials",
"label": "チュートリアル",
"parentId": "term_abc",
"description": "ハウツーガイドとチュートリアル"
} 用語を編集
- タクソノミー用語ページに移動 → 編集 → 更新 → 保存
用語を削除
- タクソノミー用語ページに移動 → 削除 → 確認
タクソノミーのクエリ
import { getTaxonomyTerms } from "emdash";
const categories = await getTaxonomyTerms("category");
const tags = await getTaxonomyTerms("tag");
const tags = await getTaxonomyTerms("tag", { includeCounts: false });
import { getTerm } from "emdash";
const category = await getTerm("category", "news");
import { getEntryTerms } from "emdash";
const categories = await getEntryTerms("posts", "post-123", "category");
import { getEmDashCollection } from "emdash";
const { entries: newsPosts } = await getEmDashCollection("posts", {
status: "published",
where: { category: "news" },
});
タクソノミーページの構築
カテゴリアーカイブ
---
import { getTaxonomyTerms, getEmDashCollection } from "emdash";
import Base from "../../layouts/Base.astro";
export async function getStaticPaths() {
const categories = await getTaxonomyTerms("category");
function flatten(terms) {
return terms.flatMap((term) => [term, ...flatten(term.children)]);
}
return flatten(categories).map((cat) => ({
params: { slug: cat.slug }, props: { category: cat },
}));
}
const { category } = Astro.props;
const { entries: posts } = await getEmDashCollection("posts", {
status: "published", where: { category: category.slug },
});
---
<Base title={category.label}>
<h1>{category.label}</h1>
{category.description && <p>{category.description}</p>}
<p>{category.count} 件の投稿</p>
<ul>
{posts.map((post) => (
<li><a href={`/blog/${post.data.slug}`}>{post.data.title}</a></li>
))}
</ul>
</Base>
タグアーカイブ
---
import { getTaxonomyTerms, getEmDashCollection } from "emdash";
import Base from "../../layouts/Base.astro";
export async function getStaticPaths() {
const tags = await getTaxonomyTerms("tag");
return tags.map((tag) => ({ params: { slug: tag.slug }, props: { tag } }));
}
const { tag } = Astro.props;
const { entries: posts } = await getEmDashCollection("posts", {
status: "published", where: { tag: tag.slug },
});
---
<Base title={`「${tag.label}」タグの投稿`}>
<h1>#{tag.label}</h1>
<ul>
{posts.map((post) => (
<li><a href={`/blog/${post.data.slug}`}>{post.data.title}</a></li>
))}
</ul>
</Base>
カテゴリリストウィジェット
---
import { getTaxonomyTerms } from "emdash";
const categories = await getTaxonomyTerms("category");
---
<nav class="category-list">
<h3>カテゴリ</h3>
<ul>
{categories.map((cat) => (
<li>
<a href={`/category/${cat.slug}`}>{cat.label} ({cat.count})</a>
{cat.children.length > 0 && (
<ul>
{cat.children.map((child) => (
<li><a href={`/category/${child.slug}`}>{child.label} ({child.count})</a></li>
))}
</ul>
)}
</li>
))}
</ul>
</nav>
タグクラウド
---
import { getTaxonomyTerms } from "emdash";
const tags = await getTaxonomyTerms("tag");
const counts = tags.map((t) => t.count ?? 0);
const maxCount = Math.max(...counts, 1);
const minSize = 0.8;
const maxSize = 2;
function getSize(count: number) {
return minSize + (count / maxCount) * (maxSize - minSize);
}
---
<div class="tag-cloud">
{tags.map((tag) => (
<a href={`/tag/${tag.slug}`} style={`font-size: ${getSize(tag.count ?? 0)}rem`}>{tag.label}</a>
))}
</div>
コンテンツでの用語の表示
---
import { getEntryTerms } from "emdash";
interface Props { collection: string; entryId: string; }
const { collection, entryId } = Astro.props;
const categories = await getEntryTerms(collection, entryId, "category");
const tags = await getEntryTerms(collection, entryId, "tag");
---
<div class="post-terms">
{categories.length > 0 && (
<div class="categories">
<span>カテゴリ:</span>
{categories.map((cat, i) => (
<>{i > 0 && ", "}<a href={`/category/${cat.slug}`}>{cat.label}</a></>
))}
</div>
)}
{tags.length > 0 && (
<div class="tags">
{tags.map((tag) => (<a href={`/tag/${tag.slug}`} class="tag">#{tag.label}</a>))}
</div>
)}
</div>
カスタムタクソノミー
POST /_emdash/api/taxonomies
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN
{
"name": "genre",
"label": "ジャンル",
"labelSingular": "ジャンル",
"hierarchical": true,
"collections": ["books", "movies"]
}
const genres = await getTaxonomyTerms("genre");
const { entries: sciFiBooks } = await getEmDashCollection("books", {
where: { genre: "science-fiction" },
});
タクソノミー API リファレンス
| エンドポイント | メソッド | 説明 |
|---|---|---|
/_emdash/api/taxonomies | GET | タクソノミー定義の一覧 |
/_emdash/api/taxonomies | POST | タクソノミーを作成 |
/_emdash/api/taxonomies/:name/terms | GET | 用語の一覧 |
/_emdash/api/taxonomies/:name/terms | POST | 用語を作成 |
/_emdash/api/taxonomies/:name/terms/:slug | GET | 用語を取得 |
/_emdash/api/taxonomies/:name/terms/:slug | PUT | 用語を更新 |
/_emdash/api/taxonomies/:name/terms/:slug | DELETE | 用語を削除 |