WordPressアドレスとサイトアドレスとhomeとsite_url｜詳解

いじっていると混乱しがちなこれらの関連性をはっきりさせるために色々とテストしてみました。

※もし実際に動かす場合はテスト環境で実施してください。
本番でやる場合サイトが表示できなくなる恐れがありますのでご注意ください。

# 結論
今回色々とテストしてわかったことをまず簡単にまとめてみます。

### WordPressアドレス(url)
管理画面のWordPressアドレス(url)はWPのコアファイルがインストールされているパスになります。
データベースのwp_optionsテーブルのsiteurlまたはwp-config.phpでdefine( 'WP_SITEURL' )が設定されていればその値が表示されます。

### サイトアドレス(url)
管理画面のサイトアドレス(url)はWPのトップページとして設定するアドレスになります。
データベースのwp_optionsテーブルのhomeまたはwp-config.phpでdefine( 'WP_HOME' )が設定されていればその値が表示されます。

### site_url()の戻り値
データベースのwp_optionsテーブルのsiteurlかwp-config.phpのdefine( 'WP_SITEURL' )が設定されていればその値が返ってきます。
つまり管理画面のWordPressアドレス(url)が返ってきます。

### home_url()の戻り値
データベースのwp_optionsテーブルのhomeかwp-config.phpのdefine( 'WP_HOME' )が設定されていればその値が返ってきます。
つまり管理画面のサイトアドレス(url)が返ってきます。

### wp-config.phpでの設定
define関数で設定しているのは定数です。DBの値を変えているわけではありません。
またdefine関数でWP_SITEURL、WP_HOMEを設定していると管理画面からの編集はできなくなり
wp-cliでのコマンド操作もできなくなります。

ただsql文やphpmyadminなどではデータベースの値を変更することはできます。
ここでも注意が必要なのはデータベースの値を変更した後はwp-config.phpに書かれている
WP_SITEURL、WP_HOMEを削除しないと反映されません。
WP_SITEURL、WP_HOMEはDBの値よりも優先される仕様になっているからです。

以下つらつらとテストした詳細を書いていきます。

# 前提
わかりやすいようにWordPressをサブディレクトリ(/wordpress)にインストールします。
設置方法は以下を参照ください。

https://wordpress.org/support/article/giving-wordpress-its-own-directory/#method-ii-with-url-change

なお今回私の方でテストした環境はDockerでローカル環境を立てて実施しました。

# 管理画面のWordPressアドレスとサイトアドレス
上記方法でインストールが完了すると以下のような設定になっています。

WordPressアドレス(url) http://example.com/wordpress
サイトアドレス（url）http://example.com

WordPressアドレス(url)はWPのコアファイルがインストールされているパスを表しています。
index.phpやwp-config.php,wp-contentディレクトリ、wp-admin、wp-includeなどがある場所ですね。
サイトアドレスはトップページとなるアドレスをWordPressに伝える役割を持っています。

# DBの値を確認してみる
DBの中でこれらの値を担っているフィールドがhomeとsiteurlという名前で保存されていますのでそれらの値を確認してみます。

```sql

SELECT * FROM wp_options WHERE option_name IN ('home','siteurl');

```

home    http://example.com
siteurl http://example.com/wordpress

wp_optionsテーブルのsiteurlが管理画面のWordPressアドレス(url)に反映されている。  
wp_optionsテーブルのhomeが管理画面のサイトアドレス（url）に反映されている。

ということがわかりました。
名前付けがねじれていることに注意が必要ですね。

# 管理画面のサイトアドレス（url） = ブラウザが見に行くアドレス　ではない
試しに管理画面からサイトアドレス（url） を以下に変更してみます。

`http://example.com/wordpress`

この状態でブラウザから
`http://example.com/wordpress`
にアクセスしてみます。

何も表示されないのではないでしょうか。
私の環境では500エラーになっていました。

次にサブディレクトリを取った
`http://example.com`
にアクセスしてみます。
トップページが表示されます。

