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. まとめ
修正の要点
-
$post
は常に存在確認するif ($post && isset($post->ID)) { /* 処理 */ }
-
配列も空チェックする
if (!empty($array)) { /* 処理 */ }
-
関数内では
global
宣言を忘れないglobal $post;
-
グローバル変数で一元管理する
- shortcodes.phpに設定関数を作成
- 各テンプレートは
global
宣言だけで使用可能
修正後のメリット
- ✅ error_logがクリーンになる
- ✅ サーバー負荷が軽減される
- ✅ デバッグが容易になる
- ✅ コードの保守性が向上する
- ✅ WordPress標準に準拠したコードになる
【WordPress】bodyのidにスラッグ名、body_classに任意のクラスを追加する方法
