Code Snippets のコードをテーマの functions.php に移す(Cannot redeclare を出さずに切り替える方法)

概要説明

Code Snippets のスニペットをテーマの functions.php に移して git で管理する手順。移したときの Cannot redeclare の原因(PHP は関数を先に作る)と、functions.php で読み込みを分けて止めずに切り替える方法、パスワードを wp-config.php に移す方法。

管理画面から PHP を足せる「Code Snippets」は便利ですが、スニペットが増えてくると、どこで何をしているのか分かりにくくなり、変更の履歴も残りません。そこで、スニペットのコードをテーマの functions.php に移し、git で管理するようにしました。

移すときに一度「Cannot redeclare」でサイトが止まりかけたので、原因と、止めずに切り替える方法をまとめます。

移す前に考えたこと

  • 中身は変えずに、そのまま移す:移し替えと直しを同時にすると、何かあったときにどちらが原因か分からなくなります。
  • 同じ順番で動かす:Code Snippets は「優先度 → id」の順に実行します。移した先でも同じ順に並べます。
  • パスワードなどは git に入れない:別の DB につなぐスニペットなどに接続情報が入っていたら、wp-config.php の定数に移します。
  • いつでも戻せるようにする:Code Snippets のプラグインを有効に戻せば、元どおりになる形にします。

有効なスニペットを書き出す

スニペットは DB の wp_snippets テーブルに入っています。有効なもの(active = 1)を、実行される順に取り出します。

SQL
SELECT id, name, priority, code
FROM wp_snippets
WHERE active = 1
ORDER BY priority, id;

これを 1 つのファイル(例:テーマの functions/site-snippets.php)に、上から順に並べます。どのスニペットから来たか分かるように、見出しに id と名前を書いておくと、あとで探しやすくなります。

並べ方の例

functions/site-snippets.php
<?php
// Code Snippets から移した処理。中身は元のまま、Code Snippets と同じ順(優先度 → id)に並べた
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/* ---- id 23:ショートコード : パーマリンク取得(優先度 10) ---- */
function my_short_code_get_permalink( $atts ) {
    // …(スニペットの中身をそのまま)
}
add_shortcode( 'permalink', 'my_short_code_get_permalink' );

/* ---- id 24:…… ---- */

「Cannot redeclare」でサイトが止まる

移したファイルを functions.php から読み込むと、Code Snippets のプラグインが有効なあいだは、同じ関数が 2 回作られます。PHP では同じ名前の関数を 2 回作れないので、次のエラーでサイトが止まります。

PHP Fatal error:  Cannot redeclare my_short_code_get_permalink() (previously declared in …/code-snippets/php/snippet-ops.php(822) : eval()'d code:4)

そこで、最初はファイルの先頭に「Code Snippets が有効なら何もしない」と書きました。

うまくいかなかった書き方

functions/site-snippets.php
<?php
// functions/site-snippets.php の先頭
if ( defined( 'CODE_SNIPPETS_FILE' ) ) {
    return; // Code Snippets が有効なら、ここで読むのをやめる…つもり
}

function my_short_code_get_permalink( $atts ) {
    // …
}

ところが、これでも同じエラーで止まります。

原因:PHP は、ファイルの一番外の関数を先に作る

PHP は、ファイルを読み込むとき、ファイルの一番外(if や関数の中ではない所)に書いた関数を、中の処理を動かす前に作ります。そのため、先頭の return まで処理が進む前に、関数を作ろうとしてエラーになります。

if の中に書いた関数は、その if が動いたときに作られます。Code Snippets の多くのスニペットが「if ( ! function_exists( ‘…’ ) ) { function …」と書かれているのは、このためです。ただ、すべてのスニペットがその書き方になっているとは限りません。

直し方:読み込む前に、functions.php で分ける

ファイルの中で止めるのではなく、読み込むかどうかを functions.php の側で決めます。

functions.php
// Code Snippets から移した処理。Code Snippets のプラグインが有効なあいだは読まない
// (同じ関数が二重に作られて止まるため。プラグインを止めると、こちらに切り替わる)
if ( ! defined( 'CODE_SNIPPETS_FILE' ) ) {
    require_once __DIR__ . '/functions/site-snippets.php';
}

こうすると、ファイルそのものを読まないので、関数が二重に作られることはありません。

  • Code Snippets が有効なあいだ:今までどおりスニペットが動き、テーマのファイルは読まれない
  • Code Snippets のプラグインを止めた瞬間:テーマのファイルが読まれて、同じ処理が動く

両方が同時に動く時間がないので、出力の置き換えのような「二重に動くとおかしくなる」処理も安全です。

Code Snippets の code_snippets() 関数は名前空間(Code_Snippets)の中にあるため、function_exists( 'code_snippets' ) は false になります。プラグインのメインファイルで定義される定数 CODE_SNIPPETS_FILE で判定します。

パスワードの入ったスニペットは wp-config.php の定数へ

別の WordPress の DB につないで記事数を数えるスニペットのように、接続情報(パスワード)が入っているものは、そのまま git に入れないようにします。接続情報を wp-config.php に定数で書き、スニペット側はそれを読むだけにします。

wp-config.php に接続情報を書く(git に入れない)

wp-config.php
define( 'MY_REMOTE_DBS', array(
    'blog' => array(
        'host'     => 'localhost',
        'database' => 'blog_db',
        'user'     => 'blog_user',
        'pass'     => '(パスワード)',
        'prefix'   => 'wp_',
    ),
) );

スニペット側は定数を読むだけにする(git に入れる)

functions/site-snippets.php
$remote_wp = defined( 'MY_REMOTE_DBS' ) ? MY_REMOTE_DBS : array();
if ( ! isset( $remote_wp[ $db_key ] ) ) {
    return '';
}
$remote_db = $remote_wp[ $db_key ];

定数に配列を入れられるのは PHP 7.0 からです。

切り替えの手順

  1. 本番のファイルとデータベースのバックアップを取る。
  2. パスワードなどを wp-config.php の定数に移す(スニペット側はまだ元のまま)。
  3. テーマの functions.php と functions/site-snippets.php を本番に上げる。Code Snippets が有効なので、この時点では何も変わらない。
  4. 主なページの HTML を保存しておく(切り替えの前と比べるため)。
  5. Code Snippets のプラグインを停止する。ここでテーマ側に切り替わる。
  6. 同じページを開いて、前と比べる。ショートコードが文字のまま出ていないか、管理画面の追加した機能(ダッシュボードのウィジェットなど)が出るかも見る。
  7. おかしければ、Code Snippets のプラグインを有効に戻す。すぐに元どおりになる。

実際に切り替えたときは、前と後の HTML の違いが、ランダムに表示している部分だけでした。

まとめ

  • ファイルの一番外に書いた関数は、return より先に作られる。「途中で return して読むのをやめる」では二重定義を防げない。
  • 読み込むかどうかを functions.php で決める(if の中で require する)。
  • Code Snippets の判定は、定数 CODE_SNIPPETS_FILE で行う。
  • パスワードは wp-config.php の定数に移して、git に入れない。
  • プラグインを止めるだけで切り替わり、有効に戻すだけで元に戻せる。

関連機能

  1. WordPress現在表示しているページのプログラムファイルを表示させるプラグイン Show Current Template

  2. WordPress W3C(ワールドワイドウェブコンソーシアム)Web標準仕様のチェック方法

  3. WordPress「 &#038; 」のコードが意図していない箇所に表示される場合の対応

[amazon_auto_links id="695"]

サイドバー

よく使うカスタマイズ

最近の記事

Profile

PAGE TOP