[WordPress] Settings API 教學 – 外掛設定頁面開發完整指南

本篇文章更新時間:2026/03/03
如有資訊過時或語誤之處,歡迎使用 Contact 功能通知或向一介資男的 LINE 社群反應。
如果本站內容對你有幫助,歡迎贊助支持


本系列文參考自 WordPress.org 官方外掛開發文件 - Settings 的繁體中文版本,並加入作者實務開發經驗補充。

WordPress Settings API 是外掛開發中處理設定頁面的標準化解決方案。當你的外掛需要讓使用者自訂行為參數時,Settings API 提供了一套完整的機制來註冊設定欄位、產生表單、驗證資料,並自動處理儲存流程。搭配 Options API 來管理鍵值資料的存取,開發者可以快速建立安全、符合 WordPress 規範的設定頁面,而不需要自行處理表單提交、nonce 驗證和資料庫操作等繁瑣細節。

Options API 基礎

在深入 Settings API 之前,我們先來了解 Options API。Options API 是 WordPress 用來儲存與讀取鍵值對(key-value pair)資料的底層機制,它將資料存放在資料庫的 wp_options 資料表中。外掛的設定值最終都是透過 Options API 來存取的,Settings API 則是在它之上提供了表單化的操作介面。

get_option() - 讀取設定值

get_option() 用來從資料庫讀取指定的選項值。它接受兩個參數:選項名稱和預設值。

// 基本用法:讀取一個選項值
$value = get_option( 'my_plugin_api_key' );

// 指定預設值:當選項不存在時回傳預設值
$is_enabled = get_option( 'my_plugin_enabled', false );

// 讀取陣列型態的選項
$settings = get_option( 'my_plugin_settings', array(
    'api_key'    => '',
    'cache_time' => 3600,
    'debug_mode' => false,
) );

當選項不存在於資料庫中時,如果未指定預設值,get_option() 會回傳 false。建議在呼叫時都提供合理的預設值,以避免因為外掛尚未儲存過設定而產生錯誤。

update_option() - 新增或更新設定值

update_option() 用來新增或更新一個選項值。如果選項已存在,它會更新為新的值;如果不存在,則會自動建立。

// 更新單一值
update_option( 'my_plugin_api_key', 'sk-abc123def456' );

// 更新布林值
update_option( 'my_plugin_enabled', true );

// 儲存陣列
update_option( 'my_plugin_settings', array(
    'api_key'    => 'sk-abc123def456',
    'cache_time' => 7200,
    'debug_mode' => true,
) );

// 第三個參數控制是否自動載入(autoload)
// 設為 false 可減少記憶體消耗,適合不常使用或資料量大的選項
update_option( 'my_plugin_large_data', $large_array, false );

update_option() 的第三個參數 $autoload 值得特別注意。WordPress 在每次頁面載入時,會將所有 autoload 設為 'yes' 的選項一次性從資料庫載入到記憶體中。對於經常使用的小型設定值,autoload 是好的;但如果你的外掛儲存了大量資料(例如快取資料或日誌記錄),應該將 autoload 設為 false,以免拖慢整個網站的效能。

delete_option() - 刪除設定值

delete_option() 用來從資料庫中移除指定的選項。這通常在外掛解除安裝(uninstall)時使用,用來清理外掛產生的資料。

// 刪除單一選項
delete_option( 'my_plugin_api_key' );

// 在 uninstall.php 中清理所有外掛選項
delete_option( 'my_plugin_settings' );
delete_option( 'my_plugin_enabled' );
delete_option( 'my_plugin_version' );

良好的外掛應該在解除安裝時清理自己產生的所有資料庫記錄。你可以在外掛的 uninstall.php 檔案中,或者透過 register_uninstall_hook() 來執行清理工作。關於外掛的啟用與解除安裝流程,可以參考外掛基礎知識中的說明。

將多個設定值合併為單一選項

在實務開發中,建議將外掛的多個設定值儲存為單一陣列選項,而非每個設定值各自獨立一筆記錄。這樣做有幾個好處:減少資料庫查詢次數、降低與其他外掛的命名衝突風險,以及方便統一管理。

