Wordpress

WooCommerce 範本過時?為什麼跳出警告,該怎麼合併修復

結帳頁在核心版本更新後忽然跑版,運費欄位擠到左邊、地址欄位掉到頁尾,手機版甚至找不到「前往付款」按鈕。打開 WooCommerce 後台的系統狀態頁面往下捲,最下面一排範本清單裡有一行標成紅色,寫著某支範本的版本落後、核心版本已經往前跳了好幾號。這種畫面壞掉、警告卻語焉不詳的狀況,是不少接手舊網站或剛升級核心版本的人共同踩過的坑。

這行警告背後對應的機制叫「範本覆寫(template override)」。主題若要客製購物車、結帳這類前台頁面,慣例做法是把外掛內建範本原封複製一份放進主題資料夾,WooCommerce 顯示頁面時會優先抓主題那份,找不到才退回外掛原始檔。核心升級之後,外掛裡的範本內容可能已經跟著改版,主題資料夾裡那份舊複製品卻原地不動,兩邊分岔,WooCommerce 範本過時的警告就是這樣冒出來的。放著不管,輕則排版跑掉,重則某個掛勾被舊檔擋住,某個功能悄悄失效卻沒有任何錯誤訊息。

排查這類問題最怕兩件事:把範本過時當成排版跑掉的唯一原因,結果白改一場;或是把整份新檔複製過去貼上,卻讓自己辛苦調整過的客製邏輯整組消失。

WooCommerce 範本過時是什麼?主題把核心檔案複製進自己目錄的客製化機制

範本覆寫,是把外掛原本放在 /wp-content/plugins/woocommerce/templates/ 底下的某支範本檔案,原封複製一份放進主題(或子主題)的 woocommerce/ 資料夾,路徑結構照舊,只是拿掉 /templates/ 這一層。WooCommerce 官方文件把這種做法列為主題客製前台頁面的標準方式,理由很直接:購物車、結帳這類頁面牽涉大量 HTML 結構,直接改外掛原始檔又會在下次外掛更新時被整個覆蓋消失,複製到主題目錄下才能長期保留這些客製內容。

這套機制運作起來很單純,WooCommerce 顯示任何一個前台頁面之前,都會先呼叫核心的 wc_get_template() 判斷該用哪一支檔案,原理近似 WordPress 主題階層,先問主題有沒有客製過,沒有才退回外掛內建的預設版本。

主題目錄優先於外掛核心的範本尋找順序

WooCommerce 尋找範本檔案只分兩層,順序固定不會倒過來。先查目前啟用的主題(有子主題就先查子主題,沒有客製才退回父主題)底下對應路徑的 /woocommerce/ 資料夾,找得到就直接拿來用,找不到才退回外掛內建 /templates/ 資料夾裡的預設版本。子主題與父主題若剛好都放了同名檔案,子主題那份會被優先採用,父主題那份等於被晾在一邊,這也是官方建議客製一律放進子主題的原因之一,萬一父主題哪天更新,子主題的覆寫還在,不會被一次洗掉。

WooCommerce 以 wc_get_template() 依子主題、父主題、外掛核心的順序尋找範本,主題目錄優先於外掛核心
WooCommerce 找範本只分兩層:先查主題的 woocommerce 資料夾,找不到才退回外掛內建的預設版本。

這個尋找順序還有一個容易被忽略的例外,主題如果自己放了一支叫 woocommerce.php 的檔案,它的優先權就會蓋過主題 woocommerce/ 資料夾裡個別的範本檔案。WooCommerce 官方文件特別提醒,這代表即使主題裡認真放了一支 archive-product.php,只要同一個主題還有 woocommerce.php,商品歸檔頁的顯示還是會被 woocommerce.php 接手,自訂範本根本沒機會生效。官方把這個設計解釋成刻意避免顯示衝突,而不是系統出錯,排查「為什麼我改的範本完全沒作用」時,先確認主題有沒有這支檔案,常常比檢查範本內容本身更快找到答案。

