functions.php とは、テーマに機能を追加するための PHP ファイルで、フック(add_action / add_filter)に関数を登録して WordPress の動きを変えます。 プラグインを増やさずに「管理画面を整える」「head の不要なタグを外す」「ショートコードを作る」といった調整ができ、子テーマに書けばテーマ更新後もそのまま残ります。

この記事では、そのまま貼って使えるコード38本を用途別に整理し、各コードに「使うフック・効果・注意点」を付けました。さらに、PHP 8.4 上で WordPress を動かして全コードを読み込み、効果を curl や PHP で確認した出力を載せています。書き方を誤ったときの白い画面(重大なエラー)も実際に起こし、表示されるメッセージ、管理者に届くメールの中身、復旧の手順までまとめました。

functions.php便利コードの早見表

まずはこの表で「やりたいこと」を探し、No. の見出しへ進んでください。 「種類」は A = add_action、F = add_filter、S = add_shortcode です。

No. やりたいこと 使うフック・関数 種類
01 管理者以外は管理バーを隠す show_admin_bar F
02 ダッシュボードの標準ウィジェットを外す wp_dashboard_setup A
03 ダッシュボードに手順メモを置く wp_dashboard_setup A
04 管理画面フッターの文言を変える admin_footer_text F
05 投稿一覧にアイキャッチ列を足す manage_post_posts_columns ほか F / A
06 管理者以外のメニューを減らす admin_menu A
07 ログイン画面ロゴのリンク先を変える login_headerurl / login_headertext F
08 管理画面の特定ページだけ CSS を読む admin_enqueue_scripts A
09 抜粋の長さと末尾記号を変える excerpt_length / excerpt_more F
10 アイキャッチと画像サイズを追加する after_setup_theme A
11 サイト内検索を投稿だけにする pre_get_posts A
12 カテゴリー一覧の表示件数を変える pre_get_posts A
13 本文の最後に案内ボックスを足す the_content F
14 カスタム投稿タイプを追加する init + register_post_type A
15 カスタムタクソノミーを追加する init + register_taxonomy A
16 外部リンクを新しいタブで開く the_content + WP_HTML_Tag_Processor F
17 絵文字スクリプトを読み込まない init + remove_action A
18 generator・RSD・shortlink を外す init + remove_action A
19 title の区切り文字を変える document_title_separator F
20 404 と日付アーカイブを noindex にする wp_robots F
21 最小限の OGP を出す wp_head A
22 アーカイブ見出しの「カテゴリー:」を外す get_the_archive_title_prefix F
23 XML-RPC とピンバックを止める xmlrpc_enabled / xmlrpc_methods / wp_headers F
24 ユーザー名が URL や REST API で見えないようにする template_redirect / rest_endpoints A / F
25 ログイン失敗メッセージを汎用にする login_errors F
26 管理者以外のアップロード形式を絞る upload_mimes F
27 リビジョンの保存数を決める wp_revisions_to_keep F
28 Heartbeat の間隔を延ばす heartbeat_settings F
29 大きな画像の縮小上限を変える big_image_size_threshold F
30 自作 JS を defer で読み込む wp_enqueue_scripts(strategy) A
31 今年の西暦を出す [year] add_shortcode S
32 ボタンを出す [button] add_shortcode + shortcode_atts S
33 ログイン中だけ表示する [members] add_shortcode S
34 特定の投稿タイプだけクラシックエディタにする use_block_editor_for_post_type F
35 投稿で使えるブロックを絞る allowed_block_types_all F
36 ブロックパターンを登録する init + register_block_pattern A
37 ブロックスタイルを追加する init + register_block_style A
38 エディタの見た目を公開画面に寄せる after_setup_theme + add_editor_style A

関数名にはすべて mytheme_ という接頭辞(プレフィックス)を付けています。 自分のサイト名などに置き換えて使ってください(理由は「つまずきやすい書き方」で説明します)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「functions.phpカスタマイズ コピペ集|便利コード38選【2026年版】」

この記事の検証環境と確認範囲

コードは全38本を構文チェックし、実際の WordPress に読み込んで効果を確認しました。 WordPress 本体は配布サイトからダウンロードできない環境だったため、npm で配布されている WordPress Playground のビルドに含まれる WordPress 本体を、PHP 8.4 の組み込みサーバーと SQLite で動かしています。

項目 内容
PHP 8.4.21(CLI、php -S 127.0.0.1:7270 で起動)
WordPress 6.7-alpha-58716(npm @wp-playground/wordpress-builds 0.9.19 に同梱の nightly)
DB SQLite(同梱の SQLite Database Integration 1.8.0)
テーマ Twenty Twenty-Four の子テーマ(tt4-child)に全コードを読み込み
構文チェック 全38本+子テーマ用コードを php -l で確認(エラー 0)
フックの確認 npm @wp-hooks/wordpress-core 1.13.0(WordPress 6.9.0 までのフック一覧)で、使ったフックがすべて存在することを確認
動作確認 curl で HTML・HTTP ヘッダーを取得、PHP から apply_filters() などで値を確認

最新の WordPress は 7.1(2026年8月19日リリース)です。 7.0(2026年5月20日)で最低 PHP は 7.4 になり、公式の推奨は PHP 8.3 以上です。この記事のコードは 7.0/7.1 の本体では実行していません。使っているフックは長く使われている安定したものですが、貼った後は自分のサイトで表示を確認してください。なお、6.9 で絵文字検出スクリプトは head からフッターへ移りましたが、公式の開発者向けノートで remove_action( 'wp_head', 'print_emoji_detection_script', 7 ) は引き続き有効と説明されています。

書く前の準備:子テーマ・バックアップ・Code Snippets

どこに書くかを決める

テーマ本体(親テーマ)の functions.php に直接書くと、テーマを更新したときに上書きされて消えます。 書き場所は次の4つから選びます。

書き場所 テーマ更新後 テーマ変更後 向いている用途
親テーマの functions.php 消える 効かない 自作テーマを自分で管理している場合
子テーマの functions.php 残る 効かない 見た目・表示に関わるコード
Code Snippets プラグイン 残る 残る 管理画面から手軽に管理したい場合
mu-plugins(wp-content/mu-plugins/) 残る 残る テーマに関係なく常に効かせたい設定

目安は「表示に関わるものは子テーマ、サイト全体の設定(セキュリティなど)はプラグイン側」です。 テーマを乗り換えるとテーマ内の functions.php は読み込まれなくなるため、XML-RPC の停止やユーザー名の非公開などは mu-plugins や Code Snippets に置くと乗り換え後も効き続けます。

子テーマを作る(ブロックテーマ)

子テーマは「Template: に親テーマのフォルダ名を書いた style.css」があれば成立します。 wp-content/themes/ に新しいフォルダ(例:tt4-child)を作り、次の2ファイルを置いて、管理画面の「外観 → テーマ」で有効化します。

/*
Theme Name: TT4 Child
Template: twentytwentyfour
Version: 1.0.0
*/
<?php
// 子テーマの functions.php:inc/ 以下のファイルをまとめて読み込む
foreach ( glob( get_stylesheet_directory() . '/inc/*.php' ) as $file ) {
    require_once $file;
}

この記事の検証では、上の functions.php から inc/01_admin_bar.php 〜 inc/38_editor_style.php を読み込みました。 1機能1ファイルに分けると、問題が起きたときにファイル名を変えるだけで1機能ずつ止められます。

子テーマの functions.php は、親テーマの functions.php より先に読み込まれます。 WordPress 本体(wp-settings.php)は wp_get_active_and_valid_themes() が返す順に functions.php を include し、その順は「子テーマ → 親テーマ」です。親テーマが if ( ! function_exists( '...' ) ) で囲んでいる関数(Twenty Twenty-Four なら twentytwentyfour_block_styles など)は、子テーマで同じ名前の関数を定義すると差し替えられます。

子テーマを作る(クラシックテーマ)

クラシックテーマでは、親テーマの style.css を子テーマから読み込むのが一般的です。 ブロックテーマ(theme.json でデザインを持つテーマ)では不要です。