// 推薦:使用單一選項儲存所有設定
$defaults = array(
    'api_key'     => '',
    'cache_time'  => 3600,
    'debug_mode'  => false,
    'log_level'   => 'error',
);

// 讀取時合併預設值,確保所有鍵都存在
$settings = wp_parse_args( get_option( 'my_plugin_settings', array() ), $defaults );

// 使用個別設定值
$api_key = $settings['api_key'];
$cache_time = $settings['cache_time'];

wp_parse_args() 是這個模式中的關鍵函式。它會將使用者儲存的設定與預設值合併,確保即使使用者從未修改過某個設定,程式也能取得合理的預設值。當你在未來版本中新增了新的設定欄位時,既有使用者的設定不會因此出錯。

Settings API 介紹

Settings API 是 WordPress 提供的一組函式,用來標準化外掛設定頁面的建立流程。它處理了表單的產生、nonce 安全驗證、資料的儲存,以及設定值的驗證(sanitization)。使用 Settings API 的最大好處是:你不需要自行處理 $_POST 資料、不需要手動呼叫 update_option()、不需要自行產生 nonce 欄位,這些都由 WordPress 核心幫你處理。

register_setting() - 註冊設定

register_setting() 是 Settings API 的核心函式,用來在 WordPress 中註冊一個設定選項。它必須在 admin_init 這個 Action Hook 中呼叫。

register_setting(
    string $option_group,   // 設定群組名稱,對應 settings_fields() 的參數
    string $option_name,    // 選項名稱,對應 wp_options 資料表中的 option_name
    array  $args = array()  // 額外參數
);

$args 陣列可以包含以下參數:

  • type(字串):選項值的資料類型,可以是 stringbooleanintegernumberarrayobject
  • description(字串):選項的描述文字,主要用於 REST API 的 schema。
  • sanitize_callback(回呼函式):在儲存前對設定值進行驗證與清理的函式。這是確保資料安全的重要環節。
  • show_in_rest(布林值):是否在 WordPress REST API 中公開此設定。預設為 false
  • default(混合型別):選項的預設值。當 get_option() 找不到資料時會使用此值。
add_action( 'admin_init', 'wporg_settings_init' );

function wporg_settings_init() {
    register_setting(
        'wporg_options',          // 設定群組
        'wporg_settings',         // 選項名稱
        array(
            'type'              => 'array',
            'sanitize_callback' => 'wporg_sanitize_settings',
            'default'           => array(
                'api_key'    => '',
                'cache_time' => 3600,
            ),
        )
    );
}

add_settings_section() - 新增設定區段

設定區段(Section)用來將多個相關的設定欄位組織在一起。每個區段可以有自己的標題和說明文字。

add_settings_section(
    string   $id,        // 區段的唯一識別碼
    string   $title,     // 區段的標題
    callable $callback,  // 輸出區段說明文字的回呼函式
    string   $page       // 此區段要顯示在哪個設定頁面(對應選單的 slug)
);
add_settings_section(
    'wporg_general_section',          // 區段 ID
    '一般設定',                         // 區段標題
    'wporg_general_section_callback', // 回呼函式
    'wporg'                           // 頁面 slug
);

function wporg_general_section_callback() {
    echo '<p>在這裡設定外掛的基本參數。</p>';
}

add_settings_field() - 新增設定欄位

設定欄位(Field)是使用者實際操作的表單元素,每個欄位都必須屬於某個區段。

add_settings_field(
    string   $id,       // 欄位的唯一識別碼
    string   $title,    // 欄位的標籤文字
    callable $callback, // 輸出欄位 HTML 的回呼函式
    string   $page,     // 此欄位要顯示在哪個設定頁面
    string   $section,  // 此欄位屬於哪個區段
    array    $args      // 傳遞給回呼函式的額外參數
);
add_settings_field(
    'wporg_api_key',                  // 欄位 ID
    'API 金鑰',                        // 欄位標籤
    'wporg_api_key_field_callback',   // 回呼函式
    'wporg',                          // 頁面 slug
    'wporg_general_section',          // 所屬區段
    array(
        'label_for' => 'wporg_api_key',  // 讓標籤可以點擊聚焦到輸入欄位
        'class'     => 'wporg-row',      // 自訂 CSS 類別
    )
);

