WordPress 5.9のサイトをPHP 8.2のローカル環境で動かしたところ、画面がDeprecated警告で埋め尽くされました。
php.ini で display_errors = Off を設定し、phpinfo() でもちゃんと Off になっている。それなのに、ブラウザで開くとエラーが表示され続けます。
原因は、WordPressが起動時に自分でPHPの設定を書き換えていたことでした。
何が起きたか
4年ほど放置していたブログを、ローカル環境で最新化しようとしていたときのことです。
本番と同じ構成(WordPress 5.9、PHP 8.2)をDDEVで再現したところ、サイトを開くたびに大量の警告が流れてきました。
Deprecated: Creation of dynamic property wpdb::$categories is deprecated in /var/www/html/wp-includes/wp-db.php on line 760
Deprecated: Using ${var} in strings is deprecated, use {$var} instead in /var/www/html/wp-includes/comment-template.php on line 1745
Deprecated: Creation of dynamic property POMO_FileReader::$is_overloaded is deprecated in /var/www/html/wp-includes/pomo/streams.php on line 26
...WordPress 5.9のリリースは2022年1月、PHP 8.2の登場は同年12月です。5.9のコードはPHP 8.2の存在を知らないので、非推奨になった書き方が大量に残っています。エラーではなく警告なので動作はしますが、画面が警告で埋まって作業になりません。
PHPの設定で止めようとする
まずはPHP側で表示を抑制することにしました。DDEVでは .ddev/php/ にiniファイルを置くと、コンテナ内のPHP設定として読み込まれます。
display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL & ~E_DEPRECATED & ~E_NOTICE & ~E_WARNING再起動して、まずコマンドラインから確認します。
ddev exec php -i | grep -E "^(display_errors|error_reporting)"display_errors => Off => Off
error_reporting => 24565 => 24565設定は効いています。WP-CLIを実行しても、以前のように警告が流れてこなくなりました。
ところが、ブラウザで開くと警告が出たままなのです。
phpinfoで確認しても Off
設定ファイルの書き方が間違っているのか。あるいはWebサーバー側(PHP-FPM)には別の設定が読み込まれているのか。
確認用に phpinfo() を出力するファイルを一時的に置いて、ブラウザから見てみました。
<?php phpinfo();結果は display_errors が Off。CLIと同じです。Webサーバー側でもきちんと設定が反映されている。
それなのに、同じサーバーで動いているWordPressの画面にはエラーが出る。
この時点で私が疑ったのは、ローカル環境そのものの設定ミスでした。DDEVやDockerの構成をよく分かっていないので、どこかで設定が競合しているか、そもそも自分の理解が間違っているのだろうと。
本番環境ではなくローカルの話なので、焦りはありませんでした。ただ、原因が見えないのは気持ちが悪い。
原因はWordPress自身だった
調べていくうちに、WordPressのコアにある wp_debug_mode() という関数が怪しそうだと思いました。
これはWordPressの起動処理のかなり早い段階で呼ばれる関数で、WP_DEBUG などの定数を見て、PHPの設定を書き換えます。
やっていることを簡略化すると、こういう内容です。
if ( WP_DEBUG ) {
error_reporting( E_ALL );
if ( WP_DEBUG_DISPLAY ) {
ini_set( 'display_errors', 1 );
} elseif ( null !== WP_DEBUG_DISPLAY ) {
ini_set( 'display_errors', 0 );
}
// ...
}ini_set() は、PHPの実行中に設定を上書きする関数です。つまり、
1. php.ini の設定が読み込まれる(display_errors = Off)
2. WordPressが起動する
3. wp_debug_mode() が ini_set('display_errors', 1) を実行
4. 設定が上書きされ、エラーが表示されるようになる
という順序で処理されていたわけです。
phpinfo() で Off と表示されていたのは当然で、あのファイルはWordPressを経由していません。WordPressを通ったときだけ設定が変わる、という状況でした。
なぜ WP_DEBUG が有効になっていたのか
DDEVは開発環境なので、WordPressのデバッグモードを有効にした状態でセットアップします。wp-config-ddev.php の中で WP_DEBUG が true に設定されていました。
開発中はエラーが見えたほうが便利なので、これ自体は妥当な設計です。ただ、今回のように「一時的に黙らせたい」場面では邪魔になります。
対処法
PHPの設定ではなく、WordPressの設定で止めます。wp-config.php に定数を書きます。
define( 'WP_DEBUG', false );
define( 'WP_DEBUG_DISPLAY', false );WP-CLIが使えるなら、コマンドで追加できます。
wp config set WP_DEBUG false --raw
wp config set WP_DEBUG_DISPLAY false --raw--raw を付けておくと、false が真偽値として書き込まれます。
これでブラウザからも警告が消えました。
WordPressのデバッグ関連の定数
今回調べていて、関連する定数の役割が整理できました。
| 定数 | 役割 | 初期値 |
|---|---|---|
WP_DEBUG | デバッグモード全体のスイッチ | false |
WP_DEBUG_DISPLAY | エラーを画面に表示するか | true |
WP_DEBUG_LOG | エラーをログファイルに記録するか | false |
SCRIPT_DEBUG | 圧縮前のCSS/JSを読み込むか | false |
WP_DEBUG が false のときは、他の定数も基本的に効きません。全体のスイッチだからです。
実務でよく使うのは、画面には出さずログにだけ残す設定でしょう。
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_DISPLAY', false );
define( 'WP_DEBUG_LOG', true );これで wp-content/debug.log にエラーが記録され、訪問者には見えなくなります。本番でトラブルを追いかけるときに有効です。
ただし、ログファイルが外部から読めてしまう可能性があるので、本番で常時有効にするのは避けたほうが無難です。
メジャーアップデートで設定が消える
もうひとつ、この作業中に遭遇したことを書いておきます。
wp-config.php に定数を追加して警告を止めたあと、WordPressを5.9から6.0にアップグレードしました。すると、また警告が表示されるようになりました。
確認してみると、追加したはずの定数が消えています。
grep -n "WP_DEBUG" wp-config.php出力は空。メジャーアップデートの過程で wp-config.php が置き換わり、書き足した内容が失われていました。
段階的にバージョンを上げていく作業をしていたので、この現象は数回起きました。バージョンを上げるたびに定数を書き直す、という流れです。
アップグレード前に wp-config.php をバックアップしておくか、上げ終わったあとに設定を確認する習慣をつけておくとよさそうです。カスタム定数を書いている場合は特に。
まとめ
php.iniでdisplay_errors = Offにしても、WordPressの画面にはエラーが出続けることがある- WordPressは起動時に
wp_debug_mode()を実行し、ini_set()でPHPの設定を上書きする - そのため
phpinfo()ではOffと表示されるのに、WordPress経由だとOnになっている、という状況が起きる - 止めるには
wp-config.phpでWP_DEBUGとWP_DEBUG_DISPLAYをfalseにする - メジャーアップデートで
wp-config.phpがリセットされ、書いた定数が消えることがある
設定ファイルに書いたのだから効くはずだ、という前提で調べていると、なかなか原因に辿り着けません。アプリケーション側が実行中に設定を変えている可能性は、頭の片隅に置いておくとよさそうです。
同じことは memory_limit や max_execution_time でも起こり得ます。WordPressはこれらも状況に応じて ini_set() で調整しているので、「サーバーで設定したのに反映されない」ときは、アプリケーション側を疑ってみてください。
なお、今回のローカル環境はMAMPからDDEVへ移行して構築したものです。
その過程でもエラーに遭遇しました。

この環境で最新化したサイトを本番へ反映した際には、
別の問題にも遭遇しています。