// クラシックテーマの子テーマ:親テーマの style.css → 子テーマの style.css の順に読み込む
add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_styles' );
function mytheme_enqueue_styles() {
    $parent = wp_get_theme()->parent();
    wp_enqueue_style(
        'mytheme-parent',
        get_template_directory_uri() . '/style.css',
        array(),
        $parent ? $parent->get( 'Version' ) : null
    );
    wp_enqueue_style(
        'mytheme-child',
        get_stylesheet_uri(),
        array( 'mytheme-parent' ),
        wp_get_theme()->get( 'Version' )
    );
}

検証環境で読み込んだときの出力です(親 → 子の順に並びます)。

<link rel='stylesheet' id='mytheme-parent-css' href='http://127.0.0.1:7270/wp-content/themes/twentytwentyfour/style.css?ver=1.1' media='all' />
<link rel='stylesheet' id='mytheme-child-css' href='http://127.0.0.1:7270/wp-content/themes/tt4-child/style.css?ver=1.0.0' media='all' />

追記前のバックアップ手順

functions.php は1文字の誤りでサイト全体が表示されなくなることがあるファイルです。 追記の前に次を済ませておくと、何かあっても数分で戻せます。

順番 やること 理由
1 今の functions.php をダウンロードして保存(例:functions.php.20261002) 元に戻すときに上書きするため
2 FTP/SFTP またはサーバーのファイルマネージャーに入れることを確かめる 管理画面に入れなくなったときの復旧経路
3 管理者メールアドレス(設定 → 一般)が受信できるか確かめる リカバリーモードのリンクが届く先
4 可能ならステージング環境で先に試す 公開中のサイトへの影響をなくす

Code Snippets で運用する場合

Code Snippets は、functions.php を編集せずに管理画面からコードを追加・有効化・無効化できるプラグインです。 2026年10月時点の WordPress.org の配布ページでは、バージョン 3.10.2、有効インストール数 100万以上、PHP 7.4 以上が必要です。この記事のコードは、<?php の行を除いた部分をそのまま1スニペットとして登録できます。

スニペットでエラーが出たときは「セーフモード」で全スニペットを一時停止できます。 公式ドキュメントの方法は次の2つです。

// wp-config.php の「編集が必要なのはここまでです」の行より上に追記
define( 'CODE_SNIPPETS_SAFE_MODE', true );

管理者でログインできる場合は、URL の末尾に &snippets-safe-mode=1(クエリがない URL なら ?snippets-safe-mode=1)を付けても一時停止できます。セーフモードは問題のスニペットを自動で無効化するのではなく、全体を止めて管理画面に入れるようにする仕組みなので、原因のスニペットを無効化したら定数を外します。

add_action / add_filter と優先度の基本

action と filter の違い

action は「決まったタイミングで処理を足す」、filter は「値を受け取って加工し、return で返す」フックです。

項目 add_action add_filter
役割 タイミングに処理を追加 値を加工して返す
return 不要 必須(返さないと値が null になる)
例 wp_head で meta タグを出力 the_content で本文に追記
外す関数 remove_action remove_filter
書式 add_action( フック名, 関数, 優先度, 引数の数 ) add_filter( フック名, 関数, 優先度, 引数の数 )
flowchart LR
    A[WordPress 本体] -->|do_action wp_head| B[登録された関数を<br>優先度の小さい順に実行]
    A -->|apply_filters the_content| C[関数1: 値を加工して return]
    C --> D[関数2: 受け取った値をさらに加工]
    D --> E[最終的な値が表示される]

優先度と引数の数を確かめる

優先度は小さい数字ほど先に実行され、省略すると 10 です。同じ優先度なら登録した順に実行されます。 第4引数(受け取る引数の数)は省略すると 1 なので、2つ目以降の引数を使うときは指定が必要です。次のコードを WordPress 読み込み後に実行しました。

<?php
// 優先度
add_filter( 'demo_title', function ( $t ) { return $t . ' [A:10]'; } );           // 既定 10
add_filter( 'demo_title', function ( $t ) { return $t . ' [B:5]'; }, 5 );
add_filter( 'demo_title', function ( $t ) { return $t . ' [C:20]'; }, 20 );
add_filter( 'demo_title', function ( $t ) { return $t . ' [D:10]'; } );           // 同じ優先度は登録順
echo apply_filters( 'demo_title', 'タイトル' ), "\n";

// 引数の数
add_filter( 'demo_two', function ( $a, $b = '(未受け取り)' ) { return "$a / $b"; } );
echo apply_filters( 'demo_two', '第1引数', '第2引数' ), "\n";
add_filter( 'demo_two2', function ( $a, $b = '(未受け取り)' ) { return "$a / $b"; }, 10, 2 );
echo apply_filters( 'demo_two2', '第1引数', '第2引数' ), "\n";

// remove_action は優先度まで一致させる
add_action( 'demo_head', 'x_func', 7 );
function x_func() {}
var_dump( remove_action( 'demo_head', 'x_func' ) );    // 優先度 10 を指定したことになる
var_dump( remove_action( 'demo_head', 'x_func', 7 ) );

実行結果(PHP 8.4.21):

タイトル [B:5] [A:10] [D:10] [C:20]
第1引数 / (未受け取り)
第1引数 / 第2引数
bool(false)
bool(true)

標準の処理を外すときは、本体が登録したときと同じ優先度を指定します。 例えば絵文字のスクリプトは本体(default-filters.php)で add_action( 'wp_head', 'print_emoji_detection_script', 7 ) と登録されているため、外すときも 7 を書きます。優先度を省くと false が返り、何も外れません。

優先度の使い分け 例
小さくする(1〜9) 他の処理より先に値を整えたい、head の上のほうに出したい
既定(10) ふつうの追加
大きくする(11〜999) 他のプラグインの加工が終わった後に最終調整したい、メニューを確実に消したい

管理画面のカスタマイズ

01 管理者以外は管理バーを隠す

フック:show_admin_bar(filter)/効果:フロント画面上部の黒いバーを管理者だけに表示。

// 管理者以外はフロント側の管理バーを表示しない
add_filter( 'show_admin_bar', 'mytheme_show_admin_bar' );
function mytheme_show_admin_bar( $show ) {
    if ( ! current_user_can( 'manage_options' ) ) {
        return false;
    }
    return $show;
}

確認:管理者でログインしてトップページを開くと id="wpadminbar" が 1 件、編集者ユーザーでは 0 件でした。current_user_can() には権限名(manage_options など)を渡します。 権限グループ名(administrator)を渡す書き方は公式に推奨されていません。

02 ダッシュボードの標準ウィジェットを外す

フック:wp_dashboard_setup(action)/効果:「WordPress イベントとニュース」「クイックドラフト」「ようこそ」パネルを非表示。

// ダッシュボードの標準ウィジェットを整理する
add_action( 'wp_dashboard_setup', 'mytheme_clean_dashboard' );
function mytheme_clean_dashboard() {
    remove_meta_box( 'dashboard_primary', 'dashboard', 'side' );     // WordPress イベントとニュース
    remove_meta_box( 'dashboard_quick_press', 'dashboard', 'side' ); // クイックドラフト
    remove_action( 'welcome_panel', 'wp_welcome_panel' );            // ようこそパネル
}

確認:ダッシュボードの HTML で3つの ID がいずれも 0 件になりました。ウィジェットの ID は開発者ツールで各ボックスの id を見ると調べられます。

03 ダッシュボードに手順メモを置く

フック:wp_dashboard_setup(action)+ wp_add_dashboard_widget/効果:更新担当者向けのメモを常に表示。