檔案開頭藏著版本註解,是版本比對的依據

每一支 WooCommerce 範本檔案開頭的註解區塊裡,都會有一行像 @version 3.5.0 這樣的標記,代表這支檔案目前的內容對應到 WooCommerce 3.5.0 那個版本。核心升級時,如果某支範本的內容真的有跟著調整,官方會同步把那支檔案的 @version 往前推進;沒有改動內容的檔案,@version 就留在原地不動。系統狀態頁面判斷一支範本過不過時,依據正是這行版本註解,拿主題裡那份複製品的 @version,跟外掛目前安裝的核心版本比對,兩者對不上,就跳出過時警告。

這行邏輯也解釋了一個常被誤解的地方,警告訊息比對的不是「這支檔案內容有沒有變」,而是純粹比對版本號碼。也就是說,就算合併完之後內容已經完全對齊新版,只要忘了把 @version 這一行改成新的版本號,系統狀態頁面照樣會顯示過時,版本註解本身就是比對的唯一依據,內容對不對跟這行數字對不對,是兩件要分開看待的事。

範本過時不是結帳頁排版跑掉的唯一嫌疑犯

看到系統狀態跳出範本過時的警告,直覺會想立刻動手合併範本,但這個警告未必是排版跑掉的主因。快取外掛或 CDN 沒清乾淨、金流閘道外掛版本落後核心版本、另一個外掛在結帳頁載入了衝突的 CSS 或 JS,都會做出類似畫面跑掉的效果,而且這幾種狀況剛好都可能跟範本過時的警告同時出現,核心升級當下,快取通常也還沒重新產生,金流外掛也可能還沒跟進更新。

排查前先做兩件事縮小範圍。第一,清乾淨快取外掛與 CDN 快取後重新整理頁面,先排除看到的其實是舊版畫面這種假警報。第二,如果懷疑是外掛衝突,可以暫時只留 WooCommerce 本身、金流外掛與一個預設主題做測試,一個一個把其他外掛啟用回去,最後啟用的那個往往就是衝突來源。這兩步做完,如果排版問題還在,才輪到懷疑主題覆寫的範本本身。

加一行除錯常數,讓範本暫時改用外掛原始版本

確認前兩步都排除之後,WooCommerce 核心本身就內建了一個排查用的開關,在 wp-config.php 裡加入 define( 'WC_TEMPLATE_DEBUG_MODE', true );,寫在 /* That's all, stop editing! */ 這行之前。這個常數的判斷邏輯寫在核心的 wc_locate_template() 函式裡(外部呼叫的 wc_get_template() 內部會轉呼叫這支函式定位檔案),一旦啟用,WooCommerce 會強制忽略主題裡的所有覆寫範本,改成統一顯示外掛內建的預設版本。

這個常數只對目前登入的管理員生效,一般訪客看到的畫面不會受影響,也因為這樣,測試的時候要記得用管理員帳號實際瀏覽有問題的那個頁面,而不是只看系統狀態頁面的文字。如果打開這個常數之後,結帳頁排版真的恢復正常,代表問題確實出在主題覆寫的範本,可以放心進入合併流程;如果排版問題依然存在,代表兇手不是範本,得回頭往快取或外掛衝突的方向繼續查。排查完成之後記得把這行常數移除或註解掉,它不是拿來長期開著的正式設定,一直留著會讓所有客製範本永遠失效,管理員看到的畫面也會跟一般訪客不一樣,容易讓人誤以為後台看起來正常、問題早就解決了。

系統狀態範本清單同時標出兩個版本號的落差

排除掉其他嫌疑犯,確定問題出在範本本身之後,下一步是打開 WooCommerce 後台「狀態」選單裡的「系統狀態」頁面,捲到頁面最下方找「範本」這個區塊。這裡會列出目前主題(或子主題)覆寫了哪些範本檔案,每一行後面都跟著兩個版本號:目前使用的版本與核心目前版本,兩者不一致的那幾行,才是真正需要處理的對象。