function wporg_api_key_field_callback( $args ) {
    $settings = get_option( 'wporg_settings' );
    ?>
    <input type="text"
           id="<?php echo esc_attr( $args['label_for'] ); ?>"
           name="wporg_settings[api_key]"
           value="<?php echo esc_attr( $settings['api_key'] ?? '' ); ?>"
           class="regular-text">
    <p class="description">
        請輸入從服務供應商取得的 API 金鑰。
    </p>
    <?php
}

注意 name 屬性的格式:wporg_settings[api_key]。因為我們在 register_setting() 中註冊的選項名稱是 wporg_settings,所以每個欄位的 name 都必須是 wporg_settings[鍵名] 的格式,這樣 WordPress 才能正確地將表單資料組合成陣列並儲存到對應的選項中。

settings_fields() 與 do_settings_sections()

這兩個函式是在設定頁面的表單中使用的輸出函式:

  • settings_fields( $option_group ):輸出隱藏的表單欄位,包含 nonce 安全驗證碼和 action 欄位。它的參數必須與 register_setting() 中的 $option_group 一致。
  • do_settings_sections( $page ):輸出所有註冊到指定頁面的區段與欄位。它的參數是設定頁面的 slug,必須與 add_settings_section() 中的 $page 一致。
// 在表單中使用
<form action="options.php" method="post">
    <?php
    // 輸出 nonce 和 action 欄位
    settings_fields( 'wporg_options' );
    // 輸出所有區段和欄位
    do_settings_sections( 'wporg' );
    // 輸出送出按鈕
    submit_button( '儲存設定' );
    ?>
</form>

表單的 action 屬性必須指向 options.php,這是 WordPress 內建的設定儲存處理程式。它會自動處理 nonce 驗證、權限檢查、呼叫 sanitize_callback 清理資料,然後將資料儲存到 wp_options 資料表中。

建立完整的設定頁面

現在我們將管理選單、Settings API 與 Options API 三者結合,建立一個完整、可運作的外掛設定頁面。這個範例包含了多種常見的表單欄位類型,並展示了資料驗證的最佳實踐。

步驟一:註冊管理選單

首先,我們需要在 WordPress 後台建立一個設定頁面的選單入口。這裡我們使用 add_options_page() 將設定頁面加入到「設定」選單下,這是官方推薦的做法。關於管理選單的詳細說明,請參考管理選單開發教學

/**
 * 在「設定」選單下新增外掛設定頁面
 */
add_action( 'admin_menu', 'wporg_options_page' );

function wporg_options_page() {
    add_options_page(
        'WPOrg 外掛設定',     // 頁面標題
        'WPOrg 設定',         // 選單名稱
        'manage_options',     // 所需權限
        'wporg',              // 選單 slug
        'wporg_options_page_html' // 回呼函式
    );
}

步驟二:註冊設定與欄位

接著在 admin_init Hook 中註冊設定選項、區段和欄位。這個範例示範了文字輸入、數字輸入、核取方塊和下拉選單四種常見的欄位類型。

/**
 * 註冊設定選項、區段和欄位
 */
add_action( 'admin_init', 'wporg_settings_init' );

