2026年5月20日

2026年5月20日

WordPressのPHP 8互換性チェック|8.0〜8.4の非互換変更と安全な移行手順

WordPressサイトのPHPを8系へ上げるときに問題になるのは、WordPress本体よりも、古いプラグイン・テーマ・自作コードに残っている書き方です。この記事では、PHP 8.0〜8.4で実際にサイトを止める原因になった変更点と、PHP_CodeSniffer+PHPCompatibilityによる静的チェック、ステージング環境での動作確認、本番切り替えと切り戻しまでの手順を整理します(2026年10月現在の情報です)。

なぜ今PHP 8系への移行が必要なのか

PHPの各バージョンには公式のサポート期限があります。2026年10月現在、PHP 8.0は2023年11月に、PHP 8.1は2025年末にサポートが終了しており、セキュリティ修正も提供されていません。PHP 8.2もセキュリティ修正のみの段階で、2026年末に終了する予定です。サポートが切れたPHPを使い続けると、PHP自体の脆弱性が修正されないままになります。

WordPress本体が推奨するPHPのバージョンは、WordPress.orgの「要件」ページに掲載されています。移行先は「サーバーで選べる、サポート期間が長いバージョン」を基準に選び、使っているプラグインがそのバージョンに対応しているかを次の手順で確かめていきます。

移行前に現在の状態を把握する

まず、今のPHPバージョンと、サイトを構成するコードの一覧を控えます。PHPバージョンは管理画面の「ツール」→「サイトヘルス」→「情報」タブの「サーバー」で確認できます。php -v で表示されるコマンドライン用のPHPは別バージョンのことがあるため、サイトヘルスの表示を正とします。

あわせて、有効なプラグインとテーマ、wp-content/mu-plugins の中身、子テーマの functions.php に書いた独自コードを洗い出します。問題は更新が止まったプラグインと古い独自コードに集中しやすいので、数年更新のないプラグインは代替を検討する候補にします。

PHP 8.0で動かなくなる主な変更

8.0は大きな変更が多く、7.4から上げたときにサイトが真っ白(致命的エラー)になる原因の多くはここにあります。

削除された関数・構文

7.x系で非推奨になっていた機能が、8.0で削除されました。呼び出した時点で致命的エラーになります。

  • create_function():無名関数(function () { ... })に置き換える
  • each():foreach に置き換える
  • $str{0} のような波括弧による文字列オフセット:$str[0] に置き換える
  • get_magic_quotes_gpc()、money_format() なども削除済み

古いウィジェットやショートコードの登録で create_function() が使われていることがよくあります。

型の扱いが厳しくなった

組み込み関数に想定外の型を渡したとき、7.x系では警告を出して null を返していた多くの場面で、8.0では TypeError が投げられて処理が止まります。WordPressのプラグインで特に多いのが count() に配列以外(null や文字列)を渡すケースです。

// PHP 7.x では警告のみ、PHP 8.0 以降は TypeError で停止する
$items = get_option( 'my_plugin_items' ); // 未設定なら false が返る
echo count( $items );

// 対策: 配列であることを確かめてから数える
$items = get_option( 'my_plugin_items', array() );
echo is_array( $items ) ? count( $items ) : 0;

文字列と数値の比較ルールの変更

== で数値と「数値でない文字列」を比べるとき、7.x系では文字列を数値に変換して比較していましたが、8.0からは数値を文字列に変換して比較します。その結果、次のように結果が反転します。

var_dump( 0 == 'abc' );  // PHP 7.x: true / PHP 8.0 以降: false
var_dump( 0 == '' );     // PHP 7.x: true / PHP 8.0 以降: false
var_dump( '1' == '01' ); // どちらも true(数値文字列同士は従来どおり)

in_array() や switch も内部で同じ比較を使うため、エラーは出ないのに条件分岐の結果だけが変わる、という見つけにくい不具合になります。権限判定や入力チェックで == を使っている箇所は、=== と型の明示に書き直すのが安全です。

名前付き引数とcall_user_func_array

8.0で名前付き引数が導入された影響で、call_user_func_array() に文字列キーの配列を渡すと、キーが引数名として解釈されるようになりました。キー名が関数の引数名と一致しないと「Unknown named parameter」のエラーで停止します。連想配列をそのまま渡しているコードは array_values() で数値添字に変換して渡します。

また、未定義の変数や存在しない配列キーの参照は通知(Notice)から警告(Warning)に格上げされ、ログが急に増える原因になります。

PHP 8.1〜8.4で増えた非推奨

8.1以降の変更は多くが「非推奨(Deprecated)」で、すぐにサイトが止まるわけではありません。ただし将来のバージョンで削除される予定のものなので、ログに出たら計画的に直します。

  • 8.1:組み込み関数の非nullable引数へのnull渡し。strlen( null )、trim( null )、str_replace() の対象に null を渡すなどが該当します。get_post_meta() の結果や未入力のフォーム値をそのまま渡しているコードで大量に出ます。(string) でのキャストや ?? '' で既定値を与えて対処します。
  • 8.1:戻り値の型の不一致。ArrayAccess や Iterator などを実装したクラスで、メソッドに戻り値の型がないと非推奨の警告が出ます。型を付けるか、互換性維持のため #[\ReturnTypeWillChange] 属性を付けます。
  • **8.1:FILTER_SANITIZE_STRING と strftime() の非推奨**。WordPressでは sanitize_text_field()、日付は wp_date() に置き換えられます。
  • 8.2:動的プロパティの非推奨。クラスで宣言していないプロパティに値を代入すると「Creation of dynamic property」の警告が出ます。プロパティを宣言するのが本来の対処で、すぐに直せない場合はクラスに #[\AllowDynamicProperties] を付けて警告を止められます。stdClass は対象外です。
  • **8.2:utf8_encode() / utf8_decode() の非推奨**。mb_convert_encoding() に置き換えます。
  • 8.4:暗黙のnullable型の非推奨。function f( WP_Post $post = null ) のように既定値 null で型をnullableにする書き方は、?WP_Post $post = null と明示する必要があります。

