Laravel と WordPress を同居させる

サイト全体は Laravel で構築しつつ、ブログや更新情報だけ WordPress を使いたい、というニーズって結構あると思います。WordPress を Laravel の外にインストールして、サブドメインとかで運用する方法もありますが、今回は Laravel のディレクトリ構造の中に WordPress をインストールして共存させることをゴールとします。使用している Laravel のバージョンは 6.x、WordPress は 5.9 です。

Laravel は、/var/www/laravel/ 以下に、WordPress は、Laravel 内の /public/wp/ 以下にそれぞれインストールし、https://example.com/blog/ 以下を WordPress で管理する想定で説明します。ディレクトリ構造が違う場合は適宜読み替えてください。

/public/.htaccess を書き換える

インストール直後の Laravel は、すべてのリクエストを /public/index.php に集めるように設定されています。このままだと、WordPress がリクエストを処理できないので、リライトの設定を行います。先に完成版を示します。

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # WordPress でプレビュー表示する際に必要
    RewriteCond %{QUERY_STRING} preview=true
    RewriteRule ^index\.php$ /wp/index.php [L]

    # WordPress の wp-json 対策
    SetEnvIf Request_URI ^/wp-json/(.*) REST_ROUTE=$1
    RewriteCond %{REQUEST_URI} ^/wp-json/
    RewriteCond %{QUERY_STRING} (.*)$
    RewriteRule . /wp/index.php?rest_route=/%{ENV:REST_ROUTE}&%1 [L]

    # WordPress 化したいページをかっこの中に列記する
    RewriteCond %{REQUEST_URI} ^/(blog)/
    RewriteRule . /wp/index.php [L]

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_URI} !^wp/wp-admin.*$
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # Handle Front Controller...
    RewriteCond %{REQUEST_URI} !^wp.*$
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>

プレビュー表示対策は、WordPress をサイトの一部のみで利用するでも説明しているので、他の部分について説明します。

wp-json 対策

現在の WordPress は、各種処理を REST API 経由で行っています。詳細は、公式ドキュメントを見てほしいのですが、特に設定を変更していない場合、/wp-json/ 以下にリクエストが飛ぶようになっています(/wp-json/wp/v2/posts など)。

実際の処理は、/wp/index.php?rest_route={rest_route} (例えば、/wp/index.php?rest_route=/wp/v2/post)が行うので、そこにリクエストが飛ぶようにリライトの設定を行います。

    SetEnvIf Request_URI ^/wp-json/(.*) REST_ROUTE=$1
    RewriteCond %{REQUEST_URI} ^/wp-json/
    RewriteCond %{QUERY_STRING} (.*)$
    RewriteRule . /wp/index.php?rest_route=/%{ENV:REST_ROUTE}&%1 [L]

先に環境変数 REST_ROUTE に /wp-json/ 以下の部分を入れておき、引数とあわせて /wp/index.php に渡しています。

WordPress に渡したい URL の処理

あとは、WordPress で管理する URL や管理画面の URL を Laravel に渡さないように除外の設定などを入れていきます。

wp-config.php の修正

せっかく Laravel と同居させるのですから、データベースの接続設定などは /.env を参照するようにします。こちらも完成版を先に。

<?php
$root_dir = '/var/www/laravel';
// Cannot redeclare __() 対策
require_once($root_dir . '/public/wp/wp-includes/l10n.php');
require_once($root_dir . '/vendor/autoload.php');

$dotenv = Dotenv\Dotenv::create($root_dir);

if (file_exists($root_dir . '/.env')) {
    $dotenv->load();
    $dotenv->required(['DB_DATABASE', 'DB_USERNAME', 'DB_PASSWORD']);
}

/**
 * WordPress の基本設定
 *
 * このファイルは、インストール時に wp-config.php 作成ウィザードが利用します。
 * ウィザードを介さずにこのファイルを "wp-config.php" という名前でコピーして
 * 直接編集して値を入力してもかまいません。
 *
 * このファイルは、以下の設定を含みます。
 *
 * * MySQL 設定
 * * 秘密鍵
 * * データベーステーブル接頭辞
 * * ABSPATH
 *
 * @link https://ja.wordpress.org/support/article/editing-wp-config-php/
 *
 * @package WordPress
 */

// 注意:
// Windows の "メモ帳" でこのファイルを編集しないでください !
// 問題なく使えるテキストエディタ
// (http://wpdocs.osdn.jp/%E7%94%A8%E8%AA%9E%E9%9B%86#.E3.83.86.E3.82.AD.E3.82.B9.E3.83.88.E3.82.A8.E3.83.87.E3.82.A3.E3.82.BF 参照)
// を使用し、必ず UTF-8 の BOM なし (UTF-8N) で保存してください。

// ** MySQL 設定 - この情報はホスティング先から入手してください。 ** //
/** WordPress のためのデータベース名 */
define('DB_NAME', $_ENV['DB_DATABASE']);

/** MySQL データベースのユーザー名 */
define('DB_USER', $_ENV['DB_USERNAME']);

