WordPress

共用サーバーで1サイトだけPHP 8.3へ|php.cgiでの切り替えと、更新作業で起きた3つのトラブル

先日、ある企業サイトの WordPress と PHP のバージョンアップを担当しました。WordPress 5.5、PHP 7.4 のまま数年動いていたサイトで、同じレンタルサーバーの中には、ほかに静的サイトと WordPress サイトが1つずつ入っています。

「このサイトだけ PHP 8.3 にしたい。でも、同じサーバーのほかのサイトには触りたくない」。共用のレンタルサーバーでは、よくある悩みだと思います。今回は制作事例として、事前の準備から当日の作業、途中で起きたトラブルと直し方までをまとめます。

今回の作業の概要

項目作業前作業後
WordPress5.5系最新版(7系)
PHP7.4(サーバー全体の設定)8.3(このサイトだけ)
プラグイン10本(配布終了のものを含む)8本(2本を削除し、機能を移行)
jQuery3.4.1(テーマが CDN から読み込み)3.7.1

サーバーはさくらのレンタルサーバです。コントロールパネルの PHP バージョン設定はサーバー全体に効くため、今回は php.cgi を使ってサイト単位で切り替えました。作業中は Basic 認証でサイトを閉じ、本番環境でそのまま作業しています。

事前の準備でやったこと

当日の作業を短くするため、サーバーのログイン情報が届く前にできることは先に済ませておきました。

テーマの事前チェックの考え方は「WordPress 4.9・PHP 7.4のサイトをPHP 8.3へ」でくわしく書いています。今回のテーマは標準的な関数しか使っていない小さなもので、PHP 8 に向けて直す箇所はありませんでした。

ほかのサイトに影響しないかは、フォルダの配置で決まる

php.cgi は、置いたフォルダと、その下の階層すべてに効きます。そのため、対象サイトが www/ の直下にあって、ほかのサイトがその下のフォルダに入っている構成だと、ほかのサイトまで PHP 8.3 に変わってしまいます。

www/
 ├ 対象サイト/   ← ここに php.cgi を置く
 ├ 静的サイト/
 └ 別のWordPress/

今回は、上のようにサイトごとに別のフォルダに分かれていて、ほかのサイトに php.cgi もありませんでした。これなら、対象サイトのフォルダに置くだけでほかのサイトは 7.4 のまま動きます。

準備中に起きたトラブル:触っていないのに「重大なエラー」

準備を進めている途中で、「サイトに重大なエラーがありました」と表示されるようになりました。こちらでは何も触っていません。調べると、エラーはログイン中だけで、一般の訪問者には普通に表示されていました。

原因を確かめるため、wp-config.php でエラーをログに書き出す設定にしました。画面には出さないので、訪問者にエラーの内容が見えることはありません。

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );

ログインした状態でトップページを開くと、wp-content/debug.log に原因が残っていました。

PHP Fatal error: Uncaught Error: Call to undefined function wp_is_block_theme()
in .../plugins/show-current-template/show-current-template.php:207

管理バーにテンプレート名を出す「Show Current Template」が自動で更新され、新しい版が WordPress 5.9 で追加された関数 wp_is_block_theme() を呼び出していました。WordPress 5.5 にはこの関数がないので、エラーになっていたわけです。管理バーはログイン中にしか出ないため、エラーもログイン中だけでした。

制作時の確認用のプラグインなので、無効化して復旧しました。あわせて次の2つも行っています。

本来、プラグインは必要な WordPress のバージョンを書いておき、条件を満たさなければ更新されない仕組みです。ただ、書いてある条件と中身がずれていることもあります。古いサイトほど、この仕組みに頼りきらないほうが安全です。

当日の作業の順番

当日は、あらかじめ作っておいたチェックリストを上から順に進めました。

  1. Basic 認証でサイトを閉じ、データベースをバックアップ
  2. WordPress 本体を更新(PHP は 7.4 のまま)
  3. 配布終了の WP Total Hacks の機能を移し、不要なプラグインと一緒に削除
  4. プラグインを1本ずつ「更新 → 有効化 → 確認」
  5. PHP 8.3 へ切り替え
  6. PHP 8 系が必要なプラグイン(WP-PageNavi)を更新し、jQuery の読み込みを変更
  7. 全ページと管理画面の確認、後片付け

PHP を先に上げると、古い WordPress やプラグインが PHP 8.3 に対応しておらず、画面が真っ白になるおそれがあります。WordPress とプラグインを先に最新にして、PHP の切り替えは後、というのが基本です。

WP Total Hacks の代わりを用意する

WP Total Hacks は、管理画面や出力をまとめてカスタマイズできるプラグインです。しかし、すでに配布が終わっているため、使っていた機能をそれぞれ別の方法に置き換えました。

使っていた機能置き換え先
WordPress のバージョン情報(generator)を出さないテーマの functions.php
管理者以外にアップデート通知を出さないテーマの functions.php
リビジョンの保存数を制限するwp-config.php
favicon の設定カスタマイザーの「サイトアイコン」
編集画面の項目やダッシュボードのウィジェットを隠すAdminimize

functions.php に追加したのは、次のようなコードです。

// WordPress のバージョン情報を出力しない
remove_action( 'wp_head', 'wp_generator' );
add_filter( 'the_generator', '__return_empty_string' );

// 管理者以外にはアップデート通知を出さない
add_action( 'admin_init', function () {
    if ( ! current_user_can( 'update_core' ) ) {
        remove_action( 'admin_notices', 'update_nag', 3 );
        remove_action( 'network_admin_notices', 'update_nag', 3 );
    }
} );

