Astro è un framework web per siti incentrati sul contenuto. Con EmDash, Astro sostituisce il tema WordPress—gestisce templating, routing e rendering.
Questa guida insegna le basi di Astro mappandole sui concetti WordPress che già capisci.
Cambi di paradigma chiave
Renderizzato sul server di default
Come PHP, il codice Astro gira sul server. A differenza di PHP, di default produce HTML statico con zero JavaScript.
Zero JS se non lo aggiungi
WordPress carica jQuery e gli script del tema automaticamente. Astro non invia nulla al browser a meno che tu non lo aggiunga esplicitamente.
Architettura a componenti
Invece di tag template e include sparsi, costruisci con componenti componibili e autocontenuti.
Routing basato su file
Niente regole di rewrite o query_vars. La struttura dei file in src/pages/ definisce direttamente gli URL.
Struttura del progetto
I temi WordPress hanno una struttura piatta con nomi file «magici». Astro usa directory esplicite:
| WordPress | Astro | Scopo |
|---|---|---|
index.php, single.php | src/pages/ | Route (URL) |
template-parts/ | src/components/ | Pezzi UI riutilizzabili |
header.php + footer.php | src/layouts/ | Involucri di pagina |
style.css | src/styles/ | CSS globale |
functions.php | astro.config.mjs | Configurazione del sito |
Un tipico progetto 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
Componenti Astro
I file .astro sono l’equivalente Astro dei template PHP. Ogni file ha due parti:
- Frontmatter (tra le barre
---) — Codice lato server, come il PHP in cima a un template - Template — HTML con espressioni, come il resto di un template PHP
---
// 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>
Differenze chiave rispetto a PHP:
- Il frontmatter è isolato. Le variabili dichiarate lì sono disponibili nel template, ma il codice non arriva mai al browser.
- Gli import vanno nel frontmatter. Componenti, dati, utility—tutto importato in cima.
- TypeScript funziona. Definisci i tipi delle props con
interface Propsper autocomplete e validazione nell’editor.
Espressioni template
I template Astro usano {graffe} al posto dei tag <?php ?>. La sintassi è simile a JSX ma produce 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; ?> Pattern di espressione
| Pattern | Scopo |
|---|---|
{variable} | Emissione di un valore |
{condition && <Element />} | Rendering condizionale |
{condition ? <A /> : <B />} | If/else |
{items.map(item => <Li>{item}</Li>)} | Cicli |
Props e slot
I componenti ricevono dati tramite props (come argomenti di funzione) e slot (come punti di inserimento 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>Uso:
<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
In WordPress, get_template_part() passa dati tramite l’array $args. Le props Astro sono tipizzate e destrutturate:
---
// Type-safe with defaults
interface Props {
title: string;
count?: number;
}
const { title, count = 10 } = Astro.props;
---
Slot vs hook
WordPress usa do_action() per creare punti di inserimento. Astro usa gli slot:
| WordPress | Astro |
|---|---|
do_action('before_content') | <slot name="before" /> |
| Default content area | <slot /> |
do_action('after_content') | <slot name="after" /> |
La differenza: gli slot ricevono elementi figli nel punto di chiamata, mentre gli hook WordPress richiedono chiamate add_action() separate altrove.
Layout
I layout avvolgono le pagine con HTML comune—<head>, header, footer e tutto ciò che è condiviso. Sostituiscono 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>
Usare il layout in una pagina:
---
import Base from "../layouts/Base.astro";
---
<Base title="Home">
<h1>Welcome</h1>
<p>Page content goes in the slot.</p>
</Base>
Styling
Astro offre diversi approcci allo stile. Il più distintivo è lo scoped style.
Scoped styles
Gli stili in un tag <style> sono automaticamente limitati a quel 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>
L’HTML generato include nomi di classe unici per evitare leakage di stile. Basta guerre di specificità.
Stili globali
Per stili su tutto il sito, crea un file CSS e importalo in un layout:
---
import "../styles/global.css";
---
Classi condizionali
La direttiva class:list sostituisce la costruzione manuale di stringhe di classi:
Astro
---
const { featured, size = "medium" } = Astro.props;
---
<article class:list={[
"card",
size,
{ featured, "has-border": true }
]}>Output: <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 lato client
Astro non invia JavaScript di default. Questo è il salto mentale più grande rispetto a WordPress.
Aggiungere interattività
Per interazioni semplici, aggiungi un 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>
Gli script sono raggruppati e deduplicati automaticamente. Se il componente compare due volte nella pagina, lo script gira una volta.
Avanzato: componenti interattivi
Per interattività più complessa, Astro può caricare componenti JavaScript (React, Vue, Svelte) on demand. È opzionale—molti siti vanno bene solo con <script>.
---
import SearchWidget from "../components/SearchWidget.jsx";
---
<!-- Only load JavaScript when the search box scrolls into view -->
<SearchWidget client:visible />
| Directive | Quando si carica JavaScript |
|---|---|
client:load | Subito al caricamento della pagina |
client:visible | Quando il componente entra nel viewport |
client:idle | Quando il browser è in idle |
Routing
Astro usa il routing basato su file. I file in src/pages/ diventano URL:
| File | 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 | Any path (catch-all) |
Route dinamiche
Per contenuti CMS, usa la sintassi con parentesi quadre per i segmenti dinamici:
---
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>
Rispetto a WordPress
| WordPress | Astro |
|---|---|
Template hierarchy (single-post.php) | Explicit file: posts/[slug].astro |
Rewrite rules + query_vars | File structure |
$wp_query determines template | URL maps directly to file |
add_rewrite_rule() | Create files or folders |
Dove vivono i concetti WordPress
Riferimento per trovare l’equivalente Astro/EmDash delle funzionalità WordPress:
Templating
| WordPress | Astro/EmDash |
|---|---|
| Template hierarchy | File-based routing in src/pages/ |
get_template_part() | Import and use components |
the_content() | <PortableText value={content} /> |
the_title(), the_*() | Access via post.data.title |
| Template tags | Template expressions {value} |
body_class() | class:list directive |
Dati e query
| WordPress | Astro/EmDash |
|---|---|
WP_Query | getEmDashCollection(type, filters) |
get_post() | getEmDashEntry(type, id) |
get_posts() | getEmDashCollection(type) |
get_the_terms() | Access via entry.data.categories |
get_post_meta() | Access via entry.data.fieldName |
get_option() | getSiteSettings() |
wp_nav_menu() | getMenu(location) |
Estensibilità
| WordPress | Astro/EmDash |
|---|---|
add_action() | EmDash hooks, Astro middleware |
add_filter() | EmDash hooks |
add_shortcode() | Portable Text custom blocks |
register_block_type() | Portable Text custom blocks |
register_sidebar() | EmDash widget areas |
| Plugins | Astro integrations + EmDash plugins |
Tipi di contenuto
| WordPress | Astro/EmDash |
|---|---|
register_post_type() | Create collection in admin UI |
register_taxonomy() | Create taxonomy in admin UI |
register_meta() | Add field to collection schema |
| Post status | Entry status (draft, published, etc.) |
| Featured image | Media reference field |
| Gutenberg blocks | Portable Text blocks |
Riepilogo
Il passaggio da WordPress ad Astro è significativo ma logico:
- Template PHP → componenti Astro — Stessa idea (codice server + HTML), organizzazione migliore
- Tag template → props e import — Flusso dati esplicito invece di globali
- File del tema → directory pages — Gli URL seguono la struttura dei file
- Hook → slot e middleware — Punti di inserimento più prevedibili
- jQuery di default → zero JS di default — Aggiungi interattività in modo intenzionale
Inizia dalla guida Getting Started per il tuo primo sito EmDash, o esplora Working with Content per interrogare e renderizzare i dati del CMS.