移植 WordPress 主題時,請將它的設計、路由範本和由資料庫管理的功能分開處理。最終得到的是一個包含 EmDash 查詢和種子檔案的完整 Astro 專案,而不是由主題執行階段載入的 PHP 主題。
從內容和 URL 開始
在轉換範本之前,先匯入具代表性的內容。記錄站台使用的 WordPress 文章類型、分類法、固定連結規則、選單、小工具區域、Customizer 值、短代碼,以及由外掛程式產生的標記。
為每種內容類型選定新的 URL。Astro 的路由是明確的檔案,因此沒有與 WordPress 範本階層對應的自動機制。
目前的部落格範本使用如下對應:
| WordPress | EmDash 範本路徑 |
|---|---|
front-page.php 或 home.php | src/pages/index.astro |
single.php | src/pages/posts/[slug].astro |
archive.php | src/pages/posts/index.astro |
page.php | src/pages/pages/[slug].astro |
category.php | src/pages/category/[slug].astro |
tag.php | src/pages/tag/[slug].astro |
search.php | src/pages/search.astro |
404.php | src/pages/404.astro |
header.php 和 footer.php | src/layouts/Base.astro |
template-parts/content.php | src/components/PostCard.astro 或其他元件 |
入門範本則使用 src/pages/[slug].astro 來承載頁面。請選定一種路由模型,並讓種子檔案中的 urlPattern 和重新導向與之保持一致。
擷取設計
收集決定最終轉譯設計的來源檔案:
style.css以及透過 enqueue 載入的樣式表。- 區塊主題的
theme.json。 - 範本標記和範本部件。
- 字型、圖示和圖片,以及它們的授權。
- 響應式斷點和互動行為。
將設計權杖複製到 Astro 專案的 CSS 中,並在 src/layouts/Base.astro 中建置共用的文件外殼。在展開各個路由之前,先把重複出現的範本部件轉換為元件。
當新元件不需要 WordPress 產生的類別名稱或 JavaScript 所提供的行為時,不要照搬它們。要保留的是可觀察的版面配置與互動,而不是實作層面的殘留。
轉換封存查詢
WP_Query 變為 getEmDashCollection()。請在查詢中完成篩選和排序,讓資料庫來做這些工作。
下面的範例轉譯一個最新文章封存:
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>
))} 請使用 orderBy,而不是 sort 或 sortBy。鍵是儲存的欄位名稱,例如 published_at、created_at,或已建立索引的集合欄位。
轉換單一條目範本
使用 Astro.params 中的 slug 呼叫 getEmDashEntry()。用 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 是 Astro 的路由識別碼,通常就是 slug。post.data.id 是儲存的 EmDash 內容 ID。留言、分類法輔助函式和視覺化編輯內容請使用 data.id。
轉換分類法封存
先用分類法名稱解析術語,再在集合的 where 篩選條件中使用該名稱。目前的部落格範本使用單數形式的分類法名稱和路由目錄:
---
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>)}
當封存頁面需要為許多條目取得術語時,請將 getTermsForEntries() 與 entry.data.id 搭配使用。這樣會批次執行關聯查詢,而不是在迴圈中為每個條目呼叫輔助函式。
轉換動態主題功能
選單
在 seed/seed.json 中建立選單定義,並用 getMenu("primary") 查詢。選單項目在設定完成後仍可重新排序和編輯,因此不要把同一份導覽再以寫死的連結形式重複寫一遍。
下面的元件保留了巢狀的選單項目,並標出目前頁面:
---
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>
)}
小工具區域
在種子檔案中定義小工具區域,並用 emdash/ui 中的 <WidgetArea name="sidebar" /> 轉譯。只有當範本註冊了對應的元件 ID 時,才使用元件小工具。
---
import { WidgetArea } from "emdash/ui";
---
<main><slot /></main>
<aside aria-label="Related content">
<WidgetArea name="sidebar" />
</aside>
站台識別
用 getSiteSettings() 讀取站台標題、副標題、標誌和站台圖示。靜態的法律文案或設計文案可以留在範本中,但由管理員管理的站台識別必須來自設定。
| WordPress 值 | EmDash 設定 |
|---|---|
| 站台標題 | title |
| 副標題 | tagline |
| 自訂標誌 | logo |
| 站台圖示 | favicon |
| 每頁文章數 | postsPerPage |
頁面範本
如果編輯者必須在多種頁面版面配置中進行選擇,請在頁面集合中新增一個選取欄位,並把每個儲存的值對應到已知的元件。不要把儲存的字串變成任意的匯入路徑。
短代碼和區塊
將承載內容的短代碼和 WordPress 區塊對應為 Portable Text 的結構。內建區塊使用一般的 PortableText 轉譯器,自訂的 _type 值則使用元件對應。
種子檔案可以提供自訂區塊資料,但它不會註冊自訂編輯器。如果移植需要封裝的 Astro 轉譯器或自訂 React 編輯介面,請使用原生外掛程式。
例如,把 WordPress 的圖庫短代碼對應為帶命名空間的 _type,如 publication.gallery,建立一個 Gallery.astro 轉譯器,並透過 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 }} />
建置種子檔案
在目前的範本中,種子檔案位於 seed/seed.json,並由 package.json#emdash.seed 指向。請宣告範本所依賴的每個集合欄位、分類法、選單、小工具區域、區段和範例條目。
下面的片段定義了文章面向路由的欄位:
{
"$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" }
]
}
]
}
有關內容 ID、參照、在地化、媒體、驗證和套用選項,請閱讀 Seed 檔案。
分階段移植並逐步驗證
-
匯入具代表性的 WordPress 匯出檔案,並記錄所有不受支援的區塊或欄位。
-
從適用於部署目標的目前 EmDash 範本開始。
-
實作共用版面配置、設計權杖、排版和響應式外殼。
-
使用匯入後的集合 slug 和欄位,實作封存路由和單一條目路由。
-
新增來源主題實際用到的分類法路由、搜尋、選單、小工具區域和站台設定。
-
為每個路由相依項目新增種子定義,並在空的資料庫上測試設定流程。
-
在行動裝置和桌面寬度下比較具代表性的公開 URL。測試空欄位、過長的標題、缺失的圖片、草稿和 404 路由。
-
在切換上線之前,為每個變更過的固定連結準備重新導向。
應對棘手的 WordPress 主題
- 子主題: 合併解析後的父主題和子主題的輸出。移植的是實際生效的範本和樣式,而不僅僅是子主題目錄。
- 區塊主題: 將
theme.json作為設計權杖的來源,將templates/*.html作為內容結構的來源,然後用 Astro 元件來表達結果。 - 頁面建構器: 先匯入具代表性的頁面。建構器的短代碼和專有 JSON 通常需要經過審慎的 Portable Text 轉換,或者重新設計頁面範本。
- WooCommerce 主題: 將商務行為視為獨立的應用程式整合。移植呈現層檔案並不能取代產品、購物車、結帳、付款或訂單的語意。