Los temas de WordPress pueden convertirse sistemáticamente a EmDash. El diseño visual, la estructura de contenido y las funciones dinámicas se transfieren utilizando un enfoque de tres fases.
Enfoque de Tres Fases
-
Extracción de Diseño
Extraiga variables CSS, fuentes, colores y patrones de diseño del tema de WordPress. Analice el sitio en vivo para capturar estilos calculados y puntos de interrupción responsivos.
-
Conversión de Plantillas
Convierta plantillas PHP a componentes Astro. Mapee la jerarquía de plantillas de WordPress a rutas de Astro y transforme etiquetas de plantilla a llamadas de API de EmDash.
-
Funciones Dinámicas
Porte menús de navegación, áreas de widgets, taxonomías y configuraciones del sitio a sus equivalentes de EmDash. Cree un archivo seed para capturar el modelo de contenido completo.
Fase 1: Extracción de Diseño
Localizar CSS y Tokens de Diseño
|| Archivo | Propósito |
|| ------------- | ------------------------------------------ |
|| style.css | Hoja de estilos principal con encabezado del tema |
|| assets/css/ | Hojas de estilo adicionales |
|| theme.json | Temas de bloques (WP 5.9+) - tokens estructurados |
Extraer Tokens de Diseño
|| Patrón de WordPress | Variable de EmDash |
|| ----------------- | ------------------ |
|| Familia de fuente del cuerpo | --font-body |
|| Fuente de encabezado | --font-heading |
|| Color primario | --color-primary |
|| Fondo | --color-base |
|| Color de texto | --color-contrast |
|| Ancho de contenido | --content-width |
Crear Diseño Base
Cree src/layouts/Base.astro con variables CSS extraídas, estructura de encabezado/pie de página, carga de fuentes y puntos de interrupción responsivos:
---
import { getSiteSettings, getMenu } from "emdash";
import "../styles/global.css";
const { title, description } = Astro.props;
const settings = await getSiteSettings();
const primaryMenu = await getMenu("primary");
const pageTitle = title ? `${title} | ${settings.title}` : settings.title;
---
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{pageTitle}</title>
</head>
<body>
<header>
{settings.logo ? (
<img src={settings.logo.url} alt={settings.title} />
) : (
<span>{settings.title}</span>
)}
<nav>
{primaryMenu?.items.map((item) => (
<a href={item.url}>{item.label}</a>
))}
</nav>
</header>
<main><slot /></main>
</body>
</html>
Fase 2: Conversión de Plantillas
Mapeo de Jerarquía de Plantillas
|| Plantilla de WordPress | Ruta de Astro |
|| --------------------------- | ----------------------------------- |
|| index.php | src/pages/index.astro |
|| single.php | src/pages/posts/[slug].astro |
|| single-{post_type}.php | src/pages/{type}/[slug].astro |
|| page.php | src/pages/[...slug].astro |
|| archive.php | src/pages/posts/index.astro |
|| category.php | src/pages/categories/[slug].astro |
|| tag.php | src/pages/tags/[slug].astro |
|| search.php | src/pages/search.astro |
|| 404.php | src/pages/404.astro |
|| header.php / footer.php | Parte de src/layouts/Base.astro |
|| sidebar.php | src/components/Sidebar.astro |
Mapeo de Etiquetas de Plantilla
|| Función de WordPress | Equivalente de EmDash |
|| ----------------------------- | -------------------------------------------- |
|| have_posts() / the_post() | getEmDashCollection() |
|| get_post() | getEmDashEntry() |
|| the_title() | post.data.title |
|| the_content() | <PortableText value={post.data.content} /> |
|| the_excerpt() | post.data.excerpt |
|| the_permalink() | /posts/${post.slug} |
|| the_post_thumbnail() | post.data.featured_image |
|| get_the_date() | post.data.publishedAt |
|| get_the_category() | getEntryTerms(coll, id, "categories") |
|| get_the_tags() | getEntryTerms(coll, id, "tags") |
Convirtiendo el Bucle
WordPress
<?php while (have_posts()) : the_post(); ?>
<article>
<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
<?php the_excerpt(); ?>
</article>
<?php endwhile; ?> EmDash
---
import { getEmDashCollection } from "emdash";
import Base from "../../layouts/Base.astro";
const { entries: posts } = await getEmDashCollection("posts", {
where: { status: "published" },
orderBy: { publishedAt: "desc" },
});
---
<Base title="Blog">
{posts.map((post) => (
<article>
<h2><a href={`/posts/${post.slug}`}>{post.data.title}</a></h2>
<p>{post.data.excerpt}</p>
</article>
))}
</Base> Convirtiendo Plantillas Individuales
WordPress
<?php get_header(); ?>
<article>
<h1><?php the_title(); ?></h1>
<?php the_content(); ?>
<div class="post-meta">
Posted in: <?php the_category(', '); ?>
</div>
</article>
<?php get_footer(); ?> EmDash
---
import { getEmDashCollection, getEntryTerms } from "emdash";
import { PortableText } from "emdash/ui";
import Base from "../../layouts/Base.astro";
export async function getStaticPaths() {
const { entries: posts } = await getEmDashCollection("posts");
return posts.map((post) => ({
params: { slug: post.slug },
props: { post },
}));
}
const { post } = Astro.props;
const categories = await getEntryTerms("posts", post.id, "categories");
---
<Base title={post.data.title}>
<article>
<h1>{post.data.title}</h1>
<PortableText value={post.data.content} />
<div class="post-meta">
Posted in: {categories.map((cat) => (
<a href={`/categories/${cat.slug}`}>{cat.label}</a>
))}
</div>
</article>
</Base> Convirtiendo Partes de Plantilla
Las llamadas a get_template_part() de WordPress se convierten en importaciones de componentes de Astro. El parcial template-parts/content-post.php se convierte en un componente PostCard.astro que importas y renderizas en un bucle.
Fase 3: Funciones Dinámicas
Menús de Navegación
Identifique menús en functions.php y cree los menús de EmDash correspondientes:
---
import { getMenu } from "emdash";
const menu = await getMenu("primary");
---
{menu && (
<nav class="primary-nav">
<ul>
{menu.items.map((item) => (
<li>
<a href={item.url} aria-current={Astro.url.pathname === item.url ? "page" : undefined}>
{item.label}
</a>
{item.children.length > 0 && (
<ul class="submenu">
{item.children.map((child) => (
<li><a href={child.url}>{child.label}</a></li>
))}
</ul>
)}
</li>
))}
</ul>
</nav>
)}
Áreas de Widgets (Barras Laterales)
Identifique áreas de widgets en el tema y renderícelas:
---
import { getWidgetArea, getMenu } from "emdash";
import { PortableText } from "emdash/ui";
import RecentPosts from "./widgets/RecentPosts.astro";
const sidebar = await getWidgetArea("sidebar");
const widgetComponents = { "core:recent-posts": RecentPosts };
---
{sidebar && sidebar.widgets.length > 0 && (
<aside class="sidebar">
{sidebar.widgets.map(async (widget) => (
<div class="widget">
{widget.title && <h3>{widget.title}</h3>}
{widget.type === "content" && <PortableText value={widget.content} />}
{widget.type === "menu" && (
<nav>
{await getMenu(widget.menuName).then((m) =>
m?.items.map((item) => <a href={item.url}>{item.label}</a>)
)}
</nav>
)}
{widget.type === "component" && widgetComponents[widget.componentId] && (
<Fragment>
{(() => {
const Component = widgetComponents[widget.componentId];
return <Component {...widget.componentProps} />;
})()}
</Fragment>
)}
</div>
))}
</aside>
)}
Mapeo de Tipos de Widget
|| Widget de WordPress | Tipo de Widget de EmDash |
|| ---------------- | -------------------------------- |
|| Text/Custom HTML | type: "content" |
|| Custom Menu | type: "menu" |
|| Recent Posts | component: "core:recent-posts" |
|| Categories | component: "core:categories" |
|| Tag Cloud | component: "core:tag-cloud" |
|| Search | component: "core:search" |
Taxonomías
Consulte las taxonomías registradas en el tema:
---
import { getTaxonomyTerms, getEntriesByTerm } from "emdash";
import Base from "../../layouts/Base.astro";
export async function getStaticPaths() {
const genres = await getTaxonomyTerms("genre");
return genres.map((genre) => ({
params: { slug: genre.slug },
props: { genre },
}));
}
const { genre } = Astro.props;
const books = await getEntriesByTerm("books", "genre", genre.slug);
---
<Base title={genre.label}>
<h1>{genre.label}</h1>
{books.map((book) => (
<article>
<h2><a href={`/books/${book.slug}`}>{book.data.title}</a></h2>
</article>
))}
</Base>
Mapeo de Configuración del Sitio
|| Personalizador de WordPress | Configuración de EmDash |
|| -------------------- | ---------------- |
|| Site Title | title |
|| Tagline | tagline |
|| Site Icon | favicon |
|| Custom Logo | logo |
|| Posts per page | postsPerPage |
Shortcodes a Texto Portable
Los shortcodes de WordPress se convierten en bloques personalizados de Texto Portable:
WordPress
add_shortcode('gallery', function($atts) {
$ids = explode(',', $atts['ids']);
return '<div class="gallery">...</div>';
}); EmDash
---
const { images } = Astro.props;
---
<div class="gallery">
{images.map((img) => (
<img src={img.url} alt={img.alt || ""} loading="lazy" />
))}
</div>Registre el componente con PortableText:
<PortableText value={content} components={{ gallery: Gallery }} /> Estructura del Archivo Seed
Capture el modelo de contenido completo en un archivo seed. Incluya configuraciones, taxonomías, menús y áreas de widgets:
{
"$schema": "https://emdashcms.com/seed.schema.json",
"version": "1",
"meta": { "name": "Ported Theme" },
"settings": { "title": "My Site", "tagline": "Welcome", "postsPerPage": 10 },
"taxonomies": [
{
"name": "category",
"label": "Categories",
"hierarchical": true,
"collections": ["posts"]
}
],
"menus": [
{
"name": "primary",
"label": "Primary Navigation",
"items": [
{ "type": "custom", "label": "Home", "url": "/" },
{ "type": "custom", "label": "Blog", "url": "/posts" }
]
}
],
"widgetAreas": [
{
"name": "sidebar",
"label": "Main Sidebar",
"widgets": [
{
"type": "component",
"componentId": "core:recent-posts",
"props": { "count": 5 }
}
]
}
]
}
Consulte Formato de Archivo Seed para la especificación completa.
Lista de Verificación de Portado
Fase 1 (Diseño): Variables CSS extraídas, fuentes cargadas, esquema de colores coincidente, puntos de interrupción responsivos funcionando.
Fase 2 (Plantillas): Página de inicio, publicaciones individuales, archivos y página 404 se renderizan correctamente.
Fase 3 (Dinámico): Configuraciones del sitio configuradas, menús funcionales, taxonomías consultables, áreas de widgets renderizadas, archivo seed completo.
Casos Especiales
Temas Hijos
Si el tema tiene un padre (verifique style.css para Template:), analice primero el tema padre y luego aplique las anulaciones del tema hijo.
Temas de Bloques (FSE)
Los temas de bloques de WordPress 5.9+ usan theme.json para tokens de diseño y templates/*.html para marcado de bloques. Convierta el marcado de bloques a componentes de Astro y extraiga tokens de theme.json.
Constructores de Páginas
El contenido creado con Elementor, Divi o similar se almacena en metadatos de publicación, no en archivos de tema. Este contenido se importa a través de WXR, no mediante portado de tema. Enfoque el portado de tema en el shell. El contenido del constructor de páginas se renderiza a través de Texto Portable después de la importación.
Próximos Pasos
- Creando Temas — Construir temas de EmDash distribuibles
- Formato de Archivo Seed — Especificación completa del archivo seed
- Migrar desde WordPress — Importar contenido de WordPress