AstroはコンテンツにフォーカスしたWebサイトを構築するためのWebフレームワークです。EmDashを使用する場合、AstroがWordPressテーマを置き換えます。テンプレート、ルーティング、レンダリングを処理します。
このガイドは、すでに理解しているWordPressの概念にマッピングすることで、Astroの基礎を教えます。
主なパラダイムシフト
デフォルトでサーバーレンダリング
PHPと同様に、AstroコードはサーバーSo実行されます。PHPとは異なり、デフォルトでゼロ JavaScriptの静的HTMLを出力します。
追加しない限りゼロJS
WordPressは自動的にjQueryとテーマスクリプトをロードします。Astroは明示的に 追加しない限り、ブラウザに何も送信しません。
コンポーネントベースのアーキテクチャ
散在するテンプレートタグやincludeの代わりに、組み立て可能で自己完結型の コンポーネントで構築します。
ファイルベースのルーティング
リライトルールやquery_varsは不要です。src/pages/のファイル構造がURLを直接定義します。
プロジェクト構造
WordPressテーマはマジックファイル名を持つフラットな構造を持っています。Astroは明示的なディレクトリを使用します:
| WordPress | Astro | 目的 |
|---|---|---|
index.php, single.php | src/pages/ | ルート(URL) |
template-parts/ | src/components/ | 再利用可能なUIパーツ |
header.php + footer.php | src/layouts/ | ページラッパー |
style.css | src/styles/ | グローバルCSS |
functions.php | astro.config.mjs | サイト設定 |
以下のツリーは、典型的なAstroプロジェクトのレイアウトを示しています:
src/
├── components/ # Reusable UI (Header, PostCard, etc.)
├── layouts/ # Page shells (Base.astro)
├── pages/ # Routes - files become URLs
│ ├── index.astro # → /
│ ├── posts/
│ │ ├── index.astro # → /posts
│ │ └── [slug].astro # → /posts/hello-world
│ └── [slug].astro # → /about, /contact, etc.
└── styles/
└── global.css
Astroコンポーネント
.astroファイルはPHPテンプレートに相当するAstroのものです。各ファイルには2つのパーツがあります:
- フロントマター(
---フェンスの間)— テンプレートの最初のPHPのような、サーバーサイドコード - テンプレート — PHPテンプレートの残りのような、式を持つHTML
以下のコンポーネントは、フロントマターで型付きpropsを宣言し、テンプレートでそれらをレンダリングします:
---
// Frontmatter: runs on server, never sent to browser
interface Props {
title: string;
excerpt: string;
url: string;
}
const { title, excerpt, url } = Astro.props;
---
<!-- Template: outputs HTML -->
<article class="post-card">
<h2><a href={url}>{title}</a></h2>
<p>{excerpt}</p>
</article>
PHPからの主な違い:
- フロントマターは分離されています。 そこで宣言された変数はテンプレートで利用可能ですが、コード自体はブラウザに到達しません。
- インポートはフロントマターに入ります。 コンポーネント、データ、ユーティリティ — すべて上部でインポートされます。
- TypeScriptが機能します。 エディターのオートコンプリートと検証のために
interface Propsでprop型を定義します。
テンプレート式
Astroテンプレートは<?php ?>タグの代わりに{波括弧}を使用します。構文はJSXに似ていますが、純粋なHTMLを出力します。
Astro
---
import { getEmDashCollection } from "emdash";
const { entries: posts } = await getEmDashCollection("posts");
const showTitle = true;
---
{showTitle && <h1>Latest Posts</h1>}
{posts.length > 0 ? (
<ul>
{posts.map(post => (
<li>
<a href={`/posts/${post.id}`}>{post.data.title}</a>
</li>
))}
</ul>
) : (
<p>No posts found.</p>
)} PHP
<?php
$posts = new WP_Query(['post_type' => 'post']);
$show_title = true;
?>
<?php if ($show_title): ?>
<h1>Latest Posts</h1>
<?php endif; ?>
<?php if ($posts->have_posts()): ?>
<ul>
<?php while ($posts->have_posts()): $posts->the_post(); ?>
<li>
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</li>
<?php endwhile; wp_reset_postdata(); ?>
</ul>
<?php else: ?>
<p>No posts found.</p>
<?php endif; ?> 式のパターン
| パターン | 目的 |
|---|---|
{variable} | 値を出力 |
{condition && <Element />} | 条件付きレンダリング |
{condition ? <A /> : <B />} | If/else |
{items.map(item => <Li>{item}</Li>)} | ループ |
PropsとSlots
コンポーネントはprops(関数引数のような)とslots(do_action挿入ポイントのような)を通じてデータを受け取ります。
Astro
---
interface Props {
title: string;
featured?: boolean;
}
const { title, featured = false } = Astro.props;
---
<article class:list={["card", { featured }]}>
<h2>{title}</h2>
<slot />
<slot name="footer" />
</article>以下のマークアップはそのコンポーネントを使用し、デフォルトスロットと名前付きfooterスロットを渡します:
<Card title="Hello" featured>
<p>This goes in the default slot.</p>
<footer slot="footer">Footer content</footer>
</Card> PHP
<?php
// Usage: get_template_part('template-parts/card', null, [
// 'title' => 'Hello',
// 'featured' => true
// ]);
$title = $args['title'] ?? '';
$featured = $args['featured'] ?? false;
$class = $featured ? 'card featured' : 'card';
?>
<article class="<?php echo esc_attr($class); ?>">
<h2><?php echo esc_html($title); ?></h2>
<?php
// No direct equivalent to slots.
// WordPress uses do_action() for similar patterns:
do_action('card_content');
do_action('card_footer');
?>
</article> Props vs $args
WordPressでは、get_template_part()は$args配列を介してデータを渡します。Astro propsは型付けされ、分割代入されます:
---
// Type-safe with defaults
interface Props {
title: string;
count?: number;
}
const { title, count = 10 } = Astro.props;
---
Slots vs Hooks
WordPressは挿入ポイントを作成するためにdo_action()を使用します。Astroはslotsを使用します:
| WordPress | Astro |
|---|---|
do_action('before_content') | <slot name="before" /> |
| デフォルトコンテンツエリア | <slot /> |
do_action('after_content') | <slot name="after" /> |
違い:slotsは呼び出しサイトで子要素を受け取りますが、WordPressフックは別の場所で別のadd_action()呼び出しが必要です。
レイアウト
レイアウトは共通のHTML構造でページをラップします — <head>、ヘッダー、フッター、ページ間で共有されるすべてのもの。これはheader.php + footer.phpを置き換えます。以下のレイアウトは、その共有シェルを定義し、ページコンテンツのスロットを公開します:
---
import "../styles/global.css";
interface Props {
title: string;
description?: string;
}
const { title, description = "My EmDash Site" } = Astro.props;
---
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content={description} />
<title>{title}</title>
</head>
<body>
<header>
<nav><!-- Navigation --></nav>
</header>
<main>
<slot />
</main>
<footer>
<p>© {new Date().getFullYear()}</p>
</footer>
</body>
</html>
ページでレイアウトを使用します:
---
import Base from "../layouts/Base.astro";
---
<Base title="Home">
<h1>Welcome</h1>
<p>Page content goes in the slot.</p>
</Base>
スタイリング
Astroはいくつかのスタイリングアプローチを提供します。最も特徴的なのはスコープスタイルです。
スコープスタイル
<style>タグ内のスタイルは自動的にそのコンポーネントにスコープされます:
<article class="card">
<h2>Title</h2>
</article>
<style>
/* Only affects .card in THIS component */
.card {
padding: 1rem;
border: 1px solid #ddd;
}
h2 {
color: navy;
}
</style>
生成されたHTMLには、スタイルの漏れを防ぐために一意のクラス名が含まれているため、セレクタの詳細度を上げることなく、コンポーネントスタイルが含まれたままになります。
グローバルスタイル
サイト全体のスタイルには、CSSファイルを作成してレイアウトにインポートします:
---
import "../styles/global.css";
---
条件付きクラス
class:listディレクティブは手動でのクラス文字列の構築を置き換えます:
Astro
---
const { featured, size = "medium" } = Astro.props;
---
<article class:list={[
"card",
size,
{ featured, "has-border": true }
]}>出力:<article class="card medium featured has-border">
PHP
<?php
$classes = ['card', $size];
if ($featured) $classes[] = 'featured';
if (true) $classes[] = 'has-border';
?>
<article class="<?php echo esc_attr(implode(' ', $classes)); ?>"> クライアントサイドJavaScript
Astroはデフォルトでゼロのjavascriptを送信します。これがWordPressからの最大のメンタルシフトです。
インタラクティビティの追加
シンプルなインタラクションには、<script>タグを追加します:
<button id="menu-toggle">Menu</button>
<nav id="mobile-menu" hidden>
<slot />
</nav>
<script>
const toggle = document.getElementById("menu-toggle");
const menu = document.getElementById("mobile-menu");
toggle?.addEventListener("click", () => {
menu?.toggleAttribute("hidden");
});
</script>
スクリプトは自動的にバンドルされ、重複排除されます。このコンポーネントがページに2回表示される場合、スクリプトは1回実行されます。
高度なインタラクティブコンポーネント
より複雑なインタラクティビティのために、AstroはオンデマンドでJavaScriptコンポーネント(React、Vue、Svelte)をロードできます。これはオプションです — ほとんどのサイトは<script>タグだけでうまく機能します。以下のページは、ビューにスクロールしたときにのみコンポーネントをロードします:
---
import SearchWidget from "../components/SearchWidget.jsx";
---
<!-- Only load JavaScript when the search box scrolls into view -->
<SearchWidget client:visible />
| ディレクティブ | JavaScriptがロードされるタイミング |
|---|---|
client:load | ページロード時に即座に |
client:visible | コンポーネントがビューポートに入ったとき |
client:idle | ブラウザがアイドル状態のとき |
ルーティング
Astroはファイルベースのルーティングを使用します。src/pages/のファイルがURLになります:
| ファイル | URL |
|---|---|
src/pages/index.astro | / |
src/pages/about.astro | /about |
src/pages/posts/index.astro | /posts |
src/pages/posts/[slug].astro | /posts/hello-world |
src/pages/[...slug].astro | 任意のパス(キャッチオール) |
動的ルート
CMSコンテンツの場合、動的セグメントにブラケット構文を使用します:
---
import { getEmDashCollection, getEmDashEntry } from "emdash";
import Base from "../../layouts/Base.astro";
import { PortableText } from "emdash/ui";
// For static builds, define which pages to generate
export async function getStaticPaths() {
const { entries: posts } = await getEmDashCollection("posts");
return posts.map(post => ({
params: { slug: post.id },
props: { post },
}));
}
const { post } = Astro.props;
---
<Base title={post.data.title}>
<article>
<h1>{post.data.title}</h1>
<PortableText value={post.data.content} />
</article>
</Base>
WordPressとの比較
| WordPress | Astro |
|---|---|
テンプレート階層(single-post.php) | 明示的なファイル:posts/[slug].astro |
リライトルール + query_vars | ファイル構造 |
$wp_queryがテンプレートを決定 | URLがファイルに直接マップ |
add_rewrite_rule() | ファイルまたはフォルダーを作成 |
WordPressの概念がどこに存在するか
WordPress機能のAstro/EmDash相当を見つけるためのリファレンス:
テンプレーティング
| WordPress | Astro/EmDash |
|---|---|
| テンプレート階層 | src/pages/でのファイルベースルーティング |
get_template_part() | コンポーネントをインポートして使用 |
the_content() | <PortableText value={content} /> |
the_title(), the_*() | post.data.title経由でアクセス |
| テンプレートタグ | テンプレート式{value} |
body_class() | class:listディレクティブ |
データとクエリ
| WordPress | Astro/EmDash |
|---|---|
WP_Query | getEmDashCollection(type, filters) |
get_post() | getEmDashEntry(type, id) |
get_posts() | getEmDashCollection(type) |
get_the_terms() | entry.data.categories経由でアクセス |
get_post_meta() | entry.data.fieldName経由でアクセス |
get_option() | getSiteSettings() |
wp_nav_menu() | getMenu(location) |
拡張性
| WordPress | Astro/EmDash |
|---|---|
add_action() | EmDashフック、Astroミドルウェア |
add_filter() | EmDashフック |
add_shortcode() | Portable Textカスタムブロック |
register_block_type() | Portable Textカスタムブロック |
register_sidebar() | EmDashウィジェットエリア |
| プラグイン | Astro統合 + EmDashプラグイン |
コンテンツタイプ
| WordPress | Astro/EmDash |
|---|---|
register_post_type() | 管理UIでコレクションを作成 |
register_taxonomy() | 管理UIでタクソノミーを作成 |
register_meta() | コレクションスキーマにフィールドを追加 |
| 投稿ステータス | エントリーステータス(draft、published等) |
| アイキャッチ画像 | メディア参照フィールド |
| Gutenbergブロック | Portable Textブロック |
概念のマッピング
このガイドでカバーされている主なWordPressからAstroへのシフト:
- PHPテンプレートはAstroコンポーネントになります:明示的なファイル編成を伴うサーバーコードとHTML。
- テンプレートタグはpropsとimportになります:データはグローバルの代わりに引数を通じて流れます。
- テーマファイルはpagesディレクトリになります:URLはファイル構造と一致します。
- フックはslotsとミドルウェアになります:挿入ポイントはコンテンツが渡される場所で定義されます。
- jQueryはWordPressではデフォルトでロードされます;Astroは追加するまでJavaScriptを送信しません。
最初のEmDashサイトを構築するにはGetting Startedガイドから始めるか、Working with Contentを探索してCMSデータをクエリしてレンダリングする方法を学びます。