前の記事では「PHP8で何が変わったか」と「error.logの読み方」を紹介しました。
この記事では、実際に発生したWarning 5パターンを、before/afterのコードつきで解説します。

PHP7→PHP8に上げたらerror.logが増えた。まず何をすべきか【WordPress】 PHP7.4からPHP8へのバージョンアップ後にerror.logが急増する原因と、最初にやるべき対処の流れを解説。sort -uでログをユニーク化する方法、FatalとWarningの優先順位の判断など、WordPressテーマをカスタマイズしているレベルの...  続きを読む

    パターン1:$post->post_name on null

    エラーメッセージ

    PHP Warning: Attempt to read property "post_name" on null in header.php on line 229
    

    原因

    グローバル変数 $post は、投稿・固定ページを表示しているときはWordPressが自動的にセットしてくれます。ところが、アーカイブページ・検索結果ページ・404ページでは $postnull になることがあります。

    PHP7.xでは null のプロパティへのアクセスがNoticeで済んでいましたが、PHP8.xではWarningになります。

    Before(よく書かれているコード)

    header.phpindex.php のように、bodyタグのid属性やスラッグ取得で使われていることが多いです。

    // header.php
    <body id='<?php echo esc_attr($post->post_name); ?>'>
    
    // index.php
    $slug = $post->post_name;
    

    After(修正後)

    isset()$post->post_name が存在するか確認してから使います。

    // header.php
    <body id='<?php echo esc_attr(isset($post->post_name) ? $post->post_name : ''); ?>'>
    
    // index.php
    $slug = isset($post->post_name) ? $post->post_name : '';
    

    ポイント

    $post 自体が null のとき、$post->post_name にアクセスしようとするとWarningが出ます。isset($post) だけでなく isset($post->post_name) と書くことで、$post が null の場合も含めて安全にチェックできます。


    パターン2:get_post_meta() の戻り値に ++ をしたときのWarning

    エラーメッセージ

    PHP Deprecated: Increment on type bool in functions.php on line 1034
    

    原因

    ビューカウント(閲覧数)の実装でよく使われるパターンです。get_post_meta()値が存在しない場合に false を返します

    PHP7.xではbool型に ++ しても動作していましたが、PHP8.3以降では Deprecated(非推奨)の警告が出ます。

    Before(よく書かれているコード)

    $post_views_count = get_post_meta($post_id, $custom_key, true);
    
    if ($post_views_count === '') {
        delete_post_meta($post_id, $custom_key);
        add_post_meta($post_id, $custom_key, '0');
    } else {
        $post_views_count++;  // falseが来たときに bool への++ になる
        update_post_meta($post_id, $custom_key, $post_views_count);
    }
    

    問題点

    get_post_meta() の戻り値は string | false です。第3引数を true にした場合、メタデータが存在しないと false が返ります。=== '' のチェックだけでは false を捕捉できないため、else ブロックに false が流れ込んで false++ になります。

    After(修正後)

    $post_views_count = get_post_meta($post_id, $custom_key, true);
    
    if ($post_views_count === '' || $post_views_count === false) {
        // メタデータが存在しない or 空のとき → 初回閲覧なので1をセット
        delete_post_meta($post_id, $custom_key);
        add_post_meta($post_id, $custom_key, '1');
    } else {
        // 明示的に (int) キャストしてから +1 する
        $post_views_count = (int) $post_views_count + 1;
        update_post_meta($post_id, $custom_key, (string) $post_views_count);
    }
    

    ポイント

    • false チェックを === '' と一緒に追加する
    • (int) で明示的に整数にキャストしてから計算する
    • 初期値は '0' より '1' が正しい(初回閲覧時点でカウント1)

    パターン3:foreach() に null を渡すWarning

    エラーメッセージ

    PHP Warning: foreach() argument must be of type array|object, null given in header.php on line 677
    

    原因

    グローバル変数を foreach しているコードで、その変数が別のテーマから複製してきた際に定義されていないケースです。

    たとえば テーマの functions.php には $global_session_params という変数が定義されていても、それをコピー元にして作った テーマでは定義が漏れていた、というケース。

    Before(よく書かれているコード)

    // header.php
    global $global_session_params;
    foreach ($global_session_params as $key => $value) {
        $_SESSION[$key] = $value;
    }
    

    $global_session_paramsnull の場合、PHP8ではWarningが出ます。

    After(修正後)

    global $global_session_params;
    if (is_array($global_session_params)) {
        foreach ($global_session_params as $key => $value) {
            $_SESSION[$key] = $value;
        }
    }
    

    ポイント

    is_array() で確認してから foreach する習慣をつけると、グローバル変数が未定義の場合でも安全に動作します。

    テーマ複製時にグローバル変数の定義が漏れることは非常によくあります。定義を追加するよりも、使用側で防御的チェックをするほうが他のテーマに使い回せて安全です。


    パターン4:存在しない $_GET キーへのアクセス

    エラーメッセージ

    PHP Warning: Undefined array key "post" in functions.php on line 976
    

    原因

    WordPress管理画面では、URL上のパラメータがページによって変わります

    たとえば投稿一覧から投稿を開くURLは /wp-admin/post.php?post=123&action=edit ですが、新規投稿作成のURLは /wp-admin/post-new.phppost パラメータがありません。

    $_GET['post'] を直接参照しているコードは、post パラメータが存在しないページでWarningが出ます。

    Before(よく書かれているコード)

    function disable_visual_editor_in_page($args) {
        $post_id = $_GET['post'];  // 新規投稿画面では存在しない
        $post_type = get_post_type($post_id);
        if ($post_type === 'page') {
            $args['tinymce'] = false;
        }
        return $args;
    }
    add_filter('wp_editor_settings', 'disable_visual_editor_in_page');
    

    After(修正後)

    function disable_visual_editor_in_page($args) {
        if (!isset($_GET['post'])) {
            return $args;  // postパラメータがないときは何もせず返す
        }
        $post_id = $_GET['post'];
        $post_type = get_post_type($post_id);
        if ($post_type === 'page') {
            $args['tinymce'] = false;
        }
        return $args;
    }
    add_filter('wp_editor_settings', 'disable_visual_editor_in_page');
    

    ポイント

    $_GET$_POST のキーにアクセスする前は、必ず isset() で存在確認をします。「このページでは必ずあるはず」という思い込みがWarningの原因になります。


    パターン5:if-elseif-else の全分岐で変数が定義されていない

    エラーメッセージ

    PHP Warning: Undefined variable $pbndSml in parts/pagecover/pageband-elf.php on line 222
    

    原因

    if-elseif-else で変数を定義する際、最後の else ブロックで変数の定義が漏れているケースです。

    Before(よく書かれているコード)

    if ($page_band_style === 'large') {
        $pbndSml = 'pbnd-lg';
    } elseif ($page_band_style === 'medium') {
        $pbndSml = 'pbnd-md';
    }
    // else ブロックがない、または else の中で $pbndSml を定義していない
    
    // 後続の処理
    echo '<div class="' . $pbndSml . '">';  // $pbndSml が未定義の場合にWarning
    

    After(修正後)

    if ($page_band_style === 'large') {
        $pbndSml = 'pbnd-lg';
    } elseif ($page_band_style === 'medium') {
        $pbndSml = 'pbnd-md';
    } else {
        $pbndSml = '';  // 主要な分岐で必ず定義する
    }
    
    echo '<div class="' . $pbndSml . '">';
    

    ポイント

    if-elseif で条件を列挙するとき、最後の else を忘れやすいです。変数を使う前に必ず初期化されているか確認しましょう。

    テンプレートファイルの先頭で $pbndSml = ''; と事前に初期化しておく方法もあります。

    // ファイルの先頭で初期化しておく方法
    $pbndSml = '';
    
    if ($page_band_style === 'large') {
        $pbndSml = 'pbnd-lg';
    } elseif ($page_band_style === 'medium') {
        $pbndSml = 'pbnd-md';
    }
    

    どちらの書き方でも問題ありませんが、「使う前に必ず定義済みの状態にする」という意識が大切です。


    まとめ

    パターン 原因 対処
    $post->post_name on null アーカイブ等で$postがnull isset($post->post_name) チェック
    bool increment get_post_meta()がfalseを返す falseチェック + (int)キャスト
    foreach() null グローバル変数の定義漏れ is_array() チェック
    $_GET undefined key URLパラメータが存在しないページ isset() チェック
    変数未定義 全分岐での定義漏れ elseブロックでも初期化

    いずれも「存在確認をしてから使う」「型を確認してから演算する」というシンプルな対処です。


    関連記事

    WordPressテーマのFatal Errorとエラーの連鎖構造を直す【PHP7→PHP8移行】 PHP8移行後にWordPressが真っ白になるFatal Errorの原因と修正方法を実例で解説。get_page_by_path()への配列渡し問題、includeの失敗がsession_startエラーを引き起こす連鎖構造のしくみ、テーマ複製時に起きやす...  続きを読む PHP7→PHP8に上げたらerror.logが増えた。まず何をすべきか【WordPress】 PHP7.4からPHP8へのバージョンアップ後にerror.logが急増する原因と、最初にやるべき対処の流れを解説。sort -uでログをユニーク化する方法、FatalとWarningの優先順位の判断など、WordPressテーマをカスタマイズしているレベルの...  続きを読む WordPress $post変数のnullエラーを完全解決!error_logを綺麗にする実践的修正ガイド WordPressのerror_logに頻出する「Attempt to read property on null」「Undefined array key」エラー。$post変数や$_GET配列が原因です。本記事では典型的なパターンと修正方法、グローバル変数...  続きを読む