Portare un tema WordPress

In questa pagina

Porta un tema WordPress separando il suo design, i template delle route e le funzionalità gestite dal database. Il risultato è un progetto Astro completo con query EmDash e un file seed, non un tema PHP caricato da un runtime dei temi.

Parti dai contenuti e dagli URL

Importa contenuti rappresentativi prima di convertire i template. Annota i tipi di contenuto di WordPress, le tassonomie, le regole dei permalink, i menu, le aree widget, i valori del Customizer, gli shortcode e il markup generato dai plugin usati dal sito.

Scegli il nuovo URL per ogni tipo di contenuto. Le route di Astro sono file espliciti, quindi non esiste un equivalente automatico della gerarchia dei template di WordPress.

L’attuale template del blog usa questa corrispondenza:

WordPressPercorso del template EmDash
front-page.php o home.phpsrc/pages/index.astro
single.phpsrc/pages/posts/[slug].astro
archive.phpsrc/pages/posts/index.astro
page.phpsrc/pages/pages/[slug].astro
category.phpsrc/pages/category/[slug].astro
tag.phpsrc/pages/tag/[slug].astro
search.phpsrc/pages/search.astro
404.phpsrc/pages/404.astro
header.php e footer.phpsrc/layouts/Base.astro
template-parts/content.phpsrc/components/PostCard.astro o un altro componente

Il template starter, invece, usa src/pages/[slug].astro per le pagine. Scegli un solo modello di route e fai in modo che urlPattern del seed e i redirect siano coerenti con esso.

Estrai il design

Raccogli i file sorgente che determinano il design renderizzato:

  • style.css e i fogli di stile accodati.
  • theme.json per un tema a blocchi.
  • Il markup dei template e le parti template.
  • Font, icone e immagini con le relative licenze.
  • Breakpoint responsive e comportamento interattivo.

Copia i token di design nel CSS del progetto Astro e costruisci il guscio del documento condiviso in src/layouts/Base.astro. Converti in componenti le parti template ripetute prima di sviluppare le singole route.

Non copiare i nomi di classe né il JavaScript generati da WordPress quando il nuovo componente non ha bisogno del loro comportamento. Conserva il layout e l’interazione osservabili, non i residui dell’implementazione.

Converti le query degli archivi

WP_Query diventa getEmDashCollection(). Filtra e ordina nella query, in modo che sia il database a fare il lavoro.

Gli esempi seguenti renderizzano un archivio degli ultimi post:

WordPress

<?php
$posts = new WP_Query([
  'post_type' => 'post',
  'post_status' => 'publish',
  'posts_per_page' => 12,
  'orderby' => 'date',
  'order' => 'DESC',
]);

while ($posts->have_posts()) :
  $posts->the_post();
?>
  <article>
    <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
  </article>
<?php endwhile; wp_reset_postdata(); ?>

EmDash

---
import { getEmDashCollection } from "emdash";

const { entries: posts, error, cacheHint } = await getEmDashCollection("posts", {
  orderBy: { published_at: "desc" },
  limit: 12,
});

if (error) return new Response("Could not load posts", { status: 500 });
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
---

{posts.map((post) => (
  <article>
    <h2><a href={`/posts/${post.id}`}>{post.data.title}</a></h2>
  </article>
))}

Usa orderBy, non sort né sortBy. Le chiavi sono nomi di campo memorizzati, come published_at, created_at o un campo indicizzato della collezione.

Converti i template a voce singola

Usa lo slug di Astro.params per chiamare getEmDashEntry(). Renderizza il rich text con PortableText.

---
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, cacheHint } = await getEmDashEntry("posts", slug);
if (error) return new Response("Could not load the post", { status: 500 });
if (!post) return Astro.rewrite("/404");
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
---

<Base title={post.data.title} content={{ collection: "posts", id: post.data.id, slug }}>
  <article>
    <h1 {...post.edit.title}>{post.data.title}</h1>
    <PortableText value={post.data.content} />
  </article>
</Base>

post.id è l’identificatore di route di Astro e normalmente è lo slug. post.data.id è l’ID del contenuto EmDash memorizzato. Usa data.id per i commenti, gli helper delle tassonomie e il contesto della modifica visuale.

Converti gli archivi delle tassonomie

Risolvi un termine con il nome della sua tassonomia, poi usa quel nome nel filtro where della collezione. L’attuale template del blog usa nomi di tassonomia e directory di route al singolare:

---
import { decodeSlug, getEmDashCollection, getTerm } from "emdash";

const slug = decodeSlug(Astro.params.slug);
const term = slug ? await getTerm("category", slug, { includeCounts: false }) : null;
if (!term) return Astro.rewrite("/404");

const { entries: posts } = await getEmDashCollection("posts", {
  where: { category: term.slug },
  orderBy: { published_at: "desc" },
});
---

<h1>{term.label}</h1>
{posts.map((post) => <a href={`/posts/${post.id}`}>{post.data.title}</a>)}

Usa getTermsForEntries() con entry.data.id quando un archivio ha bisogno dei termini di molte voci. In questo modo la query delle relazioni viene eseguita in batch, invece di chiamare un helper per ogni voce in un ciclo.

Converti le funzionalità dinamiche del tema

