Créer un blog

Sur cette page

Ce guide couvre la création d’un blog avec EmDash, de la définition du type de contenu à l’affichage des articles avec catégories et tags.

Prérequis

  • Un site EmDash configuré et fonctionnel (voir Démarrage)
  • Connaissance de base des composants Astro

Définir la collection Posts

EmDash crée une collection “posts” par défaut lors de la configuration. Personnalisez-la depuis le tableau de bord admin ou l’API.

La collection posts par défaut inclut :

  • title - Titre de l’article
  • slug - Identifiant convivial pour les URL
  • content - Corps en texte riche
  • excerpt - Description courte
  • featured_image - Image d’en-tête (optionnel)
  • status - brouillon, publié ou programmé
  • publishedAt - Date de publication (champ système)

Créer votre premier article

  1. Ouvrez le tableau de bord admin à /_emdash/admin

  2. Cliquez sur Posts dans la barre latérale

    Liste des articles EmDash montrant titres, statuts et dates
  3. Cliquez sur New Post

    Éditeur d'articles EmDash avec titre, contenu et options de publication
  4. Entrez un titre et rédigez votre contenu avec l’éditeur de texte riche

  5. Ajoutez des catégories et des tags dans le panneau latéral

  6. Définissez le statut sur Publié

  7. Cliquez sur Enregistrer

L’article est maintenant en ligne et apparaît immédiatement.

Afficher les articles sur votre site

Lister tous les articles

La page suivante affiche tous les articles publiés :

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

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

// Trier par date de publication, plus récents en premier
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>

Afficher un article individuel

La route dynamique suivante rend un article individuel :

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

Ajouter des catégories et des tags

EmDash inclut des taxonomies de catégories et de tags intégrées. Voir Taxonomies pour les détails sur la création et la gestion des termes.

Filtrer les articles par catégorie

La route suivante liste les articles d’une seule catégorie :

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

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

  // Aplatir les catégories hiérarchiques
  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>

Afficher les catégories d’un article

Le composant suivant affiche les catégories et tags assignés à un article :

---
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>Catégories :</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>

Ajouter la pagination

Pour les blogs avec beaucoup d’articles, la route suivante pagine la liste des articles :

---
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}`}>Précédent</a>
    )}
    <span>Page {currentPage} sur {totalPages}</span>
    {currentPage < totalPages && (
      <a href={`/blog/page/${currentPage + 1}`}>Suivant</a>
    )}
  </nav>
</Base>

Ajouter un flux RSS

Le endpoint suivant génère un flux RSS pour le 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: "Mon Blog",
		description: "Un blog construit avec 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}`,
		})),
	});
}

Le flux dépend du package @astrojs/rss. La commande suivante l’installe :

npm install @astrojs/rss

Étapes suivantes