2026年5月20日

2026年5月20日

テーマオプションページを作る方法|Settings APIで設定画面を追加して値を保存・表示する

フッターの著作権表示やSNSのURL、テーマの基本色などを、コードを書き換えずに管理画面から変えられるようにするのがテーマオプションページです。WordPress の Settings API を使うと、フォームの nonce 確認や保存処理を WordPress に任せられ、自分で書くのは「どの項目を出すか」と「どう検証するか」だけになります。

この記事の関数と引数は developer.wordpress.org の Settings API・Administration Menus のドキュメントと WordPress 6.9 のソースコードで2026年10月時点の内容を確認しています。クラシックテーマ(PHP テンプレートのテーマ)向けの手順です。

先に決めること: 設定ページか、カスタマイザーか

方法 向いているもの 備考
設定ページ(この記事) 文字列・URL・ON/OFF など、見た目に直接出ないものも含む設定 「外観」や「設定」の下に独自の画面を作る
カスタマイザー 色・ロゴ・レイアウトなど、プレビューしながら変えたい設定 「外観」→「カスタマイズ」。値は get_theme_mod() で取得
サイトエディター ブロックテーマの色・文字・余白 theme.json と「スタイル」で設定。PHP の設定ページは不要なことが多い

カスタマイザーで作る場合は カスタマイザーAPIの使い方 を参照してください。ここでは設定ページを作ります。

完成形の構成

  • メニュー: 「外観」→「テーマ設定」
  • 保存先: wp_options テーブルの mytheme_options(1つのオプションに配列でまとめて保存)
  • 項目: フッターの文言、X(旧Twitter)の URL、基本色

以下のコードは、テーマの functions.php か、functions.php から読み込む別ファイル(例: inc/theme-options.php)に書きます。

手順1: 初期値と取得用の関数を用意する

<?php
// 設定の初期値
function mytheme_default_options() {
    return array(
        'footer_text'   => '© ' . wp_date( 'Y' ) . ' ' . get_bloginfo( 'name' ),
        'x_url'         => '',
        'primary_color' => '#2271b1',
    );
}

// 保存値と初期値をまとめて返す(未保存の項目は初期値になる)
function mytheme_get_option( $key ) {
    $options = wp_parse_args( get_option( 'mytheme_options', array() ), mytheme_default_options() );
    return isset( $options[ $key ] ) ? $options[ $key ] : '';
}

register_setting() にも default を渡せますが、その初期値が効くのは register_setting() を実行したリクエストの中だけです。登録を admin_init で行う場合、サイトの表側では効かないため、上のような取得関数で初期値を補います。

手順2: メニューに設定ページを追加する

<?php
function mytheme_add_options_page() {
    add_theme_page(
        'テーマ設定',              // ページの <title> と見出し
        'テーマ設定',              // メニューに出る名前
        'edit_theme_options',      // 表示に必要な権限
        'mytheme-options',         // ページのスラッグ(URL の ?page= の値)
        'mytheme_render_options_page' // 画面を出力する関数
    );
}
add_action( 'admin_menu', 'mytheme_add_options_page' );
  • add_theme_page() は「外観」の下にページを追加します。中身は add_submenu_page( 'themes.php', … ) と同じです。
  • 権限 edit_theme_options は、既定では管理者が持っています。「外観」→「メニュー」などと同じ権限です。
  • 「設定」の下に置くなら add_options_page()、メニューの最上位に独立させるなら add_menu_page() を使います。add_menu_page() の第7引数(表示位置)で、既定のメニューは「外観」が 60、「プラグイン」が 65 です。同じ数字を指定しても WordPress がずらして並べますが、61 のように空いている数字を使うと位置がわかりやすくなります。

手順3: Settings API で項目を登録する

