👻

[Astro] Ghost CMS で作るブログ

2025/02/13に公開

Ghost(CMS)で投稿した記事を Astro製のブログで表示する方法です。

前提

  • Ghost でアカウント作成済み
  • Ghost で記事を投稿済み

導入方法

1. Ghost 側でサイトを非表示にする

Ghost にはヘッドレスCMSとしての使用を前提とした設定があるため有効にする。
管理画面 > Settings > General > Make site private へ移動し [Edit] をクリック。
Enable password protection をonにする。

以下が Ghost 側のブログに適用される。

  • Ghost側のフロントエンドにパスワードが設定される
  • SEO機能が無効になる
  • noindex タグが付与される

2. Ghost APIキーを作成する

管理画面 > Settings > Advanced > Integrations へ移動し、[Add Custom integration] からTitleを入力して保存する。

Content API key (read-only), Admin API key, API URLが表示されたら作成完了。

3. Astro のインストール

npm create astro@latest

画面に従って選択していく

インストール完了後、以下を実行して画面が表示されるのを確認する。

npm run dev

4. Ghost の投稿データ取得のためのセットアップ

.env ファイルに 手順2. で作成したAPIキーを入力する。

.env
CONTENT_API_KEY=<YOUR_CONTENT_API_KEY>

src/env.d.ts ファイルに以下を追記する。

src/env.d.ts
interface ImportMetaEnv {
  readonly CONTENT_API_KEY: string;
}

Ghost のAPIを利用するためのパッケージをインストールする。

npm install @tryghost/content-api
npm install --save @types/tryghost__content-api

Ghost APIのインスタンスを作成する

src/lib/ghost.ts
import GhostContentAPI from "@tryghost/content-api";

export const ghostClient = new GhostContentAPI({
  url: "http://<YOURDOMAIN>.ghost.io", // Ghostで作成したアカウントのドメインを入力
  key: import.meta.env.CONTENT_API_KEY,
  version: "v5.0",
});

5. 記事一覧を作成する

pages 配下の index.astro で記事一覧を表示します。
ここでは以下の条件で取得・表示する例です。

  • 最新8件
  • Ghost側で公開済みとなっている

※ ここでは省略しますが、日付はフォーマットが必要です。

src/pages/index.astro
---
...
import { ghostClient } from "../lib/ghost.ts";
const posts = await ghostClient.posts
  .browse({
    filter: "visibility:public",
    limit: 6,
  })
  .catch((err) => {
    console.error(err);
  });
---

<Layout>
  <main>
    {
      posts.map(
        (post) => (
          <a href={`/posts/${post.slug}`} title={post.title} class="post_link">
            <article class="">
              <div class="post_image">
                <img src={post.feature_image} alt={post.feature_image_alt} />
              </div>
              <div class="post_text">
                <div>
                  <div class="post_date">
                    <time datetime={post.published_at}>{post.published_at}</time>
                  </div>
                  <p class="post_title">{post.title}</p>
                </div>
                <p class="post_excerpt">{post.excerpt}</p>
              </div>
            </article>
          </a>
        )
      )
    }
  </main>
</Layout>

6. 記事詳細を作成する

記事のURLを /posts/post-slug/ とする場合、 src/posts/[slug].astro を作成します。

getStaticPaths() で記事データを取得して、 slug を Astro の params に記事URLとして設定します。

記事本文はAPIで html として渡されるので、

src/posts/[slug].astro
---
import type { PostsOrPages, PostOrPage } from "@tryghost/content-api";
import { ghostClient } from "../lib/ghost.ts";

export async function getStaticPaths() {
  const posts: PostsOrPages = await ghostClient.posts
    .browse({
      filter: "visibility:public",
      limit: "all",
    })
    .catch((err) => {
      console.error(err);
    });
  if (!posts) {
    throw new Error("Opps, something wrong");
  }

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

const { post } = Astro.props;
---

<article>
  <h1>{post.title}</h1>
  <p>{post.published_at}</p>
  <img src={post.feature_image} alt={post.title} />
  <Fragment set:html={post.html} />
</article>

参考

Astro 公式 Ghost 導入ガイド
https://docs.astro.build/ja/guides/cms/ghost/

Ghost をヘッドレスCMSとして利用する
https://ghost.org/docs/jamstack/

Discussion