2026年10月8日
2026年10月8日
WordPressテーマ開発の基本|functions.phpに書く初期設定・読み込み・メニュー登録
自作テーマの functions.php には、テーマの機能を有効にする設定(after_setup_theme)、CSS と JavaScript の読み込み(wp_enqueue_scripts)、メニューやウィジェットエリアの登録をまとめて書きます。この記事では、クラシックテーマを一から作る前提で、functions.php に最初に書くべき内容を順番に組み立て、ファイルが大きくなったときの分け方と、編集で画面が真っ白にならないための注意点までを説明します。
functions.php の役割と読み込まれるタイミング
functions.php は、テーマが有効なときにだけ毎回のリクエストで読み込まれる PHP ファイルです。テンプレートのように画面を出力する場所ではなく、「WordPress の動きに処理を差し込む」ための場所と考えると整理しやすくなります。
読み込みの順番は次のとおりです。
- 有効なプラグインが読み込まれる
- 子テーマがあれば子テーマの functions.php、続いて親テーマの functions.php
after_setup_themeアクションinitアクション、その後にテンプレートの表示
このため、functions.php の中でいきなり処理を書くのではなく、決められたフック(アクション・フィルター)に関数を登録するのが基本の書き方です。直接書いた処理は「まだ WordPress の準備が終わっていない段階」で動くことがあり、関数が未定義だったり、設定が反映されなかったりする原因になります。
なお、テーマとして認識されるのに最低限必要なのは、テーマ名などを書いた style.css と index.php です(クラシックテーマの場合)。テンプレートでは <head> 内に wp_head()、</body> の直前に wp_footer()、<body> の直後に wp_body_open() を置きます。これを忘れると、後で登録する CSS や JavaScript が出力されません。
テーマ機能を有効にする(after_setup_theme)
タイトルタグやアイキャッチ画像など、テーマが対応している機能を WordPress に伝えるのが add_theme_support() です。after_setup_theme に登録した関数の中で呼び出します。
<?php
// functions.php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
function mytheme_setup() {
// <title> を WordPress に出力させる
add_theme_support( 'title-tag' );
// アイキャッチ画像
add_theme_support( 'post-thumbnails' );
// 検索フォームやコメント欄を HTML5 のマークアップで出力
add_theme_support( 'html5', array( 'search-form', 'comment-form', 'comment-list', 'gallery', 'caption', 'style', 'script' ) );
// カスタムロゴ(カスタマイザーから設定)
add_theme_support( 'custom-logo', array(
'height' => 80,
'width' => 240,
'flex-height' => true,
'flex-width' => true,
) );
// 埋め込みコンテンツのレスポンシブ対応
add_theme_support( 'responsive-embeds' );
// ナビゲーションメニューの位置
register_nav_menus( array(
'primary' => __( 'メインメニュー', 'mytheme' ),
'footer' => __( 'フッターメニュー', 'mytheme' ),
) );
}
add_action( 'after_setup_theme', 'mytheme_setup' );
ポイントは次の3つです。
- title-tag:テンプレートに
<title>を手書きせず、WordPress に任せます。SEO 系プラグインがタイトルを変えるときも、この仕組みを通して反映されます。 - 関数名の接頭辞:
mytheme_のようにテーマ固有の接頭辞を付けます。プラグインと関数名がぶつかると致命的エラーで画面が止まるためです。 - 翻訳関数:
__( '文字列', 'テキストドメイン' )で囲んでおくと、後から翻訳ファイルで表示を差し替えられます。
テンプレート側では、メニューは wp_nav_menu( array( 'theme_location' => 'primary' ) );、ロゴは the_custom_logo(); で出力します。
CSS と JavaScript を読み込む(wp_enqueue_scripts)
header.php に <link> や <script> を直接書くと、プラグインとの重複読み込みや順番の問題が起きやすくなります。WordPress には読み込みを管理する仕組みがあるので、wp_enqueue_scripts アクションで登録します。
function mytheme_assets() {
$theme_version = wp_get_theme()->get( 'Version' );
wp_enqueue_style(
'mytheme-style',
get_stylesheet_uri(),
array(),
$theme_version
);
$js_path = get_theme_file_path( 'assets/js/main.js' );
wp_enqueue_script(
'mytheme-main',
get_theme_file_uri( 'assets/js/main.js' ),
array(),
file_exists( $js_path ) ? filemtime( $js_path ) : $theme_version,
array(
'in_footer' => true,
'strategy' => 'defer',
)
);
}
add_action( 'wp_enqueue_scripts', 'mytheme_assets' );
第4引数のバージョンは、ブラウザのキャッシュ対策です。値が変わると URL の ?ver= が変わり、古いファイルが使われ続ける問題を避けられます。開発中はファイルの更新時刻(filemtime)を使うと、編集のたびに自動で切り替わります。
第5引数に配列で strategy を渡す書き方は WordPress 6.3 で追加されました。defer を指定すると、HTML の解析を止めずにスクリプトを読み込めます。古いバージョンでは配列ではなく true(フッターで読み込む)を渡す書き方になるため、対応バージョンをテーマの説明に書いておくと親切です。
get_theme_file_uri() と get_theme_file_path() は、子テーマに同じパスのファイルがあればそちらを優先して返します。子テーマでの上書きを想定するなら、get_template_directory_uri() より扱いやすい関数です。
ウィジェットエリアとコンテンツ幅
サイドバーやフッターにウィジェットを置けるようにするには、widgets_init アクションで register_sidebar() を呼びます。
function mytheme_widgets() {
register_sidebar( array(
'id' => 'sidebar-1',
'name' => __( 'サイドバー', 'mytheme' ),
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h2 class="widget-title">',
'after_title' => '</h2>',
) );
}
add_action( 'widgets_init', 'mytheme_widgets' );
テンプレートでは if ( is_active_sidebar( 'sidebar-1' ) ) { dynamic_sidebar( 'sidebar-1' ); } のように、ウィジェットが置かれているときだけ出力します。id は後から変えると配置済みのウィジェットが外れるため、最初に決めたら変えないようにします。
埋め込み動画などの最大幅を伝える $content_width も、古くからある設定として残っています。本文エリアの幅に合わせて after_setup_theme の中で $GLOBALS['content_width'] = 760; のように設定しておくと、埋め込みの幅がはみ出しにくくなります。
functions.php が大きくなったら分割する
機能を足していくと functions.php は数百行になりがちです。役割ごとにファイルを分けて読み込むと、修正箇所を探しやすくなります。
// functions.php の末尾
$mytheme_includes = array(
'inc/setup.php',
'inc/assets.php',
'inc/template-tags.php',
);
foreach ( $mytheme_includes as $file ) {
require_once get_theme_file_path( $file );
}
分けるときの目安は「設定」「読み込み」「テンプレート用の関数」「管理画面の調整」です。
もう一つ大事なのが、テーマに書くべきでないものを入れないことです。カスタム投稿タイプ、ショートコード、外部サービスとの連携など、テーマを切り替えても残したい機能は、プラグイン(自作なら mu-plugins でも可)に置きます。テーマに書くと、デザインを変えた途端に投稿が管理画面から見えなくなる、本文にショートコードの文字列がそのまま出る、といった問題が起きます。
編集で画面を真っ白にしないための注意点
functions.php は毎回読み込まれるため、1文字の書き間違いでサイト全体が表示されなくなります。次の点を習慣にしてください。
- 本番で直接編集しない:ステージング環境かローカル環境で動作を見てから反映します。編集前にはファイルのバックアップを取ります。
- 構文チェックを通す:サーバーに PHP が入っていれば
php -l functions.phpで文法エラーを事前に見つけられます。 - **閉じタグ
?>を書かない**:ファイル末尾の?>の後に空白や改行が入ると「headers already sent」の警告が出ることがあります。PHP だけのファイルでは閉じタグを省略するのが一般的です。 - エラーはログで確認する:wp-config.php で
WP_DEBUGとWP_DEBUG_LOGを有効にし、WP_DEBUG_DISPLAYを false にすると、画面に出さずに wp-content/debug.log へ記録できます。確認が終わったら元に戻します。 - 管理画面に入れなくなったら:FTP やファイルマネージャーで、直前に編集したファイルを戻すか、テーマのフォルダー名を変えて既定のテーマに切り替えます。
管理画面のテーマファイルエディターは手軽ですが、保存した瞬間に本番へ反映されます。エディター自体を無効にしたい場合は wp-config.php に define( 'DISALLOW_FILE_EDIT', true ); を書く方法があります。
ブロックテーマとの違い
ここまではクラシックテーマの書き方です(2026年10月現在、WordPress の既定テーマはブロックテーマです)。ブロックテーマでは、色やフォント、レイアウト幅などの多くを theme.json で設定し、テンプレートも HTML ファイルで作ります。そのため functions.php に書く量は減りますが、スクリプトの読み込みやブロックスタイルの登録など、PHP で行う処理は引き続き functions.php に書きます。どちらの方式で作るかを最初に決めてから設計すると、後から書き直す手間を減らせます。
配布されているテーマを改造したい場合は、テーマを直接編集せず子テーマを作ってください。親テーマを更新すると、直接加えた変更は上書きされて消えます。
まとめ
- functions.php は「画面を出す場所」ではなく、フックに処理を登録する場所です。
- テーマ機能は
after_setup_themeでadd_theme_support()とregister_nav_menus()を使って有効にします。 - CSS・JavaScript は
wp_enqueue_scriptsで読み込み、バージョン引数でキャッシュを切り替えます。strategy引数は WordPress 6.3 以降です。 - 関数には接頭辞を付け、大きくなったら inc/ に分割します。カスタム投稿タイプなどはプラグイン側に置きます。
- 編集はバックアップとステージングでの確認を先に行い、エラーは debug.log で確かめます。