分類法是套用到一個或多個集合的命名分類。EmDash 從用於文章的階層 category 分類法和平坦的 tag 分類法開始。站點也可以定義諸如 genre、topic 或 difficulty 的分類法。
術語屬於某個分類法。像「Guides」這樣的分類可以有子分類,而標籤和其他平坦分類法只有一層。
管理術語
在 EmDash 管理中從 Taxonomies 開啟一個分類法。
-
點擊 Add Category、Add Tag,或目前分類法的等效操作。
-
輸入標籤和 slug。對於階層分類法,當術語屬於另一個術語之下時,選擇父級。
-
新增選用描述,然後建立術語。
-
使用術語列表中的移動控制項,在目前父組內設定順序。
編輯者從內容條目中的分類法面板指派術語。分類法定義控制哪些集合顯示每個面板。
刪除術語會移除其在內容上的指派。不會刪除內容條目本身。
向多篇文章新增一個標籤
編輯者可以在集合列表中選擇文章並點擊 Add tag,或開啟 Tags 並點擊 Add to posts 貼上公開文章 URL(每行一個,最多 50)。選擇現有標籤或在對話框中建立,然後點擊 Review posts。檢查每個相符的標題和語言,然後點擊顯示將標記多少篇文章的按鈕。與本站已發佈文章不完全相符的連結會被標記,而不是猜測。
新增標籤會立即生效,即使文章還有其他未發佈的草稿編輯;它不會發佈那些編輯。現有標籤保持不變,已有該標籤的文章會被跳過。結果列表顯示哪些文章被標記、跳過或無法標記;對寫入失敗使用 Retry failures。URL 比對使用站點設定的公開來源和集合 URL 模式,包括日期和語言路徑。
新增自訂分類法
當現有集合需要單獨分類時,建立分類法。
-
開啟 Taxonomies 並點擊 New Taxonomy。
-
輸入標籤和穩定名稱。名稱以小寫字母開頭,僅包含小寫字母、數字和底線。
-
若術語需要父子關係,啟用 Hierarchical。
-
選擇可以使用該分類法的每個集合,然後點擊 Create Taxonomy。
-
新增初始術語並將它們指派給內容。
範本查詢穩定名稱。變更顯示標籤不需要變更範本。
自訂分類法使用與分類和標籤相同的查詢與篩選輔助函式。以下範例讀取 genre 術語,並依其中一個 slug 篩選書籍:
import { getEmDashCollection, getTaxonomyTerms } from "emdash";
const genres = await getTaxonomyTerms("genre", { includeCounts: false });
const { entries: scienceFictionBooks } = await getEmDashCollection("books", {
where: { genre: "science-fiction" },
});
刪除分類法
在管理中開啟分類法,然後從頁首的操作選單中選擇 Delete taxonomy 並確認。該操作需要編輯者和管理員持有的 taxonomies:manage 權限。
刪除分類法會刪除其在每種語言中的術語,並從歸入其下的內容中移除這些術語。內容條目本身會保留。
查詢術語列表
使用 getTaxonomyTerms() 渲染分類法索引、導覽列表或篩選器集。階層分類法透過每個術語的 children 陣列回傳樹。
術語計數預設包含,並需要對分類法已指派集合進行彙總。當元件不顯示計數時,跳過該工作。
以下元件在無計數的情況下渲染分類連結:
---
import { getTaxonomyTerms } from "emdash";
import { getRelativeLocaleUrl } from "astro:i18n";
const locale = Astro.currentLocale;
const categories = await getTaxonomyTerms("category", {
locale,
includeCounts: false,
});
function categoryHref(slug: string) {
const path = `/category/${slug}`;
return locale ? getRelativeLocaleUrl(locale, path) : path;
}
---
<nav aria-label="Categories">
<ul>
{categories.map((category) => (
<li>
<a href={categoryHref(category.slug)}>{category.label}</a>
{category.children.length > 0 && (
<ul>
{category.children.map((child) => (
<li><a href={categoryHref(child.slug)}>{child.label}</a></li>
))}
</ul>
)}
</li>
))}
</ul>
</nav>
當元件顯示使用情況時,省略 includeCounts: false 並渲染 term.count。計數包含查詢所用語言環境中公開可見的條目。
建置分類法封存
在查找術語之前解碼動態路由參數。用相同的語言環境查詢術語和內容,並將產生的路徑透過 Astro 的語言環境 URL 輔助函式。
以下路由列出一個分類中的已發佈文章:
---
import { decodeSlug, getEmDashCollection, getTerm } from "emdash";
import { getRelativeLocaleUrl } from "astro:i18n";
import Base from "../../layouts/Base.astro";
const locale = Astro.currentLocale;
const slug = decodeSlug(Astro.params.slug);
const category = slug
? await getTerm("category", slug, { locale, includeCounts: false })
: null;
if (!category) {
return Astro.redirect("/404");
}
const { entries: posts } = await getEmDashCollection("posts", {
status: "published",
locale,
where: { category: category.slug },
orderBy: { published_at: "desc" },
});
function postHref(postSlug: string) {
const path = `/posts/${postSlug}`;
return locale ? getRelativeLocaleUrl(locale, path) : path;
}
---
<Base title={`${category.label} posts`}>
<h1>{category.label}</h1>
{category.description && <p>{category.description}</p>}
{posts.length > 0 ? (
<ul>
{posts.map((post) => (
post.data.slug && (
<li>
<a href={postHref(post.data.slug)}>{post.data.title}</a>
</li>
)
))}
</ul>
) : (
<p>No posts in this category.</p>
)}
</Base>
where 使用分類法名稱作為鍵,術語 slug 作為值。查詢排序識別碼使用資料庫欄位名稱,如 published_at;條目資料將對應值公開為 publishedAt。
在 postHref() 中使用集合的實際公開路由。若集合使用自訂 urlPattern,請從該模式建置連結,而不是假設 /posts/{slug}。
顯示條目的術語
getEmDashEntry() 和 getEmDashCollection() 將已指派術語水合到 entry.data.terms。讀取該值,而不是對列表中的每個條目執行一次 getEntryTerms() 查詢。
以下元件渲染已隨文章載入的分類和標籤:
---
import type { ContentEntry, InferCollectionData } from "emdash";
import { getRelativeLocaleUrl } from "astro:i18n";
interface Props {
post: ContentEntry<InferCollectionData<"posts">>;
}
const { post } = Astro.props;
const locale = Astro.currentLocale;
const categories = post.data.terms?.category ?? [];
const tags = post.data.terms?.tag ?? [];
function termHref(taxonomy: string, slug: string) {
const path = `/${taxonomy}/${slug}`;
return locale ? getRelativeLocaleUrl(locale, path) : path;
}
---
{categories.length > 0 && (
<ul aria-label="Categories">
{categories.map((category) => (
<li>
<a href={termHref("category", category.slug)}>{category.label}</a>
</li>
))}
</ul>
)}
{tags.length > 0 && (
<ul aria-label="Tags">
{tags.map((tag) => (
<li>
<a href={termHref("tag", tag.slug)}>{tag.label}</a>
</li>
))}
</ul>
)}
當你只有集合名稱和條目 ID 時,使用 getEntryTerms()。當若干條目未被內容查詢水合時,使用 getTermsForEntries() 批次取得術語。
翻譯分類法與術語
分類法定義和術語每種語言環境有一行。EmDash 記錄哪些行是同一分類法或術語的翻譯。內容指派使用該共用身分,因此在一種語言環境中做出的指派,在存在翻譯術語時會解析到另一種語言環境中的翻譯術語。
分類法定義將其欄位在分類法與各語言環境之間分配:
| 欄位 | 屬於 | 效果 |
|---|---|---|
name | 分類法 | 建立後固定。每種語言環境的定義使用相同名稱。 |
hierarchical、collections | 分類法 | 每種語言環境相同。透過任一語言環境變更任一者,會對所有語言環境生效。 |
label、labelSingular | 語言環境 | 每種語言環境的定義有自己的。 |
為已在另一語言環境中存在的名稱建立的定義會加入該分類法(無論有無 translationOf),並採用其 hierarchical 和 collections。用不同值建立會失敗;請透過更新變更它們。沒有自己定義的語言環境仍會列出分類法的術語,並顯示其回退鏈上第一個有標籤的語言環境的標籤,否則預設語言環境的標籤,否則語言環境代碼最低的語言環境的標籤。
使用分類法頁面上的語言環境切換器,在每個已設定語言環境中管理術語。開啟術語的編輯對話框,並使用其 Translations 面板新增或開啟另一種語言環境。翻譯術語可以使用不同的 slug 和標籤。
術語的父級和位置由每種語言環境共用。在沒有父級的情況下建立的翻譯會採用其術語的父級和位置。在不同父級下建立翻譯,或透過任一語言環境變更父級,會在每種語言環境中移動該術語。
查詢輔助函式在提供時使用明確語言環境。否則使用目前請求語言環境,然後是設定的預設值。當請求的翻譯不存在時,單術語查找遵循設定的回退鏈。
有關語言環境路由與回退設定,請參見 Internationalization;有關編輯條目,請參見 Working with Content。執行時期 API 參考 記錄了分類法查詢輔助函式。對於程式化變更,使用 Bearer 權杖進行身分驗證,並向每個變更狀態的請求新增 X-EmDash-Request: 1。請求主體與回應請參見 分類法端點。