非推奨の警告は、WP_DEBUG_DISPLAY が有効だとページに出力されます。画面に余計な文字が出るだけでなく、HTTPヘッダー送信後の出力になって「headers already sent」エラーを誘発したり、REST APIやAjaxのJSON応答が壊れてブロックエディターが保存できなくなったりします。本番では表示を止め、ログにだけ記録する設定にしておきます。

PHPCompatibilityで静的にチェックする

コードを実行せずに、指定したPHPバージョンで問題になる書き方を検出できるのが、PHP_CodeSniffer用のルールセット「PHPCompatibility」です。WordPress向けには、WordPressが互換関数を用意している関数を誤検出しないように調整された「PHPCompatibilityWP」があります。Composerが使える作業用の環境で、次のように導入します。

composer config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
composer require --dev dealerdirect/phpcodesniffer-composer-installer phpcompatibility/phpcompatibility-wp:"*"

# 導入されたルールセットの確認
vendor/bin/phpcs -i

# プラグインとテーマを PHP 8.2 以降の基準でチェック
vendor/bin/phpcs -p --extensions=php --standard=PHPCompatibilityWP \
  --runtime-set testVersion 8.2- \
  wp-content/plugins/my-plugin wp-content/themes/my-theme

testVersion は 8.2- で「8.2以降」、7.4-8.3 のように範囲でも指定できます。注意点が2つあります。1つ目は、PHPCompatibilityの安定版(9.x系)はPHP 8系の変更を網羅しておらず、8系の検出は開発中の10.x系で拡充が進められている点です(2026年10月現在)。導入時にリポジトリでリリース状況を確認し、8系を重点的に調べたい場合は新しい版の利用を検討してください。2つ目は、静的解析では「実行時に null が渡る」「比較結果が変わる」といった値に依存する問題を見つけられない点です。チェックが通っても、次の実機テストは省略できません。

ステージング環境で実際に動かして確認する

本番と同じ構成のステージング環境(サイトの複製)を用意し、そこだけPHPを新しいバージョンに切り替えます。多くのレンタルサーバーにはステージング機能やドメイン単位のPHPバージョン切り替えがあります。複製の前に、本番のバックアップを取っておきます。

ステージングでは wp-config.php に次の設定を入れ、エラーを画面ではなくログに記録させます。

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );      // wp-content/debug.log に記録
define( 'WP_DEBUG_DISPLAY', false ); // 画面には表示しない

そのうえで、トップページや記事を開くだけでなく、ログイン、投稿の作成・更新、画像アップロード、お問い合わせフォームの送信、会員登録や決済など、サイトの主要な操作をひととおり実行します。エラーはそのコードが実行されたときにしか出ないため、管理画面の設定ページやcronの処理まで触っておきます。

debug.log は「Fatal error」を最優先、次に「Warning」、最後に「Deprecated」の順で確認します。エラーの行にはファイルのパスが含まれるので、どのプラグインが原因かが分かります。原因が配布プラグインなら、まず最新版への更新を試し、それでも直らなければ作者のサポートフォーラムを確認するか代替プラグインを探します。自作コードは前述の変更点を参考に修正します。なお、debug.log はURLで直接開けてしまう場所にあるため、確認が終わったら削除するか、WP_DEBUG_LOG にドキュメントルート外のパスを指定してください。

本番の切り替えと切り戻しの準備

ステージングで問題が出なくなったら、アクセスの少ない時間帯に本番を切り替えます。切り替えの直前にファイルとデータベースのバックアップを取り、切り替え後すぐに主要ページと管理画面を確認します。

万一致命的エラーが出た場合でも、WordPress 5.2以降にはリカバリーモードがあり、管理者のメールアドレスに原因プラグインを一時停止した状態でログインできるリンクが届きます。ただしメールが届かない環境もあるため、サーバーのコントロールパネルからPHPバージョンを元に戻す手順を、事前に確認しておくと安心です。切り替え後数日は、サーバーのエラーログを見て、テストで触れなかった処理からエラーが出ていないかを追います。

まとめ

  • PHP 8.0は削除された関数(create_function()、each() など)、TypeError の増加、文字列と数値の比較変更でサイトが止まりやすい
  • 8.1以降は非推奨が中心で、null渡し・動的プロパティ・暗黙のnullable型がよく出る
  • PHPCompatibilityWPで静的に洗い出し、検出しきれない問題はステージングの実機テストで拾う
  • エラーは画面ではなくログに出し、Fatal → Warning → Deprecated の順に直す
  • 本番切り替え前にバックアップと、PHPバージョンを戻す手順を用意しておく

お気軽にご相談ください

お見積りへ お問い合わせへ
▲