Astro para desarrolladores de WordPress

En esta página

Astro proporciona las páginas, los layouts, los componentes y el renderizado en el servidor de un sitio de EmDash. Esta guía cubre los conceptos de Astro que usan las plantillas actuales de EmDash. Da por hecho que ya entiendes los temas de WordPress y las plantillas PHP.

Para las funciones del framework que no son específicas de EmDash, consulta la documentación de Astro.

Estructura del proyecto

Un sitio de Astro asigna un directorio explícito a cada tipo de archivo. Las plantillas actuales de EmDash usan esta estructura:

WordPressAstroPropósito
index.php, single.php, page.phpsrc/pages/Rutas de URL
template-parts/src/components/Marcado reutilizable
header.php y footer.phpsrc/layouts/Estructuras de página compartidas
style.csssrc/styles/Estilos del sitio
Configuración de plugins y base de datosastro.config.mjsIntegraciones y adaptador de servidor
Datos de configuración del temaseed/seed.jsonColecciones, menús y contenido de ejemplo

La plantilla del blog usa directorios de rutas que coinciden con sus URL públicas:

src/
├── components/
│   └── PostCard.astro
├── layouts/
│   └── Base.astro
├── pages/
│   ├── index.astro
│   ├── pages/
│   │   └── [slug].astro
│   └── posts/
│       ├── index.astro
│       └── [slug].astro
└── live.config.ts

Componentes Astro

Un componente .astro combina TypeScript del lado del servidor y una plantilla HTML. El código entre los delimitadores --- se ejecuta en el servidor. El marcado situado debajo del segundo delimitador se convierte en el HTML de la respuesta.

El siguiente componente declara props en su frontmatter y las renderiza en su plantilla:

---
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 escapa los valores renderizados con {value}. Las importaciones, las consultas a la base de datos y el resto del trabajo del servidor pertenecen al frontmatter.

Expresiones de plantilla

Las plantillas de Astro usan llaves donde una plantilla PHP cambiaría a <?php ?>. Los patrones más comunes en las plantillas de EmDash son valores, condiciones y mapeo de arrays:

ObjetivoSintaxis de Astro
Imprimir un valor{post.data.title}
Renderizar cuando existe un valor{post.data.excerpt && <p>{post.data.excerpt}</p>}
Elegir entre dos resultados{posts.length === 0 ? <p>No posts yet.</p> : <PostList />}
Renderizar una lista{posts.map((post) => <PostCard title={post.data.title} excerpt={post.data.excerpt} href={"/posts/" + post.id} />)}

La expresión puede usar variables preparadas en el frontmatter, valores de Astro.props o datos devueltos por una consulta de EmDash. Astro escapa por defecto los valores de cadena; usa un renderizador como <PortableText /> para el texto enriquecido estructurado en lugar de inyectar HTML.

Props y slots

Las props son comparables a los $args que se pasan a get_template_part(). Hacen explícita cada entrada y TypeScript puede comprobarlas.

Los slots permiten que un padre pase marcado a un componente. Un slot por defecto resulta útil para el contenido de la página, mientras que los slots con nombre ofrecen puntos de inserción adicionales:

---
interface Props {
  title: string;
}

const { title } = Astro.props;
---

<article>
  <h2>{title}</h2>
  <slot />
  <footer><slot name="footer" /></footer>
</article>

La siguiente página rellena ambos slots:

---
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>

Los slots son locales a la llamada del componente. No se comportan como las acciones de WordPress, que pueden recibir callbacks registrados en otro lugar.

Layouts

Un layout se encarga de la estructura de documento compartida que un tema de WordPress suele dividir entre header.php y footer.php. Las páginas importan el layout y pasan su contenido a través de su slot.

El siguiente layout proporciona una estructura de documento:

---
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>

La siguiente página aporta el título y el contenido principal del layout:

---
import Base from "../layouts/Base.astro";
---

<Base title="Home">
  <h1>Latest posts</h1>
</Base>

Enrutamiento basado en archivos

Los archivos de src/pages/ definen las rutas. Los nombres de archivo entre corchetes crean segmentos dinámicos.

ArchivoURL
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

Dentro de src/pages/posts/[slug].astro, Astro.params.slug contiene el valor de la URL. Lee Enrutamiento en Astro para ver los parámetros rest, las redirecciones y otras funciones de enrutamiento.

Renderizado del servidor

Las plantillas actuales de EmDash usan output: "server" en astro.config.mjs. Por eso, una página puede consultar la base de datos en cada solicitud, de modo que el contenido publicado no depende de una nueva compilación estática.

No añadas getStaticPaths() a una ruta de un tema de EmDash a menos que el sitio trate deliberadamente a EmDash como una fuente de datos en tiempo de compilación. Los temas suministrados se renderizan en el servidor.

Lee Renderizado bajo demanda en Astro para conocer el comportamiento a nivel de framework.

Consultar contenido EmDash

EmDash envuelve las colecciones de contenido en vivo de Astro con getEmDashCollection() y getEmDashEntry(). Los resultados de una colección contienen un array entries. Los resultados de una sola entrada contienen entry, que es null cuando ninguna entrada publicada coincide.

El siguiente archivo usa el mismo orden y los mismos identificadores que la plantilla actual del blog:

---
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 es el identificador de ruta que expone Astro y normalmente es el slug de la entrada. post.data.id es el identificador de la base de datos. Usa data.id cuando una API espere el ID de contenido almacenado, como ocurre con los helpers de taxonomías o de comentarios.

La siguiente ruta dinámica busca una entrada por el slug de la URL y renderiza su campo 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>

Continuar con Astro

Las plantillas de EmDash también usan estilos de componente y pequeños scripts de navegador, pero son funciones normales de Astro y no conceptos de EmDash. Lee Estilos y CSS para los estilos con ámbito y los globales, y Scripts y manejo de eventos cuando un componente necesite comportamiento en el navegador.