// ダッシュボードに「更新手順メモ」ウィジェットを追加する
add_action( 'wp_dashboard_setup', 'mytheme_add_dashboard_widget' );
function mytheme_add_dashboard_widget() {
    wp_add_dashboard_widget(
        'mytheme_howto',
        'サイト更新の手順',
        'mytheme_render_dashboard_widget'
    );
}
function mytheme_render_dashboard_widget() {
    echo '<ol>';
    echo '<li>下書き保存してプレビューで確認</li>';
    echo '<li>アイキャッチ画像と抜粋を設定</li>';
    echo '<li>担当者に確認を依頼してから公開</li>';
    echo '</ol>';
}

確認:ダッシュボードに id="mytheme_howto" のボックスが追加されました。複数人でサイトを更新するときの手順共有に便利です。

04 管理画面フッターの文言を変える

フック:admin_footer_text(filter)/効果:画面左下の「WordPress のご利用ありがとうございます。」を差し替え。

// 管理画面フッターの文言を変える
add_filter( 'admin_footer_text', 'mytheme_admin_footer_text' );
function mytheme_admin_footer_text( $text ) {
    return 'お問い合わせは サイト管理チーム(内線 1234)まで';
}

確認:ダッシュボード下部に「お問い合わせは サイト管理チーム(内線 1234)まで」と表示されました。

05 投稿一覧にアイキャッチ列を足す

フック:manage_post_posts_columns(filter)+ manage_post_posts_custom_column(action)/効果:一覧で画像の設定漏れがひと目でわかる。

// 投稿一覧に「アイキャッチ」列を追加する
add_filter( 'manage_post_posts_columns', 'mytheme_add_thumb_column' );
function mytheme_add_thumb_column( $columns ) {
    $new = array();
    foreach ( $columns as $key => $label ) {
        if ( 'title' === $key ) {
            $new['mytheme_thumb'] = 'アイキャッチ';
        }
        $new[ $key ] = $label;
    }
    return $new;
}
add_action( 'manage_post_posts_custom_column', 'mytheme_render_thumb_column', 10, 2 );
function mytheme_render_thumb_column( $column, $post_id ) {
    if ( 'mytheme_thumb' !== $column ) {
        return;
    }
    if ( has_post_thumbnail( $post_id ) ) {
        echo get_the_post_thumbnail( $post_id, array( 60, 60 ) );
    } else {
        echo '—';
    }
}

確認:投稿一覧の列見出しが mytheme_thumb → title → author → categories → tags の順になり、画像のない投稿には「—」と表示されました。フック名の post の部分を投稿タイプ名に変えると、固定ページ(manage_page_posts_columns)やカスタム投稿タイプにも使えます。 列の追加は filter なので return を忘れないようにします。

06 管理者以外のメニューを減らす

フック:admin_menu(action、優先度 999)/効果:編集者などに不要なメニューを見せない。

// 管理者以外には「コメント」「ツール」メニューを表示しない
add_action( 'admin_menu', 'mytheme_hide_menus', 999 );
function mytheme_hide_menus() {
    if ( current_user_can( 'manage_options' ) ) {
        return;
    }
    remove_menu_page( 'edit-comments.php' );
    remove_menu_page( 'tools.php' );
}

確認:編集者でログインすると「コメント」「ツール」メニューが 0 件、管理者では表示されたままでした。メニューを隠しても URL を直接開けばページは表示できます。 操作そのものを制限したい場合は、権限(ロール)の設定で行います。

07 ログイン画面ロゴのリンク先を変える

フック:login_headerurl / login_headertext(filter)/効果:ロゴのリンク先を wordpress.org から自サイトへ。

// ログイン画面のロゴのリンク先と文言をサイトに合わせる
add_filter( 'login_headerurl', 'mytheme_login_headerurl' );
function mytheme_login_headerurl() {
    return home_url( '/' );
}
add_filter( 'login_headertext', 'mytheme_login_headertext' );
function mytheme_login_headertext() {
    return get_bloginfo( 'name' );
}

確認:ログイン画面の見出しが <h1><a href="http://127.0.0.1:7270/">My WordPress Website</a> になりました。login_headertext は WordPress 5.2 から使えるフックです(以前の login_headertitle は 5.2 で非推奨)。

08 管理画面の特定ページだけ CSS を読む

フック:admin_enqueue_scripts(action)/効果:必要な画面にだけ CSS を読み込む。

// 管理画面だけに読み込む CSS(子テーマの admin.css)
add_action( 'admin_enqueue_scripts', 'mytheme_admin_css' );
function mytheme_admin_css( $hook_suffix ) {
    if ( 'edit.php' !== $hook_suffix ) { // 投稿一覧画面だけ
        return;
    }
    wp_enqueue_style(
        'mytheme-admin',
        get_stylesheet_directory_uri() . '/admin.css',
        array(),
        filemtime( get_stylesheet_directory() . '/admin.css' )
    );
}

確認:投稿一覧(edit.php)では id='mytheme-admin-css' の link タグが出力され、ダッシュボード(index.php)では出力されませんでした。引数の $hook_suffix で画面を判定でき、filemtime() をバージョンにするとファイル更新時にキャッシュが自動で切り替わります。

投稿・表示のカスタマイズ

09 抜粋の長さと末尾記号を変える

フック:excerpt_length / excerpt_more(filter)/効果:一覧に出る抜粋の長さと「[…]」を変更。

// 抜粋の長さと末尾の記号を変える
add_filter( 'excerpt_length', 'mytheme_excerpt_length', 20 );
function mytheme_excerpt_length( $length ) {
    return 80;
}
add_filter( 'excerpt_more', 'mytheme_excerpt_more' );
function mytheme_excerpt_more( $more ) {
    return '…';
}

確認:英単語 200 個の本文で get_the_excerpt() を呼ぶと、80 語+「…」になりました(英語ロケールで確認)。日本語サイトでは抜粋の長さが「語数」ではなく「文字数」で数えられます。 これは日本語翻訳で単語数の数え方が characters_excluding_spaces(空白を除く文字数)に設定されているためで、80 なら約 80 文字です(日本語ロケールでは未実行)。手動で「抜粋」欄に書いた文章にはこの長さは適用されません。優先度を 20 にしているのは、テーマ側が 10 で同じフックを使っていても後から上書きするためです。

10 アイキャッチと画像サイズを追加する

フック:after_setup_theme(action)/効果:アイキャッチ機能を有効化し、カード用の 640×360 の画像を自動生成。

// アイキャッチを有効にし、一覧用の画像サイズを追加する
add_action( 'after_setup_theme', 'mytheme_setup' );
function mytheme_setup() {
    add_theme_support( 'post-thumbnails' );
    add_image_size( 'mytheme-card', 640, 360, true ); // 16:9 で切り抜き
}

確認:current_theme_supports( 'post-thumbnails' ) が true、wp_get_registered_image_subsizes() に {"width":640,"height":360,"crop":true} が登録されました。追加したサイズは、追加後にアップロードした画像から作られます。 既存の画像にも作りたいときは、画像を再生成するプラグインや WP-CLI の wp media regenerate を使います。

11 サイト内検索を投稿だけにする

フック:pre_get_posts(action)/効果:検索結果から固定ページやカスタム投稿タイプを外す。

// サイト内検索の対象を「投稿」だけにする
add_action( 'pre_get_posts', 'mytheme_search_posts_only' );
function mytheme_search_posts_only( $query ) {
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }
    if ( $query->is_search() ) {
        $query->set( 'post_type', 'post' );
    }
}

確認:「お知らせ」で検索すると、投稿「備品管理のお知らせ」の 1 件だけになり、同じ語を含むカスタム投稿タイプ(news)の記事は出なくなりました。メインクエリの post_type は 'post' です。is_admin() と is_main_query() の判定を入れると、管理画面やウィジェットの一覧に影響しません。

12 カテゴリー一覧の表示件数を変える

フック:pre_get_posts(action)/効果:「設定 → 表示設定」の件数をページの種類ごとに変える。

// カテゴリー一覧だけ 1ページの表示件数を 12 件にする
add_action( 'pre_get_posts', 'mytheme_category_per_page' );
function mytheme_category_per_page( $query ) {
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }
    if ( $query->is_category() ) {
        $query->set( 'posts_per_page', 12 );
    }
}

