분류 체계

이 페이지

분류 체계는 콘텐츠를 정리하기 위한 분류 시스템입니다. EmDash에는 내장 카테고리와 태그가 포함되어 있으며, 전문적인 분류 요구에 맞는 사용자 정의 분류 체계를 지원합니다.

내장 분류 체계

EmDash는 두 가지 기본 분류 체계를 제공합니다:

분류 체계유형설명
카테고리계층형부모-자식 관계를 가진 중첩 분류
태그플랫계층 없는 단순 라벨

둘 다 기본적으로 게시물 컬렉션에서 사용 가능합니다.

용어 관리

용어 생성

관리자 대시보드

  1. 분류 체계 페이지로 이동합니다 (예: /_emdash/admin/taxonomies/category)

  2. 새로 추가 폼에 용어 이름을 입력합니다

  3. 선택적으로 설정:

    • 슬러그 - 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. 이름, 슬러그, 상위 또는 설명을 업데이트합니다

  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; // 용어 슬러그 ("news")
	label: string; // 표시 라벨 ("News")
	parentId?: string;
	description?: string;
	children: TaxonomyTerm[];
	count?: number; // 이 용어를 가진 항목 수
}

count 계산은 분류 체계의 컬렉션에서 모든 콘텐츠-용어 할당을 집계하며, 이는 호출에서 가장 비용이 많이 드는 부분입니다. 라벨과 슬러그만 필요하면 건너뛰세요 — 그러면 count가 반환된 용어에서 생략됩니다:

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

단일 용어 가져오기

다음 예제는 분류 체계와 슬러그로 용어를 가져옵니다:

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");

용어로 콘텐츠 필터링

getEmDashCollectionwhere 필터와 함께 사용합니다:

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"]
}

다음 단계