~/blog/wordpress-custom-post-type-cpt-guide-deep-dive.md
WordPress 開發與技巧 · 2025 / 07 / 22

WordPress 只能寫文章?解鎖 CPT 完整指南,打造獨一無二的網站結構!

Eric — 浪花科技創辦人 / AI 架構師
Eric
浪花科技創辦人 · AI 架構師
WordPress 只能寫文章?解鎖 CPT 完整指南,打造獨一無二的網站結構!
目錄 table-of-contents.md

作品集、課程列表、房地產物件全部塞進內建的「文章」或「頁面」,後台不亂成一團才怪。WordPress 真正的威力藏在 Custom Post Type:替每一種內容開一個專屬的型別,各自有自己的欄位、列表與網址結構。這篇完整指南帶你解鎖 CPT,打造獨一無二的網站結構。

每次聽到這個問題,我心裡都會默默 OS:「朋友,你該認識一下 WordPress 的精髓 —— Custom Post Type (CPT) 了!」很多人以為 WordPress 就只是個部落格系統,只能發文、建頁面,這真是天大的誤會。其實,WordPress 是一個極具彈性的內容管理系統 (CMS),而 CPT 就是解放它真正潛能的那把鑰匙。

今天,就讓我這個有點囉嗦的工程師,帶你從零開始,深入淺出地搞懂什麼是自訂文章類型 (CPT),為什麼你需要它,以及最重要的——如何親手打造一個屬於你自己網站的 CPT。別再把所有東西都塞在「文章」裡了,讓我們一起把 WordPress 後台變得更專業、更有條理吧!

一、CPT 是什麼?為什麼你不用「文章」就好了?

我們先來打個比方。想像一下你的 WordPress 後台是一個大書櫃。內建的「文章 (Posts)」就像是雜誌區,適合放有時效性、可被分類歸檔的內容;「頁面 (Pages)」就像是參考書區,適合放「關於我們」、「聯絡方式」這種比較獨立、靜態的資訊。

那如果今天你想新增一個「電影評論」區呢?每部電影都有導演、演員、上映年份、評分...這些固定的欄位。如果你用「文章」來寫,你可能得每次手動輸入這些資訊,而且它會跟你的部落格文章混在一起,管理起來簡直是場災難。

這時候,CPT 就登場了!

CPT 的核心價值:內容分離與結構化

Custom Post Type,中文叫「自訂文章類型」,它的作用就是在「文章」和「頁面」之外,幫你建立一個全新的、獨立的內容類型。以上面的電影評論為例,我們可以建立一個叫做「電影 (Movies)」的 CPT。

  • 內容分離: 在後台,你會看到一個獨立的「電影」選單,跟你原本的「文章」完全分開,井水不犯河水。
  • 結構化資料: 你可以為「電影」這個 CPT 加上專屬的分類(例如「電影類型」:科幻、愛情、恐怖)和標籤,甚至搭配 ACF (Advanced Custom Fields) 外掛,新增「導演」、「評分」等專屬欄位。
  • 專屬網址結構: 你的電影評論網址可以變成 `yourwebsite.com/movies/interstellar/`,而不是 `yourwebsite.com/interstellar/`,對 SEO 和使用者體驗都更加友善。
  • 專屬版面設計: 你可以為所有電影評論設計一個統一的頁面模板 (`single-movies.php`),讓每部電影的介紹頁面風格一致。

簡單來說,CPT 就是幫你把特定類型的內容「規格化」、「模組化」,讓管理和呈現都變得輕而易舉。這也是 WordPress 能從一個部落格系統,進化成能打造任何類型網站的強大 CMS 的關鍵。

二、建立 CPT 的兩種途徑:外掛 vs. 純程式碼

好了,理論講完了,該來點實際的了。建立 CPT 主要有兩種方法,各有優劣,身為工程師,我當然有我的偏好,但還是客觀分析給你聽。

方法一:使用外掛 (例如 CPT UI) - 新手友善的捷徑

對於不想碰程式碼的朋友來說,使用像 Custom Post Type UI (CPT UI) 這類外掛是最快的方法。安裝啟用後,你只需要在圖形化介面填填表格,就能快速建立 CPT 和它的分類 (Custom Taxonomies)。

  • 優點: 快速、直覺、零程式碼基礎也能上手。
  • 缺點: 網站多了一個外掛,就多了一份效能負擔和潛在的更新、衝突風險。而且如果外掛停用,你建立的 CPT 就會直接消失(內容還在資料庫,但後台和前台都看不到了),有被「綁架」的感覺。

方法二:手刻程式碼 - 工程師的浪漫與堅持

這才是我們今天的主菜!直接在你的佈景主題 `functions.php` 或是自訂外掛中,使用 WordPress 內建的 `register_post_type()` 函式來註冊 CPT。這聽起來很嚇人,但相信我,一旦你搞懂了,你會愛上這種完全掌控的感覺。

  • 優點: 效能最佳、穩定性高、完全客製化,所有設定都掌握在自己手裡,不會被任何外掛綁架。
  • 缺點: 需要一點點 PHP 基礎,寫錯了可能會讓網站出現白畫面(別怕,我會教你怎麼安全地做)。