is_category() の部分を is_tag()、is_post_type_archive( 'news' )、is_search() などに変えると、他の一覧ページにも応用できます。テンプレート内で query_posts() を使って件数を変えるより、pre_get_posts で変えるほうがページ送りの計算もそろいます。

13 本文の最後に案内ボックスを足す

フック:the_content(filter)/効果:すべての投稿の本文末尾に共通の文章を追加。

// 投稿本文の最後に案内ボックスを追加する
add_filter( 'the_content', 'mytheme_append_box' );
function mytheme_append_box( $content ) {
    if ( ! is_singular( 'post' ) || ! in_the_loop() || ! is_main_query() ) {
        return $content;
    }
    $box  = '<aside class="mytheme-box">';
    $box .= '<p>最後まで読んでいただき、ありがとうございます。</p>';
    $box .= '</aside>';
    return $content . $box;
}

確認:投稿ページの HTML に <aside class="mytheme-box"><p>最後まで読んでいただき、ありがとうございます。</p></aside> が出力されました。in_the_loop() と is_main_query() で判定すると、サイドバーや関連記事の抜粋に二重で付くことを防げます。

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

フック:init(action)+ register_post_type/効果:「お知らせ」など投稿とは別の種類の記事を作れる。

// カスタム投稿タイプ「お知らせ(news)」を追加する
add_action( 'init', 'mytheme_register_news' );
function mytheme_register_news() {
    register_post_type(
        'news',
        array(
            'label'         => 'お知らせ',
            'public'        => true,
            'has_archive'   => true,
            'menu_position' => 5,
            'menu_icon'     => 'dashicons-megaphone',
            'show_in_rest'  => true, // ブロックエディタで編集するために必要
            'supports'      => array( 'title', 'editor', 'thumbnail', 'excerpt' ),
            'rewrite'       => array( 'slug' => 'news' ),
        )
    );
}

確認:news の記事を作成し、/?post_type=news の一覧に表示されました。show_in_rest => true がないと、その投稿タイプはクラシックエディタで開かれます。 追加後に URL が 404 になるときは、「設定 → パーマリンク」を開いて「変更を保存」を押すとリライトルールが更新されます。

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

フック:init(action)+ register_taxonomy/効果:お知らせに専用の分類(種別)を付ける。

// お知らせ用のカテゴリー「お知らせ種別」を追加する
add_action( 'init', 'mytheme_register_news_type' );
function mytheme_register_news_type() {
    register_taxonomy(
        'news_type',
        'news',
        array(
            'label'        => 'お知らせ種別',
            'hierarchical' => true,  // true = カテゴリー型、false = タグ型
            'show_in_rest' => true,
            'rewrite'      => array( 'slug' => 'news-type' ),
        )
    );
}

hierarchical を true にするとカテゴリーのようなチェックボックス、false にするとタグのような入力欄になります。 ブロックエディタのサイドバーに表示するには、投稿タイプと同じく show_in_rest => true が必要です。

16 外部リンクを新しいタブで開く

フック:the_content(filter)+ WP_HTML_Tag_Processor(WordPress 6.2 以降の HTML API)/効果:本文中の外部リンクに target="_blank" と rel="noopener" を付ける。

// 本文中の外部リンクを新しいタブで開き、rel="noopener" を付ける(WP 6.2+ の HTML API)
add_filter( 'the_content', 'mytheme_external_links', 20 );
function mytheme_external_links( $content ) {
    if ( ! class_exists( 'WP_HTML_Tag_Processor' ) ) {
        return $content;
    }
    $home = wp_parse_url( home_url(), PHP_URL_HOST );
    $p    = new WP_HTML_Tag_Processor( $content );
    while ( $p->next_tag( 'a' ) ) {
        $href = $p->get_attribute( 'href' );
        if ( ! is_string( $href ) ) {
            continue;
        }
        $host = wp_parse_url( $href, PHP_URL_HOST );
        if ( $host && $host !== $home ) {
            $p->set_attribute( 'target', '_blank' );
            $p->set_attribute( 'rel', 'noopener' );
        }
    }
    return $p->get_updated_html();
}

確認:本文にサイト内リンクと外部リンクを1つずつ入れた投稿の出力です。

<a rel="noopener" target="_blank" href="https://example.org/guide">外部ガイド</a>
<a href="http://127.0.0.1:7270/?page_id=2">サイト内ページ</a>

正規表現での置き換えと違い、HTML API は属性の順番や引用符が違っても正しく処理できます。 既存の rel(例:nofollow)は上書きされるため、残すなら get_attribute( 'rel' ) で取得して足し合わせます。

SEO・head の整理

17 絵文字スクリプトを読み込まない

フック:init(action)で remove_action/効果:絵文字検出用の JavaScript とスタイルを出力しない。

// 絵文字用のスクリプトとスタイルを読み込まない
add_action( 'init', 'mytheme_disable_emoji' );
function mytheme_disable_emoji() {
    remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
    remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
    remove_action( 'wp_print_styles', 'print_emoji_styles' );
    remove_action( 'admin_print_styles', 'print_emoji_styles' );
    remove_action( 'wp_enqueue_scripts', 'wp_enqueue_emoji_styles' );
    remove_action( 'admin_enqueue_scripts', 'wp_enqueue_emoji_styles' );
    remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
    remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
    remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
}

WordPress 6.4 以降、絵文字のスタイルは wp_enqueue_emoji_styles で読み込まれます。 古い記事でよく見る print_emoji_styles だけを外すコードでは、6.4 以降のスタイルが残ります。上のコードは新旧の両方を外しています。

18 generator・RSD・shortlink を外す

フック:init(action)で remove_action + the_generator(filter)/効果:head の使っていないタグを減らす。

// head 内の使っていないタグを整理する
add_action( 'init', 'mytheme_head_cleanup' );
function mytheme_head_cleanup() {
    remove_action( 'wp_head', 'wp_generator' );          // <meta name="generator">
    remove_action( 'wp_head', 'rsd_link' );              // EditURI(RSD)
    remove_action( 'wp_head', 'wp_shortlink_wp_head' );  // ?p=123 の shortlink
    remove_action( 'template_redirect', 'wp_shortlink_header', 11 );
}
// RSS 内の generator も出さない
add_filter( 'the_generator', '__return_empty_string' );

17 と 18 を入れる前後で、トップページの HTML を比べました。

項目 追加前 追加後
<meta name="generator" content="WordPress 6.7-alpha-58716" /> 1 0
<link rel="EditURI" ...>(RSD) 1 0
絵文字関連(_wpemojiSettings、wp-emoji-styles) 3 0
HTML のサイズ 84,753 バイト 83,249 バイト

Windows Live Writer 用の wlwmanifest_link は WordPress 6.3 で出力されなくなったため、今は外すコードが不要です。 古いコード集にある remove_action( 'wp_head', 'wlwmanifest_link' ) は、残っていても影響はありませんが、削除して整理できます。RSD はブログ編集アプリが XML-RPC を見つけるためのタグなので、アプリから投稿しているサイトでは残します。

19 title の区切り文字を変える

フック:document_title_separator(filter)/効果:<title> の「–」を「|」に。

// <title> の区切り文字を「|」にする(例:記事名|サイト名)
add_filter( 'document_title_separator', 'mytheme_title_separator' );
function mytheme_title_separator( $sep ) {
    return '|';
}

確認:

<!-- 追加前 -->
<title>備品管理のお知らせ &#8211; My WordPress Website</title>
<!-- 追加後 -->
<title>備品管理のお知らせ | My WordPress Website</title>

区切り文字の前後には WordPress が半角スペースを入れます。 スペースなしにしたい場合は document_title_parts や pre_get_document_title で組み立て直します。SEO プラグインを使っている場合は、プラグイン側の設定が優先されます。

20 404 と日付アーカイブを noindex にする

フック:wp_robots(filter、WordPress 5.7 以降)/効果:検索エンジンに登録しなくてよいページに noindex を付ける。

