Astro é um framework web para construir sites focados em conteúdo. Ao usar EmDash, Astro substitui seu tema WordPress — ele gerencia templating, roteamento e renderização.
Este guia ensina os fundamentos do Astro mapeando-os para conceitos do WordPress que você já entende.
Principais mudanças de paradigma
Renderizado no servidor por padrão
Como PHP, o código Astro é executado no servidor. Ao contrário do PHP, ele gera HTML estático por padrão com zero JavaScript.
Zero JS a menos que você adicione
WordPress carrega jQuery e scripts de tema automaticamente. Astro não envia nada para o navegador a menos que você adicione explicitamente.
Arquitetura baseada em componentes
Em vez de tags de template dispersas e includes, construa com componentes componíveis e autocontidos.
Roteamento baseado em arquivos
Sem regras de reescrita ou query_vars. A estrutura de arquivos em src/pages/ define suas URLs diretamente.
Estrutura do projeto
Temas WordPress têm uma estrutura plana com nomes de arquivo mágicos. Astro usa diretórios explícitos:
| WordPress | Astro | Propósito |
|---|---|---|
index.php, single.php | src/pages/ | Rotas (URLs) |
template-parts/ | src/components/ | Peças de UI reutilizáveis |
header.php + footer.php | src/layouts/ | Wrappers de página |
style.css | src/styles/ | CSS global |
functions.php | astro.config.mjs | Configuração do site |
A árvore a seguir mostra um layout típico de projeto 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
Componentes Astro
Arquivos .astro são o equivalente do Astro para templates PHP. Cada arquivo tem duas partes:
- Frontmatter (entre cercas
---) — Código do lado do servidor, como PHP no topo de um template - Template — HTML com expressões, como o resto de um template PHP
O componente a seguir declara props tipadas no frontmatter e as renderiza no template:
---
// 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>
Principais diferenças do PHP:
- Frontmatter é isolado. Variáveis declaradas lá estão disponíveis no template, mas o código em si nunca chega ao navegador.
- Imports vão no frontmatter. Componentes, dados, utilitários — todos importados no topo.
- TypeScript funciona. Defina tipos de props com
interface Propspara autocompletar do editor e validação.
Expressões de template
Templates Astro usam {chaves} em vez de tags <?php ?>. A sintaxe é semelhante a JSX, mas gera HTML puro.
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; ?> Padrões de expressão
| Padrão | Propósito |
|---|---|
{variable} | Exibir um valor |
{condition && <Element />} | Renderização condicional |
{condition ? <A /> : <B />} | If/else |
{items.map(item => <Li>{item}</Li>)} | Loops |
Props e Slots
Componentes recebem dados através de props (como argumentos de função) e slots (como pontos de inserção 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>A marcação a seguir usa esse componente, passando o slot padrão e um slot footer nomeado:
<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
No WordPress, get_template_part() passa dados através do array $args. Props Astro são tipadas e desestruturadas:
---
// Type-safe with defaults
interface Props {
title: string;
count?: number;
}
const { title, count = 10 } = Astro.props;
---
Slots vs Hooks
WordPress usa do_action() para criar pontos de inserção. Astro usa slots:
| WordPress | Astro |
|---|---|
do_action('before_content') | <slot name="before" /> |
| Área de conteúdo padrão | <slot /> |
do_action('after_content') | <slot name="after" /> |
A diferença: slots recebem elementos filhos no local de chamada, enquanto hooks do WordPress exigem chamadas add_action() separadas em outro lugar.
Layouts
Layouts envolvem páginas com estrutura HTML comum — o <head>, cabeçalho, rodapé e tudo que é compartilhado entre páginas. Isso substitui header.php + footer.php. O layout a seguir define essa estrutura compartilhada e expõe um slot para conteúdo da página:
---
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>
Use o layout em uma página:
---
import Base from "../layouts/Base.astro";
---
<Base title="Home">
<h1>Welcome</h1>
<p>Page content goes in the slot.</p>
</Base>
Estilização
Astro oferece várias abordagens de estilização. A mais distintiva são os estilos com escopo.
Estilos com escopo
Estilos em uma tag <style> são automaticamente com escopo para esse componente:
<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>
O HTML gerado inclui nomes de classe únicos para prevenir vazamento de estilo, então os estilos de componentes permanecem contidos sem escalar a especificidade do seletor.
Estilos globais
Para estilos em todo o site, crie um arquivo CSS e importe-o em um layout:
---
import "../styles/global.css";
---
Classes condicionais
A diretiva class:list substitui a construção manual de strings de classe:
Astro
---
const { featured, size = "medium" } = Astro.props;
---
<article class:list={[
"card",
size,
{ featured, "has-border": true }
]}>Saída: <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 do lado do cliente
Astro envia zero JavaScript por padrão. Esta é a maior mudança mental do WordPress.
Adicionando interatividade
Para interações simples, adicione uma tag <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>
Scripts são automaticamente agrupados e deduplicados. Se esse componente aparecer duas vezes em uma página, o script é executado uma vez.
Componentes interativos avançados
Para interatividade mais complexa, Astro pode carregar componentes JavaScript (React, Vue, Svelte) sob demanda. Isso é opcional — a maioria dos sites funciona bem com apenas tags <script>. A página a seguir carrega um componente apenas quando ele rola para a vista:
---
import SearchWidget from "../components/SearchWidget.jsx";
---
<!-- Only load JavaScript when the search box scrolls into view -->
<SearchWidget client:visible />
| Diretiva | Quando JavaScript carrega |
|---|---|
client:load | Imediatamente no carregamento da página |
client:visible | Quando o componente entra no viewport |
client:idle | Quando o navegador está ocioso |
Roteamento
Astro usa roteamento baseado em arquivos. Arquivos em src/pages/ tornam-se URLs:
| Arquivo | 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 | Qualquer caminho (catch-all) |
Rotas dinâmicas
Para conteúdo CMS, use sintaxe de colchetes para segmentos dinâmicos:
---
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>
Comparado ao WordPress
| WordPress | Astro |
|---|---|
Hierarquia de templates (single-post.php) | Arquivo explícito: posts/[slug].astro |
Regras de reescrita + query_vars | Estrutura de arquivos |
$wp_query determina o template | URL mapeia diretamente para arquivo |
add_rewrite_rule() | Criar arquivos ou pastas |
Onde vivem os conceitos do WordPress
Uma referência para encontrar o equivalente Astro/EmDash de recursos do WordPress:
Templating
| WordPress | Astro/EmDash |
|---|---|
| Hierarquia de templates | Roteamento baseado em arquivos em src/pages/ |
get_template_part() | Importar e usar componentes |
the_content() | <PortableText value={content} /> |
the_title(), the_*() | Acesso via post.data.title |
| Tags de template | Expressões de template {value} |
body_class() | Diretiva class:list |
Dados e consultas
| WordPress | Astro/EmDash |
|---|---|
WP_Query | getEmDashCollection(type, filters) |
get_post() | getEmDashEntry(type, id) |
get_posts() | getEmDashCollection(type) |
get_the_terms() | Acesso via entry.data.categories |
get_post_meta() | Acesso via entry.data.fieldName |
get_option() | getSiteSettings() |
wp_nav_menu() | getMenu(location) |
Extensibilidade
| WordPress | Astro/EmDash |
|---|---|
add_action() | Hooks EmDash, middleware Astro |
add_filter() | Hooks EmDash |
add_shortcode() | Blocos personalizados Portable Text |
register_block_type() | Blocos personalizados Portable Text |
register_sidebar() | Áreas de widgets EmDash |
| Plugins | Integrações Astro + plugins EmDash |
Tipos de conteúdo
| WordPress | Astro/EmDash |
|---|---|
register_post_type() | Criar coleção na UI admin |
register_taxonomy() | Criar taxonomia na UI admin |
register_meta() | Adicionar campo ao esquema de coleção |
| Status de post | Status de entrada (draft, published, etc.) |
| Imagem destacada | Campo de referência de mídia |
| Blocos Gutenberg | Blocos Portable Text |
Mapeamento de conceitos
As principais mudanças de WordPress para Astro cobertas neste guia:
- Templates PHP tornam-se componentes Astro: código do servidor mais HTML, com organização de arquivos explícita.
- Tags de template tornam-se props e imports: dados fluem através de argumentos em vez de globais.
- Arquivos de tema tornam-se um diretório de páginas: URLs correspondem à estrutura de arquivos.
- Hooks tornam-se slots e middleware: pontos de inserção são definidos onde o conteúdo é passado.
- jQuery carrega por padrão no WordPress; Astro não envia JavaScript até você adicioná-lo.
Comece com o guia Getting Started para construir seu primeiro site EmDash, ou explore Working with Content para aprender como consultar e renderizar dados CMS.