function wporg_settings_init() {
    // 註冊設定,指定驗證回呼函式
    register_setting(
        'wporg_options',
        'wporg_settings',
        array(
            'type'              => 'array',
            'sanitize_callback' => 'wporg_sanitize_settings',
            'default'           => array(
                'api_key'    => '',
                'cache_time' => 3600,
                'debug_mode' => false,
                'log_level'  => 'error',
            ),
        )
    );

    // 新增「一般設定」區段
    add_settings_section(
        'wporg_general_section',
        '一般設定',
        'wporg_general_section_callback',
        'wporg'
    );

    // 新增「進階設定」區段
    add_settings_section(
        'wporg_advanced_section',
        '進階設定',
        'wporg_advanced_section_callback',
        'wporg'
    );

    // API 金鑰欄位(文字輸入)
    add_settings_field(
        'wporg_api_key',
        'API 金鑰',
        'wporg_api_key_callback',
        'wporg',
        'wporg_general_section',
        array( 'label_for' => 'wporg_api_key' )
    );

    // 快取時間欄位(數字輸入)
    add_settings_field(
        'wporg_cache_time',
        '快取時間(秒)',
        'wporg_cache_time_callback',
        'wporg',
        'wporg_general_section',
        array( 'label_for' => 'wporg_cache_time' )
    );

    // 除錯模式欄位(核取方塊)
    add_settings_field(
        'wporg_debug_mode',
        '除錯模式',
        'wporg_debug_mode_callback',
        'wporg',
        'wporg_advanced_section',
        array( 'label_for' => 'wporg_debug_mode' )
    );

    // 日誌等級欄位(下拉選單)
    add_settings_field(
        'wporg_log_level',
        '日誌等級',
        'wporg_log_level_callback',
        'wporg',
        'wporg_advanced_section',
        array( 'label_for' => 'wporg_log_level' )
    );
}

步驟三:實作區段與欄位的回呼函式

每個區段和欄位都需要一個回呼函式來輸出對應的 HTML。以下是各個回呼函式的實作。

/**
 * 區段回呼函式
 */
function wporg_general_section_callback() {
    echo '<p>設定外掛的基本運作參數。</p>';
}

function wporg_advanced_section_callback() {
    echo '<p>進階設定適用於開發與除錯用途,一般使用者通常不需要修改這些選項。</p>';
}

/**
 * API 金鑰欄位(文字輸入)
 */
function wporg_api_key_callback( $args ) {
    $settings = get_option( 'wporg_settings' );
    ?>
    <input type="text"
           id="<?php echo esc_attr( $args['label_for'] ); ?>"
           name="wporg_settings[api_key]"
           value="<?php echo esc_attr( $settings['api_key'] ?? '' ); ?>"
           class="regular-text">
    <p class="description">
        請輸入從服務供應商取得的 API 金鑰。
    </p>
    <?php
}

/**
 * 快取時間欄位(數字輸入)
 */
function wporg_cache_time_callback( $args ) {
    $settings = get_option( 'wporg_settings' );
    ?>
    <input type="number"
           id="<?php echo esc_attr( $args['label_for'] ); ?>"
           name="wporg_settings[cache_time]"
           value="<?php echo esc_attr( $settings['cache_time'] ?? 3600 ); ?>"
           min="0"
           max="86400"
           step="60"
           class="small-text">
    <p class="description">
        資料快取的有效時間,單位為秒。設為 0 表示不快取。預設值為 3600 秒(1 小時)。
    </p>
    <?php
}

/**
 * 除錯模式欄位(核取方塊)
 */
function wporg_debug_mode_callback( $args ) {
    $settings = get_option( 'wporg_settings' );
    ?>
    <label for="<?php echo esc_attr( $args['label_for'] ); ?>">
        <input type="checkbox"
               id="<?php echo esc_attr( $args['label_for'] ); ?>"
               name="wporg_settings[debug_mode]"
               value="1"
               <?php checked( ! empty( $settings['debug_mode'] ) ); ?>>
        啟用除錯模式(會在日誌中記錄詳細的執行資訊)
    </label>
    <?php
}

/**
 * 日誌等級欄位(下拉選單)
 */
function wporg_log_level_callback( $args ) {
    $settings = get_option( 'wporg_settings' );
    $current  = $settings['log_level'] ?? 'error';
    $levels   = array(
        'debug'   => 'Debug(除錯)',
        'info'    => 'Info(資訊)',
        'warning' => 'Warning(警告)',
        'error'   => 'Error(錯誤)',
    );
    ?>
    <select id="<?php echo esc_attr( $args['label_for'] ); ?>"
            name="wporg_settings[log_level]">
        <?php foreach ( $levels as $value => $label ) : ?>
            <option value="<?php echo esc_attr( $value ); ?>"
                    <?php selected( $current, $value ); ?>>
                <?php echo esc_html( $label ); ?>
            </option>
        <?php endforeach; ?>
    </select>
    <p class="description">
        選擇要記錄的日誌等級。等級越低,記錄的資訊越詳細。
    </p>
    <?php
}