// 404 ページと日付アーカイブに noindex を付ける(WP 5.7+ の wp_robots)
add_filter( 'wp_robots', 'mytheme_robots' );
function mytheme_robots( $robots ) {
    if ( is_404() || is_date() ) {
        $robots['noindex'] = true;
        $robots['follow']  = true;
    }
    return $robots;
}

確認:追加前後で robots meta を比べました。

ページ 追加前 追加後
検索結果(/?s=test) noindex, follow, max-image-preview:large 変化なし
404(存在しない記事 ID) max-image-preview:large max-image-preview:large, noindex, follow
日付アーカイブ(/?m=2026) max-image-preview:large max-image-preview:large, noindex, follow

検索結果ページは、WordPress 5.7 以降の本体が wp_robots_noindex_search で最初から noindex にしています。 古いコード集にある「検索結果を noindex にするコード」は、今の WordPress では追加しなくても同じ結果になります。wp_robots は robots meta を配列で受け取るため、自分で <meta name="robots"> を echo するより重複が起きにくい方法です。

21 最小限の OGP を出す

フック:wp_head(action、優先度 5)/効果:SNS でシェアされたときのタイトル・説明・画像を指定。

// 投稿・固定ページに最小限の OGP を出力する(SEO プラグインを使わない場合)
add_action( 'wp_head', 'mytheme_ogp', 5 );
function mytheme_ogp() {
    if ( ! is_singular() ) {
        return;
    }
    $post  = get_queried_object();
    $title = get_the_title( $post );
    $desc  = has_excerpt( $post ) ? get_the_excerpt( $post ) : wp_trim_words( wp_strip_all_tags( $post->post_content ), 60, '…' );
    $image = get_the_post_thumbnail_url( $post, 'large' );

    printf( '<meta property="og:type" content="article">' . "\n" );
    printf( '<meta property="og:title" content="%s">' . "\n", esc_attr( $title ) );
    printf( '<meta property="og:description" content="%s">' . "\n", esc_attr( $desc ) );
    printf( '<meta property="og:url" content="%s">' . "\n", esc_url( get_permalink( $post ) ) );
    if ( $image ) {
        printf( '<meta property="og:image" content="%s">' . "\n", esc_url( $image ) );
    }
}

確認:抜粋を設定した投稿で次のように出力されました(アイキャッチ未設定のため og:image はなし)。

<meta property="og:type" content="article">
<meta property="og:title" content="備品管理のお知らせ">
<meta property="og:description" content="備品の貸し出しルールを更新しました。">
<meta property="og:url" content="http://127.0.0.1:7270/?p=5">

SEO プラグインが OGP を出している場合は、二重出力になるため使いません。 出力値は必ず esc_attr()/esc_url() で無害化(エスケープ)します。

22 アーカイブ見出しの「カテゴリー:」を外す

フック:get_the_archive_title_prefix(filter、WordPress 5.5 以降)/効果:アーカイブ見出しを「お知らせ」のようにすっきりさせる。

// アーカイブ見出しの「カテゴリー: 」「タグ: 」を外す(WP 5.5+)
add_filter( 'get_the_archive_title_prefix', '__return_empty_string' );

__return_empty_string は空文字を返す WordPress 標準の関数で、関数を自作しなくても済みます。 同じ仲間に __return_true、__return_false、__return_null、__return_zero、__return_empty_array があります。

セキュリティ

23 XML-RPC とピンバックを止める

フック:xmlrpc_enabled / xmlrpc_methods / wp_headers(filter)/効果:使っていない外部投稿の窓口を閉じる。

// XML-RPC を使わないサイトで無効にする
add_filter( 'xmlrpc_enabled', '__return_false' );
// ピンバック用のメソッドも外す
add_filter( 'xmlrpc_methods', 'mytheme_remove_pingback_methods' );
function mytheme_remove_pingback_methods( $methods ) {
    unset( $methods['pingback.ping'], $methods['pingback.extensions.getPingbacks'] );
    return $methods;
}
// レスポンスヘッダーの X-Pingback を出さない
add_filter( 'wp_headers', 'mytheme_remove_x_pingback' );
function mytheme_remove_x_pingback( $headers ) {
    unset( $headers['X-Pingback'] );
    return $headers;
}
確認項目 追加前 追加後
投稿ページの X-Pingback ヘッダー X-Pingback: http://127.0.0.1:7270/xmlrpc.php なし
system.listMethods のメソッド数 80 78(pingback 2つを除外)
ログインが必要なメソッド(wp.getUsersBlogs) 実行可能 XML-RPC services are disabled on this site.

xmlrpc_enabled を false にして止まるのは、ログインが必要なメソッドだけです。 ピンバックはログイン不要のため、xmlrpc_methods で別に外しています。スマートフォンアプリや外部サービスから XML-RPC で投稿している場合は使いません(Jetpack など一部のプラグインも XML-RPC を使います)。

24 ユーザー名が URL や REST API で見えないようにする

フック:template_redirect(action)/rest_endpoints(filter)/効果:ログイン名を外部から調べにくくする。

