ブログを作成する

このページ

このガイドでは、EmDash でブログを作成する方法を、コンテンツタイプの定義から、カテゴリとタグを含む投稿の表示まで解説します。

前提条件

  • セットアップされ実行中の EmDash サイト(はじめにを参照)
  • Astro コンポーネントの基礎知識

Posts コレクションを定義する

EmDash はセットアップ時にデフォルトの「posts」コレクションを作成します。管理ダッシュボードまたは API からカスタマイズできます。

デフォルトの posts コレクションには以下が含まれます:

  • title - 投稿タイトル
  • slug - URL に適した識別子
  • content - リッチテキスト本文
  • excerpt - 短い説明
  • featured_image - ヘッダー画像(オプション)
  • status - 下書き、公開、または予約
  • publishedAt - 公開日(システムフィールド)

最初の投稿を作成する

  1. /_emdash/admin で管理ダッシュボードを開きます

  2. サイドバーの Posts をクリックします

    タイトル、ステータス、日付を表示する EmDash 投稿リスト
  3. New Post をクリックします

    タイトル、コンテンツ、公開オプションを含む EmDash 投稿エディター
  4. タイトルを入力し、リッチテキストエディターでコンテンツを書きます

  5. サイドバーパネルでカテゴリとタグを追加します

  6. ステータスを Published に設定します

  7. Save をクリックします

投稿が公開され、すぐに表示されます。

サイトに投稿を表示する

すべての投稿を一覧表示する

次のページは、公開されているすべての投稿を表示します:

---
import { getEmDashCollection } from "emdash";
import Base from "../../layouts/Base.astro";

const { entries: posts } = await getEmDashCollection("posts", {
  status: "published",
});

// Sort by publication date, newest first
const sortedPosts = posts.sort(
  (a, b) => (b.data.publishedAt?.getTime() ?? 0) - (a.data.publishedAt?.getTime() ?? 0)
);
---

<Base title="Blog">
  <h1>Blog</h1>
  <ul>
    {sortedPosts.map((post) => (
      <li>
        <a href={`/blog/${post.data.slug}`}>
          <h2>{post.data.title}</h2>
          <p>{post.data.excerpt}</p>
          <time datetime={post.data.publishedAt?.toISOString()}>
            {post.data.publishedAt?.toLocaleDateString()}
          </time>
        </a>
      </li>
    ))}
  </ul>
</Base>

個別の投稿を表示する

次の動的ルートは個別の投稿をレンダリングします:

---
import { getEmDashCollection, getEmDashEntry } from "emdash";
import { PortableText } from "emdash/ui";
import Base from "../../layouts/Base.astro";

export async function getStaticPaths() {
  const { entries: posts } = await getEmDashCollection("posts", {
    status: "published",
  });

  return posts.map((post) => ({
    params: { slug: post.data.slug },
  }));
}

const { slug } = Astro.params;
const { entry: post } = await getEmDashEntry("posts", slug);

if (!post) {
  return Astro.redirect("/404");
}
---

<Base title={post.data.title}>
  <article>
    {post.data.featured_image && (
      <img src={post.data.featured_image} alt="" />
    )}
    <h1>{post.data.title}</h1>
    <time datetime={post.data.publishedAt?.toISOString()}>
      {post.data.publishedAt?.toLocaleDateString()}
    </time>
    <PortableText value={post.data.content} />
  </article>
</Base>

カテゴリとタグを追加する

EmDash には組み込みのカテゴリとタグの分類法が含まれています。用語の作成と管理の詳細については、分類法を参照してください。

カテゴリ別に投稿をフィルタリングする

次のルートは、単一のカテゴリ内の投稿を一覧表示します:

---
import { getEmDashCollection, getTerm, getTaxonomyTerms } from "emdash";
import Base from "../../layouts/Base.astro";

export async function getStaticPaths() {
  const categories = await getTaxonomyTerms("category");

  // Flatten hierarchical categories
  const flatten = (terms) => terms.flatMap((t) => [t, ...flatten(t.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>}

  <ul>
    {posts.map((post) => (
      <li>
        <a href={`/blog/${post.data.slug}`}>{post.data.title}</a>
      </li>
    ))}
  </ul>
</Base>

投稿のカテゴリを表示する

次のコンポーネントは、投稿に割り当てられたカテゴリとタグを表示します:

---
import { getEntryTerms } from "emdash";

interface Props {
  postId: string;
}

const { postId } = Astro.props;
const categories = await getEntryTerms("posts", postId, "category");
const tags = await getEntryTerms("posts", postId, "tag");
---

<div class="post-meta">
  {categories.length > 0 && (
    <div class="categories">
      <span>Categories:</span>
      {categories.map((cat) => (
        <a href={`/category/${cat.slug}`}>{cat.label}</a>
      ))}
    </div>
  )}

  {tags.length > 0 && (
    <div class="tags">
      <span>Tags:</span>
      {tags.map((tag) => (
        <a href={`/tag/${tag.slug}`}>{tag.label}</a>
      ))}
    </div>
  )}
</div>

ページネーションを追加する

多数の投稿があるブログの場合、次のルートは投稿リストをページ分割します:

---
import { getEmDashCollection } from "emdash";
import Base from "../../../layouts/Base.astro";

const POSTS_PER_PAGE = 10;

export async function getStaticPaths() {
  const { entries: allPosts } = await getEmDashCollection("posts", {
    status: "published",
  });

  const totalPages = Math.ceil(allPosts.length / POSTS_PER_PAGE);

  return Array.from({ length: totalPages }, (_, i) => ({
    params: { page: String(i + 1) },
    props: { currentPage: i + 1, totalPages },
  }));
}

const { currentPage, totalPages } = Astro.props;

const { entries: allPosts } = await getEmDashCollection("posts", {
  status: "published",
});

const sortedPosts = allPosts.sort(
  (a, b) => (b.data.publishedAt?.getTime() ?? 0) - (a.data.publishedAt?.getTime() ?? 0)
);

const start = (currentPage - 1) * POSTS_PER_PAGE;
const posts = sortedPosts.slice(start, start + POSTS_PER_PAGE);
---

<Base title={`Blog - Page ${currentPage}`}>
  <h1>Blog</h1>

  <ul>
    {posts.map((post) => (
      <li>
        <a href={`/blog/${post.data.slug}`}>{post.data.title}</a>
      </li>
    ))}
  </ul>

  <nav>
    {currentPage > 1 && (
      <a href={`/blog/page/${currentPage - 1}`}>Previous</a>
    )}
    <span>Page {currentPage} of {totalPages}</span>
    {currentPage < totalPages && (
      <a href={`/blog/page/${currentPage + 1}`}>Next</a>
    )}
  </nav>
</Base>

RSS フィードを追加する

次のエンドポイントは、ブログの RSS フィードを生成します:

import rss from "@astrojs/rss";
import { getEmDashCollection } from "emdash";

export async function GET(context) {
	const { entries: posts } = await getEmDashCollection("posts", {
		status: "published",
	});

	return rss({
		title: "My Blog",
		description: "A blog built with EmDash",
		site: context.site,
		items: posts.map((post) => ({
			title: post.data.title,
			pubDate: post.data.publishedAt,
			description: post.data.excerpt,
			link: `/blog/${post.data.slug}`,
		})),
	});
}

フィードは @astrojs/rss パッケージに依存します。次のコマンドでインストールします:

npm install @astrojs/rss

次のステップ