リビジョンの数は、wp-config.php に define( 'WP_POST_REVISIONS', 5 ); を追記しました。日本語版の WordPress では「That's all, stop editing!」のコメントが日本語で書かれていることが多いので、その上か、require_once ABSPATH . 'wp-settings.php'; より上に書きます。同じ定義が2つあるとエラーになるので、先にファイル内を検索しておきます。

favicon は見落としやすいところです。テーマには favicon を出力する記述がなかったので、WP Total Hacks を消すとブラウザのタブのアイコンも消えてしまいます。今回はカスタマイザーの「サイトアイコン」で設定し直しました。

プラグインの更新で気をつけたところ

プラグインは、無効の状態で更新し、有効化して、表のページと管理画面が開くかを確かめる、という流れを1本ずつ繰り返しました。中でも注意したのは次の3つです。

Really Simple SSL はバージョンが大きく飛ぶ

5系から最新版へと大きく変わり、今はセキュリティ全般を扱うプラグインになっています。更新時に .htaccess や wp-config.php を書き換えることがあるので、更新の直前にもう一度この2つのコピーを取りました。初期設定の画面が出たら SSL の確認だけ進め、ログイン URL の変更などの追加機能は OFF のままにする予定でしたが、今回は画面が出ず、以前の設定がそのまま引き継がれました。

クラシックエディタのツールバーが1段しかない

Advanced Editor Tools を更新したあと、ツールバーが1段しか表示されず、一瞬設定が消えたかと思いました。実際は、1段目の一番右にある「ツールバー切り替え」ボタンで2段目を開く設定で、更新直後は閉じた状態で表示されていただけでした。エクスポートしておいた設定と見比べられたので、すぐに判断できました。

WP-PageNavi は PHP を上げてから

最新版の WP-PageNavi は PHP 8 系が必要で、PHP 7.4 のままでは更新できません。このプラグインだけは、PHP を切り替えたあとに更新しました。

php.cgi で PHP 8.3 に切り替える

対象サイトの公開フォルダ(wp-config.php があるフォルダ)に、次の内容で php.cgi を置きます。

#!/bin/sh
exec /usr/local/php/8.3/bin/php-cgi

ところが、これだけでは PHP のバージョンが変わりませんでした。.htaccess に次の指定を足したところ、8.3 に切り替わりました。

# BEGIN 個別PHPバージョン
Action myphp-script /php.cgi
AddHandler myphp-script .php .html
# END 個別PHPバージョン

追記する場所は、Basic 認証の記述の下、# BEGIN WordPress の上です。WordPress の記述の中に書くと、パーマリンクの保存などで消えてしまうので、外に書きます。

切り替えたあとは、次のことを確認しました。

何かあったときは、php.cgi と .htaccess の4行を元に戻せば、サーバー全体の設定(7.4)に戻ります。片方だけ消すと、.htaccess が存在しないファイルを指して500エラーになるので、戻すときは両方セットです。

jQuery を 3.7.1 にしたらスライダーが止まった

このテーマは、WordPress に同梱の jQuery を使わず、Google の CDN から jQuery 3.4.1 を読み込んでいました。WordPress を更新しても jQuery は変わらないので、表示が崩れる心配はありません。ただ、3.4.1 には 3.5.0 で修正された XSS の脆弱性があるので、読み込みの URL を 3.7.1 に変えました。

すると、トップページのスライダーが動かなくなり、コンソールに次のエラーが出ました。

Uncaught TypeError: $(...).responsiveSlides is not a function

jQuery 3.7.1 との相性を疑いましたが、原因は別のところにありました。jQuery の行を書き換えたときに、その2行下の <script> の閉じタグが </script> から </> に壊れていたのです。

<!-- 壊れていた状態 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/object-fit-images/3.2.4/ofi.js"></>

<!-- 正しい形 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/object-fit-images/3.2.4/ofi.js"></script>

<script> が閉じていないと、ブラウザはその下にあるスライダーの CSS と JS の読み込みまで、スクリプトの中身として読み飛ばしてしまいます。HTML のソースには読み込みの行が出ているのに、実際には読み込まれていない、という分かりにくい状態でした。閉じタグを直すと、スライダーは元どおり動きました。

「○○ is not a function」というエラーは、ライブラリが古いか新しいかより先に、そもそもそのファイルが読み込まれているかを確かめると早いです。開発者ツールの Network タブや、document.scripts で実際に読み込まれたスクリプトを見ると、すぐに分かります。

後片付けで「消すもの」と「残すもの」

最後に、作業のために足したものを片付けます。ここで消してはいけないものまで消すと、サイトが止まります。

消すもの残すもの
.htaccess の Basic 認証の記述php.cgi
.htpasswd(パスワードファイル).htaccess の「個別PHPバージョン」の4行
phpinfo のファイル、debug.logfunctions.php に追加したコード

Basic 認証を外したら、シークレットウィンドウで認証なしで表示されることを確かめ、更新後の状態でもう一度バックアップを取りました。将来 PHP をさらに上げるときは、php.cgi の 8.3 の部分を書き換えるだけで済みます。

プラグインの自動更新は、すべて最新にしたあとなら ON に戻すのがおすすめです。最新の状態からの更新は小さな変更が多く、今回のようなトラブルは起きにくくなります。手動で更新しないまま放置するほうが、リスクは大きいです。

まとめ

古いサイトの更新は、準備さえしておけば当日はチェックリストを順に進めるだけになります。同じような構成のサイトを抱えている方の参考になればうれしいです。

関連記事

アバター
この記事を書いた人 トノムラマサシ

masashi Webサイト屋兼ブロガー|過去に企業常駐などを経て現在はフリーランスでディレクションとコーダーとして活動しております。JS大好きなのでJSの仕事依頼お待ちしております。京都在中で5人家族。