Wordpress

自訂分類法怎麼設定?從判斷時機到參數與 404 排查一次搞懂

多數人以為分類不夠用時,只要在後台的分類項目底下多加幾筆就能湊合著用,但 WordPress 其實藏了一個更底層的機制,讓你自己造一整套全新的分類系統。假設你經營的網站除了文章之外還有「作品」這種文章類型,同時想按「服務類型」與「產業別」這兩個互不相干的角度替作品分類,硬塞進既有的分類系統只會讓詞彙列表越拉越長、越來越難管理,因為分類本來就是設計給文章這個單一維度用的父子結構,不是拿來同時裝兩套邏輯的容器。

WordPress 把這個機制叫做分類法(taxonomy)register_taxonomy() 這個函式能讓你自己開一個全新的分類法 key,賦予任何文章類型一整套獨立的分類維度。它有自己的詞彙管理頁面,前台有自己的網址結構,也能有自己的 REST API 欄位,跟原本的分類、標籤各自獨立、互不干擾。搞懂這套機制,你就能依照網站實際的內容邏輯設計分類方式,而不是被內建的兩種分類法綁死。

接下來就先從分類法跟分類、標籤這兩個內建機制的分工界線講起,再一路拆到怎麼判斷值不值得自己開一種新分類法、參數怎麼設,最後遇到分類法「設定完卻看不到」該怎麼排查。

自訂分類法是什麼?和內建分類、標籤的分工界線

分類法(taxonomy)在 WordPress 裡是一個容器層級的概念,決定「用什麼規則去分組內容」;容器裡實際裝的每一個分類項目,則叫做詞彙(term)。以「分類(category)」這個大家最熟悉的例子來說,「分類」本身就是一個分類法,而「美食」「旅遊」這些你在後台新增的具體項目才是詞彙,兩者是規則跟項目的關係,不是同一層級的東西。

WordPress 內建至少兩種公開的分類法:category,也就是階層式的「分類」,詞彙之間可以有父子關係;以及 post_tag,也就是非階層式的「標籤」,詞彙彼此平行,沒有主從之分。除此之外,媒體庫的檔案格式、選單系統、連結分類其實也各自是一套分類法,只是平常操作介面沒有明講,多數人不會特別意識到分類、標籤只是分類法的其中兩種,不是分類法的全部。

register_taxonomy() 要做的事,是在這些內建分類法之外,替文章類型,不管是內建的文章,還是你自己註冊的自訂文章類型,再掛上一個全新的分類維度。這跟你在後台「分類」畫面裡多新增一個分類值,是完全不同的兩件事:多加一個分類值只是往既有的容器裡塞一個新項目,register_taxonomy() 是造一個新的容器本身,容器有自己的詞彙管理頁、自己的網址結構、自己的 REST API 欄位。WordPress 官方外掛開發手冊對分類法的定義,是把「分組、分類事物」這件事抽象成一個專有機制,可以是階層式,也可以是扁平式;分類法實際存放在資料庫的 term_taxonomy 資料表,詞彙則存放在 terms 資料表,兩者搭配才組成一套完整可用的分類系統,手冊舉的例子是一個叫「Art」的分類法底下可以掛「Modern」「18th Century」這些詞彙。

分類法是決定分組規則的容器、詞彙是裡面的項目;分類與標籤只是內建的兩種,自訂分類法用 register_taxonomy() 再造一個獨立容器
分類法是分組規則的容器、詞彙是容器裡的項目;內建的分類、標籤之外,自訂分類法讓你再開一套彼此獨立的分類維度。

另開一個分類法的兩個判斷依據

要不要為某個分類需求另外開一個新分類法,判斷可以落在兩個具體依據上,而不是一看到「現有分類不夠用」就直接動手註冊。回到前面的例子,一個「作品」文章類型如果同時要按「服務類型」與「產業別」這兩個角度分類,用內建的「分類」機制去硬做很難兼顧兩邊,因為分類系統設計上是給單一維度用的父子結構,硬把兩種不相干的角度塞進同一棵分類樹,詞彙列表會拉得又長又難管理。

