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 mit 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-freundliche Kennung
  • 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 auf Posts in der Seitenleiste

    EmDash-Beitragsliste mit Titeln, Status und Daten
  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 Veröffentlicht

  7. Klicken Sie auf Speichern

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

// Nach Veröffentlichungsdatum sortieren, neueste zuerst
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, Image } 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 && (
      <Image image={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 eingebaute Kategorie- und Tag-Taxonomien. Siehe Taxonomien für Details zur Erstellung und Verwaltung von Begriffen.

Beiträge nach Kategorie filtern

Die folgende Route listet Beiträge 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");

  // Hierarchische Kategorien flach machen
  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 einem Beitrag zugewiesenen Kategorien und Tags:

---
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>Kategorien:</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 - Seite ${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}`}>Zurück</a>
    )}
    <span>Seite {currentPage} von {totalPages}</span>
    {currentPage < totalPages && (
      <a href={`/blog/page/${currentPage + 1}`}>Weiter</a>
    )}
  </nav>
</Base>

Einen RSS-Feed hinzufügen

Der folgende Endpoint 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: "Mein Blog",
		description: "Ein Blog erstellt mit 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 benötigt das @astrojs/rss-Paket. Der folgende Befehl installiert es:

npm install @astrojs/rss

Nächste Schritte