サブディレクトリにインストールしたWordPressのマルチサイトをマルチドメインで運用するとき

普通、マルチサイトを作成して、それぞれに独自ドメインを割り当てる場合、WordPress Multisite Domain Mappingプラグインを使用します。これは公式でも推奨されている方法です。しかし、このプラグインはサブディレクトリにインストールしたWordPressのマルチサイトには対応していません。

```
例
public_html/blog/blog/wp-content等
```

このようなサイトでこのプラグインを有効化すると、wp_die関数が呼ばれエラーメッセージが表示されます。
そこで、仕方ないので今回はこのプラグインをカスタマイズしてなんとか表示されるようになったので、やり方をメモしておきます。

## 前提知識

WordPressではWordPress アドレス (URL) とサイトアドレス (URL)を、環境変数を用いて、動的に定義すると複数のドメインでアクセスできるようになります。それぞれの詳しい説明は以下を参照下さい。<br>
[wp-config.php の編集 - WordPress Codex 日本語版](http://wpdocs.sourceforge.jp/wp-config.php_%E3%81%AE%E7%B7%A8%E9%9B%86#WordPress_.E3.82.A2.E3.83.89.E3.83.AC.E3.82.B9_.28URL.29)

しかし、この方法はマルチサイトでは機能しないそうです。なので、マルチサイト起動時にサイトとブログを判別する部分をカスタマイズして、マルチドメインを実現します。
サイトとブログの判別はwp-includesのms-settings.phpで行われていますが、その前に以下のような分岐があり、これを事前に設定しておくことで、デフォルトの判定ロジックを回避することができます。

```php:wp-includes/ms-settings.php
if ( !isset( $current_site ) || !isset( $current_blog ) ) {
```

また、この条件分岐の前に

```php:ms-settings.php
if ( defined( 'SUNRISE' ) )
    include_once( WP_CONTENT_DIR . '/sunrise.php' );
```

という記述がありwp-confing.phpに

```
define('SUNRISE', true);
```

がありwp-content/にsunrise.phpがあればそれを先に読み込んでくれます。つまり、ここで```$current_site, $current_blog```に何かがはいっていればWordPressのデフォルトの判定を回避し、サイトURLとブログURLにデフォルト以外のものを設定できるということです。
デフォルトだとwp-config.phpに記述しているサイトURLが入ってしまうため、これを行わないとマルチドメインには対応できません。


## WordPress Multisite Domain Mappingの使い方と対処方法

このプラグインはインストールするだけではダメで、プラグイン内に入っているsunrise.phpをwp-content/に置く必要があります。

普通のマルチサイトならこれで動きます。設定画面からブログIDとドメインを対応付けるだけです。
今回のような場合には設定画面を開くとエラーメッセージが表示されます。
そこで、まずはエラーになる部分をコメントアウトします。

```php:dmain-mapping.php:45
if ( $current_site->path != "/" ) {
		// wp_die( __( "The domain mapping plugin only works if the site is installed in /. This is a limitation of how virtual servers work and is very difficult to work around.", 'wordpress-mu-domain-mapping' ) );
	}

```

```php:dmain-mapping.php:130

	if ( $current_site->path != "/" ) {
		// wp_die( sprintf( __( "<strong>Warning!</strong> This plugin will only work if WordPress is installed in the root directory of your webserver. It is currently installed in &#8217;%s&#8217;.", "wordpress-mu-domain-mapping" ), $current_site->path ) );
	}
```

```php:dmain-mapping:262
	if ( $current_site->path != "/" ) {
		// wp_die( sprintf( __( "<strong>Warning!</strong> This plugin will only work if WordPress is installed in the root directory of your webserver. It is currently installed in &#8217;%s&#8217;.", "wordpress-mu-domain-mapping" ), $current_site->path ) );
	}
```

これで、設定画面が使えるようになります。
次に設定画面からブログIDとドメインを対応付けてみると、パスがおかしいため、WordPressファイルを何も読み込んでくれません。
ソースを確認すると

```
http://aaa.com/include/...
```

のような感じになっていました。本当は、

```
http://aaa.com/blog/inclue...
```

のようになって欲しいはずなので、その部分をカスタマイズします。

（実は、この時点でも、プラグインを停止にすると正常に表示されます。でも、有効化するとパスがおかしくなるため、サイト追加の際に一瞬崩れてしまうので頑張って直しましょう。）

ずっと、グローバル変数の$current_blogの中身が原因だと思ってたのですが、違いました。試しに
```var_dump```で、```$current_blog,$current_site```の中身をプラグインを有効化したときと停止したときで比べてみました。

```php
global $current_site, $current_blog;
var_dump($current_site);
var_dump($current_blog);
```

すると一緒だったので、ここが原因じゃないのが分かりました。
それ以外であるとしたら、フックをかけている部分だと思ったので見てみると、以下の様なものを見つけました。

```php:domain-mapping.php
if ( defined( 'DOMAIN_MAPPING' ) ) {
	add_filter( 'plugins_url', 'domain_mapping_plugins_uri', 1 );
	add_filter( 'theme_root_uri', 'domain_mapping_themes_uri', 1 );
	add_filter( 'pre_option_siteurl', 'domain_mapping_siteurl' );
	add_filter( 'pre_option_home', 'domain_mapping_siteurl' );
	add_filter( 'the_content', 'domain_mapping_post_content' );
	add_action( 'wp_head', 'remote_login_js_loader' );
	add_action( 'login_head', 'redirect_login_to_orig' );
	add_action( 'wp_logout', 'remote_logout_loader', 9999 );

	add_filter( 'stylesheet_uri', 'domain_mapping_post_content' );
	add_filter( 'stylesheet_directory', 'domain_mapping_post_content' );
	add_filter( 'stylesheet_directory_uri', 'domain_mapping_post_content' );
	add_filter( 'template_directory', 'domain_mapping_post_content' );
	add_filter( 'template_directory_uri', 'domain_mapping_post_content' );
	add_filter( 'plugins_url', 'domain_mapping_post_content' );
} else {
	add_filter( 'admin_url', 'domain_mapping_adminurl', 10, 3 );
}	
add_action( 'admin_init', 'dm_redirect_admin' );
```

これだ！このフックで全部、URLを指定されてたみたいです。
ここをコメントアウトでも条件をfalseにしちゃうでもなんでもいいですが、無効にすればいけます。
最後の```add_action```もちゃんとコメントアウトしないと管理画面で何か更新するとリダイレクトとかされちゃいますのでご注意！

原因追求で思い込みはよくないですね。。。
とりあえず、表示されたのでメモ。

# 追記

上記だけのやりかただと、プラグインの中に正常に動作しないものがあり、原因の調査と対応を行いました。

## 問題

動かなかったプラグインを見てみると、ライブラリの呼び出しにグローバル変数を使用していて、それには```/blog/```が入っていませんでした。

もう一度```$current_site, $current_blog```の中身を確認してみました。
すると```$current_blog```の中身がメインのドメインのサイトとマッピングしたドメインのサイトでは異なっていました。
メインがDBの内容を使っているのに対して、マッピングしたドメインでは'/'だけになっていました。

```php:main-domain
public 'path' => string '/blog/店舗名'
```

```php:mapping-domain
public 'path' => string '/'
```

(↑var_dump結果)

## 修正内容

修正箇所は２箇所です。

1.　sunrise.phpで以下の様な記述があります。これでは、データベースの中身を使われずに```$current_blog```のpathが全て'/'になってしまいます。ここをコメントアウトしてください。

```php:sunrise.php
$current_blog = $wpdb->get_row("SELECT * FROM {$wpdb->blogs} WHERE blog_id = '$domain_mapping_id' LIMIT 1");
$current_blog->path = '/' ;
```

2.　次にdomain-mapping.phpです。```template_redirect```にフックをかけてURLを独自に設定していたみたいですね。こををコメントアウトしましょう。しないとリダイレクトループとかになっちゃいます。


```php:domain-mapping.php
function redirect_to_mapped_domain() {
	global $current_blog, $wpdb;

	// don't redirect the main site
	if ( is_main_site() )
		return;
	// don't redirect post previews
	if ( isset( $_GET['preview'] ) && $_GET['preview'] == 'true' )
		return;

	// don't redirect theme customizer (WP 3.4)
	if ( isset( $_POST['customize'] ) && isset( $_POST['theme'] ) && $_POST['customize'] == 'on' )
		return;

	$protocol = is_ssl() ? 'https://' : 'http://';
	$url = domain_mapping_siteurl( false );
	if ( $url && $url != untrailingslashit( $protocol . $current_blog->domain . $current_blog->path ) ) {
		$redirect = get_site_option( 'dm_301_redirect' ) ? '301' : '302';
		if ( ( defined( 'VHOST' ) && constant( "VHOST" ) != 'yes' ) || ( defined( 'SUBDOMAIN_INSTALL' ) && constant( 'SUBDOMAIN_INSTALL' ) == false ) ) {
		$_SERVER[ 'REQUEST_URI' ] = str_replace( $current_blog->path, '/', $_SERVER[ 'REQUEST_URI' ] );
		}
		header( "Location: {$url}{$_SERVER[ 'REQUEST_URI' ]}", true, $redirect );
		exit;
	}
}
add_action( 'template_redirect', 'redirect_to_mapped_domain' );
```

以上です。

# そもそもDomain Mapping使わなければ？
だめかな^^;

```php


// パスを取得
$dm_path = $wpdb->escape( $_SERVER[ 'REQUEST_URI' ] );
$path_explode = explode('/', $dm_path);
// クエリを含む場合
if (strstr($path_explode[2], '?')){
        $path_explode[2] = preg_replace('/\?.*/','', $path_explode[2]);
}

$request_path = '/' . $path_explode[1] . '/' . $path_explode[2] . '/';

if( ( $nowww = preg_replace( '|^www\.|', '', $dm_domain ) ) != $dm_domain )
	$where = $wpdb->prepare( 'domain IN (%s,%s) AND path = %s', $dm_domain, $nowww, $request_path );
else
	$where = $wpdb->prepare( 'domain = %s AND path = %s', $dm_domain, $request_path );

$wpdb->suppress_errors();
$domain_mapping_id = $wpdb->get_var( "SELECT blog_id FROM wp_blogs WHERE {$where} ORDER BY CHAR_LENGTH(domain) DESC LIMIT 1" );
$wpdb->suppress_errors( false );
if( $domain_mapping_id ) {
	$current_blog = $wpdb->get_row("SELECT * FROM {$wpdb->blogs} WHERE blog_id = '$domain_mapping_id' LIMIT 1");
	$current_blog->domain = $_SERVER[ 'HTTP_HOST' ];
#  $current_blog->path = '/';
	$blog_id = $domain_mapping_id;
	$site_id = $current_blog->site_id;

	define( 'COOKIE_DOMAIN', $_SERVER[ 'HTTP_HOST' ] );

	$current_site = $wpdb->get_row( "SELECT * from {$wpdb->site} WHERE id = '{$current_blog->site_id}' LIMIT 0,1" );
	$current_site->blog_id = $wpdb->get_var( "SELECT blog_id FROM {$wpdb->blogs} WHERE domain='{$current_site->domain}' AND path='{$current_site->path}'" );

```