第一個依據,是這批內容是不是真的需要同時用兩個以上互不隸屬的角度分類,而不是同一個角度只是想切得更細一點。如果只是想把既有分類再切細一層,例如「新聞」底下再分「產業新聞」與「公司新聞」,用父子分類(parent term)處理就夠了,不必為此另開一個新分類法;父子關係本來就是同一個分類法裡的階層結構,不是兩個平行維度的問題。

第二個依據,是這個分類維度需不需要有自己的瀏覽入口,也就是詞彙自己的封存頁與獨立網址,而不只是在內容頁裡順便標示一下。如果讀者會想直接瀏覽「所有服務類型是網頁設計的作品」或「所有產業別是零售業的作品」,那就代表這個維度值得成為一個獨立分類法;反過來,如果只是想在單篇內容旁邊附註一個屬性、沒有瀏覽這個屬性的需求,那多半用自訂欄位處理就足夠,不必為它多開一整套分類系統。兩個依據只要符合任何一個,答案通常就是分別開兩個獨立的分類法,例如 service_typeindustry,各自管各自的詞彙表,彼此不互相牽制。

階層式與非階層式的取捨,決定編輯畫面的操作方式

hierarchical 這個參數不只是決定詞彙能不能有父子關係這麼抽象的事,它直接連動你在編輯文章時看到的操作介面長什麼樣子。這個參數的預設值是否(false),也就是說如果不特別設定,你註冊出來的分類法一律會是非階層式,編輯畫面會是一個逗號分隔、可以自由輸入新詞彙的輸入框,跟內建的「標籤」操作方式一樣,沒有父子關係。

hierarchical 設為真,詞彙就可以有父層與子層,編輯畫面會換成一棵可以打勾選取的核取方塊樹,跟內建的「分類」操作方式一樣。這種設定適合有主從關係的維度,比如「產業別」底下分「製造業」「零售業」,「零售業」底下還能再細分「電商」「實體門市」,讀者跟你自己在後台賦值時,都能沿著這個層級一路往下勾選,不必每次都輸入完整的長詞彙。

決定這個核取方塊樹或輸入框怎麼畫出來的,其實是 meta_box_cb 這個參數,只是多數人不會特別去動它,直接沿用預設值。沒指定的話,階層式分類法預設呼叫 post_categories_meta_box(),非階層式預設呼叫 post_tags_meta_box(),這兩個都是 WordPress 內建的函式;你也可以自己寫一個回呼函式接管這塊編輯畫面,或是把 meta_box_cb 設為 false,讓這個分類法完全不在編輯畫面顯示欄位。

分類法綁定文章類型的兩種寫法,登記當下或事後掛上

分類法要跟哪個文章類型產生關聯,有兩種寫法對應兩種情境,而且不能混著用。第一種是在註冊全新分類法的當下,直接把要綁定的文章類型列進去;第二種是把一個已經註冊好的分類法,事後追加掛到另一個文章類型上,這種寫法連 WordPress 內建的 categorypost_tag 都適用。

第一種寫法靠的是 register_taxonomy() 的第二個參數 $object_type,它直接接受一個文章類型的陣列,註冊當下就完成綁定,而且可以同時綁多個文章類型:

register_taxonomy(
    'service_type',
    array( 'portfolio' ),
    $args
);Code language: PHP (php)

如果你想讓「產業別」這個分類法同時掛在「作品」跟「案例分享」兩種文章類型上,只要把兩個文章類型 key 都放進這個陣列就好,兩種文章類型會共用同一套詞彙表。

第二種情境是你想把 WordPress 內建的 categorypost_tag 掛到自訂文章類型上,這時候不能也不需要重新呼叫一次 register_taxonomy(),因為那會被 WordPress 當成「修改既有分類法」,而不是新增一個獨立的分類法。正確做法是改用 register_taxonomy_for_object_type( $taxonomy, $object_type ) 這個函式,把已經存在的分類法追加綁到指定的文章類型上:

register_taxonomy_for_object_type( 'category', 'portfolio' );Code language: PHP (php)

這個函式內部會先檢查該分類法是否已經登記在 $wp_taxonomies 這個全域陣列裡、該文章類型是否存在,確認都成立才會把文章類型加進該分類法的 object_type 陣列,並觸發 registered_taxonomy_for_object_type 這個動作鉤子,讓其他程式碼能在綁定完成後接著處理。

register_taxonomy() 的核心參數與必須掛在 init 鉤子上