// ?author=1 でユーザー名入りの URL に移動しないようにする
add_action( 'template_redirect', 'mytheme_block_author_query', 5 );
function mytheme_block_author_query() {
    if ( ! is_admin() && isset( $_GET['author'] ) ) {
        wp_safe_redirect( home_url( '/' ), 301 );
        exit;
    }
}
// ログインしていない人には REST API のユーザー一覧を返さない
add_filter( 'rest_endpoints', 'mytheme_hide_user_endpoints' );
function mytheme_hide_user_endpoints( $endpoints ) {
    if ( is_user_logged_in() ) {
        return $endpoints;
    }
    unset( $endpoints['/wp/v2/users'], $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
    return $endpoints;
}
確認項目 追加前 追加後
/?author=1 200(著者アーカイブを表示) 301 でトップへ
未ログインで /?rest_route=/wp/v2/users ユーザー一覧の JSON("name":"admin" など) rest_no_route(404)
管理者ログイン中の同じ URL 一覧を返す 一覧を返す(変化なし)

ログイン中は REST API のユーザー一覧を残しているのは、ブロックエディタが投稿者の選択などで使うためです。 検証環境はパーマリンクが「基本」のため追加前は 200 でしたが、パーマリンクを設定したサイトでは /author/ユーザー名/ へ転送されます。ユーザー名を見えにくくしても、強いパスワードと二段階認証を組み合わせることが基本の対策です。

25 ログイン失敗メッセージを汎用にする

フック:login_errors(filter)/効果:「ユーザー名は合っている」ことがわかる文言を出さない。

// ログイン失敗時のメッセージを「どちらが違うか」がわからない文言にする
add_filter( 'login_errors', 'mytheme_login_errors' );
function mytheme_login_errors( $error ) {
    return 'ユーザー名またはパスワードが正しくありません。';
}

確認:存在するユーザー名で誤ったパスワードを入れたときの表示です。

追加前(英語ロケール) 追加後
Error: The password you entered for the username admin is incorrect. Lost your password? ユーザー名またはパスワードが正しくありません。

このフィルターはログイン画面のすべてのエラー表示を置き換えます。 「Cookie が無効」なども同じ文言になる点に注意します。

26 管理者以外のアップロード形式を絞る

フック:upload_mimes(filter、引数 2 つ)/効果:編集者などが ZIP や動画をアップロードできないようにする。

// 管理者以外は ZIP と動画をアップロードできないようにする
add_filter( 'upload_mimes', 'mytheme_upload_mimes', 10, 2 );
function mytheme_upload_mimes( $mimes, $user ) {
    if ( user_can( $user ? $user : get_current_user_id(), 'manage_options' ) ) {
        return $mimes;
    }
    unset( $mimes['zip'], $mimes['mp4|m4v'], $mimes['mov|qt'] );
    return $mimes;
}

確認(get_allowed_mime_types() と wp_check_filetype( 'backup.zip' ) の結果):

admin: zip=application/zip mp4=video/mp4 jpg=image/jpeg
  check backup.zip -> 'application/zip'
editor1: zip=none mp4=none jpg=image/jpeg
  check backup.zip -> false

WordPress は CSV、WebP、AVIF などを標準で許可していて、SVG と JSON は許可していません。 SVG は中にスクリプトを含められる形式のため、許可する場合は無害化(サニタイズ)するプラグインと組み合わせます。

functions.php ではなく wp-config.php に書く設定もあります。 例えば define( 'DISALLOW_FILE_EDIT', true ); は管理画面のファイルエディターを無効にし、define( 'WP_DEBUG', false ); は公開サイトでエラーを表示しない設定です。

パフォーマンス

27 リビジョンの保存数を決める

フック:wp_revisions_to_keep(filter)/効果:変更履歴が増え続けないようにする。

// リビジョン(変更履歴)の保存数を 10 件までにする
add_filter( 'wp_revisions_to_keep', 'mytheme_revisions_to_keep', 10, 2 );
function mytheme_revisions_to_keep( $num, $post ) {
    return 10;
}

確認:wp_revisions_to_keep() が 10 を返しました。wp-config.php の WP_POST_REVISIONS でも同じ設定ができ、フィルターを使うと $post->post_type で投稿タイプごとに変えられます。 既に保存されているリビジョンは、この設定だけでは削除されません。

28 Heartbeat の間隔を延ばす

フック:heartbeat_settings(filter)/効果:編集画面で定期的に送られる通信の回数を減らす。

// Heartbeat API の間隔を 60 秒にする(管理画面のサーバー負荷を下げる)
add_filter( 'heartbeat_settings', 'mytheme_heartbeat_settings' );
function mytheme_heartbeat_settings( $settings ) {
    $settings['interval'] = 60; // 秒(本体の JS で 1〜3600 の範囲に収められる)
    return $settings;
}

確認:apply_filters( 'heartbeat_settings', array() ) の interval が 60 になりました。Heartbeat は自動保存や「他の人が編集中」の表示に使われるため、止めるより間隔を延ばすほうが機能を保てます。 本体の JS は 1〜3600 秒の範囲に収めます。

29 大きな画像の縮小上限を変える

フック:big_image_size_threshold(filter、WordPress 5.3 以降)/効果:アップロードした大きな画像を自動で縮小する基準(既定 2560px)を変更。

// 大きな画像を自動縮小する上限を 2560px → 1920px に変える
add_filter( 'big_image_size_threshold', 'mytheme_big_image_threshold' );
function mytheme_big_image_threshold( $threshold ) {
    return 1920; // false を返すと縮小しない
}

確認:フィルターの戻り値が 1920 になりました。基準を超える画像は「-scaled」付きのファイル名で縮小版が作られ、元の画像も保存されます。 false を返すと縮小しません。

30 自作 JS を defer で読み込む

フック:wp_enqueue_scripts(action)+ wp_enqueue_script の第5引数(WordPress 6.3 以降の strategy)/効果:表示を止めずにスクリプトを読み込む。

// 子テーマの JS を defer 付きでフッターに読み込む(WP 6.3+ の strategy)
add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_assets' );
function mytheme_enqueue_assets() {
    $path = get_stylesheet_directory() . '/assets/main.js';
    wp_enqueue_script(
        'mytheme-main',
        get_stylesheet_directory_uri() . '/assets/main.js',
        array(),
        file_exists( $path ) ? filemtime( $path ) : null,
        array(
            'in_footer' => true,
            'strategy'  => 'defer',
        )
    );
}

確認:トップページに次のタグが出力されました。

<script src="http://127.0.0.1:7270/wp-content/themes/tt4-child/assets/main.js?ver=1790881956" id="mytheme-main-js" defer data-wp-strategy="defer"></script>

以前は script_loader_tag フィルターで文字列を置き換えて defer を付けていましたが、6.3 以降は第5引数の配列で指定できます。 strategy には defer と async を指定でき、依存関係(第3引数)に応じて WordPress が安全な読み込み方法を選びます。

ショートコード

31 今年の西暦を出す [year]

関数:add_shortcode/効果:フッターの著作権表示などで年を自動更新。

// [year] と書くと今年の西暦を表示する(例:© [year] サイト名)
add_shortcode( 'year', 'mytheme_sc_year' );
function mytheme_sc_year() {
    return esc_html( wp_date( 'Y' ) );
}

32 ボタンを出す [button]

関数:add_shortcode + shortcode_atts/効果:属性で URL と文言を指定できるボタン。

// [button url="/contact/" label="お問い合わせ"] でボタンを表示する
add_shortcode( 'button', 'mytheme_sc_button' );
function mytheme_sc_button( $atts ) {
    $atts = shortcode_atts(
        array(
            'url'   => home_url( '/' ),
            'label' => '詳しく見る',
        ),
        $atts,
        'button'
    );
    return sprintf(
        '<a class="mytheme-button" href="%s">%s</a>',
        esc_url( $atts['url'] ),
        esc_html( $atts['label'] )
    );
}

33 ログイン中だけ表示する [members]

関数:add_shortcode(囲み型)/効果:ログインしている人だけに文章を見せる。

// [members]ログイン中の人だけに見せる文[/members]
add_shortcode( 'members', 'mytheme_sc_members' );
function mytheme_sc_members( $atts, $content = '' ) {
    if ( ! is_user_logged_in() ) {
        return '<p>この内容はログインすると表示されます。</p>';
    }
    return do_shortcode( $content );
}

31〜33 を do_shortcode() でまとめて実行した結果です(未ログイン状態)。2つ目のボタンには、確認のためにわざと javascript: の URL と HTML タグを入れています。

echo do_shortcode( '© [year] Demo / [button url="/contact/" label="お問い合わせ"] / [button url="javascript:alert(1)" label="<b>x</b>"] / [members]社内向け[/members]' );
© 2026 Demo / <a class="mytheme-button" href="/contact/">お問い合わせ</a> / <a class="mytheme-button" href="">&lt;b&gt;x&lt;/b&gt;</a> / <p>この内容はログインすると表示されます。</p>

esc_url() は許可されていないスキーム(javascript: など)を空文字にし、esc_html() はタグを文字として表示します。 ショートコードは投稿者が属性を自由に書けるため、出力は必ずエスケープします。また、ショートコードの関数は echo ではなく return で返します。 echo すると本文の先頭など意図しない位置に出力されます。

ショートコードの書き方 ポイント
[year] 引数なし。wp_date() はサイトのタイムゾーン設定に従う
[button url="..." label="..."] shortcode_atts() で既定値を決め、第3引数にタグ名を渡すと shortcode_atts_button フィルターも使える
[members]...[/members] 囲み型。第2引数 $content に中身が入る。中のショートコードも動かすなら do_shortcode()

ブロックエディタでは「ショートコード」ブロックか段落の中にそのまま書けます。

ブロックエディタ

34 特定の投稿タイプだけクラシックエディタにする

フック:use_block_editor_for_post_type(filter)/効果:お知らせ(news)だけ従来の編集画面で書く。

// 「お知らせ(news)」だけクラシックエディタで編集する
add_filter( 'use_block_editor_for_post_type', 'mytheme_use_block_editor', 10, 2 );
function mytheme_use_block_editor( $use, $post_type ) {
    if ( 'news' === $post_type ) {
        return false;
    }
    return $use;
}

確認:news の編集画面ではクラシックエディタの要素(postdivrich、wp-editor-area)が出力され、通常の投稿ではブロックエディタが開きました。投稿ごとに切り替えたいときは、同じ考え方の use_block_editor_for_post フィルターを使います。

35 投稿で使えるブロックを絞る

フック:allowed_block_types_all(filter、WordPress 5.8 以降)/効果:ブロックの選択肢を減らし、書き方をそろえる。

// 投稿で使えるブロックを絞る(固定ページは制限しない)
add_filter( 'allowed_block_types_all', 'mytheme_allowed_blocks', 10, 2 );
function mytheme_allowed_blocks( $allowed, $context ) {
    if ( empty( $context->post ) || 'post' !== $context->post->post_type ) {
        return $allowed; // true = すべて許可
    }
    return array(
        'core/paragraph',
        'core/heading',
        'core/list',
        'core/list-item',
        'core/image',
        'core/quote',
        'core/table',
        'core/code',
        'core/buttons',
        'core/button',
    );
}

確認:投稿の編集コンテキストでは許可ブロックが 10 種類(core/paragraph、core/heading、core/list ...)になり、固定ページでは true(すべて許可)のままでした。リストやボタンのように「親ブロック」と「子ブロック」に分かれているものは、両方(core/list と core/list-item など)を許可します。 5.8 より前の allowed_block_types は非推奨です。

36 ブロックパターンを登録する

フック:init(action)+ register_block_pattern/効果:よく使うブロックの組み合わせをワンクリックで挿入。

// よく使う「お問い合わせ案内」をブロックパターンとして登録する
add_action( 'init', 'mytheme_register_patterns' );
function mytheme_register_patterns() {
    register_block_pattern_category( 'mytheme', array( 'label' => 'サイト共通' ) );
    register_block_pattern(
        'mytheme/contact-cta',
        array(
            'title'      => 'お問い合わせ案内',
            'categories' => array( 'mytheme' ),
            'content'    => '<!-- wp:group {"layout":{"type":"constrained"}} -->
<div class="wp-block-group"><!-- wp:paragraph -->
<p>ご不明な点はお気軽にお問い合わせください。</p>
<!-- /wp:paragraph -->
<!-- wp:buttons -->
<div class="wp-block-buttons"><!-- wp:button -->
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="/contact/">お問い合わせ</a></div>
<!-- /wp:button --></div>
<!-- /wp:buttons --></div>
<!-- /wp:group -->',
        )
    );
}

確認:WP_Block_Patterns_Registry で mytheme/contact-cta が登録済みになりました。content に入れるブロックの HTML は、エディタで作ったブロックを「コードエディター」表示に切り替えてコピーすると正確です。 ブロックテーマでは、子テーマの patterns/ フォルダに PHP ファイルを置く方法でも登録できます。

37 ブロックスタイルを追加する

フック:init(action)+ register_block_style/効果:段落ブロックのスタイル一覧に「注意書き」を追加。

// 段落ブロックに「注意書き」スタイルを追加する
add_action( 'init', 'mytheme_register_block_styles' );
function mytheme_register_block_styles() {
    register_block_style(
        'core/paragraph',
        array(
            'name'         => 'notice',
            'label'        => '注意書き',
            'inline_style' => '.is-style-notice{border-left:4px solid #d97706;background:#fffbeb;padding:1em;}',
        )
    );
}

確認:WP_Block_Styles_Registry から core/paragraph の notice を取得すると、ラベル「注意書き」が返りました。選ぶとブロックに is-style-notice クラスが付くので、CSS はこのクラス名に対して書きます。

38 エディタの見た目を公開画面に寄せる

フック:after_setup_theme(action)+ add_editor_style/効果:エディタの文字サイズや色を公開画面に近づけ、書きながら仕上がりを確認できる。

// ブロックエディタの見た目を公開画面に近づける(子テーマの editor-style.css)
add_action( 'after_setup_theme', 'mytheme_editor_style' );
function mytheme_editor_style() {
    add_theme_support( 'editor-styles' );
    add_editor_style( 'editor-style.css' );
}

確認:current_theme_supports( 'editor-styles' ) が true になりました。ブロックテーマでは theme.json の設定がエディタにも反映されるため、add_editor_style は theme.json で表せない細かな調整に使います。 パスは子テーマのフォルダからの相対パスで指定します。

白い画面(重大なエラー)の再現と復旧

わざとエラーを起こしてみる

functions.php の構文エラーは、サイト全体を表示できなくします。 子テーマの inc/ にセミコロンを1つ書き忘れたファイルを置いて試しました。

<?php
add_filter( 'excerpt_length', function ( $length ) {
    return 80
} );

php -l での構文チェック結果:

PHP Parse error:  syntax error, unexpected token "}", expecting ";" in .../inc/99_broken.php on line 4
Errors parsing .../inc/99_broken.php

このファイルを置いたままトップページを開いた結果です。

開いたページ HTTP 画面のメッセージ(英語ロケール)
トップページ 500 There has been a critical error on this website. Learn more about troubleshooting WordPress.
wp-login.php 500 There has been a critical error on this website. Please check your site admin email inbox for instructions. Learn more about troubleshooting WordPress.

日本語サイトでは「このサイトで重大なエラーが発生しました。」と表示されます。 WordPress 5.2 より前は何も表示されない「白い画面」になっていたため、今もこの状態を白い画面と呼ぶことがあります。

管理者に届くメール

管理画面やログイン画面でエラーが起きると、管理者メールアドレスに「リカバリーモード」のリンクが届きます。 トップページを開いただけでは送られず、wp-login.php を開いたときに送信されました。検証では送信の代わりにファイルへ記録しています(トークンは伏せています)。

TO: admin@localhost.com
SUBJECT: [My WordPress Website] Your Site is Experiencing a Technical Issue

WordPress has a built-in feature that detects when a plugin or theme causes a fatal error on your site, and notifies you with this automated email.

In this case, WordPress caught an error with your theme, TT4 Child.
...
http://127.0.0.1:7270/wp-login.php?action=enter_recovery_mode&rm_token=xxxxx&rm_key=xxxxx

To keep your site safe, this link will expire in 1 day. ...

Error Details
=============
An error of type E_PARSE was caused in line 4 of the file .../themes/tt4-child/inc/99_broken.php. Error message: syntax error, unexpected token "}", expecting ";"

メールには「どのテーマ(プラグイン)の、どのファイルの何行目か」が書かれています。 届く先を変えたいときは、wp-config.php に define( 'RECOVERY_MODE_EMAIL', 'web-admin@example.com' ); を書きます。

復旧の手順

最も確実なのは、FTP やファイルマネージャーで原因のファイルを元に戻す方法です。

順番 方法 手順
1 ファイルを戻す 保存しておいた functions.php をアップロードして上書き。inc/ に分けているなら、原因のファイル名を 99_broken.php.off のように変えるだけで読み込まれなくなる
2 リカバリーモード メールのリンクからログインすると、原因のテーマ・プラグインを止めた状態で管理画面に入れる。テーマファイルエディターで修正するか、別のテーマに切り替える
3 テーマを切り替える FTP で子テーマのフォルダ名を変えると、WordPress は既定のテーマに切り替えて表示を続ける
4 Code Snippets を使っていた場合 CODE_SNIPPETS_SAFE_MODE を true にして管理画面に入り、原因のスニペットを無効化

エラーの内容がわからないときは、wp-config.php でデバッグログを有効にします。 画面には出さず、ファイルにだけ記録する設定です。

// wp-config.php(「編集が必要なのはここまでです」より上)
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );      // wp-content/debug.log に記録
define( 'WP_DEBUG_DISPLAY', false ); // 画面には表示しない