<?php
function mytheme_register_settings() {
    register_setting(
        'mytheme_options_group',   // オプショングループ(フォームの settings_fields() で使う)
        'mytheme_options',         // wp_options に保存されるオプション名
        array(
            'type'              => 'array',
            'sanitize_callback' => 'mytheme_sanitize_options',
        )
    );

    add_settings_section(
        'mytheme_section_general',
        '基本設定',
        '__return_false',          // セクションの説明は出さない
        'mytheme-options'          // 手順2のページスラッグ
    );

    add_settings_field(
        'mytheme_footer_text',
        'フッターの文言',
        'mytheme_field_footer_text',
        'mytheme-options',
        'mytheme_section_general',
        array( 'label_for' => 'mytheme_footer_text' )
    );

    add_settings_field(
        'mytheme_x_url',
        'X(旧Twitter)のURL',
        'mytheme_field_x_url',
        'mytheme-options',
        'mytheme_section_general',
        array( 'label_for' => 'mytheme_x_url' )
    );

    add_settings_field(
        'mytheme_primary_color',
        '基本色',
        'mytheme_field_primary_color',
        'mytheme-options',
        'mytheme_section_general',
        array( 'label_for' => 'mytheme_primary_color' )
    );
}
add_action( 'admin_init', 'mytheme_register_settings' );

label_for を指定すると、項目名が入力欄の <label for="…"> になり、項目名をクリックすると入力欄にカーソルが移ります。値は入力欄の id と同じにします。

手順4: 入力欄を出力する関数を書く

入力欄の name は オプション名[キー] にします。こうすると、すべての項目が mytheme_options という1つの配列として送信・保存されます。

<?php
function mytheme_field_footer_text() {
    printf(
        '<input type="text" id="mytheme_footer_text" name="mytheme_options[footer_text]" value="%s" class="regular-text">',
        esc_attr( mytheme_get_option( 'footer_text' ) )
    );
    echo '<p class="description">フッターに表示する著作権表示などの文言です。HTML は使えません。</p>';
}

function mytheme_field_x_url() {
    printf(
        '<input type="url" id="mytheme_x_url" name="mytheme_options[x_url]" value="%s" class="regular-text" placeholder="https://x.com/your-account">',
        esc_attr( mytheme_get_option( 'x_url' ) )
    );
}

function mytheme_field_primary_color() {
    printf(
        '<input type="color" id="mytheme_primary_color" name="mytheme_options[primary_color]" value="%s">',
        esc_attr( mytheme_get_option( 'primary_color' ) )
    );
}

手順5: 設定ページの画面を出力する

<?php
function mytheme_render_options_page() {
    if ( ! current_user_can( 'edit_theme_options' ) ) {
        return;
    }
    ?>
    <div class="wrap">
        <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
        <?php settings_errors(); ?>
        <form action="options.php" method="post">
            <?php
            settings_fields( 'mytheme_options_group' );   // nonce と隠しフィールド
            do_settings_sections( 'mytheme-options' );    // 手順3で登録したセクションと項目
            submit_button( '設定を保存' );
            ?>
        </form>
    </div>
    <?php
}
  • フォームの送信先は options.php です。保存処理(権限と nonce の確認、サニタイズ、update_option())は WordPress が行い、終わると元の画面に戻ります。
  • 「設定を保存しました。」の通知は、「設定」の下のページなら WordPress が自動で表示しますが、「外観」の下や最上位メニューのページでは表示されません。そのため settings_errors() を呼んでいます。「設定」の下(add_options_page())に置く場合は、二重に表示されるので settings_errors() は不要です。

手順6: 保存前に値を検証する(サニタイズ)

register_setting() の sanitize_callback に渡した関数が、保存の直前に呼ばれます。送られてきた値を項目ごとに検証し、許可した値だけを返します。

