Portare i temi WordPress

In questa pagina

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

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

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

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

FileScopo
style.cssFoglio di stile principale con intestazione tema
assets/css/Fogli di stile aggiuntivi
theme.jsonTemi a blocchi (WP 5.9+) - token strutturati

Estrarre i token di design

Pattern WordPressVariabile 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 WordPressRoute Astro
index.phpsrc/pages/index.astro
single.phpsrc/pages/posts/[slug].astro
single-{post_type}.phpsrc/pages/{type}/[slug].astro
page.phpsrc/pages/[...slug].astro
archive.phpsrc/pages/posts/index.astro
category.phpsrc/pages/categories/[slug].astro
tag.phpsrc/pages/tags/[slug].astro
search.phpsrc/pages/search.astro
404.phpsrc/pages/404.astro
header.php / footer.phpParte di src/layouts/Base.astro
sidebar.phpsrc/components/Sidebar.astro

Mappatura dei tag template

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

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 WordPressTipo widget EmDash
Text/Custom HTMLtype: "content"
Custom Menutype: "menu"
Recent Postscomponent: "core:recent-posts"
Categoriescomponent: "core:categories"
Tag Cloudcomponent: "core:tag-cloud"
Searchcomponent: "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 CustomizerImpostazione EmDash
Site Titletitle
Taglinetagline
Site Iconfavicon
Custom Logologo
Posts per pagepostsPerPage

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