分类法
分类法是用于组织内容的分类系统。EmDash 内置了分类和标签,并支持自定义分类法以满足特定的分类需求。
EmDash 提供了两种默认的分类法:
| 分类法 | 类型 | 描述 |
|---|---|---|
| 分类 | 层级式 | 具有父子关系的嵌套分类 |
| 标签 | 扁平式 | 无层级的简单标签 |
默认情况下,两者都可用于文章集合。
-
转到分类法页面(例如,
/_emdash/admin/taxonomies/category) -
在 添加新项 表单中输入术语名称
-
可选设置:
- 别名 - URL 标识符(根据名称自动生成)
- 父级 - 用于层级式分类法
- 描述 - 术语描述
-
点击 添加
-
在编辑器中打开一个内容条目
-
在侧边栏中找到分类法面板
-
对于分类:勾选适用术语的复选框,或点击 + 添加新项
-
对于标签:输入标签名称,用逗号分隔
-
保存内容
POST /_emdash/api/taxonomies/category/termsContent-Type: application/jsonAuthorization: Bearer YOUR_API_TOKEN
{ "slug": "tutorials", "label": "Tutorials", "parentId": "term_abc", "description": "How-to guides and tutorials"}-
转到分类法术语页面
-
点击术语旁边的 编辑
-
更新名称、别名、父级或描述
-
点击 保存
-
转到分类法术语页面
-
点击术语旁边的 删除
-
确认删除
EmDash 提供了查询分类法术语和按术语筛选内容的函数。
获取所有术语
Section titled “获取所有术语”检索某个分类法的所有术语:
import { getTaxonomyTerms } from "emdash";
// Get all categories (returns tree structure)const categories = await getTaxonomyTerms("category");
// Get all tags (returns flat list)const tags = await getTaxonomyTerms("tag");对于层级式分类法,术语包含一个 children 数组:
interface TaxonomyTerm { id: string; name: string; // Taxonomy name ("category") slug: string; // Term slug ("news") label: string; // Display label ("News") parentId?: string; description?: string; children: TaxonomyTerm[]; count?: number; // Number of entries with this term}获取单个术语
Section titled “获取单个术语”import { getTerm } from "emdash";
const category = await getTerm("category", "news");// Returns TaxonomyTerm or null获取条目的术语
Section titled “获取条目的术语”import { getEntryTerms } from "emdash";
// Get all categories for a postconst categories = await getEntryTerms("posts", "post-123", "category");
// Get all tags for a postconst tags = await getEntryTerms("posts", "post-123", "tag");按术语筛选内容
Section titled “按术语筛选内容”使用带有 where 筛选器的 getEmDashCollection:
import { getEmDashCollection } from "emdash";
// Posts in the "news" categoryconst { entries: newsPosts } = await getEmDashCollection("posts", { status: "published", where: { category: "news" },});
// Posts with the "javascript" tagconst { entries: jsPosts } = await getEmDashCollection("posts", { status: "published", where: { tag: "javascript" },});或者使用便捷函数:
import { getEntriesByTerm } from "emdash";
const newsPosts = await getEntriesByTerm("posts", "category", "news");构建分类法页面
Section titled “构建分类法页面”创建一个列出某个分类下文章的页面:
---import { getTaxonomyTerms, getTerm, getEmDashCollection } from "emdash";import Base from "../../layouts/Base.astro";
export async function getStaticPaths() { const categories = await getTaxonomyTerms("category");
// Flatten hierarchical tree for routing 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} posts</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={`Posts tagged "${tag.label}"`}> <h1>#{tag.label}</h1>
<ul> {posts.map((post) => ( <li> <a href={`/blog/${post.data.slug}`}>{post.data.title}</a> </li> ))} </ul></Base>分类列表小部件
Section titled “分类列表小部件”显示带有文章数量的分类列表:
---import { getTaxonomyTerms } from "emdash";
const categories = await getTaxonomyTerms("category");---
<nav class="category-list"> <h3>Categories</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");
// Calculate font sizes based on countconst counts = tags.map((t) => t.count ?? 0);const maxCount = Math.max(...counts, 1);const minSize = 0.8;const maxSize = 2;
function getSize(count: number) { const ratio = count / maxCount; return minSize + ratio * (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>在内容上显示术语
Section titled “在内容上显示术语”在文章上显示分类和标签:
---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>Posted in:</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>自定义分类法
Section titled “自定义分类法”创建分类和标签之外的自定义分类法以满足特定需求。
创建自定义分类法
Section titled “创建自定义分类法”使用管理 API 创建分类法:
POST /_emdash/api/taxonomiesContent-Type: application/jsonAuthorization: Bearer YOUR_API_TOKEN
{ "name": "genre", "label": "Genres", "labelSingular": "Genre", "hierarchical": true, "collections": ["books", "movies"]}使用自定义分类法
Section titled “使用自定义分类法”查询和显示自定义分类法的方式与内置分类法相同:
import { getTaxonomyTerms, getEmDashCollection } from "emdash";
// Get all genresconst genres = await getTaxonomyTerms("genre");
// Get books in a genreconst { entries: sciFiBooks } = await getEmDashCollection("books", { where: { genre: "science-fiction" },});分类法指定其适用于哪些集合:
{ "name": "difficulty", "label": "Difficulty Levels", "hierarchical": false, "collections": ["recipes", "tutorials"]}分类法 API 参考
Section titled “分类法 API 参考”REST 端点
Section titled “REST 端点”| 端点 | 方法 | 描述 |
|---|---|---|
/_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 | 删除术语 |
将术语分配给内容
Section titled “将术语分配给内容”POST /_emdash/api/content/posts/post-123/terms/categoryContent-Type: application/jsonAuthorization: Bearer YOUR_API_TOKEN
{ "termIds": ["term_news", "term_featured"]}