プラグイン

【プラグイン】無料在席キャスト管理システム krc-cast-manager を使ってみた【続編】

krc-cast-manager を WordPress 7.0 に対応させる続編記事のアイキャッチ
サイトが真っ白になり困っているキャラクター

「前編のとおりに作ったあのサイト、数年ぶりに触ったら…本番でPHPを8に上げた瞬間、真っ白——」。時間が経った“プラグイン資産”では、こんなヒヤリが本当に起こります。

以前、無料の在席キャスト管理プラグイン「krc-cast-manager」を使ってみた記事で、テンプレートの仕組みとショートコード([todayscasthtml] など)を使って、プラグインを“動く”状態にするところまでを書きました。あれから WordPress は 7.0 の時代へ。

この続編は、じつは krc-cast-manager に限った話ではありません。「数年前に作った WordPress 資産を、7.0 時代にどう“延命”するか」――クラシックテーマ前提の古いプラグインやカスタムを抱えている人みんなに当てはまる話です。

前編 → 続編で、どこまで進むか
前編(2023)
とにかく“動かす”
テンプレート理解+ショートコードで、無料プラグインを表示できる状態に。
続編(WordPress 7.0)
“延命”して、壊さず運用する
7.0/ブロックテーマで再検証 → 不具合の恒久対処 → 本番デプロイまで。
WEBさん
WEBさん

念のため一言。ここから先はプラグインの内部コードを断定するものではなく、実際に7.0環境で検証して分かった“勘所”の整理です。適用前は必ずご自身の環境の検証環境で確認してくださいね。

① WordPress 7.0/ブロックテーマ時代に、あの構成はまだ通用するのか

気になるのはまずここですよね。

「せっかく前編で動かしたのに、7.0にしたら全部やり直し?」

結論から言うと、前編の“クラシック子テーマ+functions.phpショートコード”という構成は、WordPress 7.0でも今なお有効です。

理由は明快で、クラシックテーマはWordPress 7.0でも引き続き完全にサポートされているから。

多くのプラグインはクラシックテーマ前提で作られており、実務でも「クラシックテーマ+必要な部分だけブロック対応」という構成は現役です。

ショートコードはブロックテーマでも動く

実際に WordPress 7.0 の Local で確かめると、ショートコードはテーマの種類に依存せず、そのまま動きます。これはWordPressコアの機能だから。[todayscasthtml] のような一覧表示も、この点は心配いりません。ブロックテーマ(FSE)でも、「ショートコード」ブロックに貼り付ければOK。「本日出勤」「新人」といった一覧は、ブロックテーマへ移っても表示手段に困りません。

つまずくのは”個別キャストページ”のテンプレート

やっかいなのはここです。

前回 single-cast.php / content-cast.php で作っていたキャスト個別ページ(カスタム投稿タイプの単一表示)

クラシックテーマは single-cast.php → single.php → singular.php → index.php というテンプレート階層でPHPテンプレートを探します。