分類法的性質與歸屬確定之後,接下來就是怎麼把它實際註冊出來。register_taxonomy() 的函式簽名是 register_taxonomy( $taxonomy, $object_type, $args ),第一個參數是分類法 key(字串),第二個是要綁定的文章類型(字串或陣列,也就是前一節講的兩種綁法之一),第三個是設定用的參數陣列。這個陣列裡的每一組 key 各自管著分類法不同面向的行為,介面上顯示的文字由 labels 決定,要不要公開查詢由 public 這串參數決定,能不能被區塊編輯器讀取由 show_in_rest 決定,網址前綴則交給 rewrite

整段註冊邏輯不能隨便寫在檔案的任何位置,必須包在一個自訂函式裡,再掛進 init 這個動作鉤子,不能在 init 觸發之前呼叫:

function pongo_register_service_type_taxonomy() {
    $args = array(
        // 陣列內容見下方逐組參數
    );

    register_taxonomy( 'service_type', array( 'portfolio' ), $args );
}
add_action( 'init', 'pongo_register_service_type_taxonomy' );Code language: PHP (php)

WordPress 要等到 init 這個時機才算把核心的文章類型、分類法系統準備好,太早呼叫 register_taxonomy() 會因為底層機制還沒就緒而失敗,這也是為什麼幾乎所有自訂分類法、自訂文章類型的教學都會不約而同把註冊邏輯掛進 init

labels 陣列決定後台介面的每一句文字,未設定會沿用分類或標籤的措辭

labels$args 陣列裡的一個子陣列,純粹管後台介面上你看得到的那些文字,像是選單名稱、「新增詞彙」按鈕上寫什麼字、搜尋框的提示語,這些設定完全不影響分類法實際的運作邏輯,不設定也不會出錯。

但「不設定」不等於「不重要」,因為介面文字這時候會很奇怪地沿用內建分類或標籤的措辭,跟你這個分類法實際的用途對不上。最容易被忽略、卻最快讓介面看起來不對勁的幾個 key,是 name(複數名稱,例如「服務類型」)、singular_name(單數名稱,例如「服務項目」)、menu_name(左側選單顯示的名稱)、add_new_item(新增詞彙畫面的標題):

'labels' => array(
    'name'          => '服務類型',
    'singular_name' => '服務項目',
    'menu_name'     => '服務類型',
    'add_new_item'  => '新增服務類型',
),Code language: PHP (php)

WordPress 官方文件對這組參數的說明很直白,預設情況下非階層式分類法沿用標籤的介面文字,階層式分類法沿用分類的介面文字,所以如果你註冊的是一個階層式的「產業別」,labels 沒填,後台側欄看到的可能還是「分類」兩個字,編輯內容的人一眼看過去只會覺得莫名其妙。

public、show_ui、show_in_menu 這串開關的繼承關係

public 這個參數常被誤以為只是「這個分類法公不公開」的單一開關,實際上它是好幾個附屬開關的預設值來源。public 的預設值是真(true),publicly_queryable(能不能被前台查詢)、show_ui(後台要不要顯示管理介面)、show_in_nav_menus(選單建立時能不能選這個分類法的詞彙)這幾個附屬開關的預設值都跟著繼承這個真值,不用逐一再設一次;反過來把 public 改成否,這幾個附屬開關的預設值也會一併變成否。

show_in_menu 是另一個容易搞混的開關,它決定分類法要不要出現在後台左側的管理選單裡,但它要生效的前提是 show_ui 必須也是真,否則就算你把 show_in_menu 明確設為真,選單依然不會出現這個項目。需要更精細控制的時候,上面提到的這幾個附屬參數都可以獨立覆寫,不必整組都跟著 public 走,比如你可以讓一個分類法前台可查詢、但後台不顯示管理介面,兩者互不衝突。

show_in_rest 與 rest_base,決定分類法能不能在區塊編輯器出現

show_in_rest 是很多舊教學會漏掉、但在區塊編輯器已經是預設編輯畫面的現在必須設對的參數。設為真,這個分類法才會被納入 REST API,也才能在區塊編輯器(Gutenberg)的側欄看到這個分類法的選取面板;沒開的話,就算前面幾個參數都設對了,側欄依然找不到這個分類法的操作介面。rest_base 則可以自訂 REST API 路徑名稱,沒特別設定會直接沿用分類法 key。