這個清單的重點是,不是整個 woocommerce/ 資料夾都要重做。有些主題可能覆寫了十幾支範本檔案,但版本標記顯示落後的可能只有兩三支,這幾支核心版本本身有跟著調整內容,其餘覆寫檔案版本號一致,代表核心那段時間沒動過對應內容,可以先放著不用管。畫面呈現的格式通常是檔案相對路徑、兩個版本號,再加一句提示文字,類似「version 3.5.0 is out of date. The core version is 3.7.0」這種寫法,先把真正過時的那幾支挑出來,再逐一處理,比一次通盤重做省下大量工夫。

WooCommerce 系統狀態的範本清單列出目前版本與核心版本,落後的那支標示過時警告
系統狀態頁面拿主題複製品的版本號跟核心版本比對,只有對不上的那幾支才需要合併。

比對版本前,先查官方逐版公布的範本異動記錄

挑出真正過時的檔案之後,先別急著打開兩個版本的檔案憑肉眼從頭比到尾。WooCommerce 開發者部落格有一個「Advisories」專區,固定公告會影響第三方覆寫者的破壞性改動、棄用、安全性修補與相容性通知,先去那裡查一次這個版本區間動過什麼,合併時才知道要特別留意哪幾行。

這個專區公告的內容相當具體。舉例來說,WooCommerce 9.6 版更新了 single-product-reviews.php 這支範本,在作者與電子郵件兩個欄位加上 autocomplete 屬性,目的是讓瀏覽器能協助使用者自動帶入姓名、電子郵件這類常填的個人資訊,對無障礙體驗有直接幫助。官方公告裡明講,如果主題或外掛覆寫過這支檔案,就要在同樣的欄位補上這個屬性,並附上該次改動對應的 pull request 連結方便直接對照 diff。像這種不影響畫面外觀、卻牽涉到無障礙標準的改動,單靠肉眼掃過範本很容易漏看,先查過 Advisories 專區再動手,能省下不少摸索工夫。

除了 Advisories,另一個查證管道是直接到 WooCommerce 官方 GitHub 找對應版本 tag 的範本原始碼。查詢規則分兩段,6.0.0 版之後的路徑在 .../tree/[版本號]/plugins/woocommerce/templates,6.0.0 之前的舊版本則在 .../tree/[版本號]/templates(例如 5.9.0 版路徑就是 .../tree/5.9.0/templates)。找到對應版本的 tag,不只能看到範本目前的完整內容,還能沿著 commit 紀錄回溯這支檔案在哪個版本被改過、改了什麼,這比只讀 Advisories 的文字說明更能掌握細節。

三個步驟保留客製內容,同時併入官方新結構

官方教學給的合併建議其實很粗略,備份舊範本,把外掛最新版的同一支範本複製到主題資料夾覆蓋掉舊檔,再打開文字編輯器,憑印象把先前對舊版做過的客製改動重新謄寫進新版檔案。官方自己也承認這個過程很花時間,而且完全仰賴記憶力去回想當初改了哪裡,風險是漏掉某段客製、或誤刪某個官方新增的結構。逐段辨別哪些差異是自己刻意改的、哪些只是官方版本本身的結構調整,才是這個過程真正的重點,而不是整份覆蓋或整份保留這兩種極端做法。

安全合併 WooCommerce 過時範本的三步驟:備份並排比對、分辨客製與改版、搬進新範本並寫回版本號
合併範本的三步:備份後並排比對差異,逐段分辨客製或改版,最後把客製搬進新結構並更新 @version。

步驟一,先備份舊檔案再開啟新版範本並排比對

