error_logを確認すると、こんなエラーメッセージが大量に記録されていませんか?

PHP Warning: Attempt to read property "ID" on null
PHP Warning: Attempt to read property "post_name" on null
PHP Warning: Undefined variable $post

これらは全て $post変数がnullの状態でアクセスしようとした際に発生するエラー です。本記事では、これらのエラーを根本から解決する方法を解説します。


    1. なぜ$postがnullになるのか

    $postがnullになる主なケース

    WordPress の $post グローバル変数は、以下のような状況で null または未定義になります:

    ケース 説明
    アーカイブページ カテゴリー、タグ、日付アーカイブなど
    404ページ 存在しないURLにアクセスした場合
    検索結果ページ 特定の投稿コンテキストがない
    カスタムテンプレート ループ外で$postを参照した場合
    関数内部 global $post; 宣言なしで使用

    エラーが頻発する理由

    多くのテーマでは、以下のような「危険なコード」が散在しています:

    // ❌ 危険:$postの存在確認なし
    $slug = $post->post_name;
    $custom_field = get_post_meta($post->ID, 'key', true);
    

    これらは投稿・固定ページでは動作しますが、アーカイブページや404ページでエラーを引き起こします。


    2. よくあるエラーパターン5選

    パターン1: post_nameへの直接アクセス

    エラーメッセージ:

    PHP Warning: Attempt to read property "post_name" on null
    

    問題のあるコード:

    $slug = $post->post_name;
    

    修正後:

    global $post;
    $slug = isset($post->post_name) ? $post->post_name : '';
    

    パターン2: IDを使ったget_post_meta()

    エラーメッセージ:

    PHP Warning: Attempt to read property "ID" on null
    

    問題のあるコード:

    $custom_description = get_post_meta($post->ID, '_meta_description', true);
    

    修正後:

    global $post;
    if ($post && isset($post->ID)) {
        $custom_description = get_post_meta($post->ID, '_meta_description', true);
        if (!empty($custom_description)) {
            return $custom_description;
        }
    }
    

    パターン3: get_post_ancestors()での使用

    エラーメッセージ:

    PHP Warning: Undefined variable $post
    

    問題のあるコード:

    $ancestors_ids = array_reverse(get_post_ancestors($post));
    

    修正後:

    global $post;
    if ($post && isset($post->ID)) {
        $ancestors_ids = array_reverse(get_post_ancestors($post));
        foreach ($ancestors_ids as $ancestors_id) {
            // 処理
        }
    }
    

    パターン4: カテゴリー配列への直接アクセス

    エラーメッセージ:

    PHP Warning: Trying to access array offset on value of type bool
    

    問題のあるコード:

    $category = get_the_category();
    $cat_name = $category[0]->cat_name;
    

    修正後:

    if (has_category()) {
        $category = get_the_category();
        if (!empty($category)) {
            $cat_id = $category[0]->cat_ID;
            $cat_link = get_category_link($cat_id);
            $cat_slug = $category[0]->category_nicename;
            $cat_name = $category[0]->cat_name;
        }
    }
    

    パターン5: タグ配列への直接アクセス

    問題のあるコード:

    $posttags = get_the_tags();
    $tag_name = $posttags[0]->name;
    

    修正後:

    if (has_tag()) {
        $posttags = get_the_tags();
        if (!empty($posttags)) {
            $tag_name = $posttags[0]->name;
            $tag_id = $posttags[0]->term_id;
            $tag_link = get_tag_link($tag_id);
        }
    }
    

    3. 基本的な修正方法

    鉄則1: 必ず存在確認をする

    // ❌ NG
    $value = $post->post_name;
    
    // ✅ OK
    if ($post && isset($post->post_name)) {
        $value = $post->post_name;
    }
    

    鉄則2: global宣言を忘れない

    関数内やテンプレートファイルで$postを使う場合:

    function my_custom_function() {
        global $post; // 👈 これを忘れずに!
        
        if ($post && isset($post->ID)) {
            // 処理
        }
    }
    

    鉄則3: 配列は空チェックを行う

    // ❌ NG
    $category = get_the_category();
    $name = $category[0]->cat_name;
    
    // ✅ OK
    $category = get_the_category();
    if (!empty($category)) {
        $name = $category[0]->cat_name;
    }
    

    4. ファイル別の具体的な修正例

    header.php の修正

    修正箇所: メタディスクリプション生成関数

    <?php
    function generate_meta_description() {
        global $post;
        
        $site_name = get_bloginfo('name');
        $page_title = is_home() || is_front_page() ? '' : get_the_title();
        
        // カスタムフィールドの取得(安全に)
        if ($post && isset($post->ID)) {
            $custom_description = get_post_meta($post->ID, '_meta_description', true);
            if (!empty($custom_description)) {
                return $custom_description;
            }
        }
        
        // 抜粋の取得
        if ($post && has_excerpt()) {
            return get_the_excerpt();
        }
        
        // デフォルト
        if (!empty($page_title)) {
            return "{$site_name}の{$page_title}ページです。";
        } else {
            return get_bloginfo('description');
        }
    }
    ?>
    

    修正箇所: body_classへのカスタムタクソノミー追加

    <?php
    /* ページタグ(CPT UI)クラスを、body_class に追加 */
    if (is_singular()) {
        $term_slug_pg = '';
        global $post;
        if (isset($post) && $post) {
            $terms_pg = get_the_terms($post->ID, 'pg');
            if ($terms_pg && !is_wp_error($terms_pg)) {
                foreach ($terms_pg as $term_pg) {
                    $term_slug_pg = $term_pg->slug;
                }
            }
        }
    }
    ?>
    

    index.php の修正

    修正前:

    <?php
    $slug = $post->post_name;
    if (has_category()) {
        $category = get_the_category();
        $cat_id = $category[0]->cat_ID;
        $cat_name = $category[0]->cat_name;
    }
    ?>
    

    修正後:

    <?php
    global $post;
    $slug = isset($post->post_name) ? $post->post_name : '';
    
    if (has_category()) {
        $category = get_the_category();
        if (!empty($category)) {
            $cat_id = $category[0]->cat_ID;
            $cat_link = get_category_link($cat_id);
            $cat_slug = $category[0]->category_nicename;
            $cat_name = $category[0]->cat_name;
        }
    }
    
    if (has_tag()) {
        $posttags = get_the_tags();
        if (!empty($posttags)) {
            $tag_name = $posttags[0]->name;
            $tag_id = $posttags[0]->term_id;
            $tag_link = get_tag_link($tag_id);
        }
    }
    ?>
    

    single.php / page.php の修正

    修正前:

    <?php
    $slug = $post->post_name;
    if (has_category()) {
        $category = get_the_category();
        $cat_name = $category[0]->cat_name;
    }
    ?>
    

    修正後:

    <?php
    global $post;
    $slug = isset($post->post_name) ? $post->post_name : '';
    
    if (has_category()) {
        $categories = get_the_category();
        if (!empty($categories)) {
            $category = $categories[0];
            $cat_id = $category->cat_ID;
            $cat_link = get_category_link($cat_id);
            $cat_slug = $category->category_nicename;
            $cat_name = $category->cat_name;
        }
    }
    
    if (has_tag()) {
        $posttags = get_the_tags();
        if (!empty($posttags)) {
            $tag_name = $posttags[0]->name;
            $tag_id = $posttags[0]->term_id;
            $tag_link = get_tag_link($tag_id);
        }
    }
    ?>
    

    breadcrumb.php の修正

    パンくずリストでも$postを使用する場合、ファイルの冒頭で宣言:

    <!-- breadcrumb.php -->
    <?php global $post; ?>
    <nav class="breadcrumb leckermaul mx-auto py-0.5r">
      <ul class="breadcrumb-wrapper">
        <li><a href="<?php echo home_url('/'); ?>"><i></i>トップ</a></li>
        
        <?php if (is_single() && get_post_type() === 'post' && !is_404()) : ?>
          <!-- 投稿ページの処理 -->
        <?php else : ?>
          <!-- 固定ページの処理 -->
          <?php
          if ($post && has_category()) {
              $ancestors_ids = array_reverse(get_post_ancestors($post));
              foreach ($ancestors_ids as $ancestors_id) {
                  echo '<li><a href="' . get_page_link($ancestors_id) . '">';
                  echo wp_strip_all_tags(get_page($ancestors_id)->post_title, false);
                  echo '</a></li>';
              }
          }
          ?>
        <?php endif; ?>
      </ul>
    </nav>
    

    5. グローバル変数で一元管理する方法

    functions.php でグローバル変数を設定

    同じコードを各テンプレートに書くのは非効率です。functions.php で一元管理しましょう。

    shortcodes.php(functions内:include('~/shortcodes.php');) に追加:

    <?php
    /* ■ 投稿情報のグローバル変数を設定
    ====================================== */
    function setup_global_post_variables() {
        global $post;
        global 
            $slug,  //スラッグ
            $cat_id, $cat_link, $cat_slug, $cat_name,  //カテゴリー
            $tag_id, $tag_link, $tag_name;  //タグ
        
        // $postが存在するか確認
        if (!isset($post) || !$post) {
            return;
        }
        
        // スラッグの取得
        $slug = isset($post->post_name) ? $post->post_name : '';
        
        // カテゴリーの取得
        if (has_category()) {
            $categories = get_the_category();
            if (!empty($categories)) {
                $category = $categories[0];
                $cat_id = $category->cat_ID;
                $cat_link = get_category_link($cat_id);
                $cat_slug = $category->category_nicename;
                $cat_name = $category->cat_name;
            }
        }
        
        // タグの取得
        if (has_tag()) {
            $posttags = get_the_tags();
            if (!empty($posttags)) {
                $tag_name = $posttags[0]->name;
                $tag_id = $posttags[0]->term_id;
                $tag_link = get_tag_link($tag_id);
            }
        }
    }
    add_action('template_redirect', 'setup_global_post_variables');
    ?>
    

    各テンプレートでの使用方法

    上記の設定後、各テンプレートファイルでは以下のように簡潔に書けます:

    <?php
    //グローバル変数
    global 
        $slug,  //スラッグ
        $cat_id, $cat_link, $cat_slug, $cat_name,  //カテゴリー
        $tag_id, $tag_link, $tag_name;  //タグ
    ?>
    
    <!-- これだけでOK! -->
    <h1><?php echo $cat_name; ?></h1>
    

    6. 一括修正チェックリスト

    ステップ1: エラーログを確認

    # エラーログの場所を確認
    tail -f /path/to/error_log
    

    ステップ2: 検索パターンで問題箇所を特定

    以下のパターンをテーマディレクトリ全体で検索:

    • $post->post_name
    • $post->ID
    • get_post_meta($post
    • get_post_ancestors($post
    • get_the_category()[0]
    • get_the_tags()[0]

    ステップ3: ファイルごとに修正

    ファイル 修正内容
    header.php メタディスクリプション生成関数を修正
    index.php スラッグ・カテゴリー・タグ取得を修正
    single.php 同上
    page.php 同上
    breadcrumb.php global $post; を追加
    parts/*.php 各パーツファイルを確認

    ステップ4: ショートコード関数を修正

    shortcodes.php 内の修正例:

    //error-null-9560で、スラッグを出力
    function shortcode_slug() {
        global $post;
        if ($post && isset($post->post_name)) {
            return $post->post_name;
        }
        return '';
    }
    add_shortcode('slug', 'shortcode_slug');
    
    //WordPressで、最初のカテゴリー名を出力
    function shortcode_cat_name() {
        if (has_category()) {
            $category = get_the_category();
            if (!empty($category)) {
                return $category[0]->cat_name;
            }
        }
        return '';
    }
    add_shortcode('cat_name', 'shortcode_cat_name');
    

    ステップ5: 動作確認

    以下のページで動作確認を行います:

    • ✅ フロントページ
    • ✅ 投稿ページ
    • ✅ 固定ページ
    • ✅ カテゴリーアーカイブ
    • ✅ タグアーカイブ
    • ✅ 検索結果ページ
    • ✅ 404ページ

    ステップ6: error_logを再確認

    # エラーログをクリアして監視
    > /path/to/error_log
    tail -f /path/to/error_log
    

    各ページを巡回して、新しいエラーが出ないことを確認します。


    7. まとめ

    修正の要点

    1. $postは常に存在確認する

      if ($post && isset($post->ID)) { /* 処理 */ }
      
    2. 配列も空チェックする

      if (!empty($array)) { /* 処理 */ }
      
    3. 関数内ではglobal宣言を忘れない

      global $post;
      
    4. グローバル変数で一元管理する

      • shortcodes.phpに設定関数を作成
      • 各テンプレートはglobal宣言だけで使用可能

    修正後のメリット

    • ✅ error_logがクリーンになる
    • ✅ サーバー負荷が軽減される
    • ✅ デバッグが容易になる
    • ✅ コードの保守性が向上する
    • ✅ WordPress標準に準拠したコードになる

    【WordPress】bodyのidにスラッグ名、body_classに任意のクラスを追加する方法 WordPressで<body>にIDやクラスを追加する方法:<body id='<?php echo($post->post_name); ?>'> 実はこのコード、エラーが発生します。今回はなぜエラーが起きるのか、そしてどうすれば正しく実装できるのかを、初心者の方にもわかりやすく解説します。   続きを読む

    参考リンク