這裡最容易漏掉的地方是「兩邊都要開」:分類法本身要開 show_in_rest,它綁定的那個文章類型自己也要開 show_in_rest,少一邊都看不到側欄面板。原因不難理解,文章類型本身如果還在用經典編輯器,綁在它身上的分類法自然也不會出現在區塊編輯器介面裡,這是實際除錯時最容易卡在這裡、卻不容易第一時間想到的地方,遇到分類法怎麼設都不出現,先檢查這兩邊的 show_in_rest 是不是都設成真,通常問題就在這裡。

rewrite 與 query_var 決定分類法的網址前綴和查詢變數

rewritequery_var 這兩個參數合起來決定這個分類法在前台長什麼網址,也是後面「封存頁 404」那個常見卡點的根源之一,先在這裡把邏輯講清楚,設定的時候才不會漏掉。rewrite 的預設值是真,也就是直接用分類法 key 當網址前綴;把它設為一個陣列,就能自訂更細的行為:slug 決定網址前綴字串本身,with_front 決定要不要套用目前固定連結結構設定的前綴(預設真),hierarchical 決定網址要不要呈現詞彙的父子階層(預設否)。設為否,則完全不處理這個分類法的網址重寫規則,等於這個分類法不會有獨立的前台網址。

'rewrite' => array(
    'slug'         => 'service',
    'with_front'   => false,
    'hierarchical' => true,
),Code language: PHP (php)

query_var 則決定 ?{query_var}={詞彙slug} 這種查詢字串能不能被使用,沒特別設定會沿用分類法 key,設為否會關掉這個查詢方式。改動 rewrite 之後有一個容易忘記的步驟,一定要重新整理永久連結,設定才會真的生效,光改程式碼、不重整永久連結,網址還是打不開。

show_admin_column 與 capabilities,決定列表多一欄和詞彙管理權限

show_admin_column 預設是否,設為真會在這個文章類型的列表頁,也就是後台「所有文章」那種畫面,多顯示一欄,直接列出每篇內容被賦予了哪些詞彙,不用點進去編輯畫面才看得到,對內容量大、需要快速掃視分類狀況的網站很實用。

capabilities 則是一組陣列,決定誰有權限操作這個分類法的詞彙,包含 manage_terms(管理詞彙)、edit_terms(編輯詞彙)、delete_terms(刪除詞彙)、assign_terms(把詞彙賦予給內容)這四個子鍵。沒特別設定的話,前三個預設分別對應到 manage_categories 這個內建權限,最後一個 assign_terms 預設對應 edit_posts,也就是說預設情況下,能編輯文章的人就能替內容賦予詞彙,但要新增、編輯或刪除詞彙本身,得有 manage_categories 這個層級的權限,兩者是分開的兩件事,不會因為某人能寫文章就自動能亂改詞彙表。

分類法 key 的命名限制與撞名會直接覆蓋既有分類法

命名這個分類法 key 的時候,最容易踩的是兩個雷,一個是字元數上限,一個是跟 WordPress 既有的分類法撞名,而且撞名不會直接跳出錯誤訊息,是被當成修改既有分類法在處理,比報錯更難第一時間察覺。

分類法 key 的長度上限是 32 個字元,超過會觸發錯誤,而且只能用小寫英文字母、數字、破折號、底線這幾種字元,WordPress 原始碼裡對應的驗證邏輯,就是在超過長度時直接呼叫 _doing_it_wrong() 丟出提示。取名的時候也要避開跟 WordPress 內建分類法撞名,像 categorypost_tag 這兩個 key 已經是登記好的內建分類法,不能拿來用在你自己的新分類法上。

如果你拿一個已經存在的分類法 key,不論是 WordPress 內建的,還是你自己之前註冊過的,再呼叫一次 register_taxonomy(),WordPress 不會把這當成新增一個獨立的分類法,而是當成「修改既有分類法」,原本綁定的文章類型清單會被這次呼叫的內容整個覆蓋掉,不是疊加上去。也就是說,如果你原本已經把 service_type 綁在 portfolio 上,後來不小心又用同一個 key 呼叫了一次 register_taxonomy()、這次只綁了 case_studyportfolio 那邊的綁定會直接消失,而不是兩個文章類型都保留。WordPress 官方文件在說明裡特別標註,如果是在修改一個既有的分類法物件,原始註冊時的 $object_type 會被這次呼叫的值整個覆蓋,這種行為不容易第一時間發現,通常是排查到分類法「莫名其妙不見了」才會追溯到這裡。

