WordPressで「重大なエラー」がスマホだけに発生:原因特定と対処、半年後の再トラブル

WordPressで運営している当ブログ「MAGE OUTDOOR」で、ある日突然、スマートフォンからアクセスしたときだけ「重大なエラー」が表示されるようになりました。PCからは普通に表示でき、WordPressの管理画面にも入れます。それなのにスマホでは、一瞬だけ正常に表示されたあとレイアウトが崩れ、ページ下部にエラーが出るという少し変わった症状です。

エラーログを調べたところ、最初のFatal Errorの直接原因は、使用しているWordPressテーマ「THE THOR」に関連するis_bot()という関数が定義されていないことでした。当時は子テーマ側で不足している関数を補うことで正常に戻り、その後も半年ほど問題なく運用できていました。ところが約半年後、THE THORをアップデートしたことをきっかけに再び重大なエラーが発生し、復旧と比較作業を進めるうちに、最初の障害の見方も改めることになりました。

スマホからアクセスしたときだけ「重大なエラー」が発生

最初に疑ったのは、CSSの崩れ、JavaScriptの競合、スマホ用スタイルの記述ミス、プラグインやキャッシュの影響でした。プラグインを無効化したりソースを確認したりしましたが、PC表示は常に安定しており、単に見た目が崩れるというより処理が途中で落ちているように見えます。そこでCSSやJavaScriptではなく、PHP側でエラーが発生している可能性が高いと判断しました。

決定打はサーバーのエラーログ

ブラウザ画面には具体的なエラー内容が表示されないため、スマホで症状を再現した直後にサーバー側のPHPエラーログを確認しました。そこには、次のFatal Errorが記録されていました。

PHP Fatal error: Call to undefined function is_bot()

つまり、存在しないis_bot()を呼び出したため、PHPの処理が停止していました。該当箇所を追うとTHE THORのsingle.phpに行き着き、スマホ表示やユーザーエージェント判定などの特定条件でこの関数を通る処理がありました。PCではその分岐を通らないため、スマホだけにエラーが出る挙動になっていたと考えられます。

is_bot()を子テーマに定義して応急処置

当時確認した範囲では、同じTHE THORユーザーの間でこのエラーが一般的に発生している様子はありませんでした。また、障害はテーマ更新の直後ではなく、それまで正常に動いていた環境で突然発生しています。根本原因は特定できませんでしたが、少なくとも直接のエラーは、呼び出されているis_bot()が存在しないことでした。

テーマ本体を直接編集するとアップデートで上書きされるため、THE THOR CHILDのfunctions.phpに次のコードを追加しました。管理画面に入れない場合は、FTPやサーバーのファイルマネージャーから/wp-content/themes/(子テーマ名)/functions.phpを編集できます。

if ( ! function_exists('is_bot') ) {
    function is_bot() {
        if ( empty($_SERVER['HTTP_USER_AGENT']) ) {
            return false;
        }

        $bots = [
            'Googlebot',
            'bingbot',
            'Slurp',
            'DuckDuckBot',
            'Baiduspider',
            'YandexBot',
            'Sogou',
            'Exabot',
            'facebot',
            'ia_archiver'
        ];

        foreach ( $bots as $bot ) {
            if ( stripos($_SERVER['HTTP_USER_AGENT'], $bot) !== false ) {
                return true;
            }
        }

        return false;
    }
}

ポイントは、function_exists('is_bot')で存在確認をしていることです。将来テーマ側に同じ関数が追加されても、すでに存在していれば子テーマ側では定義せず、二重定義を避ける意図でした。保存後はスマホ表示が正常に戻り、サーバーのerror_logにも新しいFatal Errorが出ていないことを確認できました。

半年後、THE THORを更新したら再び「重大なエラー」

それから約半年後、THE THORの新しいバージョンが公開されたため、WordPressの管理画面から親テーマを更新しました。すると今度はサイト全体が「重大なエラー」となり、管理画面にも入れません。以前の対策ではfunction_exists()で関数の重複を防いでいたので、テーマ側にis_bot()が追加されても問題は起きない想定でしたが、その通りにはいきませんでした。

WordPressで「このサイトで重大なエラーが発生しました」と表示された画面

WordPress上から元に戻すこともできないため、サーバーのJetBackupを使い、更新前のTHE THORを復元しました。幸い、これでサイトと管理画面は正常な状態に戻りました。そこで、復元した更新前版と、エラーを起こした更新版のTHE THORを比較することにしました。

新旧テーマを比較してわかったこと

更新版のTHE THORでは、以前問題になったis_bot()がテーマ側で定義されていました。一方、バックアップから復元した更新前版では、最新版でis_bot()が定義されているファイルが空の状態でした。最初の障害時にis_bot()を利用できなかったこと自体は間違いありませんが、なぜその状態になっていたのかは改めて考える必要があります。

