Astroは、EmDashサイトのページ、レイアウト、コンポーネント、サーバーレンダリングを提供します。このガイドでは、現在のEmDashテンプレートで使用されているAstroの概念を解説します。WordPressのテーマとPHPテンプレートを既に理解していることを前提としています。
EmDash固有でないフレームワーク機能については、Astroドキュメントを参照してください。
プロジェクト構造
Astroサイトは、各種ファイルに明示的なディレクトリを割り当てます。現在のEmDashテンプレートは以下の構造を使用しています:
| WordPress | Astro | 用途 |
|---|---|---|
index.php、single.php、page.php | src/pages/ | URLルート |
template-parts/ | src/components/ | 再利用可能なマークアップ |
header.php と footer.php | src/layouts/ | 共有ページシェル |
style.css | src/styles/ | サイトスタイル |
| プラグインとデータベースのセットアップ | astro.config.mjs | インテグレーションとサーバーアダプター |
| テーマセットアップデータ | seed/seed.json | コレクション、メニュー、サンプルコンテンツ |
ブログテンプレートは、公開URLに対応するルートディレクトリを使用しています:
src/
├── components/
│ └── PostCard.astro
├── layouts/
│ └── Base.astro
├── pages/
│ ├── index.astro
│ ├── pages/
│ │ └── [slug].astro
│ └── posts/
│ ├── index.astro
│ └── [slug].astro
└── live.config.ts
Astroコンポーネント
.astroコンポーネントは、サーバーサイドのTypeScriptとHTMLテンプレートを組み合わせます。---フェンス間のコードはサーバー上で実行されます。2つ目のフェンスの下のマークアップがレスポンスHTMLになります。
次のコンポーネントは、フロントマターでpropsを宣言し、テンプレートでレンダリングします:
---
interface Props {
title: string;
excerpt?: string;
href: string;
}
const { title, excerpt, href } = Astro.props;
---
<article>
<h2><a href={href}>{title}</a></h2>
{excerpt && <p>{excerpt}</p>}
</article>
Astroは{value}でレンダリングされる値をエスケープします。インポート、データベースクエリ、その他のサーバー処理はフロントマターに記述します。
テンプレート式
AstroテンプレートはPHPテンプレートが<?php ?>に切り替える箇所で波括弧を使用します。EmDashテンプレートで最も一般的なパターンは、値、条件、配列マッピングです:
| 目的 | Astro構文 |
|---|---|
| 値を出力する | {post.data.title} |
| 値が存在する場合にレンダリングする | {post.data.excerpt && <p>{post.data.excerpt}</p>} |
| 2つの結果から選択する | {posts.length === 0 ? <p>まだ投稿がありません。</p> : <PostList />} |
| リストをレンダリングする | {posts.map((post) => <PostCard title={post.data.title} excerpt={post.data.excerpt} href={"/posts/" + post.id} />)} |
式はフロントマターで準備された変数、Astro.propsの値、またはEmDashクエリから返されたデータを使用できます。Astroはデフォルトで文字列値をエスケープします。HTMLを注入する代わりに、構造化されたリッチテキストには<PortableText />のようなレンダラーを使用してください。
Propsとスロット
Propsはget_template_part()に渡される$argsに相当します。各入力を明示的にし、TypeScriptで検証できます。
スロットは親がコンポーネントにマークアップを渡すことを可能にします。デフォルトスロットはページコンテンツに便利で、名前付きスロットは追加の挿入ポイントを提供します:
---
interface Props {
title: string;
}
const { title } = Astro.props;
---
<article>
<h2>{title}</h2>
<slot />
<footer><slot name="footer" /></footer>
</article>
次のページは両方のスロットを埋めます:
---
import Card from "../components/Card.astro";
---
<Card title="最新の投稿">
<p>カードのメインコンテンツ。</p>
<a slot="footer" href="/posts/latest">投稿を読む</a>
</Card>
スロットはコンポーネント呼び出しにローカルです。別の場所で登録されたコールバックを受け取れるWordPressのアクションとは異なる動作をします。
レイアウト
レイアウトは、WordPressテーマがheader.phpとfooter.phpに分割することが多い共有ドキュメント構造を所有します。ページはレイアウトをインポートし、そのスロットを通じてコンテンツを渡します。
次のレイアウトはドキュメントシェルを提供します:
---
interface Props {
title: string;
}
const { title } = Astro.props;
---
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>{title}</title>
</head>
<body>
<header><a href="/">マイサイト</a></header>
<main><slot /></main>
</body>
</html>
次のページはレイアウトのタイトルとメインコンテンツを提供します:
---
import Base from "../layouts/Base.astro";
---
<Base title="ホーム">
<h1>最新の投稿</h1>
</Base>
ファイルベースルーティング
src/pages/内のファイルがルートを定義します。括弧付きのファイル名は動的セグメントを作成します。
| ファイル | URL |
|---|---|
src/pages/index.astro | / |
src/pages/posts/index.astro | /posts |
src/pages/posts/[slug].astro | /posts/hello-world |
src/pages/pages/[slug].astro | /pages/about |
src/pages/posts/[slug].astro内では、Astro.params.slugにURLからの値が含まれます。レストパラメータ、リダイレクト、その他のルーティング機能についてはAstroルーティングを参照してください。
サーバーレンダリング
現在のEmDashテンプレートはastro.config.mjsでoutput: "server"を使用しています。そのため、ページはリクエストごとにデータベースをクエリでき、公開コンテンツは新しい静的ビルドに依存しません。
サイトがEmDashをビルド時のデータソースとして意図的に扱う場合を除き、EmDashテーマのルートにgetStaticPaths()を追加しないでください。提供されるテーマはサーバーレンダリングされます。
フレームワークレベルの動作についてはAstroオンデマンドレンダリングを参照してください。
EmDashコンテンツのクエリ
EmDashはgetEmDashCollection()とgetEmDashEntry()でAstroライブコンテンツコレクションをラップします。コレクション結果はentries配列を含みます。単一エントリの結果はentryを含み、公開されたエントリが一致しない場合はnullになります。
次のアーカイブは、現在のブログテンプレートと同じ並び順と識別子を使用しています:
---
import { getEmDashCollection } from "emdash";
import Base from "../../layouts/Base.astro";
const { entries: posts, error } = await getEmDashCollection("posts", {
orderBy: { published_at: "desc" },
});
if (error) {
return new Response("投稿を読み込めませんでした", { status: 500 });
}
---
<Base title="投稿">
{posts.map((post) => (
<article>
<h2><a href={`/posts/${post.id}`}>{post.data.title}</a></h2>
{post.data.excerpt && <p>{post.data.excerpt}</p>}
</article>
))}
</Base>
post.idはAstroが公開するルート識別子で、通常はエントリのスラグです。post.data.idはデータベース識別子です。タクソノミーやコメントヘルパーなど、APIが保存されたコンテンツIDを期待する場合はdata.idを使用してください。
次の動的ルートはURLのスラグで投稿を検索し、そのPortable Textフィールドをレンダリングします:
---
import { decodeSlug, getEmDashEntry } from "emdash";
import { PortableText } from "emdash/ui";
import Base from "../../layouts/Base.astro";
const slug = decodeSlug(Astro.params.slug);
if (!slug) return Astro.redirect("/404");
const { entry: post, error } = await getEmDashEntry("posts", slug);
if (error) return new Response("投稿を読み込めませんでした", { status: 500 });
if (!post) return Astro.redirect("/404");
---
<Base title={post.data.title}>
<article>
<h1>{post.data.title}</h1>
<PortableText value={post.data.content} />
</article>
</Base>
Astroを続ける
EmDashテンプレートはコンポーネントスタイルや小さなブラウザスクリプトも使用しますが、これらはEmDashの概念ではなく通常のAstro機能です。スコープ付きおよびグローバルスタイルについてはスタイルとCSSを、コンポーネントがブラウザサイドの動作を必要とする場合はスクリプトとイベントハンドリングを参照してください。