步驟四:實作資料驗證(Sanitize Callback)

資料驗證是設定頁面中最重要的安全環節之一。sanitize_callback 會在 WordPress 將資料寫入資料庫之前被自動呼叫,你必須在這裡檢查每一個欄位的值是否合法,並清理任何不安全的內容。

/**
 * 驗證並清理設定值
 *
 * @param array $input 使用者提交的表單資料
 * @return array 清理後的資料
 */
function wporg_sanitize_settings( $input ) {
    $sanitized = array();

    // API 金鑰:清理文字,只保留英數字和連字號
    if ( isset( $input['api_key'] ) ) {
        $sanitized['api_key'] = sanitize_text_field( $input['api_key'] );
    }

    // 快取時間:確保是 0 到 86400 之間的整數
    if ( isset( $input['cache_time'] ) ) {
        $cache_time = absint( $input['cache_time'] );
        $sanitized['cache_time'] = min( $cache_time, 86400 );
    }

    // 除錯模式:轉為布林值
    $sanitized['debug_mode'] = ! empty( $input['debug_mode'] );

    // 日誌等級:確保是允許的值之一
    $valid_levels = array( 'debug', 'info', 'warning', 'error' );
    if ( isset( $input['log_level'] ) && in_array( $input['log_level'], $valid_levels, true ) ) {
        $sanitized['log_level'] = $input['log_level'];
    } else {
        $sanitized['log_level'] = 'error'; // 預設值
    }

    return $sanitized;
}

在驗證函式中,有幾個重要的原則:

  • 文字欄位使用 sanitize_text_field() 清除 HTML 標籤和多餘的空白。
  • 數字欄位使用 absint()intval() 轉換為整數,並用 min() / max() 限制範圍。
  • 核取方塊使用 ! empty() 轉為布林值,因為未勾選的核取方塊不會出現在 $_POST 資料中。
  • 下拉選單和單選鈕使用白名單驗證(in_array()),確保提交的值是預先定義的合法選項之一。

步驟五:輸出設定頁面 HTML

最後,我們實作管理頁面的回呼函式,將所有元素組合成完整的設定頁面。

/**
 * 設定頁面的 HTML 輸出
 */
function wporg_options_page_html() {
    // 檢查使用者權限
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }

    // 顯示設定儲存成功的通知
    if ( isset( $_GET['settings-updated'] ) ) {
        add_settings_error(
            'wporg_messages',
            'wporg_message',
            '設定已儲存。',
            'updated'
        );
    }

    // 輸出錯誤與通知訊息
    settings_errors( 'wporg_messages' );
    ?>
    <div class="wrap">
        <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
        <form action="options.php" method="post">
            <?php
            // 輸出安全欄位(nonce、action、option_page)
            settings_fields( 'wporg_options' );
            // 輸出所有區段與欄位
            do_settings_sections( 'wporg' );
            // 輸出送出按鈕
            submit_button( '儲存設定' );
            ?>
        </form>
    </div>
    <?php
}

這個頁面結構的重點:

  • current_user_can():即使選單已有權限控制,在頁面輸出時再次檢查是良好的防禦性程式設計。
  • settings_errors():顯示由 add_settings_error() 加入的通知訊息,包括成功儲存的提示和驗證錯誤。
  • get_admin_page_title():動態取得頁面標題,而非硬編碼,這樣修改選單設定時不需要同步修改頁面內容。
  • <div class="wrap">:WordPress 後台標準的頁面容器,確保樣式與其他後台頁面一致。

完整外掛程式碼

以下是將上述所有步驟整合成的完整外掛程式碼,你可以直接使用:

<?php
/**
 * Plugin Name: WPOrg Settings Demo
 * Description: 示範如何使用 WordPress Settings API 建立設定頁面
 * Version:     1.0.0
 * Author:      Developer Name
 * Text Domain: wporg-settings-demo
 */

// 防止直接存取
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * 在「設定」選單下新增外掛設定頁面
 */
add_action( 'admin_menu', 'wporg_options_page' );

function wporg_options_page() {
    add_options_page(
        'WPOrg 外掛設定',
        'WPOrg 設定',
        'manage_options',
        'wporg',
        'wporg_options_page_html'
    );
}

