Einen Blog erstellen

Auf dieser Seite

Diese Anleitung behandelt die Erstellung eines Blogs mit EmDash, von der Definition des Inhaltstyps bis zur Anzeige von Beiträgen mit Kategorien und Tags.

Voraussetzungen

  • Eine eingerichtete und laufende EmDash-Site (siehe Erste Schritte)
  • Grundkenntnisse in Astro-Komponenten

Die Posts-Collection definieren

EmDash erstellt während der Einrichtung eine Standard-”posts”-Collection. Passen Sie sie über das Admin-Dashboard oder die API an.

Die Standard-Posts-Collection enthält:

  • title - Beitragstitel
  • slug - URL-freundlicher Bezeichner
  • content - Rich-Text-Inhalt
  • excerpt - Kurzbeschreibung
  • featured_image - Header-Bild (optional)
  • status - Entwurf, veröffentlicht oder geplant
  • publishedAt - Veröffentlichungsdatum (Systemfeld)

Ihren ersten Beitrag erstellen

  1. Öffnen Sie das Admin-Dashboard unter /_emdash/admin

  2. Klicken Sie in der Seitenleiste auf Posts

    EmDash-Beitragsliste mit Titeln, Status und Datumsangaben
  3. Klicken Sie auf New Post

    EmDash-Beitragseditor mit Titel, Inhalt und Veröffentlichungsoptionen
  4. Geben Sie einen Titel ein und schreiben Sie Ihren Inhalt mit dem Rich-Text-Editor

  5. Fügen Sie Kategorien und Tags im Seitenleisten-Panel hinzu

  6. Setzen Sie den Status auf Published

  7. Klicken Sie auf Save

Der Beitrag ist jetzt live und erscheint sofort.

Beiträge auf Ihrer Site anzeigen

Alle Beiträge auflisten

Die folgende Seite zeigt alle veröffentlichten Beiträge an:

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

Einen einzelnen Beitrag anzeigen

Die folgende dynamische Route rendert einen einzelnen Beitrag:

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

Kategorien und Tags hinzufügen

EmDash enthält integrierte Kategorien- und Tag-Taxonomien. Siehe Taxonomien für Details zum Erstellen und Verwalten von Begriffen.

Beiträge nach Kategorie filtern

Die folgende Route listet Beiträge in einer einzelnen Kategorie auf:

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

Beitragskategorien anzeigen

Die folgende Komponente zeigt die Kategorien und Tags, die einem Beitrag zugewiesen sind:

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

Paginierung hinzufügen

Für Blogs mit vielen Beiträgen paginiert die folgende Route die Beitragsliste:

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

Einen RSS-Feed hinzufügen

Der folgende Endpunkt generiert einen RSS-Feed für den Blog:

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}`,
		})),
	});
}

Der Feed hängt vom @astrojs/rss-Paket ab. Der folgende Befehl installiert es:

npm install @astrojs/rss

Nächste Schritte