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>No posts yet.</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="Latest post">
<p>The main card content.</p>
<a slot="footer" href="/posts/latest">Read the post</a>
</Card>
スロットは、コンポーネントの呼び出しごとに閉じています。他の場所で登録されたコールバックを受け取れる WordPress のアクションとは、動作が異なります。
レイアウト
レイアウトは、WordPress のテーマが header.php と footer.php に分割することの多い、共有のドキュメント構造を受け持ちます。ページはレイアウトをインポートし、そのスロットを通じて自分のコンテンツを渡します。
次のレイアウトは、ドキュメントシェルを提供します。
---
interface Props {
title: string;
}
const { title } = Astro.props;
---
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>{title}</title>
</head>
<body>
<header><a href="/">My site</a></header>
<main><slot /></main>
</body>
</html>
次のページは、レイアウトのタイトルとメインコンテンツを渡します。
---
import Base from "../layouts/Base.astro";
---
<Base title="Home">
<h1>Latest posts</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 は、Astro のライブコンテンツコレクションを getEmDashCollection() と getEmDashEntry() でラップしています。コレクションの結果には 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("Could not load posts", { status: 500 });
}
---
<Base title="Posts">
{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.rewrite("/404");
const { entry: post, error } = await getEmDashEntry("posts", slug);
if (error) return new Response("Could not load the post", { status: 500 });
if (!post) return Astro.rewrite("/404");
---
<Base title={post.data.title}>
<article>
<h1>{post.data.title}</h1>
<PortableText value={post.data.content} />
</article>
</Base>
Astro を続ける
EmDash テンプレートでは、コンポーネントのスタイルや小さなブラウザースクリプトも使用しますが、これらは EmDash の概念ではなく、通常の Astro の機能です。スコープ付きスタイルとグローバルスタイルについてはスタイルと CSSを、コンポーネントでブラウザー側の動作が必要な場合はスクリプトとイベント処理を参照してください。