このサイトでは、ちょっとした PHP の処理を、Code Snippets というプラグインに入れて動かしていました。
有効なスニペットは 13 個ありました。
これを、テーマの中のファイル(functions/site-snippets.php)に、中身のまま移しました。
この記事では、止めずに切り替えるための形と、作業環境で確かめた結果をまとめます。
なぜテーマに移すのか
Code Snippets は、管理画面から PHP を書いて動かせる、便利なプラグインです。
ただ、このサイトのテーマは git で管理していて、push すると自動で公開される流れにしています。
スニペットだけが DB の中にあると、そこだけ流れから外れます。
| Code Snippets | テーマのファイル | |
|---|---|---|
| 置き場所 | DB(スニペットの表) | テーマのフォルダ |
| 変えた記録 | 残りにくい | git に残る。前に戻せる |
| 公開のしかた | 管理画面で保存すると、すぐ本番で動く | push すると自動で公開 |
| 管理画面から PHP を書き換えられるか | 書き換えられる | 書き換えられない |
git で管理できることと、管理画面から PHP を書き換える仕組みを減らすことが、移した理由です。
テーマを git などで管理していないサイトや、FTP でファイルを直すのが手間なサイトでは、Code Snippets は今でも便利でおすすめです。
このサイトは、テーマを git で管理しているので、そちらにまとめました。
そのまま移すと止まる
スニペットの中には、関数を作るものがあります。
WordPress は、プラグインを先に読み込み、そのあとでテーマの functions.php を読みます。
プラグインが有効なまま、テーマにも同じ関数を書くと、同じ名前の関数が 2 回作られます。
PHP は、同じ名前の関数を作り直せません。
「Cannot redeclare」という Fatal error になり、サイトが止まります。
テーマを公開してからプラグインを止めるまでのあいだも、サイトは動いていてほしいです。
そこで、「プラグインが有効なあいだは、テーマ側のファイルを読まない」形にしました。
移し方
1. 有効なスニペットを、順番どおりに書き出す
Code Snippets は、優先度の小さい順に、同じ優先度なら id の順にスニペットを動かします。
テーマのファイルにも、同じ順で並べました。
有効なものと順番は、作業環境の DB で次のように出しました(表の頭の wp_ は、サイトの設定に合わせて変えます)。
SELECT id, name, scope, priority FROM wp_snippets WHERE active = 1 ORDER BY priority, id;
| 書き方 | 役目 |
|---|---|
active = 1 |
有効なスニペットだけ |
scope |
どこで動かすか(どこでも・管理画面だけ・表のページだけ など) |
ORDER BY priority, id |
Code Snippets が動かす順に並べる |
このサイトの 13 個は、どれも「どこでも動かす」(global)で、優先度も全部 10 でした。
そのため、id の順に並べるだけで済みました。
「管理画面だけ」などのスニペットがあるときは、テーマ側で is_admin() などを使って分ける必要があります(このサイトにはなかったので、試していません)。
テーマのファイルは、次の形です(関数の名前は例です)。
<?php
// Code Snippets のプラグインに入れていた処理を、テーマに移したもの。
// 並びは Code Snippets と同じ(優先度 → id)。中身は元のまま。
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/* ---- id 8:(スニペットの名前)(優先度 10) ---- */
function my_example_head() {
// スニペットの中身をそのまま
}
add_action( 'wp_head', 'my_example_head' );
/* ---- id 9:(スニペットの名前)(優先度 10) ---- */
if ( ! function_exists( 'my_example_cache' ) ) {
function my_example_cache() {
// スニペットの中身をそのまま
}
}
// …(有効なスニペットの数だけ続く)
| 書き方 | 役目 |
|---|---|
if ( ! defined( 'ABSPATH' ) ) exit; |
このファイルを URL で直接開かれたときに、何もしないで終わる |
/* ---- id 8:… ---- */ |
Code Snippets の一覧の id と名前を見出しにする。あとで元と見比べられる |
| 中身 | スニペットのコードを、変えずにそのままコピーする |
中身は変えずにコピーしました。
直したいところがあっても、移すのとは別にして、あとで 1 つずつ直します。
2. functions.php で、読むかどうかを分ける
Code Snippets は、読み込まれると CODE_SNIPPETS_FILE という定数を作ります。
この定数があるかどうかで、プラグインが有効かを見分けます。
<?php
// Code Snippets から移した処理。
// Code Snippets のプラグインが有効なあいだは読まない(同じ関数が二重に作られて止まるため)。
// プラグインを止めると、こちらに切り替わる。
if ( ! defined( 'CODE_SNIPPETS_FILE' ) ) {
require_once ( dirname(__FILE__) . '/functions/site-snippets.php' );
}
| 書き方 | 役目 |
|---|---|
defined( 'CODE_SNIPPETS_FILE' ) |
Code Snippets が読み込まれていれば true |
if ( ! defined( … ) ) |
プラグインがないときだけ、中に進む |
require_once |
テーマ側のファイルを 1 回だけ読む |
| いちばん上に書く | テーマのほかの処理が、移した関数を使う前に読んでおく |
プラグインは、テーマより先に読み込まれます。
そのため、functions.php が動くときには、定数はもうできています。
3. 公開してから、プラグインを止める
| 順 | すること | 動いている処理 |
|---|---|---|
| 1 | テーマの変更を push する(自動で公開) | プラグインのスニペット(テーマ側は読まない) |
| 2 | Code Snippets のプラグインを止める | テーマ側のファイル |
| 3 | しばらく様子を見て、問題がなければ、プラグインを消す | テーマ側のファイル |
どの順のときも、同じ関数は 1 回しか作られません。
もし何かおかしければ、プラグインを有効に戻すだけで、元の動きに戻せます。
確かめた結果
このサイトの作業環境(PHP 8.3.32)で確かめました。
検証用スクリプトは、作業環境のテーマとは別の場所に置いて動かしました。
定数がどこで作られるか
Code Snippets の本体(3.10.2)を grep で探しました。
定数を作っているのは、本体のファイル code-snippets.php の 1 か所だけでした。
// Code Snippets の本体(code-snippets.php・3.10.2)の一部
if ( ! defined( 'CODE_SNIPPETS_FILE' ) && version_compare( phpversion(), '7.4', '>=' ) ) {
// …
define( 'CODE_SNIPPETS_FILE', __FILE__ );
// …
require_once dirname( __FILE__ ) . '/php/Core/load.php';
}
まだ定数がなく、PHP が 7.4 以上のときに、定数を作ってプラグインの本体を読み込みます。
プラグインを止めていれば、このファイルは読まれないので、定数もできません。
同じ関数を 2 回作ると止まるか
小さな試しのファイルで確かめました。
<?php
// first.php
function my_hello() { return 'first'; }
// second.php
function my_hello() { return 'second'; }
// run1.php:2 つとも読む
require __DIR__ . '/first.php';
require __DIR__ . '/second.php';
echo "not reached";
| 試したこと | 結果 |
|---|---|
| 同じ名前の関数を、2 つのファイルで作る | Fatal error: Cannot redeclare my_hello()(終了コード 255)。そのあとの行は動かない |
2 つ目を if ( ! function_exists( 'my_hello' ) ) で包む |
止まらない。1 つ目の関数が使われる(first) |
定数があるとき/ないときに、どちらが読まれるか
<?php
// run3.php:定数があるとき/ないときに、2 つ目のファイルを読むか
$mode = $argv[1] ?? 'off';
if ( 'on' === $mode ) {
define( 'CODE_SNIPPETS_FILE', __FILE__ ); // プラグインが有効なとき
require __DIR__ . '/first.php'; // プラグイン側で関数ができている
}
if ( ! defined( 'CODE_SNIPPETS_FILE' ) ) {
require_once __DIR__ . '/second.php'; // テーマ側
}
echo $mode, ': ', my_hello();
| 試したこと | 結果 |
|---|---|
| 定数なし(プラグインを止めたとき) | off: second(テーマ側のファイルが読まれた) |
| 定数あり(プラグインが有効なとき) | on: first(テーマ側は読まれず、エラーもなし) |
作業環境の WordPress で
次に、作業環境の WordPress を読み込む検証用スクリプトで、本物のテーマとプラグインで確かめました。
作業環境では、Code Snippets のプラグインは止めてあり、スニペットの表には有効なものが 13 個残っています。
| 試したこと | 定数 | テーマ側のファイル | 結果 |
|---|---|---|---|
| プラグインなし(今の作業環境) | なし | 読まれた | 移した関数はテーマ側にできた |
| プラグインあり(読み込むプラグインの一覧に、検証用スクリプトの中だけで足した) | あり | 読まれない | 移した関数は、プラグイン側(スニペット)にできた。エラーなし |
| プラグインありで、分けずにテーマ側のファイルも読む | あり | 読んだ | Cannot redeclare の Fatal error。WordPress の「重大なエラー」の画面になった |
3 つ目は、分ける形がないとどうなるかを見るために、わざと読ませたものです。
ファイルのいちばん初めに出てくる関数の所で止まりました。
画面で見た
最後に、作業環境の DB で、プラグインを一時的に有効にして、トップのページを開きました。
見たあとは、有効なプラグインの一覧を、メモしておいた元の値に戻しました。
| プラグイン | トップのページ |
|---|---|
| 止めたとき(テーマ側が動く) | 200。フッターまで出た。エラーの画面なし |
| 有効なとき(スニペットが動く) | 200。フッターまで出た。エラーの画面なし |
戻したあとに、プラグインの一覧と Code Snippets の設定・スニペットの表を、試す前と比べ、同じであることを確かめました。
気をつけること
- 全部の関数を
function_exists()で包めば、Fatal error は避けられます。ただ、それでは中身を書き換えることになるので、ファイルごと読まない形にしました - プラグインを止めても、スニペットは DB に残ります。すぐに消さず、様子を見てから片付けます
- Code Snippets には、スニペットを動かさない「セーフモード」があります。コードを読むかぎり、セーフモードでも定数はできるので、そのときはテーマ側も読まれないはずです(試していません)
- 本番の PHP のバージョンに合わせて、移すときに新しいバージョンだけの書き方を足さないようにしました
まとめ
- Code Snippets のスニペットは、テーマのファイルに中身のまま移せる。並びは優先度 → id の順にそろえる
- プラグインが有効なまま同じ関数をテーマに書くと、Cannot redeclare で止まる
functions.phpでCODE_SNIPPETS_FILEがあるかを見て、ないときだけテーマ側を読めば、公開 → プラグインを止める、の順で止めずに切り替えられる- おかしいときは、プラグインを有効に戻せば元に戻る