身為一個有格調的開發者,我們當然要選第二條路。走,我們來寫 Code!

三、實戰教學:用程式碼打造你的第一個 CPT

我們來建立一個「專案作品 (Projects)」的 CPT,讓設計公司或工作室可以在網站上展示他們的作品。

Step 1: 程式碼要放哪裡?

這是一個非常重要的問題!很多人會直覺地把程式碼丟到當前啟用佈景主題的 `functions.php` 檔案裡。但這不是最好的做法! 因為一旦你更新佈景主題,你寫的程式碼就會被覆蓋掉,消失得無影無蹤。

你有兩個更好的選擇:

  1. 使用子佈景主題 (Child Theme) 這是 WordPress 官方推薦的方式。在子佈景主題的 `functions.php` 裡新增程式碼,這樣即使主佈景主題更新,你的客製化程式碼也能安然無恙。
  2. 建立一個專屬的功能性外掛 (Site-specific Plugin): 這是我個人最推薦的方式,也更專業。把所有跟網站功能相關的程式碼(例如註冊 CPT)都打包成一個外掛。這樣的好處是,你的核心功能跟外觀(佈景主題)完全分離,未來就算想換佈景主題,你的「專案作品」CPT 依然存在。

為了教學方便,我們先假設你選擇了比較簡單的子佈景主題方案。請打開你的子佈景主題中的 `functions.php` 檔案。

Step 2: 註冊 CPT - `register_post_type()` 函式詳解

把下面的程式碼貼到你的 `functions.php` 檔案中。別急著複製貼上,我會一行一行解釋這些設定是什麼意思。


function roamer_create_project_cpt() {

    $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' ),
        'featured_image'        => _x( '專案封面', 'Overrides the “Featured Image” phrase for this post type.', 'roamer-text-domain' ),
        'set_featured_image'    => _x( '設定專案封面', 'Overrides the “Set featured image” phrase for this post type.', 'roamer-text-domain' ),
        'remove_featured_image' => _x( '移除專案封面', 'Overrides the “Remove featured image” phrase for this post type.', 'roamer-text-domain' ),
    );

    $args = array(
        'labels'             => $labels,
        'public'             => true,
        'publicly_queryable' => true,
        'show_ui'            => true,
        'show_in_menu'       => true,
        'query_var'          => true,
        'rewrite'            => array( 'slug' => 'projects' ), // 這會決定你的網址 /projects/your-project-name
        'capability_type'    => 'post',
        'has_archive'        => true, // 啟用專案作品的彙整頁面 /projects/
        'hierarchical'       => false,
        'menu_position'      => 5, // 顯示在後台選單的位置,5 是在「文章」下面
        'menu_icon'          => 'dashicons-portfolio', // 使用 WordPress 內建的 Dashicons 圖示
        'supports'           => array( 'title', 'editor', 'thumbnail', 'excerpt', 'comments' ),
        'show_in_rest'       => true, // 非常重要!讓你的 CPT 支援 Gutenberg 區塊編輯器和 REST API
    );

    register_post_type( 'project', $args );
}

add_action( 'init', 'roamer_create_project_cpt' );

程式碼解析:

  • add_action('init', 'roamer_create_project_cpt');: 這行是告訴 WordPress,在它初始化完成後,去執行我們定義的 `roamer_create_project_cpt` 這個函式。CPT 必須掛載在 `init` 這個 hook 上,太早或太晚都會出錯。
  • $labels: 這是一個陣列,用來定義 CPT 在後台各個地方顯示的文字。例如「新增文章」會變成「新增專案」,非常直觀,建議全部都設定好,使用者體驗會大大提升。
  • $args: 這是最重要的設定陣列。
    • 'public' => true: 設為 `true` 會讓這個 CPT 在前台可見,並且會自動將 `publicly_queryable`, `show_ui`, `show_in_menu` 都設為 true,通常直接設這個就好了。
    • 'rewrite' => array('slug' => 'projects'): 設定 CPT 的網址 slug。這裡設為 `projects`,所以單一專案的網址會是 `.../projects/專案名稱/`。
    • 'has_archive' => true: 啟用彙整頁面。這樣訪客就可以透過 `.../projects/` 這個網址看到你所有的專案列表。
    • 'menu_icon' => 'dashicons-portfolio': 我最喜歡的功能之一!你可以到 Dashicons 官網挑一個喜歡的圖示,讓你的後台選單更具辨識度。
    • 'supports' => array(...): 決定這個 CPT 支援哪些 WordPress 核心功能。`title` (標題), `editor` (編輯器), `thumbnail` (特色圖片) 是最基本的。你可以根據需求增減。
    • 'show_in_rest' => true: 在這個 API 和區塊編輯器當道的時代,這個設定極度重要。設為 `true` 才能讓你的 CPT 完美支援 Gutenberg 編輯器,也才能透過 REST API 來存取資料。

Step 3: 新增專屬分類 (Custom Taxonomy)