まず子テーマに追加していた独自コードを削除すると、更新前版のTHE THORでは以前と同じエラーが再発しました。その状態のまま親テーマを最新版へ更新すると、今度はPC・スマートフォンともに正常に表示され、管理画面にも入れます。実測できた流れは、独自コードあり+更新前版は正常、独自コードなし+更新前版はエラー、独自コードなし+最新版は正常というところまでです。

最初のエラーの根本原因は不明

最初のFatal Errorの直接原因は、THE THOR内で呼び出されたis_bot()が未定義だったことです。ただし、障害はテーマ更新直後ではなく、それまで正常だった環境で突然発生し、当時調べてもTHE THORユーザーに一般的なエラーとは確認できませんでした。そのため、これだけでTHE THOR自体に実装漏れがあったと断定するのは適切ではありません。

今回の比較結果からは、当時のテーマファイルの一部が欠損・破損していたなど、別の要因も考えられます。しかし、当時の状態を完全に再現できない以上、ここは推測の域を出ません。直接原因と根本原因を分け、根本原因は不明としておくのが正確だと思います。

function_exists()があったのに、なぜ最新版で問題になったのか

子テーマの応急処置は、テーマ側に同じ関数が追加された場合を考えてfunction_exists()で囲んでいました。それでも最新版への更新時には重大なエラーが発生し、独自コードを削除して更新すると正常に動作しました。単純な関数の二重定義だけでは説明しにくく、技術的な理由は確認できていません。

原因がわからない部分について、無理に答えを作ることはしません。確かなのは、応急処置が半年ほど正常に機能したことと、現在は独自コードを削除した最新版のTHE THORで問題なく動作していることです。応急処置にも十分な意味はありましたが、本体側や環境が変わったときには、以前のカスタマイズがまだ必要か見直した方がよさそうです。

復旧作業中に、もう一つ妙なことに気づく

テーマの問題は解決しましたが、JetBackupで復元作業をしている途中、別の数字が目に入りました。バックアップ履歴には約269GBというサイズが日ごとに並んでいます。ブログ一つのデータ量としては、さすがに大きすぎます。

JetBackupに約269GBのバックアップが日ごとに並んでいる画面

サーバーのディスク使用量は269.4GB / 300GB、使用率は89.8%になっていました。WordPressのファイルを調べると、wp-content/uploadsの中から10GB前後ある巨大な.tar.tar.gzファイルが大量に見つかりました。作成していたのは、バックアッププラグイン「BackWPup」です。

バックアップのバックアップを毎日取っていた

BackWPupはWordPressのバックアップを同じサーバー内に保存していました。一方、サーバー側のJetBackupはホームディレクトリを毎日バックアップしています。そのため、BackWPupが作った巨大なバックアップファイルを含むWordPress全体を、JetBackupがさらにバックアップする入れ子状態になっていました。

同一サーバー内のバックアップは、サーバー自体に障害が起きた場合の冗長化としても強くありません。実際、今回のTHE THOR更新失敗からサイトを救ってくれたのはJetBackupでした。これまでBackWPupからの復元がうまくいった経験もなかったため、この機会にBackWPupを廃止することにしました。

BackWPupを整理したら約258GB減った

まずBackWPupの管理画面から保存されていたバックアップ履歴を削除し、プラグイン本体も削除しました。さらにcPanelのファイルマネージャーで、残っていたバックアップ、ログ、一時ファイル、復元用ディレクトリを確認しながら整理しました。その結果、サーバーのディスク使用量は269.4GBから11.16GBへ、使用率は89.8%から3.72%へ下がり、約258GBを削減できました。

BackWPup整理後のcPanelディスク使用量11.16GB・3.72%の表示

今回の経験からわかったこと

WordPressで「重大なエラー」が表示された場合、エラーログにテーマやプラグインの名前が出ていても、それだけで製品自体に不具合があるとは限りません。今回も、最初の直接原因はis_bot()の未定義でしたが、なぜ未定義になったのかという根本原因までは特定できませんでした。テーマ、プラグイン、PHP、サーバー環境など複数の要素が絡むため、確認できた事実と推測を分けることが大切だと思います。

また、応急処置で正常に戻っても、本来の原因まで解決したとは限りません。一方で、その対応によって半年ほど問題なく運用できたことには十分意味があります。環境や本体が更新されたときに、以前のカスタマイズがまだ必要か見直すところまで含めて、ひとつの対処なのだと思います。

バックアップも、「取っているから安心」ではなく、どこに、何を、どう保存しているのかまで確認した方がよさそうです。THE THORをアップデートしたらブログが壊れ、JetBackupから復旧し、半年前のエラーの見方まで変わり、最後には258GBの不要なバックアップまで見つかりました。何を直していたのかわからなくなってきます。

 
まあ、ブログのネタにはなったので良しとします。