本篇文章更新時間:2026/03/03
如有資訊過時或語誤之處,歡迎使用 Contact 功能通知或向一介資男的 LINE 社群反應。
如果本站內容對你有幫助,歡迎贊助支持 。
本系列文參考自 WordPress.org 官方外掛開發文件 - Administration Menus 的繁體中文版本,並加入作者實務開發經驗補充。
WordPress 後台選單開發是外掛開發中不可或缺的一環。當你的外掛需要提供設定頁面或管理介面時,就必須透過 Administration Menus API 在後台建立對應的選單項目。WordPress 提供了兩種選單類型:頂層選單(Top-Level Menus)與子選單(Sub-Menus),開發者可以根據外掛的複雜度與功能需求,選擇最適合的方式來建立管理頁面。本篇教學將從基礎的 add_menu_page() 開始,逐步介紹如何建立完整的後台管理選單架構。
頂層選單 (Top-Level Menus)
頂層選單會顯示在 WordPress 後台左側的主選單列中,與「文章」、「頁面」、「設定」等內建選單並列。要建立頂層選單,需要使用 add_menu_page() 函式,並將其掛載在 admin_menu 這個 Action Hook 上。
add_menu_page(
string $page_title,
string $menu_title,
string $capability,
string $menu_slug,
callable $function = '',
string $icon_url = '',
int $position = null
);
各參數說明如下:
- $page_title(字串):頁面的標題,會顯示在瀏覽器的標題列中。
- $menu_title(字串):選單中顯示的名稱文字。
- $capability(字串):使用者需要具備的權限能力才能看到此選單項目,例如
manage_options代表需要管理員權限。 - $menu_slug(字串):此選單的唯一識別碼(slug),同時也作為頁面的 URL 參數。建議使用外掛名稱作為前綴以避免衝突。
- $function(回呼函式):當使用者點擊此選單時,負責輸出頁面內容的回呼函式。
- $icon_url(字串):選單項目旁的圖示 URL。可以是圖片路徑、Dashicons 類別名稱(如
dashicons-admin-generic),或以 base64 編碼的 SVG 圖示。留空則使用預設齒輪圖示。 - $position(整數):選單在左側選單列中的排列位置。數字越小越靠上方,留空則排在最後。內建選單的位置參考值:2(儀表板)、4(分隔線)、5(文章)、10(媒體)、20(頁面)、25(留言)、60(外觀)、65(外掛)、70(使用者)、75(工具)、80(設定)。
完整範例:建立頂層選單
以下範例展示如何建立一個帶有設定表單的頂層選單頁面:
/**
* 註冊頂層選單頁面
*/
add_action( 'admin_menu', 'wporg_options_page' );
function wporg_options_page() {
add_menu_page(
'WPOrg', // 頁面標題
'WPOrg Options', // 選單名稱
'manage_options', // 所需權限
'wporg', // 選單 slug
'wporg_options_page_html', // 回呼函式
plugin_dir_url( __FILE__ ) . 'images/icon.png', // 圖示
20 // 位置(在「頁面」之後)
);
}
/**
* 頂層選單頁面的 HTML 輸出
*/
function wporg_options_page_html() {
// 檢查使用者權限
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
?>
<div class="wrap">
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
<form action="options.php" method="post">
<?php
settings_fields( 'wporg_options' );
do_settings_sections( 'wporg' );
submit_button( __( 'Save Settings', 'textdomain' ) );
?>
</form>
</div>
<?php
}
在回呼函式中,使用 get_admin_page_title() 來取得頁面標題,而非硬編碼標題文字。外層的 <div class="wrap"> 是 WordPress 後台頁面的標準容器,使用它可以確保你的頁面樣式與後台其他頁面一致。
使用 Dashicons 作為選單圖示
WordPress 內建了 Dashicons 圖示字型,你可以直接使用 Dashicons 的類別名稱作為 $icon_url 參數,而不需要額外準備圖片檔案:
add_menu_page(
'My Plugin',
'My Plugin',
'manage_options',
'my-plugin',
'my_plugin_page_html',
'dashicons-admin-tools', // 使用 Dashicons 圖示
30
);
常用的 Dashicons 圖示包括:dashicons-admin-generic(齒輪)、dashicons-admin-tools(工具)、dashicons-chart-bar(圖表)、dashicons-shield(盾牌)、dashicons-database(資料庫)等。完整的圖示列表可以在 WordPress Dashicons 官方頁面 查詢。
子選單 (Sub-Menus)
子選單會出現在某個頂層選單的展開列表中。對於只有單一設定頁面的外掛,官方建議將設定頁面加入到既有的頂層選單(如「設定」或「工具」)作為子選單,而非建立新的頂層選單,以避免後台選單過於臃腫。
add_submenu_page(
string $parent_slug,
string $page_title,
string $menu_title,
string $capability,
string $menu_slug,
callable $function = ''
);
各參數說明如下:
- $parent_slug(字串):父層選單的 slug。若要加入到內建選單下,可使用對應的 PHP 檔名,例如
options-general.php(設定)、tools.php(工具)、edit.php(文章)等。若要加入到自訂頂層選單下,則使用該頂層選單的$menu_slug。 - $page_title(字串):頁面標題,顯示在瀏覽器標題列。
- $menu_title(字串):子選單中顯示的名稱。
- $capability(字串):使用者需要具備的權限能力。
- $menu_slug(字串):此子選單的唯一識別碼。
- $function(回呼函式):負責輸出頁面內容的回呼函式。
範例:將設定頁面加入「設定」選單下
add_action( 'admin_menu', 'wporg_options_page' );
function wporg_options_page() {
add_submenu_page(
'options-general.php', // 父層選單:設定
'WPOrg Options', // 頁面標題
'WPOrg', // 選單名稱
'manage_options', // 所需權限
'wporg', // 選單 slug
'wporg_options_page_html' // 回呼函式
);
}
function wporg_options_page_html() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
?>
<div class="wrap">
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
<form action="options.php" method="post">
<?php
settings_fields( 'wporg_options' );
do_settings_sections( 'wporg' );
submit_button( __( 'Save Settings', 'textdomain' ) );
?>
</form>
</div>
<?php
}
在自訂頂層選單下加入子選單
如果你的外掛已經建立了頂層選單,可以在其下方加入多個子選單來組織不同的功能頁面:
add_action( 'admin_menu', 'wporg_register_menus' );
function wporg_register_menus() {
// 先建立頂層選單
add_menu_page(
'WPOrg',
'WPOrg',
'manage_options',
'wporg',
'wporg_main_page_html',
'dashicons-admin-generic',
30
);
// 加入子選單:一般設定
add_submenu_page(
'wporg', // 父層選單的 slug
'General Settings',
'General',
'manage_options',
'wporg', // 與父層相同 slug,會取代預設的第一個子選單
'wporg_main_page_html'
);
// 加入子選單:進階設定
add_submenu_page(
'wporg',
'Advanced Settings',
'Advanced',
'manage_options',
'wporg-advanced',
'wporg_advanced_page_html'
);
}
注意上面範例中,第一個子選單的 $menu_slug 與頂層選單相同(都是 wporg),這是一個常見的技巧。WordPress 在建立頂層選單時,會自動產生一個同名的子選單項目。透過將第一個子選單的 slug 設定為與頂層相同,就可以覆蓋掉預設的子選單名稱,讓選單名稱更有意義。
預定義的子選單輔助函式
WordPress 提供了多個便捷的輔助函式,讓你不必記住每個內建選單的 parent slug,就能快速將子選單加入到對應的位置:
add_dashboard_page()- 加入到「儀表板」選單下add_posts_page()- 加入到「文章」選單下add_media_page()- 加入到「媒體」選單下add_pages_page()- 加入到「頁面」選單下add_comments_page()- 加入到「留言」選單下add_theme_page()- 加入到「外觀」選單下add_plugins_page()- 加入到「外掛」選單下add_users_page()- 加入到「使用者」選單下add_management_page()- 加入到「工具」選單下add_options_page()- 加入到「設定」選單下add_network_admin_page()- 加入到多站點網路管理選單下
這些輔助函式的參數與 add_submenu_page() 相同,只是省略了 $parent_slug 參數。例如,add_options_page() 等同於呼叫 add_submenu_page( 'options-general.php', ... )。
移除選單
在某些情況下,你可能需要移除後台中不需要的選單項目。WordPress 提供了 remove_menu_page() 與 remove_submenu_page() 兩個函式來達成這個目的。
移除頂層選單項目:
remove_menu_page( string $menu_slug );
移除子選單項目:
remove_submenu_page( string $parent_slug, string $menu_slug );
範例:移除不需要的選單
add_action( 'admin_menu', 'wporg_remove_menus', 999 );
function wporg_remove_menus() {
// 移除「工具」頂層選單
remove_menu_page( 'tools.php' );
// 移除「設定」下的「寫作」子選單
remove_submenu_page( 'options-general.php', 'options-writing.php' );
}
請注意,移除選單並不會真正阻止使用者存取該頁面。如果使用者知道正確的 URL,仍然可以直接輸入網址進入。若要真正限制存取,必須搭配權限檢查來實現。此外,移除選單的 Hook 優先順序應該設定較高的數值(如 999),以確保在所有選單都註冊完成後才執行移除。
表單提交處理
在管理選單頁面中建立表單後,需要正確處理表單的提交。WordPress 建議搭配 Settings API 來處理設定的儲存,這樣可以自動處理 nonce 驗證與資料清理。
使用 Settings API 處理表單
在前面的範例中,我們已經使用了 settings_fields() 與 do_settings_sections()。表單的 action 指向 options.php,這是 WordPress 內建的設定處理程式。完整的流程如下:
/**
* 註冊設定欄位
*/
add_action( 'admin_init', 'wporg_settings_init' );
function wporg_settings_init() {
// 註冊設定群組
register_setting( 'wporg_options', 'wporg_field_api_key', array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'default' => '',
) );
// 新增設定區段
add_settings_section(
'wporg_section_general',
__( 'General Settings', 'textdomain' ),
'wporg_section_general_callback',
'wporg'
);
// 新增設定欄位
add_settings_field(
'wporg_field_api_key',
__( 'API Key', 'textdomain' ),
'wporg_field_api_key_callback',
'wporg',
'wporg_section_general'
);
}
function wporg_section_general_callback() {
echo '<p>' . __( 'Enter your API settings below.', 'textdomain' ) . '</p>';
}
function wporg_field_api_key_callback() {
$value = get_option( 'wporg_field_api_key' );
echo '<input type="text" name="wporg_field_api_key" value="' . esc_attr( $value ) . '" class="regular-text">';
}
自行處理表單提交
如果你不使用 Settings API,也可以自行處理表單提交。此時必須注意安全性驗證:
function wporg_custom_page_html() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
// 處理表單提交
if ( isset( $_POST['wporg_nonce'] ) && wp_verify_nonce( $_POST['wporg_nonce'], 'wporg_save_settings' ) ) {
$api_key = sanitize_text_field( $_POST['wporg_api_key'] ?? '' );
update_option( 'wporg_api_key', $api_key );
echo '<div class="notice notice-success"><p>Settings saved.</p></div>';
}
$current_key = get_option( 'wporg_api_key', '' );
?>
<div class="wrap">
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
<form method="post">
<?php wp_nonce_field( 'wporg_save_settings', 'wporg_nonce' ); ?>
<table class="form-table">
<tr>
<th scope="row">
<label for="wporg_api_key">API Key</label>
</th>
<td>
<input type="text" id="wporg_api_key" name="wporg_api_key"
value="<?php echo esc_attr( $current_key ); ?>"
class="regular-text">
</td>
</tr>
</table>
<?php submit_button(); ?>
</form>
</div>
<?php
}
在自行處理表單時,務必使用 wp_nonce_field() 產生 nonce 欄位,並在提交時以 wp_verify_nonce() 驗證,以防止 CSRF 攻擊。同時,所有使用者輸入的資料都必須經過適當的清理(sanitize)與跳脫(escape)處理。關於外掛安全性的詳細說明,請參考外掛開發安全性指南。
作者實務經驗分享:
1. 優先使用子選單而非頂層選單:除非你的外掛功能非常龐大,需要多個管理頁面,否則建議將設定頁面作為子選單加入到「設定」或「工具」選單下。每個外掛都建立自己的頂層選單,會讓後台左側選單變得又長又亂,對使用者體驗是一大傷害。
2. 善用 Dashicons:如果你確實需要頂層選單,建議使用 WordPress 內建的 Dashicons 作為圖示。Dashicons 不需要載入額外的圖片資源,渲染效能最好,而且風格與 WordPress 後台一致。選擇圖示時,挑選最能代表你外掛功能的圖示,避免使用過於常見的齒輪圖示(
dashicons-admin-generic),以免與其他外掛混淆。3. 權限控制不可省略:在管理頁面的回呼函式中,一定要加上
current_user_can()的權限檢查。即使選單本身已經設定了 capability 參數,在頁面輸出函式中再做一次驗證是良好的防禦性程式設計。此外,處理表單提交時,nonce 驗證也是不可缺少的安全措施。更多安全性相關的實務建議,請參考外掛開發安全性指南。4. 選單 slug 命名規範:建議使用外掛名稱作為選單 slug 的前綴,例如
my-plugin-settings,以避免與其他外掛或 WordPress 核心的 slug 衝突。slug 應只包含小寫英文字母、數字和連字號。5. 搭配 Hooks 使用:管理選單的註冊必須透過
admin_menu這個 Action Hook 來進行,而設定欄位的註冊則使用admin_init。如果你對 WordPress Hook 機制還不夠熟悉,建議先閱讀 Hooks 的運作機制這篇文章。
本文是「WordPress 外掛開發完整指南」系列的第 5 篇。
上一篇:[WordPress] 外掛開發安全性指南 - 上架外掛前必須通過的考驗
下一篇:[WordPress] Settings API 教學 - 外掛設定頁面開發完整指南