光有 CPT 還不夠,我們還需要幫「專案作品」加上分類,例如「網頁設計」、「品牌識別」、「App 開發」。這就要用到 `register_taxonomy()` 函式。

在剛剛的 `add_action` 之前,加入以下程式碼:


// 註冊一個名為「專案分類」的分類法
function roamer_create_project_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-category' ),
        'show_in_rest'      => true, // 同樣,支援 Gutenberg 和 REST API
    );

    // 注意第三個參數,它告訴 WordPress 這個分類法是屬於 'project' 這個 CPT 的
    register_taxonomy( 'project_category', array( 'project' ), $args ); 

}

// 記得也要掛載到 init hook 上
add_action( 'init', 'roamer_create_project_taxonomy' );

這段程式碼的邏輯跟註冊 CPT 非常像,最關鍵的一行是 `register_taxonomy( 'project_category', array( 'project' ), $args );`。第二個參數 `array('project')` 就是在告訴 WordPress:「嘿,這個新的『專案分類』是專門給『project』這個 CPT 用的喔!」

Step 4: 刷新固定網址 (Flush Rewrite Rules)

將以上程式碼都儲存後,你可能會興高采烈地去後台查看,然後點擊「檢視專案」,結果... 404 Not Found!

別慌,這是正常現象,幾乎每個 WordPress 開發者都遇過。這是因為 WordPress 還不知道你新增了 `.../projects/` 這個網址規則。你需要手動去刷新一下它的「記憶」。

方法很簡單:到 WordPress 後台的「設定」→「固定網址」,什麼都不用改,直接點擊「儲存設定」按鈕。這個動作會強制 WordPress 重建它的網址規則,你新增的 CPT 頁面就能正常顯示了。

恭喜你!到這裡,你已經成功建立了一個功能完整的 Custom Post Type,後台選單也出現了帶有帥氣圖示的「專案作品」選項,旁邊還有「專案分類」的子選單。你已經超越了 90% 的 WordPress 使用者了!

四、結語:CPT 是你邁向專業開發者的第一步

今天我們從 CPT 的概念,一路聊到動手實作,希望你對這個強大的功能不再感到陌生。學會使用 CPT,意味著你不再被 WordPress 的預設框架所限制,你可以根據客戶的任何需求,打造出邏輯清晰、易於管理的網站後台結構。這不僅能大幅提升客戶的滿意度,也是區分業餘玩家和專業開發者的重要分水嶺。

當然,CPT 的世界還很廣闊,包含如何製作專屬的頁面模板 (`archive-project.php`, `single-project.php`)、如何在主查詢中包含 CPT 的內容等等,這些都是你可以繼續深入研究的方向。但今天,你已經踏出了最關鍵的一步。

如果你覺得今天的教學對你有幫助,但又覺得實作上遇到困難,或是你的網站有更複雜的客製化需求,別忘了,浪花科技的團隊永遠在這裡。我們專精於 WordPress 深度客製化開發,從 CPT 規劃到 API 串接,都能為你提供最專業的解決方案。

延伸閱讀

準備好讓你的 WordPress 網站脫胎換骨了嗎?立即聯繫我們,讓浪花科技的專業團隊,協助你打造一個真正符合需求的強大網站!

// FAQ

常見問題

什麼是 WordPress 的自訂文章類型(CPT)?
Custom Post Type(CPT,自訂文章類型)是在內建的「文章」與「頁面」之外,建立全新且獨立的內容類型。例如電影評論、作品集或房地產物件都可建立專屬類型,讓後台管理與前台呈現都更結構化。
為什麼不直接用「文章」就好,要另外建立 CPT?
CPT 的核心價值在於內容分離與結構化。它在後台提供獨立選單與原本文章分開、可搭配專屬分類與欄位(例如配合 ACF 新增導演、評分)、能有專屬網址結構(如 /movies/)對 SEO 更友善,也能套用統一的頁面模板,讓特定內容規格化、模組化。
建立 CPT 用外掛還是寫程式碼比較好?
兩種都可以。用 CPT UI 這類外掛圖形化操作快速、零程式碼門檻,但多一個外掛的效能負擔與衝突風險,且外掛停用後 CPT 會從前後台消失。手刻程式碼用 register_post_type() 註冊則效能最佳、穩定且完全可控、不被外掛綁架,但需要一點 PHP 基礎。
註冊 CPT 的程式碼應該放在哪裡?
不建議直接放在當前佈景主題的 functions.php,因為更新主題時程式碼會被覆蓋消失。較好的做法是放在子佈景主題(Child Theme)的 functions.php,或建立專屬的功能性外掛(Site-specific Plugin)把功能與外觀分離,這樣換佈景主題後 CPT 仍存在。
~/roamer-tech/newsletter // FREE
// newsletter

訂閱免費電子報

把 AI 自動化、企業系統設計與 WordPress / Laravel 開發的真實案例和可直接照做的技巧,整理成電子報寄給你。只寄精選內容、不灌垃圾信,一鍵就能退訂。

$
// final.exec()

準備好讓你的網站開始為你工作了嗎?