WordPressカスタマイズ入門|functions.php便利コード集


functions.php とは、有効化中のテーマが読み込まれるときに WordPress が自動で実行する PHP ファイルです。テーマに機能を足したり、コアの既定動作を止めたりするために使います。プラグインを入れずにサイトの挙動を変えられる一方で、テーマを切り替えた瞬間に、書いた内容はすべて効かなくなります

この記事は「コピペできるコード集」であると同時に、そのコードをどこに貼り、効いたかどうかをどこで確かめ、壊したときにどう戻すかまでを扱います。ネット上のスニペット集の多くは WordPress 5.0 より前に書かれたままで、現行バージョンでは動かない行や、貼っても何も起きない行が混ざっています。ここで紹介する 10 本はすべて WordPress 7.0.2 のコアで挙動を確認し、それぞれに「効いたか確認」の合否ラインを付けました。


functions.php とは何か、そしてどこに書くか

functions.php は、テーマフォルダの直下に置かれる PHP ファイルです。WordPress は起動処理の途中で「有効化されているテーマ」のフォルダを見に行き、そこに functions.php があれば無条件に読み込みます。子テーマを使っている場合は、子テーマと親テーマの両方が読み込まれます。プラグインと同じことができるファイルですが、プラグインがサイトに属するのに対し、functions.php はテーマに属します。この一点が、後で出てくる「何を書くべきか」の判断基準になります。

そもそもフックや関数といった仕組みから押さえたい場合は、WordPressのfunctions.phpとは?基本と役割を先に読むと、この記事のコードが何をしているのか読み解きやすくなります。

読み込まれるタイミングは「テーマが決まった後」

順番を知っておくと、後述するリビジョンの落とし穴が理解できます。WordPress の起動処理(wp-settings.php)は、おおまかに次の順で進みます。

  1. wp-config.php が読み込まれる(ここで書いた定数が最初に確定する)
  2. コアが「まだ定義されていない定数」に既定値を入れる
  3. プラグインが読み込まれる
  4. 有効なテーマの functions.php が読み込まれる
  5. after_setup_themeinit の順にフックが走る

重要なのは 2 が 4 より先に走るという点です。つまり、コアが既定値を入れてしまう定数は、functions.php からいくら define() しても上書きできません。これが「ネットで見たコードを貼ったのに何も変わらない」の典型的な原因です。

親テーマと子テーマ、どちらに書くか

配布テーマを使っているなら、必ず子テーマの functions.php に書きます。親テーマに直接書くと、テーマがアップデートされた時点で書いた内容ごと上書きされて消えます。子テーマの functions.php は親テーマを「置き換える」のではなく、親テーマより先に読み込まれて追加されるので、必要な行だけを書けば十分です。

自作テーマなら親テーマの functions.php にそのまま書いて構いません。配布テーマを使い続けるか自作に切り替えるかで迷っている段階なら、オリジナルテーマと既存テーマの違いで判断材料を整理しています。テーマ内のどのファイルが何を担当しているかはWordPressテーマのテンプレートファイル一覧と役割にまとめてあります。


この記事で扱うスニペット一覧

貼る前に、それぞれが何をして、どこに副作用が出て、効いたかをどこで見るのかを一覧にしました。「リスク」の欄が空欄でないものは、貼る前に一度立ち止まってください。

スニペット用途効果リスク確認場所
管理バー非表示表示調整ログイン中でも公開ページに黒いバーが出ない編集画面への近道が消える公開ページの画面上部
バージョン非出力表示調整meta name="generator" が消えるこれだけでは隠しきれないソース内の generator
抜粋の長さ変更表示調整アーカイブの抜粋が指定量で切れるロケールで単位が変わるアーカイブページ
リビジョン無効化DB軽量化更新時に履歴を作らなくなる復元できなくなる編集画面のリビジョン欄
絵文字の読み込み停止高速化絵文字用の JS と CSS が出なくなる古い環境で絵文字が崩れるソース内の emoji
アイキャッチ有効化機能追加投稿にアイキャッチ欄が出る編集画面の右サイドバー
画像サイズ追加機能追加指定サイズの画像が生成される既存画像には遡らないuploads 内の新規ファイル
メニュー登録機能追加外観→メニューに表示位置が出る外観→メニュー
ウィジェットエリア登録機能追加外観→ウィジェットに枠が出る外観→ウィジェット
カスタム投稿タイプ/タクソノミー機能追加独自の投稿種別と分類が使えるテーマを変えると消える管理画面左メニューとアーカイブURL

