本篇文章更新時間:2026/03/03
如有資訊過時或語誤之處,歡迎使用 Contact 功能通知或向一介資男的 LINE 社群反應。
如果本站內容對你有幫助,歡迎贊助支持 。
本系列文參考自 WordPress.org 官方外掛開發文件 - Custom Post Types 和 Taxonomies 的繁體中文版本,並加入作者實務開發經驗補充。
WordPress 自訂內容類型(Custom Post Type)是擴展 WordPress 內容架構的核心機制。WordPress 預設提供了文章(Post)、頁面(Page)、附件(Attachment)等內容類型,但在實務開發中,我們經常需要建立全新的內容結構來滿足專案需求——例如「產品」、「作品集」、「活動」等。搭配自訂分類法(Custom Taxonomy),開發者能夠為這些自訂內容建立專屬的分類與標籤體系,打造出完整且直覺的內容管理架構。本文將從自訂內容類型與分類法的基礎概念開始,逐步介紹 register_post_type() 與 register_taxonomy() 的完整用法,並分享永久連結處理與實務開發建議。
內容目錄
什麼是自訂內容類型(Custom Post Types)
在 WordPress 中,所有內容都儲存在 wp_posts 資料表中,透過 post_type 欄位區分不同的內容類型。WordPress 核心內建了以下幾種內容類型:
- post:文章(部落格文章)
- page:頁面(靜態頁面)
- attachment:附件(媒體檔案)
- revision:修訂版本
- nav_menu_item:選單項目
- wp_block:可重複使用的區塊
- wp_template:區塊佈景主題範本
- wp_template_part:範本組件
自訂內容類型(Custom Post Type,簡稱 CPT)讓開發者可以註冊全新的內容類型,每種 CPT 在後台管理介面中會有自己的選單、編輯畫面和列表頁面。由於所有 CPT 資料都儲存在同一張 wp_posts 資料表中,WordPress 內建的查詢引擎(WP_Query)和 REST API 都可以直接操作這些自訂內容,無需額外建立資料庫結構。
常見的 CPT 應用場景包括:
- 電商網站的「產品」(WooCommerce 的
product類型) - 作品展示的「作品集」(Portfolio)
- 活動管理的「活動」(Event)
- 房產網站的「物件」(Property)
- 知識庫的「文件」(Documentation)
註冊自訂內容類型 - register_post_type()
使用 register_post_type() 函式來註冊自訂內容類型,此函式必須掛載在 init Hook 上執行。函式接受兩個參數:內容類型名稱(最多 20 個字元,僅限小寫英文與底線)和一個設定陣列。
/**
* 註冊「書籍」自訂內容類型的完整範例
*/
function myplugin_register_book_post_type() {
$labels = array(
'name' => '書籍',
'singular_name' => '書籍',
'menu_name' => '書籍管理',
'name_admin_bar' => '書籍',
'add_new' => '新增書籍',
'add_new_item' => '新增書籍',
'new_item' => '新書籍',
'edit_item' => '編輯書籍',
'view_item' => '檢視書籍',
'all_items' => '所有書籍',
'search_items' => '搜尋書籍',
'parent_item_colon' => '上層書籍:',
'not_found' => '找不到書籍',
'not_found_in_trash' => '回收桶中找不到書籍',
'archives' => '書籍彙整',
'insert_into_item' => '插入書籍',
'uploaded_to_this_item' => '已上傳到這本書籍',
'filter_items_list' => '篩選書籍列表',
'items_list_navigation' => '書籍列表導覽',
'items_list' => '書籍列表',
);
$args = array(
// 標籤設定
'labels' => $labels,
'description' => '書籍內容類型',
// 公開性設定
'public' => true, // 前台與後台皆可存取
'publicly_queryable' => true, // 前台可查詢
'show_ui' => true, // 後台顯示管理介面
'show_in_menu' => true, // 在後台選單中顯示
'show_in_nav_menus' => true, // 可加入導覽選單
'show_in_admin_bar' => true, // 顯示在管理列
'exclude_from_search'=> false, // 不排除在搜尋結果之外
// REST API 與 Gutenberg 支援(重要!)
'show_in_rest' => true, // 啟用 REST API 與區塊編輯器支援
// 功能設定
'supports' => array(
'title', // 標題
'editor', // 內容編輯器
'author', // 作者
'thumbnail', // 特色圖片
'excerpt', // 摘要
'comments', // 留言
'revisions', // 修訂版本
'custom-fields', // 自訂欄位
),
// 彙整與永久連結
'has_archive' => true, // 啟用彙整頁面(/books/)
'rewrite' => array(
'slug' => 'books', // 自訂網址 slug
'with_front' => false, // 不加上全域前綴
),
// 階層與選單
'hierarchical' => false, // 非階層式(類似文章)
'menu_position' => 5, // 選單位置(5 = 文章下方)
'menu_icon' => 'dashicons-book-alt', // 選單圖示
// 權限
'capability_type' => 'post', // 使用與文章相同的權限
'map_meta_cap' => true, // 對應 meta capabilities
);
register_post_type( 'myplugin_book', $args );
}
add_action( 'init', 'myplugin_register_book_post_type' );
重要參數詳解
labels 陣列:定義後台管理介面中所有顯示文字。雖然只有 name 和 singular_name 是必填的,但建議完整填寫所有標籤,讓管理介面更加在地化。
supports 陣列:控制內容類型支援哪些編輯功能。常用的值包括:
title- 標題欄位editor- 內容編輯器(Gutenberg 或傳統編輯器)author- 作者選擇器thumbnail- 特色圖片excerpt- 摘要comments- 留言功能revisions- 修訂版本追蹤page-attributes- 頁面屬性(排序與上層選擇,需搭配hierarchical => true)
show_in_rest:這是 WordPress 5.0 以後最重要的參數之一。設為 true 時,你的 CPT 將同時支援 Gutenberg 區塊編輯器和 REST API。如果設為 false 或省略,編輯畫面會退回傳統編輯器,且無法透過 REST API 存取此內容類型。
rewrite 陣列:控制永久連結結構。slug 定義了 URL 中的路徑前綴(例如 /books/my-first-book/),with_front 決定是否在 slug 前加上 WordPress 設定中的永久連結前綴。
內容類型命名規範
註冊 CPT 時,命名是一個需要特別注意的細節:
- 名稱最多 20 個字元
- 僅使用小寫英文字母、數字和底線
- 建議加上外掛前綴以避免衝突(例如
myplugin_book而非book) - 不可使用 WordPress 保留名稱,例如
post、page、attachment、revision、action、author、order、theme等
什麼是分類法(Taxonomies)
分類法(Taxonomy)是 WordPress 用來對內容進行分類與分組的機制。「Taxonomy」這個詞源自生物學中的分類學概念——正如生物學家將生物分為界、門、綱、目、科、屬、種,WordPress 的分類法讓你能夠以階層式或扁平式的方式來組織內容。
WordPress 內建了幾種分類法:
- category(分類):階層式分類法,可以有父子關係
- post_tag(標籤):非階層式分類法,扁平結構
- nav_menu:導覽選單分類
- link_category:連結分類(WordPress 3.5 後已棄用)
- post_format:文章格式
分類法中的每個項目稱為「分類項目」(Term)。例如「分類」這個分類法可以包含「技術文章」、「生活雜記」等 Term;「標籤」分類法可以包含「WordPress」、「PHP」等 Term。Term 的資料儲存在 wp_terms 和 wp_term_taxonomy 資料表中。
階層式 vs 非階層式
自訂分類法最核心的設計決策就是選擇「階層式」或「非階層式」:
| 特性 | 階層式(如分類 Category) | 非階層式(如標籤 Tag) |
|---|---|---|
| 父子關係 | 支援,可建立多層樹狀結構 | 不支援,所有項目為扁平結構 |
| 後台介面 | 勾選框(Checkbox) | 自由輸入標籤框 |
| 適用情境 | 明確的分類體系,如:產品類別 | 靈活的標記系統,如:技能標籤 |
| hierarchical 參數 | true |
false |
註冊自訂分類法 - register_taxonomy()
使用 register_taxonomy() 函式來註冊自訂分類法,同樣需要掛載在 init Hook 上。函式接受三個參數:分類法名稱、要關聯的內容類型(可以是字串或陣列),以及設定陣列。
/**
* 註冊「書籍類型」階層式分類法(類似分類)
*/
function myplugin_register_genre_taxonomy() {
$labels = array(
'name' => '書籍類型',
'singular_name' => '書籍類型',
'menu_name' => '書籍類型',
'all_items' => '所有書籍類型',
'parent_item' => '上層書籍類型',
'parent_item_colon' => '上層書籍類型:',
'new_item_name' => '新書籍類型名稱',
'add_new_item' => '新增書籍類型',
'edit_item' => '編輯書籍類型',
'update_item' => '更新書籍類型',
'view_item' => '檢視書籍類型',
'separate_items_with_commas' => '以逗號分隔書籍類型',
'add_or_remove_items' => '新增或移除書籍類型',
'choose_from_most_used' => '從最常使用的選取',
'popular_items' => '熱門書籍類型',
'search_items' => '搜尋書籍類型',
'not_found' => '找不到書籍類型',
'no_terms' => '沒有書籍類型',
'items_list' => '書籍類型列表',
'items_list_navigation' => '書籍類型列表導覽',
);
$args = array(
// 標籤設定
'labels' => $labels,
'description' => '書籍的類型分類',
// 階層式(true = 類似分類,false = 類似標籤)
'hierarchical' => true,
// 公開性
'public' => true,
'publicly_queryable'=> true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_nav_menus' => true,
'show_tagcloud' => true,
'show_admin_column' => true, // 在文章列表中顯示為欄位
// REST API 與 Gutenberg 支援
'show_in_rest' => true,
// 永久連結
'rewrite' => array(
'slug' => 'genre', // 自訂 URL slug
'with_front' => false,
'hierarchical' => true, // 支援階層式 URL
),
// 查詢參數
'query_var' => true,
);
register_taxonomy( 'myplugin_genre', array( 'myplugin_book' ), $args );
}
add_action( 'init', 'myplugin_register_genre_taxonomy' );
以下是另一個非階層式(類似標籤)分類法的範例:
/**
* 註冊「書籍標籤」非階層式分類法(類似標籤)
*/
function myplugin_register_book_tag_taxonomy() {
$labels = array(
'name' => '書籍標籤',
'singular_name' => '書籍標籤',
'menu_name' => '書籍標籤',
'all_items' => '所有書籍標籤',
'new_item_name' => '新書籍標籤名稱',
'add_new_item' => '新增書籍標籤',
'edit_item' => '編輯書籍標籤',
'update_item' => '更新書籍標籤',
'search_items' => '搜尋書籍標籤',
'not_found' => '找不到書籍標籤',
'separate_items_with_commas' => '以逗號分隔書籍標籤',
'add_or_remove_items' => '新增或移除書籍標籤',
'choose_from_most_used' => '從最常使用的選取',
'popular_items' => '熱門書籍標籤',
);
$args = array(
'labels' => $labels,
'hierarchical' => false, // 非階層式 = 類似標籤
'public' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_in_rest' => true,
'rewrite' => array(
'slug' => 'book-tag',
),
'query_var' => true,
);
register_taxonomy( 'myplugin_book_tag', array( 'myplugin_book' ), $args );
}
add_action( 'init', 'myplugin_register_book_tag_taxonomy' );
將分類法關聯到現有內容類型
除了在 register_taxonomy() 的第二個參數指定內容類型外,你也可以使用 register_taxonomy_for_object_type() 將分類法關聯到已存在的內容類型:
/**
* 將自訂分類法關聯到文章(post)內容類型
*/
function myplugin_connect_taxonomy_to_posts() {
register_taxonomy_for_object_type( 'myplugin_genre', 'post' );
}
add_action( 'init', 'myplugin_connect_taxonomy_to_posts' );
這在以下情境特別有用:當你想讓自訂分類法同時套用到多種內容類型,或是想把分類法掛載到其他外掛註冊的 CPT 上時。
註冊順序很重要
如果你的分類法要關聯到自訂內容類型,請確保分類法在內容類型之前註冊,或是在 register_post_type() 的 taxonomies 參數中明確指定關聯:
// 方法一:先註冊分類法,再註冊 CPT
add_action( 'init', 'myplugin_register_genre_taxonomy' );
add_action( 'init', 'myplugin_register_book_post_type' );
// 方法二:在 CPT args 中指定 taxonomies
$args = array(
// ...其他設定
'taxonomies' => array( 'myplugin_genre', 'myplugin_book_tag' ),
);
register_post_type( 'myplugin_book', $args );
永久連結處理 - flush_rewrite_rules()
註冊 CPT 和自訂分類法後,WordPress 需要重新建立永久連結規則(Rewrite Rules)才能正確解析新的 URL 結構。但切記:絕對不要在 init Hook 中呼叫 flush_rewrite_rules(),因為這個操作非常耗費資源,它會寫入資料庫並影響每次頁面載入的效能。
正確的做法是在外掛啟用時(register_activation_hook)執行一次永久連結重建:
/**
* 外掛啟用時刷新永久連結規則
*/
function myplugin_activate() {
// 先註冊 CPT 和分類法,因為啟用時 init hook 可能尚未觸發
myplugin_register_book_post_type();
myplugin_register_genre_taxonomy();
myplugin_register_book_tag_taxonomy();
// 刷新永久連結規則
flush_rewrite_rules();
}
register_activation_hook( __FILE__, 'myplugin_activate' );
/**
* 外掛停用時也要刷新,移除不再需要的規則
*/
function myplugin_deactivate() {
// 不需要先註冊 CPT/分類法,因為停用後它們本來就不該存在
flush_rewrite_rules();
}
register_deactivation_hook( __FILE__, 'myplugin_deactivate' );
關於 register_activation_hook() 和 register_deactivation_hook() 的詳細說明,請參考「WordPress 外掛基礎知識篇」中的外掛啟用與停用章節。
開發期間的小技巧:如果你在開發過程中修改了 rewrite 設定但前台顯示 404,可以到後台「設定 → 永久連結」頁面,不需要修改任何設定,直接點擊「儲存設定」就能觸發永久連結重建。這比在程式碼中臨時加入 flush_rewrite_rules() 安全得多。
實務建議
作者實務經驗分享:
1. 何時使用 CPT,何時使用自訂資料表:如果你的資料具有「內容」的特質(有標題、有內文、需要被搜尋和瀏覽),優先使用 CPT,因為你可以直接享受 WordPress 的查詢引擎、快取機制、REST API、SEO 外掛支援等完整生態系。只有在資料結構高度特殊化(例如大量數值型日誌記錄、需要複雜的 JOIN 查詢)或資料量極大(百萬筆以上且需要高效能查詢)時,才考慮自訂資料表。我自己的經驗是:八成以上的需求都可以用 CPT + Post Meta 解決。
2. 務必啟用 show_in_rest:從 WordPress 5.0 開始,
show_in_rest不僅控制 REST API 存取,更直接決定了是否啟用 Gutenberg 區塊編輯器。如果你省略此參數或設為false,你的 CPT 編輯畫面會退回傳統編輯器。除非你有明確的理由(例如資料安全考量)不公開 REST 端點,否則建議一律設為true。如果需要細緻的 REST API 權限控制,可以透過rest_controller_class參數自訂控制器。3. 分類法的命名考量:分類法名稱最多 32 個字元,同樣建議加上外掛前綴。另外要注意的是,WordPress 內部會將分類法名稱用於資料庫查詢中的
taxonomy欄位,所以命名時要避免使用 SQL 保留字和 WordPress 已用的名稱(如category、post_tag、post_format)。4. 善用 show_admin_column:在分類法設定中將
show_admin_column設為true,可以在後台文章列表中直接顯示該分類欄位,方便管理者快速檢視與篩選。這是一個小設定,但對使用體驗有很大的提升。5. 搭配 Hooks 建立完整流程:CPT 與分類法的註冊只是第一步。在實務開發中,你通常還需要搭配
add_meta_boxes建立自訂欄位介面、使用save_post_{$post_type}儲存資料、透過manage_{$post_type}_posts_columns自訂後台列表欄位等。如果你對 WordPress Hook 機制還不熟悉,建議先閱讀「WordPress Hooks 完整教學」建立基礎觀念。6. 永久連結規則只在啟用時刷新:這是我在 code review 中最常看到的錯誤之一——開發者在
inithook 中呼叫flush_rewrite_rules()。這會導致每次頁面載入都寫入資料庫,嚴重影響效能。正確做法是只在外掛啟用和停用時刷新,開發階段則透過後台的永久連結設定頁面手動觸發。
本文是「WordPress 外掛開發完整指南」系列的第 9 篇。
上一篇:[WordPress] Metadata 與 Custom Meta Box 開發教學
下一篇:[WordPress] 使用者管理與角色權限開發教學