註冊完成後要重新整理永久連結,分類法的封存頁才會生效

這是整篇教學裡最短、卻最多人漏掉的一步:明明照著前面的程式碼把分類法註冊好了,前台的封存頁卻怎麼打都是 404。原因在於 WordPress 用一份內部的「網址對照規則」表,決定哪個網址要對應到哪一種內容,這份表不會因為你新增了分類法、或改了 rewrite 設定就自動更新,程式碼寫對了,網址規則卻還是舊的。

最簡單的解法不需要碰任何程式碼,登入後台,到「設定」裡的「永久連結」,什麼都不用改,直接按一次儲存,WordPress 就會重新產生這份網址對照表。這個步驟在開發階段很容易被跳過,尤其是改了 rewriteslug 之後,忘記重整永久連結,會誤以為是程式碼哪裡寫錯,實際上只是這張表沒更新。

分類法封存頁 404 多半是網址對照規則表沒重建,到後台設定的永久連結按一次儲存重建對照表,封存頁就會正常開啟
分類法封存頁打不開通常不是程式碼寫錯,而是網址對照規則沒重建;到「設定 → 永久連結」按一次儲存就能解決。

網址規則對了之後,分類法頁面實際要用哪個樣板顯示,傳統佈景主題會依序找 taxonomy-{分類法key}-{詞彙slug}.phptaxonomy-{分類法key}.phptaxonomy.phparchive.phpindex.php,找不到更精確的就往後退到通用樣板;區塊主題,也就是全站編輯(FSE),遵循同一套查找順序,只是把 PHP 樣板檔換成主題 templates 目錄下的 HTML 區塊樣板,可以透過後台「外觀」的「編輯器」介面,針對特定分類法設計專屬的封存頁樣板,不必自己寫 PHP 檔案。不管是哪一種佈景主題,這個網址對照表沒重建,分類法頁面一律打不開,差別只在打開之後要用哪一種樣板顯示。

分類法沒出現的兩種常見卡點

分類法照著前面幾組參數設定完,實際測試時最常見的卡點集中在兩種,各自指向某一組參數沒對齊。先確認的是後台編輯畫面本身,再確認前台的封存頁能不能打開,兩種症狀查的方向不太一樣。

編輯畫面看不到分類法欄位,多半是綁定或 show_in_rest 沒對齊

第一種症狀是後台編輯文章時,側欄或編輯畫面裡完全看不到你新註冊的分類法欄位,程式碼跑起來沒有報錯,但畫面上就是沒有東西。這時候先檢查這個文章類型是不是真的被加進了分類法的 object_type,也就是回頭確認前面「分類法綁定文章類型的兩種寫法」那一步有沒有漏掉,是不是忘了在 register_taxonomy() 的第二個參數裡把這個文章類型列進去,或是原本想用 register_taxonomy_for_object_type() 事後追加,卻漏了呼叫這個函式。

如果綁定確認沒問題,接下來看你用的是不是區塊編輯器。如果是,就要檢查分類法的 show_in_rest 跟這個文章類型本身的 show_in_rest 是不是兩邊都設為真,只開一邊,側欄面板依然不會出現,這是前面「show_in_rest 與 rest_base」那一節已經拆過的邏輯,實務上這兩個原因幾乎就涵蓋了大部分「欄位不見了」的情況。

分類法封存頁 404,通常卡在永久連結未重整或網址撞名

第二種症狀是後台編輯畫面一切正常,詞彙也賦予得好好的,但點進前台的分類法封存頁卻是 404。最常見的原因,是剛註冊完分類法、或是改過 rewrite 設定之後,忘了重新整理永久連結,前面已經拆過這一步為什麼不能省,這裡再確認一次是不是真的按過那次儲存。