表示まわりを整える

まずは副作用が小さく、貼った結果が目で見て分かるものから始めます。この 3 つは動作確認の練習にも向いています。

管理バーを非表示にする

ログイン中に公開ページの上部へ出る黒いバーを消します。デザイン確認のときに高さがずれるのが煩わしい、という理由で使われることが多い設定です。

add_filter('show_admin_bar', '__return_false');
確認する場所合格不合格のとき
ログインしたまま公開ページを開く画面上部の黒いバーが消えているバーが残る=貼った先が有効テーマではない(子テーマのつもりで親テーマに貼った、別テーマが有効になっている)

WordPress のバージョン情報を出力しない

WordPress は既定で <meta name="generator" content="WordPress 7.x"> を出力します。これを止めます。

remove_action('wp_head', 'wp_generator');

ただし、これを「セキュリティ対策」と呼ぶのは言い過ぎです。この 1 行が消すのは HTML の head に出る 1 行だけで、RSS フィード内の generator 要素、CSS や JS に付く ?ver= のクエリ文字列、/readme.html など、バージョンが読み取れる場所は他にも残ります。バージョンを外から見えにくくする施策の一部にすぎず、脆弱性そのものは塞ぎません。実際の防御は本体・テーマ・プラグインを更新し続けることで、この行はその代わりにはなりません。

確認する場所合格不合格のとき
公開ページで Ctrl+U(Mac は ⌘+U)→ generator を検索meta name="generator" の行が出ない出る=別のプラグインが独自に generator を出力している。プラグインを 1 つずつ止めて特定する

抜粋の長さを変える

アーカイブページなどで the_excerpt() が出す抜粋の長さを変えます。

function my_excerpt_length( $length ) {
  return 50;
}
add_filter('excerpt_length', 'my_excerpt_length');

ここでよく誤解されるのが「50」の単位です。WordPress 公式リファレンスの excerpt_length は「The maximum number of words. Default 55.」、つまり仕様上は単語数と書かれています。実際に切り出す wp_trim_words() はロケールの単語カウント方式を見て動きが変わり、日本語ロケールでは文字単位に切り替わります。そのため日本語サイトでは「50 文字」、英語ロケールのサイトでは「50 単語」として扱われます。多言語サイトで同じ数値を使い回すと見た目の長さが揃わないので注意してください。

確認する場所合格不合格のとき
カテゴリーページなどアーカイブの抜粋表示日本語サイトなら約 50 文字で が付く変わらない=テーマが the_excerpt() を使わず本文を独自に切り出している。テンプレート側を確認する

テーマ側がどこで抜粋を出しているかを追う手順は、WordPressループの書き方archive.phpの使い方とカスタマイズで扱っています。


読み込みと保存を軽くする

ここから 2 つは、ネット上に出回っているコードがそのままでは正しく動かない典型例です。片方は PHP の警告を出し、もう片方は貼っても何も起きません。理由まで含めて置き換えてください。

リビジョンを止める、または件数を絞る

リビジョンは投稿を更新するたびに履歴を DB へ積み上げる機能です。記事数が増えると wp_posts テーブルが膨らむため、無効化や件数制限がよく紹介されます。まず前提として、リビジョンと自動保存は別の機能です。自動保存は編集中に一定間隔で下書きを保存する仕組みで、これから紹介するコードでは止まりません。以降は「リビジョン」の話に限定します。

完全に無効化する場合は、functions.php にこの 1 行だけを書きます。

// functions.php — リビジョンを完全に無効化する
remove_action('post_updated', 'wp_save_post_revision');