<?php
function mytheme_sanitize_options( $input ) {
    $defaults = mytheme_default_options();
    $output   = array();

    if ( ! is_array( $input ) ) {
        return $defaults;
    }

    $output['footer_text'] = isset( $input['footer_text'] )
        ? sanitize_text_field( $input['footer_text'] )
        : $defaults['footer_text'];

    $output['x_url'] = isset( $input['x_url'] )
        ? esc_url_raw( $input['x_url'] )
        : '';

    $color = isset( $input['primary_color'] ) ? sanitize_hex_color( $input['primary_color'] ) : '';
    if ( ! $color ) {
        $color = $defaults['primary_color'];
        add_settings_error( 'mytheme_options', 'invalid_color', '基本色の値が正しくないため、初期値に戻しました。' );
    }
    $output['primary_color'] = $color;

    return $output;
}
  • sanitize_text_field() はタグや改行を取り除きます。改行を残したい項目には sanitize_textarea_field() を使います。
  • esc_url_raw() は http・https などの許可されたプロトコル以外の URL を空にします。
  • sanitize_hex_color() は #fff や #2271b1 の形式以外を受け付けません。
  • add_settings_error() で登録したメッセージは、手順5の settings_errors() で画面に表示されます。

手順7: テーマで設定値を使う

footer.php などのテンプレートでは、手順1の取得関数で値を読み、出力の直前にエスケープします。

<?php
// footer.php など
$x_url = mytheme_get_option( 'x_url' );
?>
<footer class="site-footer">
    <p><?php echo esc_html( mytheme_get_option( 'footer_text' ) ); ?></p>
    <?php if ( $x_url ) : ?>
        <a href="<?php echo esc_url( $x_url ); ?>" rel="noopener">X</a>
    <?php endif; ?>
</footer>

基本色は CSS 変数として <head> に出力しておくと、テーマの CSS から var(--mytheme-primary) で使えます。

<?php
function mytheme_output_primary_color() {
    $color = sanitize_hex_color( mytheme_get_option( 'primary_color' ) );
    if ( $color ) {
        echo '<style id="mytheme-options-css">:root{--mytheme-primary:' . esc_html( $color ) . ';}</style>' . "\n";
    }
}
add_action( 'wp_head', 'mytheme_output_primary_color' );

動作を確認する

  1. 管理画面の「外観」→「テーマ設定」を開き、値を入れて「設定を保存」を押す
  2. 画面上部に「設定を保存しました。」と表示されることを確認する
  3. サイトの表側でフッターと色が変わっていることを確認する

保存された値は WP-CLI でも確認できます。

wp option get mytheme_options --format=json

注意点

  • 権限の確認は2か所で行われます。add_theme_page() の権限でメニューと画面の表示が制限され、保存時には options.php が権限と nonce を確認します。update_option() を自前のフォーム処理で呼ぶ場合は、current_user_can() と check_admin_referer() を自分で書く必要があり、漏れやすいので Settings API を使う方が安全です。
  • 既定では、options.php への保存に必要な権限は manage_options です。ページの表示権限を edit_theme_options にした場合でも、管理者以外が保存すると権限エラーになります。管理者以外にも保存させたいときは option_page_capability_mytheme_options_group フィルターで edit_theme_options を返します。
  • テーマを切り替えても mytheme_options は wp_options に残ります。不要になったら wp option delete mytheme_options で削除できます。
<?php
// 管理者以外(edit_theme_options を持つユーザー)にも保存を許可する場合
function mytheme_options_capability() {
    return 'edit_theme_options';
}
add_filter( 'option_page_capability_mytheme_options_group', 'mytheme_options_capability' );

まとめ

  • add_theme_page() で「外観」の下に設定ページを追加する
  • register_setting()・add_settings_section()・add_settings_field() で項目を登録し、name="オプション名[キー]" で1つの配列に保存する
  • フォームは options.php に送り、settings_fields()・do_settings_sections()・submit_button() で組み立てる
  • 値は sanitize_callback で検証し、表示するときは esc_html()・esc_url() でエスケープする
  • 表側の初期値は register_setting() の default に頼らず、取得関数で補う

お気軽にご相談ください

お見積りへ お問い合わせへ
▲