Porter un thème WordPress

Sur cette page

Portez un thème WordPress en séparant son design, ses modèles de route et les fonctionnalités gérées par la base de données. Le résultat est un projet Astro complet avec des requêtes EmDash et un fichier seed, et non un thème PHP chargé par un runtime de thèmes.

Commencer par le contenu et les URL

Importez un contenu représentatif avant de convertir les modèles. Notez les types de contenu WordPress, les taxonomies, les règles de permaliens, les menus, les zones de widgets, les valeurs du Customizer, les shortcodes et le balisage généré par les plugins qu’utilise le site.

Choisissez la nouvelle URL de chaque type de contenu. Les routes Astro sont des fichiers explicites : il n’existe donc pas d’équivalent automatique de la hiérarchie des modèles de WordPress.

Le modèle de blog actuel utilise cette correspondance :

WordPressChemin du modèle EmDash
front-page.php ou 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 et footer.phpsrc/layouts/Base.astro
template-parts/content.phpsrc/components/PostCard.astro ou un autre composant

Le modèle de démarrage utilise en revanche src/pages/[slug].astro pour les pages. Choisissez un modèle de routes et faites en sorte que le urlPattern du seed et les redirections soient cohérents avec lui.

Extraire le design

Rassemblez les fichiers source qui déterminent le design rendu :

  • style.css et les feuilles de style mises en file d’attente.
  • theme.json pour un thème de blocs.
  • Le balisage des modèles et les parties de modèle.
  • Les polices, les icônes et les images, avec leurs licences.
  • Les points de rupture responsives et les comportements interactifs.

Copiez les jetons de design dans le CSS du projet Astro et construisez l’enveloppe de document partagée dans src/layouts/Base.astro. Convertissez en composants les parties de modèle répétées avant de développer chaque route.

Ne copiez pas les noms de classe ni le JavaScript générés par WordPress lorsque le nouveau composant n’a pas besoin de leur comportement. Conservez la mise en page et l’interaction observables, pas les résidus de l’implémentation.

Convertir les requêtes d’archive

WP_Query devient getEmDashCollection(). Filtrez et triez dans la requête afin que la base de données fasse le travail.

Les exemples suivants affichent une archive des derniers articles :

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

Utilisez orderBy, et non sort ou sortBy. Les clés sont des noms de champ stockés, tels que published_at, created_at, ou un champ de collection indexé.

Convertir les modèles d’entrée unique

Utilisez le slug provenant de Astro.params pour appeler getEmDashEntry(). Affichez le texte enrichi avec 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 est l’identifiant de route d’Astro et correspond normalement au slug. post.data.id est l’ID de contenu EmDash stocké. Utilisez data.id pour les commentaires, les assistants de taxonomie et le contexte de l’édition visuelle.

Convertir les archives de taxonomie

Résolvez un terme avec le nom de sa taxonomie, puis utilisez ce nom dans le filtre where de la collection. Le modèle de blog actuel utilise des noms de taxonomie et des répertoires de route au singulier :

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

Utilisez getTermsForEntries() avec entry.data.id lorsqu’une archive a besoin des termes de nombreuses entrées. La requête de relation est alors traitée par lots, au lieu d’appeler un assistant par entrée dans une boucle.

Convertir les fonctionnalités dynamiques du thème

Créez les définitions de menu dans seed/seed.json et interrogez-les avec getMenu("primary"). Les éléments de menu peuvent être réordonnés et modifiés après la configuration ; ne dupliquez donc pas la même navigation sous forme de liens codés en dur.

Le composant suivant conserve les éléments de menu imbriqués et signale la page courante :

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

Zones de widgets

Définissez les zones de widgets dans le seed et affichez-les avec <WidgetArea name="sidebar" /> depuis emdash/ui. N’utilisez des widgets de composant que si le modèle enregistre l’ID de composant correspondant.

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

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

Identité du site

Lisez le titre du site, le slogan, le logo et le favicon avec getSiteSettings(). Les textes juridiques ou de design statiques peuvent rester dans le modèle, mais l’identité gérée par l’administrateur doit provenir des paramètres.

Valeur WordPressParamètre EmDash
Titre du sitetitle
Slogantagline
Logo personnalisélogo
Icône du sitefavicon
Articles par pagepostsPerPage

Modèles de page

Si les éditeurs doivent choisir parmi plusieurs mises en page, ajoutez un champ de sélection à la collection de pages et associez chaque valeur stockée à un composant connu. Ne transformez pas une chaîne stockée en chemin d’import arbitraire.

Shortcodes et blocs

Associez les shortcodes porteurs de contenu et les blocs WordPress à des structures Portable Text. Utilisez le moteur de rendu PortableText ordinaire pour les blocs intégrés et une table de composants pour les valeurs _type personnalisées.

Un seed peut fournir des données de bloc personnalisées, mais il n’enregistre pas d’éditeur personnalisé. Utilisez un plugin natif lorsque le portage requiert des moteurs de rendu Astro packagés ou une interface d’édition React personnalisée.

Par exemple, associez un shortcode de galerie WordPress à un _type avec espace de noms, tel que publication.gallery, créez un moteur de rendu Gallery.astro et transmettez-le via la table de composants de 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 }} />

Construire le seed

Dans les modèles actuels, le seed se trouve dans seed/seed.json, et package.json#emdash.seed y pointe. Déclarez chaque champ de collection, taxonomie, menu, zone de widgets, section et entrée d’exemple que le modèle suppose présents.

Le fragment suivant définit les champs des articles qui interviennent dans les routes :

{
  "$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" }
      ]
    }
  ]
}

Lisez Fichiers seed pour les ID de contenu, les références, la localisation, les médias, la validation et les options d’application.

Porter par étapes vérifiables

  1. Importez un export WordPress représentatif et notez les blocs ou champs non pris en charge.

  2. Partez du modèle EmDash actuel correspondant à la cible de déploiement.

  3. Implémentez la mise en page partagée, les jetons, la typographie et l’enveloppe responsive.

  4. Implémentez les routes d’archive et d’entrée unique en utilisant les slugs et les champs des collections importées.

  5. Ajoutez les routes de taxonomie, la recherche, les menus, les zones de widgets et les paramètres du site que le thème source utilise réellement.

  6. Ajoutez des définitions seed pour chaque dépendance de route et testez la configuration sur une base de données vide.

  7. Comparez des URL publiques représentatives en largeur mobile et bureau. Testez les champs vides, les titres longs, les images manquantes, les brouillons et les routes 404.

  8. Préparez les redirections de chaque permalien modifié avant la bascule.

Gérer les thèmes WordPress difficiles

  • Thèmes enfants : combinez la sortie résolue du thème parent et du thème enfant. Portez les modèles et les styles effectifs, et pas seulement le répertoire du thème enfant.
  • Thèmes de blocs : utilisez theme.json comme source des jetons de design et templates/*.html comme structure du contenu, puis exprimez le résultat sous forme de composants Astro.
  • Constructeurs de pages : importez d’abord des pages représentatives. Les shortcodes et le JSON propriétaire des constructeurs exigent généralement une conversion réfléchie vers Portable Text ou un modèle de page repensé.
  • Thèmes WooCommerce : traitez le comportement e-commerce comme une intégration applicative distincte. Porter les fichiers de présentation ne remplace pas la sémantique des produits, du panier, du paiement, du règlement ou des commandes.