不只是文章和頁面!解放 WordPress 潛能,用 Custom Post Type 打造獨一無二的網站結構
哈囉,我是浪花科技的資深工程師 Eric。每次接手一個新的 WordPress 維護案,我最常做的第一件事就是深呼吸,然後點開後台的「文章」列表。如果我看到客戶用文章分類來區分「最新消息」、「產品介紹」、「成功案例」… 我大概就知道接下來的日子不好過了。這就像你明明有螺絲起子,卻堅持用鐵鎚把螺絲敲進去,雖然能用,但後續的維護根本是場災難。
WordPress 的核心很強大,但很多人對它的理解只停留在「部落格系統」,以為全世界的內容不是「文章 (Post)」就是「頁面 (Page)」。但說真的,如果你要做的網站稍微複雜一點,例如一個房地產網站、一個食譜分享平台,或是一個團隊的作品集,你很快就會發現,光靠文章和頁面根本不夠用。這時候,就是「自訂文章類型 (Custom Post Type,簡稱 CPT)」大顯身手的時刻了!今天,就讓我這個有點囉嗦的工程師,帶你徹底搞懂這個解放 WordPress 潛能的黑魔法。
什麼是自訂文章類型 (Custom Post Type)?為什麼你非用不可?
我們先來搞清楚一件事:在 WordPress 的世界裡,「Post Type」指的並不是「文章」這個單一的東西,而是一種「內容類型」的統稱。WordPress 預設就內建了好幾種 Post Type,包括:
- 文章 (post): 你最熟悉的,有時間序列、可以用分類和標籤。
- 頁面 (page): 靜態內容,例如「關於我們」、「聯絡我們」,沒有分類和標籤。
- 附件 (attachment): 你上傳到媒體庫的圖片、檔案等。
- 修訂 (revision): 自動儲存的文章或頁面歷史版本。
- 選單 (nav_menu_item): 你在後台外觀 -> 選單裡建立的每個項目。
所謂的「自訂文章類型 (Custom Post Type)」,就是讓我們可以跳出預設的框架,創造屬於我們自己網站的全新內容類型。例如,你可以為房地產網站建立一個「房屋 (Property)」的 CPT,為食譜網站建立一個「食譜 (Recipe)」的 CPT。
擺脫「分類」與「標籤」的無限迴圈
很多新手會試圖用「文章分類」來解決問題。例如,建立一個「作品集」的分類,然後把所有作品都當成一般文章發表。短期來看好像沒問題,但長期下來你會遇到:
- 後台混亂: 你的「文章」列表會混雜著部落格文章和作品,管理起來非常痛苦。
- 功能受限: 「作品」和「文章」需要的欄位可能完全不同。作品可能需要「客戶名稱」、「專案年份」、「技術堆疊」等欄位,但這些欄位對一般文章來說根本沒用。你總不能一直用自訂欄位硬幹吧?
- 網址結構不佳: 你的作品網址可能會是 `yoursite.com/category/portfolio/project-a`,而不是更語意化、對 SEO 更友善的 `yoursite.com/portfolio/project-a`。
使用 CPT,就像是給你的「作品集」內容一個專屬的家。它在 WordPress 後台會有自己獨立的管理選單,完全跟「文章」分開,乾淨又俐落。
為你的內容建立專屬的「資料模型」
從工程師的角度來看,CPT 的核心價值在於「結構化資料」。你不再是把所有東西都塞進一個名為「文章」的大籃子裡,而是為不同類型的內容,定義不同的「資料模型」。一個「房屋」CPT 可以有「價格」、「坪數」、「房型」等專屬欄位;一個「食譜」CPT 可以有「烹飪時間」、「食材」、「難易度」等欄位。這樣做不僅讓後台編輯體驗更好,也讓前端呈現資料、做篩選、做搜尋變得無比簡單且高效。這才是專業網站開發的基石。
實戰開始:手把手教你註冊第一個 Custom Post Type
好了,理論講夠了,該來動手了。註冊 CPT 主要有兩種方式:用外掛,或是自己寫程式碼。兩種我都會講,但你應該猜得到我偏愛哪一種。
方法一:懶人福音,使用外掛 CPT UI
對於不想碰程式碼的人來說,Custom Post Type UI (CPT UI) 這個外掛是你的好朋友。它提供了一個圖形化介面,讓你點幾下滑鼠就能建立 CPT。
- 優點: 快速、簡單、直覺,不需要寫任何程式碼。
- 缺點: 多裝一個外掛就多一個潛在的效能負擔和安全風險。且如果外掛停用,你註冊的 CPT 也會跟著消失(內容還在資料庫,但後台介面和功能會不見)。
使用步驟大致如下:
- 到 WordPress 後台安裝並啟用「Custom Post Type UI」外掛。
- 左邊選單會出現「CPT UI」,點擊「Add/Edit Post Types」。
- 填寫最重要的三個欄位:
- Post Type Slug (e.g. portfolio): 這是 CPT 的唯一識別碼,只能用小寫英文、數字,不能有空格。非常重要,設定後就不要改了。
- Plural Label (e.g. 作品集): 複數名稱,會顯示在選單上。
- Singular Label (e.g. 作品): 單數名稱。
- 往下捲動,你會看到一堆設定,我們先用預設值就好,待會用程式碼版本會詳細解釋。
- 點擊「Add Post Type」按鈕,你會發現左邊選單立刻多出了一個「作品集」的選項!
方法二:工程師的堅持,用程式碼 `register_post_type`
身為一個工程師,我強烈推薦用程式碼來做這件事。為什麼?因為它性能最好、最穩定,而且能讓你完全掌控所有細節。你可以把這段程式碼放在佈景主題的 `functions.php` 檔案裡,但更專業的做法是為你的網站建立一個專屬的功能外掛(site-specific plugin),把所有客製化功能都放進去。這樣就算你未來更換佈景主題,這些核心功能也不會消失。
我們來用程式碼註冊一個跟剛剛一樣的「portfolio」CPT。打開你的 `functions.php` 或你的功能外掛檔案,加入以下程式碼:
function roamer_create_portfolio_post_type() {
$labels = array(
'name' => _x( '作品集', 'Post type general name', 'roamer-text-domain' ),
'singular_name' => _x( '作品', 'Post type singular name', 'roamer-text-domain' ),
'menu_name' => _x( '作品集', 'Admin Menu text', 'roamer-text-domain' ),
'name_admin_bar' => _x( '作品', 'Add New on Toolbar', 'roamer-text-domain' ),
'add_new' => __( '新增作品', 'roamer-text-domain' ),
'add_new_item' => __( '新增作品', 'roamer-text-domain' ),
'new_item' => __( '新作品', 'roamer-text-domain' ),
'edit_item' => __( '編輯作品', 'roamer-text-domain' ),
'view_item' => __( '檢視作品', 'roamer-text-domain' ),
'all_items' => __( '所有作品', 'roamer-text-domain' ),
'search_items' => __( '搜尋作品', 'roamer-text-domain' ),
'parent_item_colon' => __( '父作品:', 'roamer-text-domain' ),
'not_found' => __( '找不到作品', 'roamer-text-domain' ),
'not_found_in_trash' => __( '垃圾桶中沒有作品', 'roamer-text-domain' ),
);
$args = array(
'labels' => $labels,
'public' => true, // 讓 CPT 在前後台都可見
'publicly_queryable' => true, // 可以在前端用網址查詢
'show_ui' => true, // 顯示後台管理介面
'show_in_menu' => true, // 顯示在後台選單
'query_var' => true, // 允許 a=query&post_type=portfolio 這種查詢
'rewrite' => array( 'slug' => 'portfolio' ), // 設定網址的 slug
'capability_type' => 'post',
'has_archive' => true, // 啟用 CPT 的歸檔頁面
'hierarchical' => false, // 是否像「頁面」一樣有層級關係
'menu_position' => 5, // 在後台選單的位置,5 是在「文章」下面
'menu_icon' => 'dashicons-portfolio', // 選單圖示,可從 Dashicons 找
'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields', 'revisions' ), // 支援的功能
'show_in_rest' => true, // 讓這個 CPT 支援 REST API
);
register_post_type( 'portfolio', $args );
}
add_action( 'init', 'roamer_create_portfolio_post_type' );
這段程式碼看起來很長,但其實非常直觀。我們透過 `add_action(‘init’, …)` 這個 WordPress Hook,在 WordPress 初始化的時候,去執行 `register_post_type` 函式。`$labels` 陣列定義了後台各處顯示的文字,`$args` 陣列則是這個 CPT 的核心設定。我加了詳細的註解,你可以看到我們能控制的細節遠比外掛多得多。
不只有 CPT,更要有專屬的分類法 (Custom Taxonomy)
有了「作品集」CPT 之後,你可能需要幫作品分類,例如「網頁設計」、「App 開發」、「品牌識別」。這時候你千萬不要又跑去用文章的「分類」!我們應該為「作品集」建立它專屬的「自訂分類法 (Custom Taxonomy)」。
同樣,我們也用程式碼來實作。假設我們要建立一個名為「專案類型 (Project Type)」的分類法,並且讓它有關連階層(像文章分類一樣)。
function roamer_create_project_type_taxonomy() {
$labels = array(
'name' => _x( '專案類型', 'taxonomy general name', 'roamer-text-domain' ),
'singular_name' => _x( '專案類型', 'taxonomy singular name', 'roamer-text-domain' ),
'search_items' => __( '搜尋專案類型', 'roamer-text-domain' ),
'all_items' => __( '所有專案類型', 'roamer-text-domain' ),
'parent_item' => __( '上層類型', 'roamer-text-domain' ),
'parent_item_colon' => __( '上層類型:', 'roamer-text-domain' ),
'edit_item' => __( '編輯專案類型', 'roamer-text-domain' ),
'update_item' => __( '更新專案類型', 'roamer-text-domain' ),
'add_new_item' => __( '新增專案類型', 'roamer-text-domain' ),
'new_item_name' => __( '新專案類型名稱', 'roamer-text-domain' ),
'menu_name' => __( '專案類型', 'roamer-text-domain' ),
);
$args = array(
'hierarchical' => true, // 設定為 true,它就像「分類」;設定為 false,它就像「標籤」
'labels' => $labels,
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'project-type' ), // 分類法的網址 slug
'show_in_rest' => true, // 讓這個分類法支援 REST API
);
// 第一個參數是分類法的 slug,第二個參數是它要附加到的 Post Type
register_taxonomy( 'project_type', array( 'portfolio' ), $args );
}
add_action( 'init', 'roamer_create_project_type_taxonomy' );
把這段程式碼也加到 `functions.php` 或功能外掛中。注意 `register_taxonomy` 的第二個參數 `array(‘portfolio’)`,這就是關鍵!它告訴 WordPress,這個「專案類型」分類法是專門給「portfolio」這個 CPT 用的。存檔後回到後台,你會發現在「作品集」選單下,多出了一個「專案類型」的子選單,完美!
讓你的 CPT 真正「活」起來:顯示在前端
好了,後台都設定好了,也可以新增內容了,但前端怎麼顯示呢?如果你現在去 `yoursite.com/portfolio`,你可能會看到頁面,也可能看到 404。這取決於你的佈景主題是怎麼寫的。要讓 CPT 完美地顯示,你需要了解 WordPress 的「模板層級 (Template Hierarchy)」。
認識模板層級 (Template Hierarchy)
這聽起來很嚇人,但概念很簡單。當你瀏覽一個網址時,WordPress 會根據這個網址的類型,按照一個優先順序去尋找對應的 PHP 模板檔案來呈現內容。對於我們的「portfolio」CPT 來說:
- 歸檔頁 (Archive Page): 當你瀏覽所有作品的列表頁 (e.g., `yoursite.com/portfolio`),WordPress 會依序尋找:
- `archive-portfolio.php` (CPT 專屬歸檔頁模板)
- `archive.php` (通用歸檔頁模板)
- `index.php` (最終的預設模板)
- 單一內容頁 (Single Page): 當你瀏覽單一作品頁 (e.g., `yoursite.com/portfolio/project-a`),WordPress 會依序尋找:
- `single-portfolio.php` (CPT 專屬單一頁模板)
- `single.php` (通用單一文章頁模板)
- `index.php` (最終的預設模板)
所以,要客製化 CPT 的外觀,最標準的做法就是建立專屬的模板檔案。你可以直接複製佈景主題裡的 `archive.php` 和 `single.php`,並分別重新命名為 `archive-portfolio.php` 和 `single-portfolio.php`,然後再進去修改裡面的 HTML 結構和 PHP 迴圈 (The Loop),來呈現你想要的樣子,例如加入作品的專屬欄位等等。
工程師小提示: 如果你用程式碼新增完 CPT 和分類法後,發現前台頁面一直出現 404 錯誤,別慌張!這通常是因為 WordPress 的「重寫規則 (Rewrite Rules)」還沒更新。你只需要到後台的「設定」->「固定網址」,什麼都不用改,直接按一下「儲存設定」按鈕。這個動作會強制 WordPress 清除並重建快取,通常就能解決 404 的問題。這招跟重開機治百病有異曲同工之妙。
結語:結構化內容是專業網站的基石
從今天起,請答應我,不要再用文章分類來假裝你有不同的內容類型了。學會使用 Custom Post Type 和 Custom Taxonomy,是從 WordPress 新手村畢業、邁向專業開發者的關鍵一步。它能讓你的網站結構清晰、易於維護、對 SEO 友善,更能為未來的擴充(例如整合 REST API)打下堅實的基礎。
這背後代表的是一種「先思考架構,再開始實作」的工程師思維。一個好的內容架構,能讓你的網站在未來五年、十年都依然穩固。這才是我們作為專業開發者,應該為客戶提供的真正價值。
延伸閱讀
- WordPress 開發的任督二脈:搞懂 Action & Filter Hooks,客製化功力大爆發!
- 解鎖 WordPress 的無限可能:資深工程師帶你深入 REST API 的黑魔法世界
- 你的 WordPress 資料庫肥到走不動?資深工程師的終極瘦身指南,榨出110%的網站效能!
需要更複雜的網站架構規劃嗎?
看完這篇文章,你是否對網站的內容架構有了新的想法?或許你的需求不僅僅是簡單的 CPT,還需要更複雜的資料關聯、前端篩選功能,或是與外部系統的 API 整合。這些正是浪花科技的強項。
我們專注於提供高品質的 WordPress 客製化開發與顧問服務,幫助您的網站從一個普通的部落格,蛻變為一個強大的商業平台。如果您有任何想法或挑戰,歡迎與我們聯繫,讓我們的專業團隊為您打造最穩固、最有效率的網站架構。






