把舊的 WordPress 傳統佈景主題搬進 Block Theme

前面我們從零做了一個完整的區塊佈景主題,但真實世界裡你手上更可能是一個跑了三年的傳統佈景主題:header.phpsingle.php、一支兩千行的 style.cssfunctions.php 塞滿了各種 hook。客戶不會給你打掉重練的預算,你也不敢一次全換。

這篇講漸進遷移,重點不是「怎麼把舊主題改成新主題」,而是怎麼分階段讓每一步都能單獨上線,隨時停在中間也不會壞

傳統佈景主題三階段移轉

很多人以為「區塊佈景主題」是一個要嘛全有、要嘛全無的狀態,實際看 WordPress 核心的判定,會發現至少有三個獨立的開關:

開關判定依據打開之後
讀不讀 theme.json檔案存不存在外觀選單的「區塊版面配置」變成「設計」
吃不吃 HTML 範本current_theme_supports( 'block-templates' )templates/*.html 開始參與範本階層
是不是區塊佈景主題templates/index.html 存不存在網站編輯器全開,PHP 範本全面停用

這三個開關可以分開打開,中間的每一個狀態都是合法的、可以上線的。整個遷移策略就建立在這件事上。

第零步:先盤點舊主題有什麼

動手之前先盤點以下四類:

  1. 範本檔header.phpfooter.phpsingle.phparchive.php… 哪些真的有人用,哪些是三年前複製來就沒動過的
  2. functions.php 的內容add_theme_support 開了什麼、enqueue 了什麼、掛了哪些 hook
  3. 寫死的設計值style.css 裡出現過幾種顏色、幾種字級、幾種間距
  4. 選單與小工具區register_nav_menusregister_sidebar 註冊了哪些

第 3 項最適合交給 AI,做法跟 everything-wp 的 make-block 指令是同一套思路,只是掃描對象從別人的網站換成自己的舊 CSS,可以請它把所有色碼列出來、依出現次數排序、把相近的分群,最後產出一份「原始值 → 建議語意名稱」的對照表。

階段一:先加 theme.json,主題還是傳統主題

第一步只做一件事:把散在 CSS 裡的顏色、字級、間距彙整起來寫進 theme.json

{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 3,
  "settings": {
    "color": {
      "palette": [
        { "slug": "primary",  "color": "#ffd24d", "name": "Primary" },
        { "slug": "contrast", "color": "#060606", "name": "Contrast" }
      ]
    },
    "spacing": { "spacingSizes": [ … ] },
    "typography": { "fontSizes": [ … ] }
  }
}

這一步的風險極低,因為前台外觀不會變。你的 style.css 還在原地跑,theme.json 只是多提供了一組變數,這樣整理後有兩個好處:

第一個是區塊編輯器的顏色與字級面板會跟設計對齊,編輯不再從無限色盤裡挑一個接近的顏色。第二個比較意外:後台「外觀」選單底下原本那個「區塊版面配置」,會變成「設計」,傳統佈景主題只要有 theme.json,就能進網站編輯器看樣式手冊(Style Book):

這個樣式手冊是唯讀的,你在裡面改不了任何東西,換句話說,加 theme.json 換到的是「看得到」不是「改得動」,要調預設樣式仍然只有改 theme.json 一途,要能在後台改,得等到階段三把主題變成真正的區塊佈景主題才行。

另一個好處是只要主題有 theme.jsonWordPress 就自動開啟 block-templates 支援,也就是說你放進 templates/ 的 HTML 範本從這一刻起就會生效了,不需要另外宣告什麼。

階段二:混合式主題,先把頁首頁尾交出去

第二步是把 header.php 和 footer.php 改成可以在網站編輯器裡編的區塊範本組件。先宣告支援:

add_theme_support( 'block-template-parts' ); // WP 6.1 起.

接著建 parts/header.html,內容就是區塊標記:

<!-- wp:group {"layout":{"type":"constrained"}} -->
<div class="wp-block-group">
  <!-- wp:site-logo /-->
  <!-- wp:site-title /-->
  <!-- wp:navigation /-->
</div>
<!-- /wp:group -->

然後把 header.php 的內容換掉:

<?php
// 舊的:一堆 HTML 加 wp_nav_menu().
// 新的:把頁首交給區塊範本組件.
block_header_area();

block_header_area() 和 block_footer_area() 是 WordPress 5.9 就有的函式(wp-includes/block-template-utils.php),底層都是 block_template_part( $part ),可以印出任何一個 parts/*.html

做完這一步,網站擁有者已經可以在後台改頁首頁尾了,而其他頁面仍然由你的 PHP 範本渲染。主題到這裡還不是區塊佈景主題,wp_is_block_theme() 仍然回傳 false

我建議從頁首頁尾開始,是因為它們是全站共用、改動效益最大,而且結構相對單純(logo、選單、幾個連結),翻成區塊標記的風險比 single.php 那種帶迴圈與條件判斷的低很多。

階段三:逐個換範本,最後才放 index.html

第三步才開始動範本,而且可以一個一個換。能這樣做的原因在 locate_block_template()

// wp-includes/block-template.php
function locate_block_template( $template, $type, array $templates ) {
	if ( ! current_theme_supports( 'block-templates' ) ) {
		return $template;
	}

	if ( $template ) {
		// locate_template() 已經找到一個 PHP 範本,
		// 所以只考慮「specificity 高於或等於它」的區塊範本.
		$index     = array_search( $relative_template_path, $templates, true );
		$templates = array_slice( $templates, 0, $index + 1 );
	}

	$block_template = resolve_block_template( $type, $templates, $template );
	…
}

看懂這段就懂了整個策略:PHP 範本和 HTML 範本可以共存。WordPress 先照傳統的範本階層找到 PHP 範本,再看有沒有同樣(或更精確)的區塊範本可以取代它。你放了 templates/single.html,single 就走區塊範本;沒放 templates/archive.html,archive 就繼續用 archive.php

所以要遷移的話建議是從流量低、結構單純的開始:

  1. 404.php → templates/404.html(幾乎沒有邏輯,最好練手)
  2. search.phparchive.php → 用 Query Loop 取代 The Loop
  3. page.phpsingle.php → 帶精選圖片、meta、留言的,最複雜
  4. front-page.php → 首頁通常最多客製,留到最後

每換一個就部署觀察一段時間,出事只會出在那一種頁面,回退也只要刪掉那一個 HTML 檔。

最後才處理 index.html,因為它是那個總開關:

// wp-includes/class-wp-theme.php
public function is_block_theme() {
	$paths_to_index_block_template = array(
		$this->get_file_path( '/templates/index.html' ),
		$this->get_file_path( '/block-templates/index.html' ),
	);
	…
}

is_block_theme() 只看這個檔案存不存在。放上去的那一刻,主題正式成為區塊佈景主題:網站編輯器全開、所有 PHP 範本停止作用。所以這一步等於「確認前面每一個範本都已經有 HTML 版本」的最終驗收,不要提早放。

遷移路上最容易出事的三件事

一、掛在 wp_head 與 get_header 上的邏輯。 區塊佈景主題沒有 header.phpget_header() 不會執行,掛在 get_header 這個 action 上的東西就跟著消失。wp_head 本身還在(範本渲染時仍會呼叫),但那些「假設一定會經過 header.php」的程式碼要一個個確認。這是遷移時最常見的「東西不見了但沒有錯誤訊息」。

二、選單的資料搬遷。 wp_nav_menu() 讀的是 nav_menu 分類法,Navigation 區塊存的是自己的區塊標記(在 wp_navigation 這個文章類型裡),兩者資料結構不同不會自動同步。第一次插入 Navigation 區塊時,編輯器會提供從既有選單匯入的選項,用它匯一次,之後就以區塊那份為準,舊選單留著不會有作用。

三、小工具區。 register_sidebar 註冊的側邊欄在區塊佈景主題裡沒有位置,內容要改放進範本或範本組件,如果客戶習慣自己拖小工具,這件事要先講清楚,因為這是操作習慣的改變,不是技術問題。

這段路 AI 能幫什麼

最適合交給 AI 的有三件:

  1. 把舊 CSS 抽成設計屬性:掃 style.css 列出所有色碼與尺寸、分群、命名,產出 theme.json
  2. 把 PHP 範本翻成區塊標記single.php 裡的 The Loop 對應 Query Loop、the_post_thumbnail() 對應 Post Featured Image 區塊,這種一對一的翻譯它做得又快又準。
  3. 盤點 hook 相依:請它掃 functions.php,列出所有掛在 get_headerget_footerget_sidebar 上的函式,那就是上一節第一個坑的清單。

而你要自己判斷的是這幾件:遷移順序怎麼排、哪些舊功能趁這次直接放棄、客戶的哪些操作習慣需要事先溝通、以及什麼時候按下 index.html 那個開關。這些都不是技術題,是專案判斷。

還有一個要提醒的:不要讓 AI 一次把整個主題做遷移。 它能做到,但你會拿到一個無法逐步驗證的大改動,出事時不知道是哪一步壞的,一次一個範本,換完部署,看兩天,再換下一個。漸進遷移的價值就在這裡,別為了快而放棄它。

遷移 vs. 打掉重練

雖然有 AI 協助但要完成遷移還是一項滿費工的作業,另一條路是把舊網站當成設計稿,用之前介紹的流程重新做一個區塊佈景主題,做好之後切換。

這兩條路的差別在成本什麼時候發生、風險集中在哪裡

漸進遷移照舊站重做
成本發生的時間分散在每個階段集中在上線前
何時看得到成果加完 theme.json 就有全部做完才有
上線風險一次換一個範本,可單獨回退一次性切換,風險集中在同一天
舊技術債跟著搬過去這是清掉它的唯一機會
設計一致性從舊 CSS 反推,容易連原本的不一致一起繼承從第一天就是單一來源
PHP 客製(WooCommerce 範本覆蓋、會員、自訂查詢)可以先留著,慢慢處理要重寫一遍
中途可以停嗎可以,混合式主題本身就是合法狀態不行,沒有中間狀態
長期維護成本較高,可能長期維持兩套邏輯較低

**選漸進遷移:**如果站台正在營運而且不能停、舊主題有大量 woocommerce/ 範本覆蓋或會員邏輯、預算需要分批處理,這些情境的共同點是「不能出事」比「做得漂亮」重要。

**打掉重練:**如果那支 style.css 已經爛到沒人敢動、設計本來就要順便翻新、舊主題的 PHP 客製其實不多(只是版面)、或者這個站你要長期維護下去。共同點是「以後每次改動都會受益」的情境。

有一個判準我覺得特別好用:問自己「舊主題裡有多少東西是我想留的」。如果答案是「版面和配色要留,程式碼一行都不想留」,那你要的其實是重做,只是用舊站當設計稿而已。

AI 讓天平往重做那邊偏了一點

過去重做的成本高得嚇人,因為要重看設計、重刻 CSS、重建整套元件。但上一篇那條流程改變了計算方式:/make-block 接受的輸入就是一個網址,而你的舊網站就是一個現成的網址

/make-block https://your-old-site.com

它會掃過舊站的每個代表頁、抽出實際的 computed style、盤點元件清單,然後生成 theme.json 與一整組區塊,換句話說,「照舊站重做」以前是一個月的工作,現在前面 80% 是自動的,你的工作變成審 UI Library 那一頁、把不對的地方挑出來。

所以如果你三年前評估過「重做太貴」而選擇了將就,現在值得重新評估一次。

實務上可以這樣做:兩條路混著走

老實說我自己的做法不是二選一,而是用重做的方式產生資產,用遷移的節奏上線

  1. 先對舊站跑一次 /make-block,拿到乾淨的 theme.json 與一整組區塊 — 這是重做的產物,沒有繼承舊 CSS 的歷史包袱
  2. 不要一次換掉整個主題。把產出的 theme.json 與區塊放進舊主題裡,然後照本篇的三個階段,一個範本一個範本替換
  3. 每換一個就部署、觀察,最後才放 templates/index.html

這樣前面拿到重做的乾淨資產,後面保留遷移的低風險節奏。代價是中間那段時間你要同時看著兩套東西,但比起「一次性切換的那一天」,我寧願分散這個壓力。

最後補一個誠實的提醒:漸進遷移最大的風險,是中間狀態變成永久狀態。 混合式主題可以跑得很好,好到你永遠不會去按 index.html 那個開關,於是三年後這個主題還是一半 PHP 一半 HTML,新來的人看不懂它到底是哪一種。要避免這件事,開始遷移的時候就把最後一步排進行事曆,而不是等「有空的時候」。

下一篇我們介紹如何用 AI 跑完程式碼規範、靜態分析、測試與多語系這四道關卡,把主題整理到可以交付的狀態。

AI 文章延伸

讓 AI 幫你讀這篇文章

選擇平台後會自動帶入閱讀脈絡,快速整理重點、補齊盲點,並延伸到同站相關文章。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料