分類法

本頁內容

分類法是用於組織內容的分類系統。EmDash 包含內建的分類和標籤,並支援自訂分類法以滿足專業化的分類需求。

內建分類法

EmDash 提供兩種預設分類法:

分類法類型描述
分類階層型具有父子關係的巢狀分類
標籤扁平型無階層的簡單標籤

兩者預設可用於文章集合。

管理術語

建立術語

管理面板

  1. 前往分類法頁面(例如 /_emdash/admin/taxonomies/category

  2. 新增表單中輸入術語名稱

  3. 可選設定:

    • Slug - URL 識別碼(從名稱自動產生)
    • 父級 - 用於階層型分類法
    • 描述 - 術語描述
  4. 點擊新增

內容編輯器

  1. 在編輯器中開啟一個內容條目

  2. 在側邊欄找到分類法面板

  3. 對於分類,勾選適用術語的核取方塊,或點擊 + 新增

  4. 對於標籤,輸入用逗號分隔的標籤名稱

  5. 儲存內容

API

以下請求在 category 分類法中建立一個術語:

POST /_emdash/api/taxonomies/category/terms
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN

{
  "slug": "tutorials",
  "label": "教學",
  "parentId": "term_abc",
  "description": "操作指南和教學"
}

編輯術語

  1. 前往分類法術語頁面

  2. 點擊術語旁邊的編輯

  3. 更新名稱、slug、父級或描述

  4. 點擊儲存

刪除術語

  1. 前往分類法術語頁面

  2. 點擊術語旁邊的刪除

  3. 確認刪除

查詢分類法

EmDash 提供用於查詢分類法術語和按術語篩選內容的函式。

取得所有術語

擷取分類法的所有術語:

import { getTaxonomyTerms } from "emdash";

// 取得所有分類(回傳樹狀結構)
const categories = await getTaxonomyTerms("category");

// 取得所有標籤(回傳扁平列表)
const tags = await getTaxonomyTerms("tag");

對於階層型分類法,術語包含 children 陣列:

interface TaxonomyTerm {
	id: string;
	name: string; // 分類法名稱 ("category")
	slug: string; // 術語 slug ("news")
	label: string; // 顯示標籤 ("News")
	parentId?: string;
	description?: string;
	children: TaxonomyTerm[];
	count?: number; // 使用此術語的條目數
}

計算 count 會聚合分類法集合中的每個內容-術語分配,這是呼叫中最昂貴的部分。如果你只需要標籤和 slug,可以略過——count 將從回傳的術語中省略:

const tags = await getTaxonomyTerms("tag", { includeCounts: false });

取得單一術語

以下範例按分類法和 slug 取得術語:

import { getTerm } from "emdash";

const category = await getTerm("category", "news");
// 回傳 TaxonomyTerm 或 null

取得條目的術語

以下範例擷取分配給單一條目的分類和標籤:

import { getEntryTerms } from "emdash";

// 取得文章的所有分類
const categories = await getEntryTerms("posts", "post-123", "category");

// 取得文章的所有標籤
const tags = await getEntryTerms("posts", "post-123", "tag");

按術語篩選內容

使用 getEmDashCollection 搭配 where 篩選器:

import { getEmDashCollection } from "emdash";

// "news" 分類的文章
const { entries: newsPosts } = await getEmDashCollection("posts", {
	status: "published",
	where: { category: "news" },
});

// "javascript" 標籤的文章
const { entries: jsPosts } = await getEmDashCollection("posts", {
	status: "published",
	where: { tag: "javascript" },
});

或使用便捷函式:

import { getEntriesByTerm } from "emdash";

const newsPosts = await getEntriesByTerm("posts", "category", "news");

建構分類法頁面

分類封存

建立一個列出某分類文章的頁面:

---
import { getTaxonomyTerms, getTerm, 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) {
  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>

在內容上顯示術語

在文章上顯示分類和標籤:

---
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>

自訂分類法

為專業化需求建立超越分類和標籤的分類法。

建立自訂分類法

使用管理 API 建立分類法:

POST /_emdash/api/taxonomies
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN

{
  "name": "genre",
  "label": "類型",
  "labelSingular": "類型",
  "hierarchical": true,
  "collections": ["books", "movies"]
}

使用自訂分類法

以與內建分類法相同的方式查詢和顯示自訂分類法:

import { getTaxonomyTerms, getEmDashCollection } from "emdash";

// 取得所有類型
const genres = await getTaxonomyTerms("genre");

// 取得某類型的書籍
const { entries: sciFiBooks } = await getEmDashCollection("books", {
	where: { genre: "science-fiction" },
});

分配到集合

分類法指定它們適用於哪些集合:

{
  "name": "difficulty",
  "label": "難度級別",
  "hierarchical": false,
  "collections": ["recipes", "tutorials"]
}

分類法 API 參考

REST 端點

端點方法描述
/_emdash/api/taxonomiesGET列出分類法定義
/_emdash/api/taxonomiesPOST建立分類法
/_emdash/api/taxonomies/:name/termsGET列出術語
/_emdash/api/taxonomies/:name/termsPOST建立術語
/_emdash/api/taxonomies/:name/terms/:slugGET取得術語
/_emdash/api/taxonomies/:name/terms/:slugPUT更新術語
/_emdash/api/taxonomies/:name/terms/:slugDELETE刪除術語

為內容分配術語

以下請求為文章分配分類術語:

POST /_emdash/api/content/posts/post-123/terms/category
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN

{
  "termIds": ["term_news", "term_featured"]
}

下一步