/** MySQL データベースのパスワード */
define('DB_PASSWORD', $_ENV['DB_PASSWORD']);

/** MySQL のホスト名 */
define('DB_HOST', $_ENV['DB_HOST']);

/** データベースのテーブルを作成する際のデータベースの文字セット */
define('DB_CHARSET', $_ENV['DB_CHARSET']);

/** データベースの照合順序 (ほとんどの場合変更する必要はありません) */
define('DB_COLLATE', $_ENV['DB_COLLATION']);

/**#@+
 * 認証用ユニークキー
 *
 * それぞれを異なるユニーク (一意) な文字列に変更してください。
 * {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org の秘密鍵サービス} で自動生成することもできます。
 * 後でいつでも変更して、既存のすべての cookie を無効にできます。これにより、すべてのユーザーを強制的に再ログインさせることになります。
 *
 * @since 2.6.0
 */
define('AUTH_KEY', $_ENV['WP_AUTH_KEY']);
define('SECURE_AUTH_KEY', $_ENV['WP_SECURE_AUTH_KEY']);
define('LOGGED_IN_KEY', $_ENV['WP_LOGGED_IN_KEY']);
define('NONCE_KEY', $_ENV['WP_NONCE_KEY']);
define('AUTH_SALT', $_ENV['WP_AUTH_SALT']);
define('SECURE_AUTH_SALT', $_ENV['WP_SECURE_AUTH_SALT']);
define('LOGGED_IN_SALT', $_ENV['WP_LOGGED_IN_SALT']);
define('NONCE_SALT', $_ENV['WP_NONCE_SALT']);
/**#@-*/

/**
 * WordPress データベーステーブルの接頭辞
 *
 * それぞれにユニーク (一意) な接頭辞を与えることで一つのデータベースに複数の WordPress を
 * インストールすることができます。半角英数字と下線のみを使用してください。
 */
$table_prefix = $_ENV['WP_TABLE_PREFIX'];

/**
 * 開発者へ: WordPress デバッグモード
 *
 * この値を true にすると、開発中に注意 (notice) を表示します。
 * テーマおよびプラグインの開発者には、その開発環境においてこの WP_DEBUG を使用することを強く推奨します。
 *
 * その他のデバッグに利用できる定数についてはドキュメンテーションをご覧ください。
 *
 * @link https://ja.wordpress.org/support/article/debugging-in-wordpress/
 */
define('WP_DEBUG', !!$_ENV['APP_DEBUG']);

/* カスタム値は、この行と「編集が必要なのはここまでです」の行の間に追加してください。 */

/* 編集が必要なのはここまでです ! WordPress でのパブリッシングをお楽しみください。 */

/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
    define( 'ABSPATH', __DIR__ . '/' );
}

/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';

単純に /vendor/autoload.php を require_once するだけだと、Laravel と WordPress の両方に __() 関数があるため、Cannot redeclare __() のエラーが発生してしまいます。そこで、WordPress 側の __() 関数を定義している /public/wp/wp-includes/l10n.php を先に読み込んでおきます。

ちなみに、/.env ファイルはこんな感じ。

APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=
DB_CHARSET=utf8mb4
DB_COLLATION=utf8mb4_general_ci

BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

# WordPressテーブル接頭辞
WP_TABLE_PREFIX=wp_

# WordPress認証用ユニークキー(https://api.wordpress.org/secret-key/1.1/salt/ で作成したものを下に転記する)
WP_AUTH_KEY=
WP_SECURE_AUTH_KEY=
WP_LOGGED_IN_KEY=
WP_NONCE_KEY=
WP_AUTH_SALT=
WP_SECURE_AUTH_SALT=
WP_LOGGED_IN_SALT=
WP_NONCE_SALT=

Laravel Mix の利用

基本的には WordPress で管理するページのスタイルシートは WordPress のテーマファイルで設定すればよいのですが、Laravel 側で使用している CSS を流用したいこともあると思います。Laravel Mix を使って CSS や JS をコンパイルし、キャッシュ対策のためにバージョン付けをしている場合、Laravel 内であれば、blade テンプレート内で {{ mix('/js/app.js') }} のように書けば、バージョン付きのパスに自動的に変換してくれますが、WordPress ではそうはいきません。そこで、mix 関数と互換性がある wp_mix 関数を定義します。テーマファイル内の function.php に以下のコードを追加してください。

function wp_mix($path) {
    $mix_manifest = WWW_ROOT . 'mix-manifest.json';
    $json = file_get_contents($mix_manifest);

    $decoded_json = json_decode($json, true);

    echo $decoded_json[$path];
}

これで、WordPress のテンプレートファイル内で

<link rel="stylesheet" type="text/css" href="<?php wp_mix('/css/app.css'); ?>">

のように記述することで、バージョン付きのパスが取得できます。

この記事を書いた人

グッドネイバー

“ Webに悩むお客さまの「よき隣人」でありたい ” をモットーに、Web システム開発(主に Laravel)、Web マーケティング支援の仕事をしています。詳しい業務内容はこちら。お仕事のご依頼・ご相談はこちらからお気軽にどうぞ。