WordPressで環境別に設定ファイルを分けてみる

サイトイメージ

こんにちは、もりたです。

先日Webサイトをリニューアルしました。

WordPressを使ったんですが、いきなり公開する本番サーバで開発ってしないと思うんです。

最初は自分のマシンの中にサーバと似たような環境を作って地道にせこせことカスタマイズしていくわけです。

それで出来上がってもろもろ確認が出来たら晴れて本番サーバにアップロードしてさらに確認とかして公開、ってのが一般的な流れかと思うんです。

その時に手でFTPソフトとかを立ち上げてアップロードしてもいいんですが、ツリー全体の各ファイル達の履歴とかを管理したかったのと、手でのアップロードはミスをしやすいのと(自分だけかもしれないけど)、そもそもFTP(SFTP)ソフト立ち上げるのがめんどくさかったりしたので、gitでやってしまおう!と思ったわけです。

本番サーバにリモートリポジトリを置いといて、ローカルからそこへめがけてpush -> 本番サーバはそれをフックして公開ディレクトリにpull、といった形です。

このへんはわりとよくある形なんで省略しますが、(よくわからない方は「git hook pull」で検索すると山ほど出てきます・・・)

問題は環境によって記述の違うファイルなんです。

今回の場合WordPressなんで、「wp-config.php」がそれにあたります。

こいつをローカルの情報を記述した状態でリモートにpushでもしたらたちまち動かなくなります。

まあ、DB接続先を常にlocalhost、ユーザ&パスワードも本番サーバと同一のもの、っていうルールみたいなのを決めたらいいんでしょうけど、あまりに汎用性がないですね。

要は何がしたいかって言うと、railsやnode.jsのconfigでやってるような感じで、環境によって異なるファイルを予め環境の数だけ記述しておいて、プログラムでなくサーバ設定からプログラムの動作が決まるようにしたいんです。

けれど、全く別の環境にポンとツリーをcloneしてきても元々のWordPressの動きは損なわずに開発環境の設定だけ決めれば動く状態でありたい。。。

上記の条件が満たされれば、開発環境用のファイルをいくら変更してコミットしてツリーまるごとpushしても本番の動作はそのままでいられるので、ヒューマンミス的なのが減るかな、と。

これを実現するのにいくつか方法があると思うんですが、その中で一つ。

とりあえずサーバとプログラムで最低限の下準備がいりますね。

以下、本番環境(production)はNginx + php-fpm、デフォルトでは開発環境とします。

まずはNginxの一部。

nginx.conf (…の箇所は環境に応じて)

server {
    listen ...;
    server_name ...;
    root ...;
    access_log ...;
    index index.php index.html index.htm;

    set $app_env production;

    location / {
        if (-f $request_filename) {
            break;
        }

        if (!-e $request_filename) {
            rewrite ^(.+)$ /index.php?q=$1 last;
        }
    }

    location ~ \.php$ {
        include        fastcgi_params;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        fastcgi_index  index.php;
        fastcgi_param  APP_ENV $app_env;
    }

    ...

仕込みとして8行目$app_envの環境宣言、さらにそれをfastcgiのAPP_ENVパラメータにセット。

次にWordPress。 まずは環境用のファイルconfig-env/production/wp-config.phpを設置。
config-envproductionディレクトリは作成する。

他にも必要な場合はconfig-env以下にstagingディレクトリ等を作る。 どの環境ディレクトリにも「wp-config.php」という名前で設定値だけを変更した同様のファイルを設置。

次に「wp-load.php」を編集。

wp-load.php

<?php
/**
 * Bootstrap file for setting the ABSPATH constant
 * and loading the wp-config.php file. The wp-config.php
 * file will then load the wp-settings.php file, which
 * will then set up the WordPress environment.
 *
 * If the wp-config.php file is not found then an error
 * will be displayed asking the visitor to set up the
 * wp-config.php file.
 *
 * Will also search for wp-config.php in WordPress' parent
 * directory to allow the WordPress directory to remain
 * untouched.
 *
 * @internal This file must be parsable by PHP4.
 *
 * @package WordPress
 */

/** Define ABSPATH as this file's directory */
define( 'ABSPATH', dirname(__FILE__) . '/' );

error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );

/////////////////////////////////////////////////////////////////////////////////
// 環境変数APP_ENV(fastcgiのparam)によって設定ファイルを変更する処理を入れています。
/////////////////////////////////////////////////////////////////////////////////

// if ( file_exists( ABSPATH . 'wp-config.php') ) {

//  /** The config file resides in ABSPATH */
//  require_once( ABSPATH . 'wp-config.php' );

// } elseif ( file_exists( dirname(ABSPATH) . '/wp-config.php' ) && ! file_exists( dirname(ABSPATH) . '/wp-settings.php' ) ) {

//  /** The config file resides one level above ABSPATH but is not part of another install */
//  require_once( dirname(ABSPATH) . '/wp-config.php' );

// } else {