検証時の wp-content/debug.log です(パスは一部省略)。

[01-Oct-2026 19:14:37 UTC] PHP Parse error:  syntax error, unexpected token "}", expecting ";" in .../themes/tt4-child/inc/99_broken.php on line 4

原因がわかったら、WP_DEBUG を false に戻し、debug.log を削除します。 debug.log は URL で直接開ける場所に作られるため、WP_DEBUG_LOG にファイルのパスを指定して公開ディレクトリの外に置く方法もあります。

エラーメッセージ別の原因と直し方

debug.log のメッセージ 主な原因 直し方
syntax error, unexpected token "}", expecting ";" セミコロンの書き忘れ 示された行の1つ前の行末を確認
syntax error, unexpected end of file { と } の数が合っていない、コピー範囲の欠け コードを最後の } まで貼り直す
Cannot redeclare function mytheme_setup() 同じ名前の関数を2回定義 接頭辞を変える、片方を削除
Call to undefined function ... 関数名の打ち間違い、まだ読み込まれていない関数を呼んだ フックの中で呼ぶ
Cannot modify header information - headers already sent ?> の後ろの空行、BOM 付き UTF-8 末尾の ?> を削除、BOM なしで保存
Function wp_enqueue_style was called incorrectly フックの外で CSS/JS を読み込んだ wp_enqueue_scripts の中で呼ぶ

