Zenn
🚀

[Astro] 投稿記事のURLをファイルベースではなく指定の文字列にする

2025/02/11に公開

先日ブログサイト( https://chocolat5.com/ )を Next.js から Astro へ移行した際に、一番気掛かりだったのが「投稿記事のURLがマークダウンファイルのファイル名と違う」ことです。

Astro のルーティングはファイル名がURLになるファイルベース方式をとっていますが、移行したブログサイトでは以下のような構造とルールで管理していました。

  • 記事内に画像がある場合は フォルダ/index.md 、画像がない場合はマークダウンファイルのみ
  • ファイルまたはフォルダ名の先頭は投稿年月日
  • 記事のURLはファイル名の年月日を除いた部分(例: 2024-02-24-post-1.md → /blog/post-1/)
/src
  /content
    /blog
       /2024-02-24-post-1.md
       /2024-02-27-post-2/index.md
       /2024-05-14-post-3/index.md
       /2024-07-24-post-4.md

ファイル・フォルダ名の年月日は、フォルダ内での投稿記事の見通しをよくするために付けています(フォルダ内で記事が日付順に並ぶ)。画像がない場合でも一律でフォルダにするとさらに統一されて見通しがよくなるのですが、今のところはこの形式を維持しています。

既存のファイル構造とURLをAstroへの移行後も維持するためには、それに合わせたURLとファイルへのパスを設定する必要がありました。

前提

  • Astro 5.0
  • マークダウンファイルで投稿記事を管理している
  • Astro の Content collections を使用する

URL, ファイルパスの指定方法

slug と path を生成

URLとして使用される slug 、記事として表示するファイルまでのルートである path をそれぞれ自分のサイトの構造と合わせたものを生成します。

移行したブログサイトを例にすると、各記事に対して必要な slug と path は以下になります。

ファイル名 slug path
2024-02-24-post-1.md post-1 2024-02-24-post-1.md
2024-02-27-post-2/index.md post-2 2024-02-27-post-2/index.md

getCollection() で取得できるデータの中に filePath というsrcから記事ファイルまでのルートパスがあるため、そこから slugpath を生成することも可能です。

※ slug と path は各サイトの構造に依存するため、具体的な生成方法はここでは省略します。

getStaticPaths で設定

生成した slugpath をそれぞれ投稿記事を表示する [slug].astrogetStaticPaths() 内で params として設定して、Astroのデフォルトの slugpath を上書きします。

[slug].astro
---
export async function getStaticPaths() {
  /* 全投稿記事を取得 */
  const posts = await getCollection("blog");

  return posts.map((post) => ({
    /* ここでAstroのデフォルトの slug と path を上書きする */
    params: { slug: [YOUR_SLUG], path: [YOUR_PATH] },
    props: { post },
  }));
}

const post = Astro.props;
const { Content } = await render(post);
---

<Content />

ブログサイトでは post を受け取って { slug, path } を返す getPostParam() を作成して、getStaticPaths()return 内を以下のように変更しました。

[slug].astro
export async function getStaticPaths() {
...
  return posts.map((post) => ({
-    params: { slug: [YOUR_SLUG], path: [YOUR_PATH] },
+    params: getPostParam(post),
    props: { post },
  }));
}

Discussion

ログインするとコメントできます