この 1 行は WordPress 7.0.2 でも問題なく動きます。コアはリビジョン保存を post_updated フックに優先度 10 で登録しており、上の remove_action() はそれと一致します。WordPress 6.4 で wp_after_insert_post 経由の保存経路が追加されましたが、その処理は最初に「post_updatedwp_save_post_revision が残っているか」を確認して、無ければ何もせずに戻る作りになっています。1 行で両方の経路が止まります。

問題は、この行とセットで紹介されることの多い define('WP_POST_REVISIONS', 3); です。functions.php に書いた場合、この行は効かないうえに PHP の警告を出します。理由は冒頭で触れた読み込み順です。コアは functions.php より前の段階で WP_POST_REVISIONS に既定値を入れてしまうため、functions.php での define() は「すでに定義済みの定数を再定義しようとした」ことになります。

WordPress 7.0.2 で実際に試すと、次のようになります。

core defined  : bool(true)
PHP Warning:  Constant WP_POST_REVISIONS already defined in .../functions.php on line 6
after theme   : bool(true)      # 3 にならない

WP_DEBUG_DISPLAY が有効な開発環境では、この警告が全ページの先頭に表示されます。さらにこの 2 行は論理的にも矛盾しています。1 行目でリビジョン保存そのものを止めておきながら、2 行目で「3 つに制限する」と書いているからです。並べて貼ってはいけません。

件数を絞りたい場合は、functions.php ではなく wp-config.php に書きます。wp-config.php はコアが既定値を入れるより先に読み込まれるので、こちらの値が採用されます。

// wp-config.php — 「編集が必要なのはここまでです」の行より前に書く
define('WP_POST_REVISIONS', 3);

どうしても functions.php 側で制御したい、あるいは投稿タイプごとに件数を変えたいという場合は、定数ではなく wp_revisions_to_keep フィルタを使います。ここまでに挙げた「無効化」「wp-config での件数制限」「フィルタでの件数制限」は同時に使うものではないので、いずれか 1 つだけを選んでください。

// functions.php — 件数を絞る場合はこちら(上の remove_action とは併用しない)
function my_revisions_to_keep( $num, $post ) {
  return 3;
}
add_filter('wp_revisions_to_keep', 'my_revisions_to_keep', 10, 2);
確認する場所合格不合格のとき
投稿を 3 回更新し、編集画面の右サイドバーにある「リビジョン」欄を見る無効化した場合は「リビジョン」欄そのものが表示されない。件数制限の場合は 3 で止まる数字が増え続ける=remove_action が実行されていない。または define を functions.php に書いていて効いていない

絵文字関連の読み込みを止める

WordPress は絵文字を古い環境でも表示するための JavaScript と CSS を既定で出力します。使わないなら止められますが、広く出回っている 2 行のコードは、現行の WordPress では片方しか効きません。

WordPress 6.4 で絵文字 CSS の出力フックが wp_print_styles から wp_enqueue_scripts に移りました。コア側にも「後方互換のために残してあり、新しい関数側で解除される」という趣旨のコメントが添えられています。つまり remove_action('wp_print_styles', 'print_emoji_styles'); は、今では何も起きない行です。CSS まで確実に止めるには 3 行目が要ります。

// 絵文字検出スクリプト(head 内)
remove_action('wp_head', 'print_emoji_detection_script', 7);

// 旧バージョン向け。WordPress 6.3 以前を使う場合だけ意味がある
remove_action('wp_print_styles', 'print_emoji_styles');

// WordPress 6.4 以降はこちらが本体。この行が無いと CSS が残る
remove_action('wp_enqueue_scripts', 'wp_enqueue_emoji_styles');

なお、oEmbed の埋め込み用ページ(embed_head)にも同じ検出スクリプトが別途登録されているため、上の 3 行では埋め込み側の出力までは消えません。自サイトの記事を他サイトに埋め込ませていない限り実害はほとんどありませんが、完全に消したい場合は embed_head 側も同様に解除します。読み込むファイル自体を整理したい場合は、WordPressでCSSを読み込む正しい方法JavaScriptの読み込み方法もあわせて確認してください。

確認する場所合格不合格のとき
公開ページで Ctrl+Uemoji を検索wp-emoji-release.min.jswp-emoji-styles も出てこないwp-emoji-styles だけ残る=3 行目(wp_enqueue_scripts の解除)が抜けている

