택소노미

이 페이지

택소노미는 콘텐츠 분류 체계입니다. EmDash에는 카테고리와 태그가 기본 제공되며 특수한 분류가 필요하면 사용자 정의 택소노미를 추가할 수 있습니다.

기본 택소노미

EmDash는 두 가지 기본 택소노미를 제공합니다:

택소노미유형설명
카테고리계층형부모-자식 관계가 있는 중첩 분류
태그비계층계층 없는 단순 라벨

둘 다 기본적으로 posts 컬렉션에서 사용할 수 있습니다.

용어 관리

용어 만들기

관리 대시보드

  1. 택소노미 페이지로 이동합니다(예: /_emdash/admin/taxonomies/category)

  2. Add New 폼에 용어 이름을 입력합니다

  3. 선택 사항을 설정합니다:

    • Slug — URL 식별자(이름에서 자동 생성)
    • Parent — 계층형 택소노미의 경우
    • Description — 용어 설명
  4. Add를 클릭합니다

콘텐츠 편집기

  1. 편집기에서 콘텐츠 항목을 엽니다

  2. 사이드바에서 택소노미 패널을 찾습니다

  3. 카테고리: 해당 용어의 체크박스를 선택하거나 + Add New를 클릭합니다

  4. 태그: 쉼표로 구분해 태그 이름을 입력합니다

  5. 콘텐츠를 저장합니다

API

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

{
  "slug": "tutorials",
  "label": "Tutorials",
  "parentId": "term_abc",
  "description": "How-to guides and tutorials"
}

용어 편집

  1. 택소노미 용어 페이지로 이동합니다

  2. 용어 옆의 Edit를 클릭합니다

  3. 이름, slug, 부모, 설명을 수정합니다

  4. Save를 클릭합니다

용어 삭제

  1. 택소노미 용어 페이지로 이동합니다

  2. 용어 옆의 Delete를 클릭합니다

  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; // 이 용어가 있는 항목 수
}

단일 용어 가져오기

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": "Genres",
  "labelSingular": "Genre",
  "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": "Difficulty Levels",
  "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"]
}

다음 단계