Astro para desenvolvedores WordPress

Nesta página

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:

WordPressAstroPropósito
index.php, single.phpsrc/pages/Rotas (URLs)
template-parts/src/components/Peças de UI reutilizáveis
header.php + footer.phpsrc/layouts/Wrappers de página
style.csssrc/styles/CSS global
functions.phpastro.config.mjsConfiguraçã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:

  1. Frontmatter (entre cercas ---) — Código do lado do servidor, como PHP no topo de um template
  2. 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 Props para 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ãoPropó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:

WordPressAstro
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>&copy; {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 />
DiretivaQuando JavaScript carrega
client:loadImediatamente no carregamento da página
client:visibleQuando o componente entra no viewport
client:idleQuando o navegador está ocioso

Roteamento

Astro usa roteamento baseado em arquivos. Arquivos em src/pages/ tornam-se URLs:

ArquivoURL
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].astroQualquer 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

WordPressAstro
Hierarquia de templates (single-post.php)Arquivo explícito: posts/[slug].astro
Regras de reescrita + query_varsEstrutura de arquivos
$wp_query determina o templateURL 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

WordPressAstro/EmDash
Hierarquia de templatesRoteamento 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 templateExpressões de template {value}
body_class()Diretiva class:list

Dados e consultas

WordPressAstro/EmDash
WP_QuerygetEmDashCollection(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

WordPressAstro/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
PluginsIntegrações Astro + plugins EmDash

Tipos de conteúdo

WordPressAstro/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 postStatus de entrada (draft, published, etc.)
Imagem destacadaCampo de referência de mídia
Blocos GutenbergBlocos 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.