テーマの機能を有効化する

ここからは「テーマにこの機能を使わせる」という宣言系のコードです。自作テーマで管理画面に項目が出てこないときは、たいていこのどれかを書き忘れています。

アイキャッチ画像を有効にする

投稿・固定ページでアイキャッチ画像を設定できるようにします。add_theme_support() は公式リファレンスに「テーマの functions.php で呼ぶ必要がある」と明記されている関数なので、フックに包まず直接書いて構いません。

add_theme_support('post-thumbnails');
確認する場所合格不合格のとき
投稿の編集画面の右サイドバー「アイキャッチ画像」パネルが出る出ない=そのテーマが読まれていない。有効テーマと貼った場所を照合する

画像サイズを追加する

アップロード時に生成される画像サイズを追加します。公式リファレンスの add_image_size の第 4 引数を true にすると、指定した縦横比で切り抜かれます。

add_theme_support('post-thumbnails');
add_image_size('custom-thumb', 300, 200, true);

// 追加したサイズを、ブロックエディタの画像サイズ選択欄にも出す
function my_image_size_names( $sizes ) {
  return array_merge( $sizes, array(
    'custom-thumb' => 'カスタムサムネイル',
  ) );
}
add_filter('image_size_names_choose', 'my_image_size_names');

ここで多くの人が詰まるポイントが 2 つあります。ひとつは、add_image_size() だけでは編集画面の「画像サイズ」の選択肢に出てこないこと。テンプレート内から名前を指定して呼び出す分には使えますが、編集者に選ばせたいなら上の image_size_names_choose フィルタが要ります。もうひとつは、この設定は既にアップロード済みの画像には遡って適用されないことです。追加サイズが生成されるのは、コードを書いた後にアップロードした画像だけです。既存画像にも適用したい場合は、サムネイル再生成系のプラグインなどで一括生成する必要があります。

確認する場所合格不合格のとき
画像を 1 枚新規アップロードし、wp-content/uploads/ の該当フォルダを見る-300x200 が付いたファイルが生成されている生成されない=既存画像を見ている。必ず新規アップロードで確認する(既存画像には遡らない仕様)

uploads の中を確認するときのパスの数え方は、WordPressの絶対パスと相対パスの違いで整理しています。

ナビゲーションメニューを登録する

管理画面の「外観 → メニュー」で選べる表示位置を作ります。

function register_my_menus() {
  register_nav_menus( array(
    'header-menu' => 'ヘッダーメニュー',
    'footer-menu' => 'フッターメニュー',
  ) );
}
add_action('init', 'register_my_menus');

古い記事ではこの前に add_theme_support('menus'); を書くよう案内されていますが、この 1 行は不要です。公式リファレンスの add_theme_supportmenus について「read-only parameter. Use register_nav_menu() or register_nav_menus() instead」と明記しており、実際 register_nav_menus() の内部で自動的に呼ばれます。書いても害はありませんが、意味のない行が残るだけです。

確認する場所合格不合格のとき
管理画面 → 外観 → メニュー「メニューの設定」の表示位置に 2 つのチェックボックスが出る1 つも出ない=init より後のフックに掛けている。または関数名が他と衝突している

ウィジェットエリアを登録する

サイドバーなど、ウィジェットを置ける枠を作ります。widgets_init フックに掛けるのが公式の作法です。

function my_widgets_init() {
  register_sidebar( array(
    'name'          => 'サイドバー',
    'id'            => 'sidebar-1',
    'description'   => '記事ページの横に表示されるウィジェットエリアです。',
    'before_widget' => '<div id="%1$s" class="widget %2$s">',
    'after_widget'  => '</div>',
    'before_title'  => '<h3 class="widget-title">',
    'after_title'   => '</h3>',
  ) );
}
add_action('widgets_init', 'my_widgets_init');

before_widget の中にある %1$s%2$s は省略できません。公式リファレンスの register_sidebar は、この 2 つがそれぞれウィジェットの id 属性とクラス名を受け取ると説明しています。よくある '<div class="widget">' のように両方を省いた書き方だと、出力される全ウィジェットが同じ見た目のタグになり、個別の id もクラスも付きません。結果として「特定のウィジェットだけ CSS で調整する」ができなくなり、ウィジェット id を前提に動くプラグインも正しく動作しません。単なる作法の問題ではなく、機能が欠けます。