第一步是備份。把主題資料夾裡那支舊版範本另外存一份到主題目錄以外的地方(或直接交給版本控制系統暫存),確保合併途中出錯還能復原到原本能動的狀態。備份完成後,去外掛安裝路徑 /wp-content/plugins/woocommerce/templates/[對應路徑] 底下,複製目前站上實際安裝、已經升級到最新的那份範本檔案。這一步要注意的是新版範本必須從自己網站上實際安裝的外掛拿,而不是隨便找一個網路上流傳的版本,版本號對不上的話,合併完系統狀態照樣會判定過時。

拿到新舊兩份檔案之後,用程式編輯器內建的與另一檔案比較功能,或是把兩份內容分別貼進線上 diff 比對工具的左右欄位,一鍵標出所有差異。多數情況下改動不多,肉眼掃過差異列表就能抓到重點;如果範本被大幅改動過,用工具逐行標示會比自己盯著兩份檔案來回切換可靠得多。

步驟二,分辨差異來自客製邏輯或版本本身改版

diff 工具標出來的每一段差異,都要問一次同一個問題,這段改動是自己當初刻意動過的客製邏輯,還是官方版本本身結構本來就長這樣。判斷靠兩個線索。第一個線索是這段差異有沒有對應到記得的客製需求,像是刻意藏起某個欄位、在某個位置加了額外的提示文字,如果有印象,這段就該保留自己的版本。第二個線索是這段差異是不是純粹的 HTML 結構調整、新增的掛勾、或函式呼叫方式改變,這種通常代表官方版本本身往前演進了,應該採用官方的新寫法,而不是死守舊寫法。

遇到真的判斷不出來的差異,保守的做法是先保留自己那段客製,同時記下這個位置,等合併完成、實際跑過前台功能之後再回頭確認有沒有問題。純粹的排版差異(字距、class 名稱、標籤順序這類)多半是主題客製化時本來就會動的地方,可以放心沿用主題寫法;反而是新出現的 do_action()apply_filters() 或函式呼叫方式的改變,才是版本合併裡最容易被忽略、卻最容易在日後出問題的地方,它們不會讓畫面立刻跑掉,卻可能讓某個功能悄悄失效。

步驟三,把客製邏輯搬進新範本並寫回版本號

判斷完哪些差異是真的客製之後,把這幾段程式碼手動搬進新版檔案對應的位置,其餘全部採用官方的新結構,不要只複製貼上客製那一小段就結束,要留意這段客製前後銜接的縮排與 HTML 結構是不是完整,貼進去之後結構不能斷掉。

全部搬完,最後一個動作是把檔案開頭的版本註解改成目前核心的版本號,例如把 @version 3.5.0 改成 @version 3.7.0。這一步常常被漏掉,結果就是內容明明已經合併好了,系統狀態頁面卻還是判定過時,因為系統比對的依據是這行數字,不是檔案實際內容。

版本合併最容易漏掉的改動比排版差異更難察覺

排版差異靠肉眼掃過 diff 工具就能抓到,真正容易漏掉的是兩類不會讓畫面立刻跑掉的改動,它們不會讓合併完的頁面看起來有異狀,卻可能讓某個功能悄悄失效,或是幾個版本之後才突然爆出錯誤。

舊函式被新函式取代後範本不報錯但行為悄悄改變

WooCommerce 核心汰換一支函式時,通常不會直接刪掉它,而是先標記為棄用(deprecated),讓它繼續運作一段時間,只在後台丟出開發者才看得到的棄用通知。一個實際的例子是 is_ajax() 這支函式,從 WooCommerce 6.1.0 版起被標記為棄用,官方建議改用 wp_doing_ajax(),這項紀錄公開列在官方 GitHub 的 issue 追蹤上。如果主題覆寫的範本檔案裡還在呼叫 is_ajax(),網站前台不會有任何異狀,但只要開啟 WP_DEBUG 或查看錯誤日誌,就會看到棄用通知不斷出現。