つまずきやすい書き方と直し方

ファイル末尾の ?> と空行

PHP だけのファイルでは、末尾の ?> は書かないのが WordPress のコーディング規約です。 ?> の後ろに空行があると、その空行が HTML より先に出力されます。次のファイルを置き、出力バッファリング(output_buffering)を 0 にしたサーバーで試しました。

<?php
add_filter( "excerpt_more", "mytheme_more" );
function mytheme_more() { return "…"; }
?>

ログインを試すと、本来は 302 でダッシュボードへ転送されるところが 200 のままログイン画面に戻り、debug.log に次の警告が記録されました。

PHP Warning:  Cannot modify header information - headers already sent by (output started at .../tt4-child/inc/98_trailing.php:5) in .../wp-login.php on line 82

RSS フィード(/?feed=rss2)も先頭が改行で始まり、<?xml の前に空行が入りました。XML 宣言は文書の先頭に置く決まりがあるため、フィードリーダーによっては読み込めなくなります。直し方は「末尾の ?> を削除する」だけです。 サーバーで出力バッファリングが有効な場合は症状が表に出ないこともあるため、最初から書かない習慣にしておくと安心です。

関数名の衝突とプレフィックス

PHP では同じ名前の関数を2回定義すると致命的エラーになります。 10番のコードと同じ mytheme_setup を別ファイルで定義すると、次のエラーで HTTP 500 になりました。

PHP Fatal error:  Cannot redeclare function mytheme_setup() (previously declared in .../inc/10_theme_support.php:4) in .../inc/97_dup.php on line 2
書き方 衝突しやすさ 補足
function setup() 高い 他のテーマ・プラグインと重なりやすい
function mytheme_setup() 低い サイト名などの接頭辞を付ける(この記事の方式)
無名関数 function () {} なし 後から remove_filter で外せない
namespace MySite; +関数 なし フックには __NAMESPACE__ . '\\setup' の形で渡す

コード集から複数のコードを貼るときは、関数名が重ならないかを先に確認します。 同じフックに同じ処理を2回登録している場合(例:抜粋の長さを2か所で設定)は、エラーにはならず、優先度の大きいほうの値が使われます。

filter で return を書き忘れる

filter の関数が値を返さないと、その値は null になります。 本文に追記するつもりで return を書き忘れた例です。

<?php
$c = '<p>本文です</p>';

// 直す前:return がない
function bad_filter( $content ) { $content .= '<p>追記</p>'; }
add_filter( 'demo_content', 'bad_filter' );
var_dump( apply_filters( 'demo_content', $c ) );
remove_filter( 'demo_content', 'bad_filter' );

// 直した後
function good_filter( $content ) { return $content . '<p>追記</p>'; }
add_filter( 'demo_content', 'good_filter' );
var_dump( apply_filters( 'demo_content', $c ) );
NULL
string(32) "<p>本文です</p><p>追記</p>"

the_content で同じことをすると、本文が丸ごと表示されなくなります。 条件に合わないときも、受け取った値をそのまま return する形(13番のコードのように先頭で return $content;)にします。

フックの外で処理を書く

functions.php の一番外側に書いた処理は、WordPress の準備が整う前に実行されます。 CSS をフックの外で読み込んだときの debug.log です。

PHP Notice:  Function wp_enqueue_style was called <strong>incorrectly</strong>. Scripts and styles should not be registered or enqueued until the <code>wp_enqueue_scripts</code>, <code>admin_enqueue_scripts</code>, or <code>login_enqueue_scripts</code> hooks. This notice was triggered by the <code>mytheme-early</code> handle. ...
やりたいこと 書くフック
CSS/JS を読み込む wp_enqueue_scripts(管理画面は admin_enqueue_scripts)
テーマ機能・画像サイズ・メニュー位置の登録 after_setup_theme
投稿タイプ・タクソノミー・ショートコード・パターンの登録 init
ログイン状態や現在のページで分岐 template_redirect、wp、pre_get_posts など
管理画面のメニュー操作 admin_menu

追記前後のチェックリスト

貼る前と貼った後に、次の項目を順に確認すると安心です。

タイミング 確認すること
貼る前 子テーマ(または Code Snippets)に書こうとしている
貼る前 現在の functions.php を保存した
貼る前 FTP/ファイルマネージャーに入れる
貼る前 関数名の接頭辞を自分のサイト用に変えた
貼る前 使う WordPress のバージョン以上で動くフックか確認した(例:wp_robots は 5.7 以降)
貼った後 php -l functions.php またはエディターの構文チェックでエラーなし
貼った後 トップ・投稿・固定ページ・管理画面・ログイン画面を開いて表示を確認
貼った後 ブラウザの「ページのソースを表示」で head の出力を確認
貼った後 一般ユーザー(ログアウト状態)と管理者の両方で見え方を確認
貼った後 WP_DEBUG を有効にしたステージングで debug.log に警告が出ていない

よくある質問

Q. functions.php の冒頭に <?php は毎回必要ですか? A. ファイルの一番上に1回だけあれば十分です。既存の functions.php に追記するときは、この記事のコードの <?php 行を除いて、ファイルの末尾に貼ります。Code Snippets に登録するときも <?php は不要です。

Q. 子テーマの functions.php は親テーマの functions.php を上書きしますか? A. 上書きではなく、両方が読み込まれます。子テーマが先、親テーマが後です。親テーマの関数を差し替えられるのは、親テーマ側が function_exists() で囲んでいる関数か、フックで登録されていて remove_action() で外せる処理に限られます。

Q. コードを貼ったのに何も変わりません。どこを見ればよいですか? A. よくある原因は、(1) 有効化していないテーマのファイルを編集している、(2) キャッシュ系プラグインやサーバーのキャッシュが残っている、(3) テーマやプラグインが同じフックを後の優先度で上書きしている、の3つです。(3) の場合は、add_filter() の第3引数(優先度)を 20 や 99 に上げて試します。

Q. プラグインと functions.php は、どちらを使えばよいですか? A. 数行で済む調整は functions.php(または Code Snippets)、設定画面が必要なものや多くの機能をまとめて扱うもの(SEO 全般、フォーム、バックアップなど)はプラグインが向いています。同じ機能をプラグインとコードの両方で入れると重複するため、どちらか一方にそろえます。

まとめ

  • functions.php はフックに関数を登録してWordPressの動きを変えるファイルで、action は処理の追加、filter は値の加工(return 必須)に使います。
  • 書く場所は子テーマか Code Snippets。inc/ に1機能1ファイルで分けると、問題のある機能だけを止めやすくなります。
  • 優先度は小さいほど先に実行され、標準の処理を remove_action で外すときは登録時と同じ優先度を指定します。
  • 管理画面・投稿・SEO・セキュリティ・パフォーマンス・ショートコード・ブロックエディタの38本は、すべて実際の WordPress で効果を確認しました。
  • 絵文字は 6.4 以降の wp_enqueue_emoji_styles、defer は 6.3 以降の strategy、外部リンクは 6.2 以降の HTML API など、新しいバージョンの書き方を選ぶとコードが短く確実になります。
  • 重大なエラーが出たら、FTP で原因のファイルを戻すか、管理者メールのリカバリーモードで入る。原因は debug.log とメールの「Error Details」でわかります。
  • 末尾の ?> は書かない、関数名には接頭辞、出力はエスケープの3点を守ると、よくあるつまずきを避けられます。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「functions.phpカスタマイズ コピペ集|便利コード38選【2026年版】」

株式会社RJCでは、WordPress のフックの仕組みや安全なカスタマイズの書き方を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?