/**
 * 註冊設定選項、區段和欄位
 */
add_action( 'admin_init', 'wporg_settings_init' );

function wporg_settings_init() {
    register_setting(
        'wporg_options',
        'wporg_settings',
        array(
            'type'              => 'array',
            'sanitize_callback' => 'wporg_sanitize_settings',
            'default'           => array(
                'api_key'    => '',
                'cache_time' => 3600,
                'debug_mode' => false,
                'log_level'  => 'error',
            ),
        )
    );

    // 一般設定區段
    add_settings_section(
        'wporg_general_section',
        '一般設定',
        function() {
            echo '<p>設定外掛的基本運作參數。</p>';
        },
        'wporg'
    );

    // 進階設定區段
    add_settings_section(
        'wporg_advanced_section',
        '進階設定',
        function() {
            echo '<p>進階設定適用於開發與除錯用途。</p>';
        },
        'wporg'
    );

    // API 金鑰
    add_settings_field(
        'wporg_api_key',
        'API 金鑰',
        'wporg_api_key_callback',
        'wporg',
        'wporg_general_section',
        array( 'label_for' => 'wporg_api_key' )
    );

    // 快取時間
    add_settings_field(
        'wporg_cache_time',
        '快取時間(秒)',
        'wporg_cache_time_callback',
        'wporg',
        'wporg_general_section',
        array( 'label_for' => 'wporg_cache_time' )
    );

    // 除錯模式
    add_settings_field(
        'wporg_debug_mode',
        '除錯模式',
        'wporg_debug_mode_callback',
        'wporg',
        'wporg_advanced_section',
        array( 'label_for' => 'wporg_debug_mode' )
    );

    // 日誌等級
    add_settings_field(
        'wporg_log_level',
        '日誌等級',
        'wporg_log_level_callback',
        'wporg',
        'wporg_advanced_section',
        array( 'label_for' => 'wporg_log_level' )
    );
}

/**
 * 欄位回呼函式
 */
function wporg_api_key_callback( $args ) {
    $settings = get_option( 'wporg_settings' );
    ?>
    <input type="text"
           id="<?php echo esc_attr( $args['label_for'] ); ?>"
           name="wporg_settings[api_key]"
           value="<?php echo esc_attr( $settings['api_key'] ?? '' ); ?>"
           class="regular-text">
    <p class="description">請輸入從服務供應商取得的 API 金鑰。</p>
    <?php
}

function wporg_cache_time_callback( $args ) {
    $settings = get_option( 'wporg_settings' );
    ?>
    <input type="number"
           id="<?php echo esc_attr( $args['label_for'] ); ?>"
           name="wporg_settings[cache_time]"
           value="<?php echo esc_attr( $settings['cache_time'] ?? 3600 ); ?>"
           min="0" max="86400" step="60"
           class="small-text">
    <p class="description">
        資料快取的有效時間,單位為秒。設為 0 表示不快取。
    </p>
    <?php
}

function wporg_debug_mode_callback( $args ) {
    $settings = get_option( 'wporg_settings' );
    ?>
    <label for="<?php echo esc_attr( $args['label_for'] ); ?>">
        <input type="checkbox"
               id="<?php echo esc_attr( $args['label_for'] ); ?>"
               name="wporg_settings[debug_mode]"
               value="1"
               <?php checked( ! empty( $settings['debug_mode'] ) ); ?>>
        啟用除錯模式
    </label>
    <?php
}

function wporg_log_level_callback( $args ) {
    $settings = get_option( 'wporg_settings' );
    $current  = $settings['log_level'] ?? 'error';
    $levels   = array(
        'debug'   => 'Debug(除錯)',
        'info'    => 'Info(資訊)',
        'warning' => 'Warning(警告)',
        'error'   => 'Error(錯誤)',
    );
    ?>
    <select id="<?php echo esc_attr( $args['label_for'] ); ?>"
            name="wporg_settings[log_level]">
        <?php foreach ( $levels as $value => $label ) : ?>
            <option value="<?php echo esc_attr( $value ); ?>"
                    <?php selected( $current, $value ); ?>>
                <?php echo esc_html( $label ); ?>
            </option>
        <?php endforeach; ?>
    </select>
    <p class="description">選擇要記錄的日誌等級。</p>
    <?php
}