Crea le definizioni dei menu in seed/seed.json e interrogale con getMenu("primary"). Le voci di menu possono essere riordinate e modificate dopo la configurazione, quindi non duplicare la stessa navigazione come link scritti a mano.

Il componente seguente conserva le voci di menu annidate e segna la pagina corrente:

---
import { getMenu } from "emdash";

const menu = await getMenu("primary");
---

{menu && (
  <nav aria-label="Primary navigation">
    <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>
              {item.children.map((child) => (
                <li><a href={child.url}>{child.label}</a></li>
              ))}
            </ul>
          )}
        </li>
      ))}
    </ul>
  </nav>
)}

Aree widget

Definisci le aree widget nel seed e renderizzale con <WidgetArea name="sidebar" /> da emdash/ui. Usa i widget di tipo componente solo quando il template registra l’ID del componente corrispondente.

---
import { WidgetArea } from "emdash/ui";
---

<main><slot /></main>
<aside aria-label="Related content">
  <WidgetArea name="sidebar" />
</aside>

Identità del sito

Leggi titolo del sito, slogan, logo e favicon con getSiteSettings(). Il testo legale o di design statico può restare nel template, ma l’identità gestita dall’amministratore deve provenire dalle impostazioni.

Valore WordPressImpostazione EmDash
Titolo del sitotitle
Slogantagline
Logo personalizzatologo
Icona del sitofavicon
Post per paginapostsPerPage

Template di pagina

Se gli editor devono scegliere tra più layout di pagina, aggiungi un campo select alla collezione delle pagine e associa ogni valore memorizzato a un componente noto. Non trasformare una stringa memorizzata in un percorso di import arbitrario.

Shortcode e blocchi

Associa gli shortcode che portano contenuto e i blocchi di WordPress a strutture Portable Text. Usa il normale renderer PortableText per i blocchi integrati e una mappa di componenti per i valori _type personalizzati.

Un seed può fornire dati di blocchi personalizzati, ma non registra un editor personalizzato. Usa un plugin nativo quando il porting richiede renderer Astro impacchettati o un’interfaccia di modifica React personalizzata.

Ad esempio, associa uno shortcode di galleria di WordPress a un _type con namespace, come publication.gallery, crea un renderer Gallery.astro e passalo tramite la mappa di componenti di PortableText:

---
import type { PortableTextBlock } from "emdash";
import { PortableText } from "emdash/ui";
import Gallery from "./blocks/Gallery.astro";

interface Props {
  value: PortableTextBlock[];
}

const { value } = Astro.props;
const customTypes = { "publication.gallery": Gallery };
---

<PortableText value={value} components={{ type: customTypes }} />

Costruisci il seed

Nei template attuali il seed si trova in seed/seed.json, e package.json#emdash.seed punta a esso. Dichiara ogni campo di collezione, tassonomia, menu, area widget, sezione e voce di esempio che il template dà per scontati.

Il frammento seguente definisce i campi dei post che riguardano le route:

{
  "$schema": "https://emdashcms.com/seed.schema.json",
  "version": "1",
  "collections": [
    {
      "slug": "posts",
      "label": "Posts",
      "labelSingular": "Post",
      "supports": ["drafts", "revisions", "search", "seo"],
      "urlPattern": "/posts/{slug}",
      "fields": [
        { "slug": "title", "label": "Title", "type": "string", "required": true },
        { "slug": "content", "label": "Content", "type": "portableText" },
        { "slug": "excerpt", "label": "Excerpt", "type": "text" },
        { "slug": "featured_image", "label": "Featured image", "type": "image" }
      ]
    }
  ]
}

Leggi File seed per ID dei contenuti, riferimenti, localizzazione, media, convalida e opzioni di applicazione.

Porta in fasi verificabili

  1. Importa un export WordPress rappresentativo e annota i blocchi o i campi non supportati.

  2. Parti dal template EmDash attuale per la destinazione di deployment.

  3. Implementa il layout condiviso, i token, la tipografia e il guscio responsive.

  4. Implementa le route degli archivi e delle voci singole usando gli slug e i campi delle collezioni importate.

  5. Aggiungi le route delle tassonomie, la ricerca, i menu, le aree widget e le impostazioni del sito che il tema di origine usa davvero.

  6. Aggiungi le definizioni seed per ogni dipendenza delle route e testa la configurazione su un database vuoto.

  7. Confronta URL pubblici rappresentativi con larghezze mobile e desktop. Testa campi vuoti, titoli lunghi, immagini mancanti, bozze e route 404.

  8. Prepara i redirect per ogni permalink modificato prima del passaggio.

Gestisci i temi WordPress difficili

  • Temi figlio: combina l’output risolto del tema genitore e del tema figlio. Porta i template e gli stili effettivi, non solo la directory del figlio.
  • Temi a blocchi: usa theme.json come fonte dei token di design e templates/*.html come struttura dei contenuti, quindi esprimi il risultato come componenti Astro.
  • Page builder: importa prima pagine rappresentative. Gli shortcode e il JSON proprietario dei builder richiedono in genere una conversione deliberata in Portable Text o un template di pagina riprogettato.
  • Temi WooCommerce: tratta il comportamento e-commerce come un’integrazione applicativa separata. Portare i file di presentazione non sostituisce la semantica di prodotto, carrello, checkout, pagamento o ordine.