ここで一つ確認したいのが
ブラウザに`http://example.com`を入力した時
管理画面のサイトアドレス（url） は影響を与えていない
ということです。

ではどこに影響が出るかというと
管理画面の左上にある家のマーク→サイトを表示
ここのリンク先が変わっています。

またWordPressが内部的にURLを生成、変換する際にも影響が出ます。

# WordPressが内部的にURLを生成、変換する具体例
内部的にURLを生成、変換するところを実際に見てみましょう。
管理画面→左メニューの設定→パーマリンクを見ると
`http://example.com/wordpress?p=123`
のような形で表示されていると思います。

これは管理画面のサイトアドレス（url）と連動しています。
従って管理画面のサイトアドレス（url）を`http://example.com/　`に変更すると
`http://example.com/?p=123 `になります。

またここは少しマニアックなので読み飛ばしても良いのですが
$post->guidで取得した`http://example.com/?p=111111`
のようなリンクは影響を受けます。これはWordPressが管理している一意のアドレスで
パーマリンクはこのアドレスを基本情報としてURLを変換してくれています。
この時、管理画面のサイトアドレス（url）を反映しながらURLを生成してくれているのです。

私のテストした環境ですとパーマリンクを%postname%と設定していました。
そうすると`http://example.com/?p=111111`というリンクはパーマリンクを経由し
管理画面のサイトアドレス（url）に従ってURLを生成します。

なぜか投稿ページへのリンクだけが切れるという症状の場合
$post->guidでURLを取得していないか確認するのも一つの方法です。

# その他影響を受ける関数たち
主には以下の関数がわかりやすいので具体例を出してみます。
## home_url()
home_url()は管理画面のサイトアドレス（url）で設定された値を返します。

※ここで注意が必要なのが管理画面のサイトアドレス（url）は
データベースのwp_optionsテーブルのhomeの場合もあれば
wp-config.phpでdefine( 'WP_HOME' )を使って値を変更している場合もあるということです。

wp-config.phpでdefine( 'WP_HOME' )を使っている場合はその値が優先され戻り値として返ってきます。
使っていない場合はデータベースのwp_optionsテーブルのhomeが戻り値として返ってきます。

## site_url()
site_url()は管理画面のWordPressアドレス(url) で設定された値を返します。

※ここで注意が必要なのが管理画面のWordPressアドレス（url）は
データベースのwp_optionsテーブルのsiteurlの場合もあれば
wp-config.phpでdefine( 'WP_SITEURL' )を使って値を変更している場合もあるということです。

wp-config.phpでdefine( 'WP_SITEURL' )を使っている場合はその値が優先され戻り値として返ってきます。
使っていない場合はデータベースのwp_optionsテーブルのsiteurlが戻り値として返ってきます。

### ※defineによる変更の注意点
管理画面に入れなくなった際などによく使われる手法ですが
ルートディレクトリにあるwp-config.phpに以下のような形で追記すると変更ができます。

```wp-config.php

define( 'WP_HOME', 'http://example.com' ); 
define( 'WP_SITEURL', 'http://example.com/wordpress' );

```

ここで注意したいのが上記のdefine()は定数を定義するphpの関数で
WP_HOME、WP_SITEURLという定数を定義しているだけです。
従ってデータベースの値は変わりません。
wp_optionsテーブルのhome、wp_optionsテーブルのsiteurlの値を
mysqlコマンドなどで確認すると変わっていないのがわかります。
反面、管理画面のWordPressアドレス(url)、サイトアドレス（url）
さらにhome_url()やsite_url()の戻り値には反映されます。
おそらくdefineコマンドで定数を指定することでデータベースの値を読まずに
WordPressが応急処置的に値を適用させているのだと思います。

その他にもURLが絡む関数では少なくともどちらかの影響を受けると考えておいた方が良いでしょう。

# 設定方法４パターン
管理画面のWordPressアドレス(url)、サイトアドレス（url）を設定する４パターンをまとめてみます。

### 管理画面から
一番オーソドックスなのが
管理画面 → 設定 → 一般からWordPressアドレス(url)、サイトアドレス（url）を設定するパターンですね。