如果永久連結確定重整過,404 還是沒解決,第二個要查的原因是網址撞名,這個分類法的網址前綴,也就是 rewriteslug,是不是跟網站上既有的頁面、或另一個分類法用了同一個字串,導致 WordPress 判斷網址時互相衝突、不知道該對應到哪一種內容。解法是把 slug 改成一個網站上還沒被用過的字串,改完別忘了再重整一次永久連結,讓新的網址規則生效。

CPT UI 外掛能同時建立文章類型與分類法,不寫程式碼也能完成

前面整套都是直接寫程式碼的做法,如果你不想碰程式碼,或是想先用介面試出設定、之後再讓工程師接手維護,Custom Post Type UI(簡稱 CPT UI)是一個被廣泛使用的免費外掛,同時提供「文章類型」與「分類法」兩種註冊介面,填欄位就能建立分類法,不必寫任何一行程式碼。

它的分類法設定畫面,其實就是把前面教的 register_taxonomy() 參數,一一轉成表單欄位讓你填:標籤要怎麼寫、要不要階層式、要綁定哪些文章類型、要不要啟用封存頁的網址結構,這些前面拆過的每一組設定,在這支外掛的介面上幾乎都能找到對應的欄位,填完存檔就等同於執行了一次 register_taxonomy()。用外掛設定完成後,該重新整理永久連結的步驟一樣不能省,這一點不因為改用介面操作就不需要。

對已經照前面章節寫過程式碼的人來說,這支外掛還有一個實用的地方,它能把後台填好的設定匯出成對應的 PHP 程式碼,讓想從介面操作過渡到自己寫程式碼維護的人有個對照的起點,不必從零開始猜每個參數該怎麼填。

register_taxonomy() 表面上是一個函式呼叫,實際上決定的是使用者未來要怎麼瀏覽你網站上的內容。分類系統設計對了,讀者能沿著服務類型或產業別,一路點進真正想找的那批作品;設計錯了,不管內容做得再完整,讀者也只能在既有的分類、標籤裡打轉,找不到真正符合他需求的分組方式。

真正動手註冊之前,先花時間想清楚這個分類維度是不是真的需要獨立成一套新分類法,比急著把程式碼寫出來更重要。等到判準確定了,剩下的階層式或非階層式、要綁哪個文章類型、labelsshow_in_restrewrite 這些參數,每一組其實都只是把你想清楚的分類邏輯,翻譯成 WordPress 看得懂的設定值而已。

常見問答

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

自訂分類法跟內建的分類、標籤有什麼不同?

分類(category)是階層式、標籤(post_tag)是非階層式,兩者都是分類法的其中兩種;自訂分類法是再造一個全新的容器,擁有自己的詞彙管理頁、URL 結構與 REST API 欄位,跟原本的分類、標籤各自獨立、互不干擾。

什麼情況該另外開一個自訂分類法?

判斷依據有兩個:這批內容是不是真的需要同時用兩個以上互不隸屬的角度分類,而不是同一角度想切得更細;以及這個分類維度需不需要有自己的瀏覽入口與獨立 URL,只要符合其中一個,通常就值得分別開一個獨立的分類法。

分類法設成階層式後,編輯畫面長什麼樣?

設為真,詞彙就能有父層與子層,編輯畫面會換成一棵可以打勾選取的核取方塊樹,跟內建的「分類」操作方式一樣;預設是否,也就是非階層式,編輯畫面則是逗號分隔、可自由輸入新詞彙的輸入框,跟「標籤」一樣。

分類法在區塊編輯器側欄看不到,要查什麼?

要檢查 show_in_rest 是不是兩邊都設成真:分類法本身要開這個參數,它綁定的那個文章類型自己也要開,少一邊都看不到側欄的選取面板,這是實務上除錯時最容易漏掉、卻最常卡住的地方。

分類法封存頁打開是 404,怎麼排查?

最常見的原因是剛註冊完分類法或改過 rewrite 設定之後,忘了到「設定」的「永久連結」按一次儲存重新整理;如果永久連結確定重整過還是 404,就要檢查這個分類法的 URL 前綴是不是跟既有頁面或另一個分類法撞名了。

資料來源
  1. Taxonomies — WordPress
  2. register_taxonomy() — WordPress
  3. register_taxonomy_for_object_type() — WordPress
  4. Taxonomy Templates — WordPress
  5. Custom Post Type UI — Custom Post Type UI