一方ブロックテーマは、PHPファイルではなく /templates/ 内のHTMLテンプレート(+DB上の wp_templateでページを組み立てます。

つまり、フルにブロックテーマ(FSE)へ移すなら、キャスト個別ページは single-cast.php の“作り直し”になります。具体的には、

  • キャストのカスタム投稿タイプを show_in_rest 有効で登録し、サイトエディターでテンプレート編集できるようにする
  • スケジュールや写真などのカスタムフィールドは、ブロックバインディングや専用ブロック(WordPress 7.0ではPHPのみで書けるブロックも追加されました)で描画する
  • 従来 get_header() / get_footer() に依存していた箇所は、ブロックテーマではテンプレートパーツ(ヘッダー/フッター)へ置き換える

とくに1つ目が要です。

カスタム投稿タイプに show_in_rest が無いと、そもそもブロックエディターもサイトエディターも開けません。登録はこうなります。

// ブロックテーマのサイトエディターで single-cast を編集できるようにする
add_action( 'init', function () {
    register_post_type( 'cast', array(
        'label'        => 'キャスト',
        'public'       => true,
        'has_archive'  => true,
        'show_in_rest' => true,          // ← これが無いと FSE で編集できない
        'supports'     => array( 'title', 'editor', 'thumbnail', 'custom-fields' ),
        'rewrite'      => array( 'slug' => 'cast' ),
    ) );
} );

ここが移行コストの中心です。「一覧ショートコードだけならブロックテーマでも即移せるが、個別ページのテンプレートは再実装が要る」――これが移行可否の分かれ目。整理すると次の通りです。

観点クラシックテーマブロックテーマ(FSE)
一覧ショートコード(本日出勤・新人など)そのまま動く「ショートコード」ブロックで動く
キャスト個別ページsingle-cast.phpsingle-cast.html+バインディング(要再実装)
ヘッダー/フッターget_header() / get_footer()テンプレートパーツ
このプラグインとの相性◎ そのまま使える△ 個別ページは作り直し
移行の分かれ道
Q. 使うのは一覧表示(本日出勤・新人など)だけ?
YES → ブロックテーマでもOK。ショートコードブロックでそのまま動く。
個別ページも要る → クラシック(ハイブリッド)テーマ維持が現実解。無理にFSE化しない。
WEBさん
WEBさん

だからこそ、この手のプラグインは『クラシック(ハイブリッド)テーマのまま運用』が現実解になることが多いんです。無理にFSE化せず、必要なところだけブロック対応にする――その割り切りも立派な設計判断ですよ。

PHP 7.4 → 8.x の”地雷”に注意

そして、冒頭の“真っ白”の主犯になりやすいのがPHPのバージョン差です。

前編は PHP 7.4 でしたが、現在の推奨は PHP 8.3以上。PHP 8系では、null を文字列関数に渡したときの挙動や配列キーの扱いなどで古いコードが警告・エラーになることがあります。

プラグインやカスタム関数が数年前のものなら、本番でPHPを上げる前に、必ず検証環境で同じPHPバージョンにして動作を確認してください。

② krc-cast-manager の不具合([todayscasthtml])を”暫定対処”から”恒久対処”へ

前編では、[todayscasthtml](本日出勤キャスト表示)の不具合に対して暫定的な修正PHPを追記しました。

正直、あのときは「動いたからヨシ」で止めていました。でも、その場しのぎは同じ症状をまた呼びます。ここでは“恒久対処”にするための考え方を整理します。

「本日出勤」のように“今日”を判定して出し分けるショートコードは、次の3つが不具合の定番原因になりがちです(実際の原因はコードで確認するのが前提です)。

  • 日付・タイムゾーンのズレ:サーバー時刻とWordPressのタイムゾーン設定が食い違うと、「本日」の境界(0時)がズレて、出勤しているのに表示されない/前日の分が残る、という症状が出ます。
  • 空データの未考慮:その日にスケジュールが1件も無いとき、配列が空のまま処理が進んで警告や表示崩れになる。
  • PHP 8系の仕様変更:古い書き方が新しいPHPでエラーになる。
時刻ズレの不具合に困るキャラクター

現場でいちばん多いのが、この「時刻ズレ」です。サーバーのタイムゾーンがUTCのままだと、日本時間の“今日”と1日ずれて、深夜0時をまたいだ瞬間に「本日出勤」へ前日のキャストが残り続ける――翌朝、店長さんから「昨日の子が載ってるよ」と連絡が来て、はじめて気づく。“幽霊出勤”とでも呼びたくなる、あるあるのヒヤリです。

恒久対処の方針はシンプルです。

①“今日”の判定はサイトのタイムゾーンに沿った current_time() で行う

②データが空でも壊れないフォールバックを置く

③出力は必ずエスケープする

この3点を、テーマ更新で消えない場所(Code Snippets やカスタムプラグイン)に実装します。イメージは次の通りです(フィールド名などはお使いの環境に合わせてください)。

add_shortcode( 'todayscasthtml', function () {

    // ① 「今日」はサーバー時刻ではなく、WordPress のタイムゾーンで判定する
    $today = current_time( 'Y-m-d' );

    // 同じ日の再計算を避けるため 1 時間キャッシュ(任意だが実運用では効く)
    $cache_key = 'todays_cast_' . $today;
    $cached    = get_transient( $cache_key );
    if ( false !== $cached ) {
        return $cached;
    }

    $query = new WP_Query( array(
        'post_type'      => 'cast',
        'posts_per_page' => -1,
        'meta_key'       => 'work_date', // 出勤日を保存したフィールド
        'meta_value'     => $today,      // 今日の分だけ取得
    ) );

    // ② 出勤ゼロでも「壊れない」フォールバック
    if ( ! $query->have_posts() ) {
        return '<p class="cast-empty">本日の出勤情報はまだありません。</p>';
    }

    $out = '<ul class="cast-list">';
    while ( $query->have_posts() ) {
        $query->the_post();
        // ③ 出力は必ずエスケープしてから連結する
        $out .= sprintf(
            '<li><a href="%s">%s</a></li>',
            esc_url( get_permalink() ),
            esc_html( get_the_title() )
        );
    }
    $out .= '</ul>';
    wp_reset_postdata();

    set_transient( $cache_key, $out, HOUR_IN_SECONDS );
    return $out;
} );

暫定パッチとの違いは、「その日だけ直る」ではなく「原因の型ごと塞ぐ」点です。current_time() で 0 時の境界ズレを、have_posts() の判定で空データ落ちを、esc_url()esc_html() で不正な出力を、それぞれまとめて防いでいます。

PHP 8 で”急に動かなくなる”典型パターン

krc-cast-manager の不具合として見落とされやすいのが、PHP を 8 系へ上げた途端に噴き出す警告・非推奨(Deprecated)です。

数年前のコードは null を文字列関数に渡す前提で書かれていることがあり、未定義キーの参照で警告が出るうえ、PHP 8.1 以降は trim(null) のような呼び出しが非推奨になります(致命的エラーではありませんが、ログが荒れ、将来のPHPでは動かなくなります)。

// PHP 7.4 では通っていたが、PHP 8 で警告・非推奨になりがちな書き方
$name = strtoupper( trim( $cast['name'] ) );      // 'name' 未定義で警告+PHP 8.1以降は trim(null) が非推奨

// null 合体演算子でガードすれば、PHP 8 でも安全
$name = strtoupper( trim( $cast['name'] ?? '' ) );

ポイントは、「暫定パッチを当てて動いた」で止めないこと。タイムゾーン・空データ・PHP 互換の3点を潰しておけば、同じ系統の不具合の再発をまとめて防げます。

③ 検証環境から本番へ ― 壊さないデプロイと保守

前編は「プラグインを動かすところまで」で、検証環境(Local)の話でした。

でも実際のお店のサイトに載せるなら、本番への持ち出しと、その後の保守まで設計しておかないと、冒頭のような“真っ白”に足をすくわれます。

流れはこうです。

壊さない本番デプロイの流れ
STEP 1
検証環境で完成
STEP 2
本番をバックアップ
STEP 3
dry-runで確認
STEP 4
search-replace本実行
STEP 5
checksum+表示確認

検証環境で”完成”させてから本番へ

いきなり本番でカスタムするのは事故のもとです。

Localなどの検証環境で組み上げ、動作確認まで済ませてから本番へ移すのが鉄則です。移行は All-in-One WP Migration のようなツールで、DB・アップロード・プラグイン/テーマをまとめて運べます。

URL置換は”手打ちSQL”ではなくWP-CLIで

検証環境(localhost)と本番ではURLが変わります。ここで wp_posts を素朴に UPDATE するのは危険です。

WordPressは設定やカスタムフィールドをシリアライズ(直列化)された形で保存していることがあり、単純置換すると「文字数」の情報が実体とズレて壊れます。具体的にはこうなります。

// シリアライズ値は「s:文字数:"中身";」の形。長さが先頭に埋め込まれている
s:22:"https://web-navigator.blog/webnavi-blog";

// これを素朴な SQL 置換で「https://example.com」に変えると…
s:22:"https://example.com";   // ← 長さは 22 のまま、中身は 19 文字。壊れて読めなくなる

だからURL置換は、シリアライズの長さまで正しく直してくれる wp search-replace(WP-CLI)で行います。実際の手順はこうです。

# 1) まず本番の現状をまるごとバックアップ
wp db export backup-$(date +%Y%m%d).sql

# 2) いきなり実行せず、まず --dry-run で影響件数を確認する
wp search-replace 'https://web-navigator.blog/webnavi-blog' 'https://example.com' --dry-run --precise --skip-columns=guid

# 3) 問題なければ本実行(guid は仕様上そのままにするのが定石)
wp search-replace 'https://web-navigator.blog/webnavi-blog' 'https://example.com' --precise --skip-columns=guid

# 4) コア/プラグインが改ざん・破損していないかチェックサムで検査
wp core verify-checksums
wp plugin verify-checksums --all
WEBさん
WEBさん

実は――dry-runを飛ばしていきなり本実行して、うっかり guid まで書き換えてしまい、購読者のRSSに古い記事が“新着”として一気に流れてしまった…という事故、本当にあるんです。バックアップさえあれば戻せますが、無いと血の気が引きます。だから“この3つ”は省かないでくださいね。

--dry-run で「どのテーブルが何件変わるか」を先に見る、guid は置換しない、実行前に wp db export でバックアップを取る――この3つを守るだけで、移行時の事故はほとんど防げます。

“更新で壊れる”を前提に備える

  • 更新前にバックアップを取る(本体・テーマ・プラグイン更新の前は必須)。
  • カスタムPHPは Code Snippets等で個別ON/OFF できるようにし、不具合時に切り分けやすくする。
  • プラグインが長く更新されていない場合は、PHPバージョン互換を「ツール > サイトヘルス」や検証環境のPHP切り替えで定期的に確認する。
  • 「本日出勤」など時刻に依存する表示は、日付をまたぐタイミング(深夜0時前後)で一度実機確認しておく。
  • 本番反映後は wp core verify-checksums と表示確認をワンセットにして、「移した直後に壊れていないか」を必ずチェックする。

まとめ ― 古いプラグインも、”延命”の道はある

安心した表情のキャラクター

冒頭の「本番で真っ白」も、この3点――移行の分かれ道・不具合の恒久対処・壊さないデプロイ――を押さえておけば、慌てずに済みます。

「krc-cast-manager」のような、クラシックテーマ前提のマニアックなプラグインも、頭から諦める必要はありません。クラシックテーマもショートコードも WordPress 7.0 で有効なので、“延命”できる余地は十分にあります。

ただし「そのまま動く」保証はありません

②で見たとおり、数年前のコードは PHP 8 で警告やエラーを出すことがあるため、必ず検証環境で確かめてからが前提です。

そのうえで、

①個別ページのテンプレートはブロックテーマ化すると再実装が要る、

②時刻依存のショートコードはタイムゾーン・空データ・PHP互換を潰して恒久対処にする、

③本番へはWP-CLIとバックアップを前提に“壊さず”移す

――この3点を押さえれば、数年前に作った資産も長く運用しやすくなります。

合わせて読みたい:【前編】無料在席キャスト管理システム krc-cast-manager を使ってみた歯科衛生士コミュニティを WordPress で構築した制作事例