##### ※WordPressアドレス(url)、サイトアドレス（url）がグレーアウトして編集できない場合
ここがグレーアウトしていて編集できない場合は以下のwp-config.phpで設定されている場合があります。
それを解除するには後述するsqlを直接編集し、現在管理画面で設定されている値に戻してから
wp-config.phpのdefine関数で指定されているWP_HOME,WP_SITEURLの行を削除すれば管理画面から編集できるようになります。
※↑ここの編集の順番を間違えるとサイトが表示できなくなるエラーになりますのでご注意ください。

### wp-config.php
次にWordPressのルートディレクトリにあるwp-config.phpに追加するパターンです。
管理画面に入れなくなってもFTPでwp-config.phpが書き換えられれば修復できます。
これは何をやっているかというとWP_HOME、WP_SITEURLという定数を設定しています。
それにより管理画面の値を上書きしていますが裏側のデータベースの値は変わっていません。

```wp-config.php
define( 'WP_HOME', 'http://example.com' ); 
define( 'WP_SITEURL', 'http://example.com/wordpress' );
```

上記を追加すると管理画面のサイトアドレス（url）やWordPressアドレス(url)の値には反映されます。（変更できなくなります）
またhome_url()やsite_url()の戻り値にも反映されます。
さらにこの設定をしていると後述するwp-cliコマンドでの変更も無効になります。
その時は以下のようなエラーが出ます。

```shellscript
# wp option update --allow-root home 'http://example.com'
Error: Could not update option 'home'.
```

ちなみにデータベースのコマンドでoptionのhome,siteurlを変えることはできます。
ただ当然ながら管理画面の値やhome_url()やsite_url()の戻り値は
WP_HOME、WP_SITEURLという定数によって上書きされた値が反映されます。
これらの動きを見ているとデータベースの値と
WP_HOME、WP_SITEURLという定数は全く別物として扱われていることがわかりますね。

### wp-cli
WordPressのコマンドラインツールwp-cliで設定するのも便利です。
Dockerコンテナ作成時に以下のようなコマンドを組み込むことで設定できたりします。

```shellscript
  wp option update --allow-root home 'https://example.com'
  wp option update --allow-root siteurl 'https://example.com/wordpress'
```

### DBのコマンド
DBのコマンドで直接変えるやり方です。

```sql
UPDATE wp_options SET option_value = 'http://www.example.com' where option_name IN ('home');
UPDATE wp_options SET option_value = 'http://www.example.com' where option_name IN ('siteurl');
```

これはwp-config.phpで定数を指定していても関係なくデータベースの値を書き換えることができます。
ただWordPress側への反映はwp-config.phpの定数が優先されます。
データベースを変更しても反映されない場合はwp-config.phpで
WP_HOME、WP_SITEURLという定数が指定されていないかどうかを確認してみましょう。

※phpmyadminもデータベースのsqlをGUI環境で動かしているだけなのでやっていることは同じになります。
コマンド操作が苦手な方はこちらでやっても大丈夫だと思います。

# .htaccessは何をしているか
.htaccessはapacheというサーバの設定ファイルです。
このapacheにドメインを別途設定するのですが
設定されたドメイン名でアクセスがあった際にどのファイルを動かすか
という設定を追加しているのがこの.htaccessファイルになります。

なので今回のようなサブディレクトリへのインストールになると
そちらを編集する必要も出てきたりして混乱しがちになります。

.htaccessはapacheの設定
wp-config.phpはWordPressの設定
さらにはデータベースでも設定があり
urlとWordPressのインストールディレクトリを設定している
ということがわかると問題の切り分けがしやすくなるかも知れません。

# 後書き
一度サーバを立てたことがあれば.htaccessの役割などもわかり
理解が進むと思いますが、それ以外でもなんとなくやっていると混乱しがちなところだと思います。
特に管理画面の表記が少しねじれているので要注意ですね。

間違いなどありましたらご指摘いただけたら嬉しいです。