這種棄用跟真正的移除之間通常隔著好幾個大版本,目的是讓開發者有時間跟進更新,不會一升級就整片壞掉。問題正出在這個時間差,因為前台看起來一切正常,這類警告很容易被長期忽略,拖到官方真的把舊函式從程式碼裡拿掉的那一天,前台才會直接報錯。合併範本的時候順手掃一次檔案裡有沒有呼叫已知被標記棄用的函式,遠比等到它真正壞掉才處理省事得多。

官方新增的動作掛勾,貼上舊檔等於刪掉這個掛勾

WooCommerce 範本檔案裡穿插著大量 do_action()apply_filters(),這些掛勾點是官方刻意留給外部程式碼介入輸出內容的位置,通常上方會有一行 @hooked 註解,列出目前掛在這個動作上的函式。以 admin-new-order.php 這支範本為例,do_action( 'woocommerce_email_order_details', ... ) 前面的 @hooked 註解就寫明掛了 WC_Emails::order_details() 這個函式,負責輸出訂單明細表格。

如果核心某次更新在範本裡新增了一個掛勾,而合併時圖方便直接沿用整份舊檔案、只手動補幾行明顯看得到的排版差異,這個新掛勾就會整個消失在網站上。任何依賴這個掛勾運作的外掛功能,都會悄悄失效,而且不會跳出任何錯誤訊息,沒有視覺線索,通常要等到某個依賴這個掛勾的外掛功能真的故障,才會被使用者發現、回頭追查原因。這正是逐段比對差異、而不是整份覆蓋貼上的價值所在,少了這個步驟,新掛勾消失得無聲無息,卻可能讓一整個外掛功能失靈。

合併後的系統狀態驗證與前台實際操作驗證

範本合併完成,不代表工作就結束了,只看畫面感覺正常就結案,很容易漏掉版本號沒對齊、或某個功能分支沒測到的狀況。合併之後有兩個檢查點都要各自確認一次:系統狀態頁面的過時警告有沒有真的消失,以及前台結帳流程實際跑一遍有沒有恢復正常。兩者缺一不可,只改版本號沒改內容,警告會消失但排版還是壞的;只改內容沒更新版本號,排版對了但系統狀態還是會誤判過時。

系統狀態的過時警告,要先確認是否真的消失

回到 WooCommerce 後台「狀態」選單裡的「系統狀態」頁面,重新整理後捲到範本區塊,原本標示過時的那支檔案應該已經從清單裡消失,或是兩邊版本號變成一致,不再顯示類似「is out of date」這類提示文字。這個檢查每次核心升級後都值得重做一次,尤其是同時合併了好幾支範本的時候,容易漏看其中一支還沒改到。

如果清單還在、警告訊息沒有變化,代表某個環節出了問題,最常見的原因是漏改了檔案開頭的 @version 這一行,其次是合併時放錯了資料夾層級,導致系統狀態偵測到的其實不是同一支檔案。逐一比對路徑與版本號,通常很快就能找到漏掉的地方。

訪客身分和會員身分都要各自跑一次結帳流程

版本號對齊只代表系統狀態的比對邏輯滿意了,不代表功能真的正常,這一步要靠實際操作驗證。WooCommerce 有些範本邏輯會依照使用者是否登入、有沒有儲存過的付款方式、帳號欄位要不要顯示而分成不同分支,只用管理員帳號測試一次很容易漏掉訪客結帳會踩到的狀況,尤其結帳頁排版問題常常就跟帳號欄位、地址欄位的顯示邏輯綁在一起。

實際驗證時,訪客身分要留意帳號建立與引導登入這幾個欄位的排版是否正常;已登入會員身分則要確認先前儲存的地址與付款方式呈現得對不對。建議兩種身分各自清除一次快取後再測試,避免看到的其實是快取住的舊版畫面,誤以為問題還沒解決。

往後升級不再手忙腳亂的兩個做法

這次的排查與合併做完之後,值得往前想一步,怎麼讓下一次核心升級的排查更省力。以下兩個做法能降低往後遇到範本過時的頻率與代價。

能用掛勾解決就不複製整份檔案