確認する場所合格不合格のとき
管理画面 → 外観 → ウィジェット「サイドバー」エリアが出る。ウィジェットを置いた公開ページのソースで、div に固有の id が付いているエリアが出ない=widgets_init 以外のフックに掛けている。id が付かない=%1$s を省いている

独自のコンテンツ種別を追加する

「制作実績」「お知らせ」のような独自の投稿種別と、それを分類する独自のカテゴリーを追加します。ただしこの 2 つは、functions.php に書くべきかどうかを最初に判断してください。投稿タイプの登録がテーマの functions.php にあると、テーマを切り替えた瞬間にその投稿タイプが未登録になり、記事データは DB に残ったまま管理画面から見えなくなります。テーマを変える予定があるなら、この 2 つは自作の小さなプラグインに移すのが安全です。プラグイン化といっても、同じコードを wp-content/plugins/ 内の PHP ファイルに移し、先頭にプラグイン名のコメントを書くだけで済みます。

カスタム投稿タイプを追加する

function create_custom_post_type() {
  register_post_type( 'works', array(
    'label'         => '制作実績',
    'public'        => true,
    'has_archive'   => true,
    'show_in_rest'  => true,  // これが無いとブロックエディタで開かない
    'supports'      => array('title', 'editor', 'thumbnail'),
    'menu_position' => 5,
    'menu_icon'     => 'dashicons-portfolio',
  ) );
}
add_action('init', 'create_custom_post_type');

この記事で最も重要な追記が 'show_in_rest' => true です。公式リファレンスの register_post_type のとおり、この引数の既定値は false です。そして WordPress は「その投稿タイプをブロックエディタで開くか」を判定する際に show_in_rest を見ており、false なら問答無用でクラシックエディタにフォールバックします。2018 年の WordPress 5.0 より前に書かれたスニペットをそのまま貼ると、追加した投稿タイプだけ古い編集画面で開くのはこれが原因です。

もうひとつ、'has_archive' => true にした場合はパーマリンクの再保存が必要です。WordPress は URL の振り分け規則(リライトルール)を DB に保存しており、投稿タイプを追加しただけでは更新されません。管理画面左メニューには「制作実績」が出るのに、/works/ を開くと 404 になるのはこのためです。設定 → パーマリンクを開いて「変更を保存」を 1 回押せば解決します。設定内容を変える必要はありません。

確認する場所合格不合格のとき
管理画面の左メニューと、ブラウザで /works/「制作実績」がメニューに出て、/works/ が 200 で表示される。新規追加するとブロックエディタで開くメニューは出るのに /works/ が 404 →設定 → パーマリンクを開いて「変更を保存」を 1 回押す。クラシックエディタで開く→show_in_rest が抜けている

カスタムタクソノミーを追加する

追加した投稿タイプを分類するための、独自のカテゴリー(またはタグ)を作ります。

function create_custom_taxonomy() {
  register_taxonomy( 'genre', 'works', array(
    'label'        => 'ジャンル',
    'hierarchical' => true,   // true でカテゴリー型、false でタグ型
    'public'       => true,
    'show_in_rest' => true,   // ブロックエディタのサイドバーに出すために必要
  ) );
}
add_action('init', 'create_custom_taxonomy');

タクソノミー側の show_in_rest も既定は false です。投稿タイプ側だけ true にしてタクソノミー側を忘れると、ブロックエディタの右サイドバーに分類の入力欄が出てきません。投稿タイプとタクソノミーはセットで true にしてください。

確認する場所合格不合格のとき
「制作実績」の新規追加画面の右サイドバー「ジャンル」の入力欄が出る出ない=タクソノミー側の show_in_rest が抜けている。左メニューにも出ない=第 2 引数の投稿タイプ名が実際の登録名と一致していない

