I temi WordPress possono essere convertiti sistematicamente in EmDash. Il design visivo, la struttura dei contenuti e le funzionalità dinamiche si trasferiscono utilizzando un approccio in tre fasi.
Approccio in tre fasi
-
Estrazione del design
Estrai variabili CSS, font, colori e pattern di layout dal tema WordPress. Analizza il sito live per catturare stili calcolati e breakpoint responsive.
-
Conversione dei template
Converti i template PHP in componenti Astro. Mappa la gerarchia dei template WordPress sulle route Astro e trasforma i tag dei template in chiamate API EmDash.
-
Funzionalità dinamiche
Porta menu di navigazione, aree widget, tassonomie e impostazioni del sito ai loro equivalenti EmDash. Crea un file seed per catturare il modello di contenuto completo.
Fase 1: Estrazione del design
Localizzare CSS e token di design
| File | Scopo |
|---|---|
style.css | Foglio di stile principale con intestazione tema |
assets/css/ | Fogli di stile aggiuntivi |
theme.json | Temi a blocchi (WP 5.9+) - token strutturati |
Estrarre i token di design
| Pattern WordPress | Variabile EmDash |
|---|---|
| Famiglia font corpo | --font-body |
| Font intestazioni | --font-heading |
| Colore primario | --color-primary |
| Sfondo | --color-base |
| Colore testo | --color-contrast |
| Larghezza contenuto | --content-width |
Creare il layout base
Crea src/layouts/Base.astro con le variabili CSS estratte, la struttura header/footer, il caricamento dei font e i breakpoint responsive:
---
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: Conversione dei template
Mappatura della gerarchia dei template
| Template WordPress | Route 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 di src/layouts/Base.astro |
sidebar.php | src/components/Sidebar.astro |
Mappatura dei tag template
| Funzione WordPress | Equivalente 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") |
Convertire il Loop
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> Convertire i template singoli
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> Convertire le parti template
Le chiamate WordPress get_template_part() diventano importazioni di componenti Astro. La parte template-parts/content-post.php diventa un componente PostCard.astro che importi e renderizzi in un ciclo.
Fase 3: Funzionalità dinamiche
Menu di navigazione
Identifica i menu in functions.php e crea i menu EmDash corrispondenti:
---
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>
)}
Aree widget (barre laterali)
Identifica le aree widget nel tema e renderizzale:
---
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>
)}
Mappatura dei tipi di widget
| Widget WordPress | Tipo widget 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" |
Tassonomie
Interroga le tassonomie registrate nel 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>
Mappatura delle impostazioni del sito
| WordPress Customizer | Impostazione EmDash |
|---|---|
| Site Title | title |
| Tagline | tagline |
| Site Icon | favicon |
| Custom Logo | logo |
| Posts per page | postsPerPage |
Shortcode a Portable Text
Gli shortcode WordPress diventano blocchi personalizzati Portable Text:
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>Registra il componente con PortableText:
<PortableText value={content} components={{ gallery: Gallery }} /> Struttura del file seed
Cattura il modello di contenuto completo in un file seed. Includi impostazioni, tassonomie, menu e aree widget:
{
"$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 }
}
]
}
]
}
Consulta Formato file seed per la specifica completa.
Checklist di porting
Fase 1 (Design): Variabili CSS estratte, font caricati, schema colori corrispondente, breakpoint responsive funzionanti.
Fase 2 (Template): Homepage, articoli singoli, archivi e pagina 404 renderizzati correttamente.
Fase 3 (Dinamico): Impostazioni del sito configurate, menu funzionanti, tassonomie interrogabili, aree widget renderizzate, file seed completato.
Casi particolari
Temi figlio
Se il tema ha un tema padre (controlla style.css per Template:), analizza prima il tema padre, poi applica le personalizzazioni del tema figlio.
Temi a blocchi (FSE)
I temi a blocchi di WordPress 5.9+ utilizzano theme.json per i token di design e templates/*.html per il markup dei blocchi. Converti il markup dei blocchi in componenti Astro ed estrai i token da theme.json.
Page builder
I contenuti costruiti con Elementor, Divi o simili sono memorizzati nei meta dei post, non nei file del tema. Questi contenuti si importano tramite WXR, non tramite il porting del tema. Concentra il porting del tema sulla struttura. I contenuti dei page builder vengono renderizzati tramite Portable Text dopo l’importazione.
Prossimi passi
- Creare temi — Costruire temi EmDash distribuibili
- Formato file seed — Specifica completa del file seed
- Migrare da WordPress — Importare contenuti WordPress