//  // A config file doesn't exist

//  // Set a path for the link to the installer
//  if ( strpos($_SERVER['PHP_SELF'], 'wp-admin') !== false )
//      $path = 'setup-config.php';
//  else
//      $path = 'wp-admin/setup-config.php';

//  define( 'WPINC', 'wp-includes' );
//  define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' );
//  require_once( ABSPATH . WPINC . '/load.php' );
//  require_once( ABSPATH . WPINC . '/version.php' );

//  wp_check_php_mysql_versions();
//  wp_load_translations_early();

//  require_once( ABSPATH . WPINC . '/functions.php' );

//  // Die with an error message
//  $die  = __( "There doesn't seem to be a <code>wp-config.php</code> file. I need this before we can get started." ) . '';
//  $die .= '' . __( "Need more help? <a href='http://codex.wordpress.org/Editing_wp-config.php'>We got it</a>." ) . '';
//  $die .= '' . __( "You can create a <code>wp-config.php</code> file through a web interface, but this doesn't work for all server setups. The safest way is to manually create the file." ) . '';
//  $die .= '<a href="' . $path . '" class="button button-large">' . __( "Create a Configuration File" ) . '</a>';

//  wp_die( $die, __( 'WordPress › Error' ) );
// }

$config = 'wp-config.php';

if (!empty($_SERVER['APP_ENV']) && file_exists( ABSPATH . 'config-env/' . $_SERVER['APP_ENV'] . '/' . $config)) {
    $config = 'config-env/' . $_SERVER['APP_ENV'] . '/' . $config;
}

if ( file_exists( ABSPATH . $config) ) {

    /** The config file resides in ABSPATH */
    require_once( ABSPATH . $config );

} elseif ( file_exists( dirname(ABSPATH) . '/' . $config ) && ! file_exists( dirname(ABSPATH) . '/wp-settings.php' ) ) {

    /** The config file resides one level above ABSPATH but is not part of another install */
    require_once( dirname(ABSPATH) . '/' . $config );

} else {

    // A config file doesn't exist

    // Set a path for the link to the installer
    if ( strpos($_SERVER['PHP_SELF'], 'wp-admin') !== false )
        $path = 'setup-config.php';
    else
        $path = 'wp-admin/setup-config.php';

    define( 'WPINC', 'wp-includes' );
    define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' );
    require_once( ABSPATH . WPINC . '/load.php' );
    require_once( ABSPATH . WPINC . '/version.php' );

    wp_check_php_mysql_versions();
    wp_load_translations_early();

    require_once( ABSPATH . WPINC . '/functions.php' );

    // Die with an error message
    $die  = __( "There doesn't seem to be a <code>{$config}</code> file. I need this before we can get started." ) . '';
    $die .= '' . __( "Need more help? <a href='http://codex.wordpress.org/Editing_{$config}'>We got it</a>." ) . '';
    $die .= '' . __( "You can create a <code>{$config}</code> file through a web interface, but this doesn't work for all server setups. The safest way is to manually create the file." ) . '';
    $die .= '<a href="' . $path . '" class="button button-large">' . __( "Create a Configuration File" ) . '</a>';

    wp_die( $die, __( 'WordPress › Error' ) );
}

大きな変更は$configの箇所。

$config = 'wp-config.php';

if (!empty($_SERVER['APP_ENV']) && file_exists( ABSPATH . 'config-env/' . $_SERVER['APP_ENV'] . '/' . $config)) {
    $config = 'config-env/' . $_SERVER['APP_ENV'] . '/' . $config;
}

ここで読み込むconfigを変えてしまおうという作戦。

けれど、APP_ENVなんて全くセットされてない場合にデフォルトの動作ができるように。

あとは$configにセットされたファイルを読み込むようにしただけです。

本番環境、ステージング環境、開発環境が全部同じパスの値を参照してしまうと色々としんどいのでこれで被らないで済みました。

現状サーバ設定内では$app_envは一箇所しか使ってないですが、ログファイル等の名前も環境用に変更したい場合とかは$app_envとかをファイル名に挟み込んでセットしていけば色々なことに使えますね。

他の方法としては、wp-config.phpの作り方は前述の方法と一緒だけど、index.phpを同じディレクトリに名前を変えて複数作ってしまう方法。

index.staging.php

index.production.php

などなど。

これらの中身でグローバルに参照できる環境定数を宣言してしまって(define('APP_ENV', 'production'); など)、wp-load.phpで読み込むconfigを分けてみたり。

 ちなみにApacheからパラメータを渡す場合はSetEnvとかになるのかと思います。

他にも実はこんな方法があるよ!というのがあったらぜひぜひ教えて下さい。

あおぞらTwitter: @aozora_create

僕個人Twitter: @ym_aozora

どちらでも構いません。

環境の部分は本当に単純なミスが怖いものです。

できるだけ効率よくミスなくできる方法をこれからも研究していきたいです。

以上です。

Recent Posts

Archive