引数の一つひとつの意味、アーカイブやパーマリンクの設計まで踏み込む場合は、WordPressカスタム投稿タイプの作り方と設定ガイドにまとめてあります。表示側のテンプレートを作る段階になったら、single.phpの使い方archive.phpの使い方が対応します。カスタムフィールドまで含めて管理画面を作り込む場合は、ACFで管理画面をカスタマイズする方法が参考になります。


functions.php を壊したときの戻し方

まず前提を更新しておきます。「1 文字のミスでサイトが真っ白になり何もできなくなる」というのは、現在の WordPress では正確ではありません。WordPress 5.2 で致命的エラー保護(リカバリーモード)が入り、PHP の致命的エラーが起きるとサイト全体が白紙になる代わりに専用の画面へ切り替わり、管理者メールに復旧用のリンクが届きます。とはいえ「届くはずのメールが届かない」ときに手が止まるので、作業を始める前に、次の 3 つのうち最低 2 つを使える状態にしておいてください。

管理者メールのリカバリーモードリンクを使う

致命的エラーが発生すると、WordPress は管理者メールアドレス宛に「サイトで技術的な問題が発生しています」という件名のメールを送ります。本文にはリカバリーモードへ入るためのリンクが含まれており、そこから通常どおり管理画面にログインして、問題を起こしているテーマやプラグインを止められます。宛先は「設定 → 一般 → 管理者メールアドレス」です(RECOVERY_MODE_EMAIL 定数が定義されていればそちらが優先されます)。リンクの有効期間は既定で 1 日です。

合否ライン:functions.php を触る前に、そのメールアドレスが実際に受信できるかを 1 通テスト送信して確かめます。届かない環境ではこの手段は使えませんので、その場合は下の 2 か 3 を必ず用意してください。共用サーバーでメール送信が制限されている、管理者メールが退職者のアドレスのまま、といったケースは珍しくありません。

FTP/ファイルマネージャーで直接戻す

最も確実な方法です。管理画面が開けなくても、ファイルにさえ触れれば必ず戻せます。

  1. FTP クライアント、またはレンタルサーバーの管理画面にあるファイルマネージャーで接続する
  2. /wp-content/themes/<使用中のテーマ>/functions.php を開く
  3. 追加した行を削除して上書き保存する
  4. サイトを再読み込みして表示が戻ったことを確認する

合否ライン:編集を始める前に、手順 1〜2(接続してファイルを開くところまで)を一度通しておきます。エラーが出てから接続情報を探し始めると、探している間ずっとサイトは止まったままです。「接続できる」ことと「接続情報がどこかにあるはず」は別物です。

WP_DEBUG でエラーの行番号を特定する

どこを間違えたのか分からないときは、wp-config.php に次の 3 行を書きます。

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);

この設定にすると、エラーは画面ではなく wp-content/debug.log に記録されます。WP_DEBUG_DISPLAYfalse にしているのは、訪問者にエラー内容を見せないためです。詳細は WordPress 公式のデバッグ解説にまとまっています。ログの最終行には、次のような形でファイル名と行番号が出ます。

PHP Parse error:  syntax error, unexpected token ";" in /path/to/wp-content/themes/my-theme/functions.php on line 42

合否ライン:debug.log に functions.php の行番号が出ていれば、原因特定はそこで完了です。その行を消せば復旧します。ログにそもそも functions.php というファイル名が出てこない場合は、functions.php が原因ではありません。その場合は直前に入れたプラグインを疑ってください(ここで追跡は打ち切って構いません)。作業が終わったら WP_DEBUG は必ず false に戻します。

管理画面のテーマファイルエディターは使うべきか

「テーマファイルエディターで編集するとサイトが壊れて戻せなくなる」という説明も、現在は正確ではありません。WordPress 4.9 以降、PHP ファイルを保存するとコアが自作サイトに対して内部リクエストを送り、サイトが壊れていれば保存前の内容へ自動的に巻き戻します。実装コード上にも「ユーザーが自分でホワイトスクリーンを起こしていないか確認するためのループバックリクエスト」という趣旨のコメントが残っています。