/**
 * 驗證並清理設定值
 */
function wporg_sanitize_settings( $input ) {
    $sanitized = array();

    if ( isset( $input['api_key'] ) ) {
        $sanitized['api_key'] = sanitize_text_field( $input['api_key'] );
    }

    if ( isset( $input['cache_time'] ) ) {
        $sanitized['cache_time'] = min( absint( $input['cache_time'] ), 86400 );
    }

    $sanitized['debug_mode'] = ! empty( $input['debug_mode'] );

    $valid_levels = array( 'debug', 'info', 'warning', 'error' );
    if ( isset( $input['log_level'] ) && in_array( $input['log_level'], $valid_levels, true ) ) {
        $sanitized['log_level'] = $input['log_level'];
    } else {
        $sanitized['log_level'] = 'error';
    }

    return $sanitized;
}

/**
 * 設定頁面 HTML
 */
function wporg_options_page_html() {
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }

    if ( isset( $_GET['settings-updated'] ) ) {
        add_settings_error(
            'wporg_messages',
            'wporg_message',
            '設定已儲存。',
            'updated'
        );
    }

    settings_errors( 'wporg_messages' );
    ?>
    <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( '儲存設定' );
            ?>
        </form>
    </div>
    <?php
}

實務開發建議

作者實務經驗分享:

1. Settings API vs 自建表單的選擇:Settings API 最大的優勢是它幫你處理了 nonce 驗證、權限檢查和資料儲存這些繁瑣但重要的安全機制。對於標準的設定頁面,我強烈建議使用 Settings API。但如果你的表單需要複雜的互動邏輯(例如 AJAX 即時儲存、拖放排序、動態新增欄位等),Settings API 的制式結構可能反而成為限制,這時候自建表單會更靈活。自建表單時,務必自行處理好 nonce 驗證和資料清理,細節可以參考外掛開發安全性指南中的說明。

2. 使用 sanitize_callback 驗證設定值:不要忽略 sanitize_callback,這是你最後一道資料驗證防線。即使前端已經有了 JavaScript 驗證,使用者仍然可以透過瀏覽器開發者工具修改表單資料後提交。在 sanitize_callback 中,你可以使用 add_settings_error() 來顯示驗證錯誤訊息,讓使用者知道哪些欄位的值不合法。例如,當 API 金鑰格式不正確時,可以顯示「API 金鑰格式不正確,請重新輸入」的錯誤提示,並拒絕儲存該欄位的值。

3. 將多個設定值合併為單一選項:如同前面 Options API 章節中提到的,將所有設定值存在同一個陣列選項中(例如 my_plugin_settings),而非每個欄位各自一個選項。這不僅減少了資料庫查詢,也讓你在 register_setting() 中只需要註冊一次,sanitize_callback 也只需要一個函式就能處理所有欄位的驗證。

4. 設定頁面與管理選單的搭配:如果你的外掛功能單純,只需要一個設定頁面,建議使用 add_options_page() 將頁面加入到「設定」選單下,而不要另外建立頂層選單。只有當外掛需要多個管理頁面(例如設定頁、報表頁、日誌頁等)時,才考慮建立頂層選單。關於選單架構的設計原則,可以參考管理選單開發教學

5. 善用 WordPress 內建的 CSS 類別:在欄位回呼函式中,使用 regular-textsmall-textlarge-text 等 WordPress 內建的 CSS 類別來控制輸入欄位的寬度,使用 description 類別來標示說明文字。這些類別能讓你的設定頁面自動與 WordPress 後台的視覺風格一致,不需要額外撰寫 CSS。


本文是「WordPress 外掛開發完整指南」系列的第 6 篇。

上一篇:[WordPress] 外掛管理選單開發 - 建立後台管理頁面的完整教學

下一篇:[WordPress] Shortcodes 短碼開發教學 - 建立自訂內容功能


Share:

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *


文章
Filter
Apply Filters
Mastodon