多數客製化需求,其實不必整份覆寫範本檔案就能達成,調整某段文字、在某個位置加一段提示、隱藏某個區塊,只要範本裡本來就留了掛勾點,用 add_action()add_filter() 掛進去就能做到。以前面提到的 admin-new-order.php 為例,只要在程式碼片段外掛裡寫 add_action( 'woocommerce_email_order_details', 'my_custom_woo_function' ); 搭配對應的函式內容,就能在這個位置插入客製內容,完全不需要動到範本檔案本身,自然也就不會有日後版本比對的問題。

判斷一個需求該不該走覆寫這條路,可以先問掛勾點能不能碰到要改的位置,碰得到就優先用掛勾,真正需要走覆寫的,通常是牽涉整體 HTML 結構大幅調整、掛勾點確實不夠用的情況。

一定要覆寫時,應留一份範本清單方便下次比對

如果客製需求真的複雜到非整份覆寫不可,至少替自己留一份紀錄:目前覆寫了哪些範本檔案、各自改了哪個地方、為什麼要改。這份清單可以是一份簡單的文件,也可以直接靠版本控制系統(如 Git)的提交紀錄留言來記錄,後者本身就是一種天然的異動說明,比事後憑記憶回想可靠得多。下次核心升級跳出過時警告時,不必從頭回想這支檔案當初改了哪裡,直接對照清單或提交紀錄,就能快速判斷差異、決定要不要合併。

範本覆寫這套機制本身沒有問題,真正容易出狀況的是升級之後沒人記得回頭比對。系統狀態頁面的過時警告,其實只是提醒,它不會告訴你排版跑掉的真正原因,也不會替你判斷哪些改動是客製邏輯、哪些是版本演進。把排查、比對、合併這幾步走完,再各自驗證版本號與實際功能,結帳頁的排版問題多半能一次處理乾淨,下一次升級也不會再從頭摸索。

常見問答

本區問答由 AI 依文章內容自動整理,僅供快速參考,正式內容仍以全文為準。

什麼是 WooCommerce 的「範本覆寫」?

範本覆寫是把外掛原本放在 templates 資料夾裡的範本檔案,原封複製一份放進主題的 woocommerce 資料夾,讓主題能客製購物車、結帳這類前台頁面,且不會在外掛更新時被覆蓋消失。

主題有 woocommerce.php 範本為何失效?

因為 woocommerce.php 的優先權會蓋過主題 woocommerce 資料夾裡的個別範本檔案,就算另外放了 archive-product.php,商品歸檔頁仍會被 woocommerce.php 接手,自訂範本沒機會生效。

系統狀態怎麼判斷範本是否過時?

系統狀態頁面拿主題裡那份複製品開頭的 @version 版本註解,跟外掛目前安裝的核心版本比對,兩者對不上就跳出過時警告;比對的是版本號碼,不是檔案內容有沒有真的改過。

怎麼確認結帳頁跑版是範本造成的?

在 wp-config.php 加入 define( ‘WC_TEMPLATE_DEBUG_MODE’, true ),WooCommerce 會強制忽略主題覆寫、改顯示外掛內建版本,管理員瀏覽問題頁面,排版恢復正常就代表問題出在範本。

合併範本時沿用整份舊檔案有什麼風險?

如果核心新增了掛勾點,合併時卻圖方便直接沿用整份舊檔案,這個新掛勾就會整個消失,任何依賴它運作的外掛功能都會悄悄失效,而且不會跳出任何錯誤訊息,通常要等到功能真的故障才會被發現。

資料來源
  1. Template structure & Overriding templates via a theme — WooCommerce
  2. Fixing outdated WooCommerce templates — WooCommerce
  3. Advisories — WooCommerce
  4. Dev advisory: Product review form template version update — WooCommerce
  5. The is_ajax function is deprecated since version 6.1.0. Replace with wp_doing_ajax() — WooCommerce
  6. wc-core-functions.php — WooCommerce