ただし、巻き戻しが働くのは「致命的エラーで応答が返らない」場合だけです。構文としては正しいが挙動がおかしいコード、たとえばフックの優先度を間違えて別の機能を壊すようなものは検知されません。また、コード履歴が残らないため、変更を辿ることもできません。結論として「使うな」は妥当ですが、理由は「復旧できないから」ではなく「壊れ方によっては守られないうえ、変更履歴が残らないから」です。FTP が使える環境なら、FTP での編集を推奨します。


まとめ

functions.php で難しいのはコードを書くことではなく、そのコードが今の WordPress でまだ有効かどうかを見分けることです。この記事で置き換えた 4 か所は、どれも「古い記事のまま貼ると静かに失敗する」ものでした。

  • リビジョンの件数制限は functions.php では効かない(wp-config.php かフィルタを使う)
  • 絵文字 CSS の停止は WordPress 6.4 で対象フックが変わった
  • カスタム投稿タイプ・タクソノミーには show_in_rest が要る
  • ウィジェット登録の %1$s%2$s は省略できない

そして、貼ったら必ず各節の「確認する場所」を開いて、合格しているかを見てください。効いていないコードを効いているつもりで積み重ねるのが、一番厄介な状態です。テーマ制作全体の流れの中でこのファイルがどこに位置するのかは、WordPress入門ガイドから順に追えます。


よくある質問(FAQ)

Q. functions.php とは何ですか?

functions.php は、有効化中のテーマのフォルダに置かれ、WordPress の起動処理の中で自動的に読み込まれる PHP ファイルです。アクションフックやフィルターフックを使って、プラグインを入れずにテーマの機能を追加したり、WordPress の既定動作を止めたりできます。ただしテーマに属するファイルなので、テーマを切り替えると書いた内容はすべて効かなくなります。

Q. コードを貼ったのに反映されません。どこを見ればいいですか?

順番に 3 つを確認してください。まず、貼った functions.php が「今有効になっているテーマ(子テーマを使っているなら子テーマ)」のものかどうか。次に、wp-content/debug.log に PHP エラーが出ていないかどうか。最後に、そのコードが現行バージョンでも有効かどうかです。リビジョン件数の define や絵文字 CSS の停止のように、エラーは出ないのに何も起きない書き方が実際に存在します。

Q. 親テーマと子テーマ、どちらの functions.php に書くべきですか?

配布テーマを使っているなら子テーマです。親テーマに直接書くと、テーマのアップデートでファイルごと上書きされ、書いた内容が消えます。子テーマの functions.php は親テーマを置き換えるのではなく、親テーマより先に読み込まれて追加される仕組みなので、必要な行だけを書けば十分です。自作テーマの場合は、そのテーマの functions.php にそのまま書いて構いません。

Q. functions.php とプラグインはどう使い分けますか?

判断基準は「テーマを切り替えても残したい機能か」です。ロゴの出力変更、メニューの登録、ウィジェットエリアの追加のように、そのテーマの見た目に紐づくものは functions.php に書きます。一方、カスタム投稿タイプやカスタムタクソノミーのように、テーマを変えても残っていないと困るものはプラグインに置きます。テーマの functions.php に置いたままテーマを切り替えると、投稿タイプが未登録になり、データは DB に残っているのに管理画面から見えなくなります。

Q. カスタム投稿タイプを追加したのに、一覧ページが 404 になります。

リライトルールが更新されていないことが原因です。WordPress は URL の振り分け規則を DB に保存しており、投稿タイプを追加しただけでは反映されません。設定 → パーマリンクを開いて「変更を保存」を 1 回押せば解決します。設定内容そのものを変更する必要はありません。管理画面の左メニューには表示されるのにアーカイブ URL だけ 404 になる、という症状であれば、ほぼこれです。

Q. 管理画面のテーマファイルエディターで編集しても大丈夫ですか?

WordPress 4.9 以降、PHP ファイルを保存するとコアが内部リクエストで表示を確認し、致命的エラーが起きていれば保存前の内容に自動で巻き戻します。そのため「保存した瞬間に復旧不能になる」ことはほとんどありません。ただし巻き戻しが働くのは応答が返らないレベルの壊れ方だけで、構文は通るが挙動がおかしいコードは検知されず、変更履歴も残りません。FTP やファイルマネージャーが使える環境なら、そちらで編集することを推奨します。