
PHP7からPHP8に上げた瞬間、今まで問題ない(ように見えていた)WordPressの自作コードが、突然Warningを吐き始めました。
Warning: Undefined variable $object ... on line 41
Warning: Trying to access array offset on value of type null ... on line 33
Warning: Attempt to read property "ID" on null ... on line 228
「PHP8にしたら壊れた?」と思いましたが、実際は壊れたわけではなく、 「今まで見逃してた未定義・nullアクセスが見える化した」だけでした。これは今までのコードを直すチャンスでもあります。
体験談として「なぜ同時にエラーが出たのか」と「WordPress(functions.php+ACF)での直し方」と、また起きない形までまとめます。
WordPressサイトをPHP7→PHP8にして警告が増えた理由
PHP8で突然ダメになったというより、未定義やnullが「Warning」として表に出やすくなったことが理由です。
WordPressは、$post などのグローバル変数や「ループ内ならある前提」で書かれたコードがよくあります。そのためfunctions.phpに関数を書いて、好きなタイミングで呼ぶようになると、その前提が一気に崩れます。
私のケースもまさにそれで、functions.phpの関数内で $post->ID といったコードを当然のように使っていたのが原因でした。
Warning: Undefined va friable(未定義変数)の原因と直し方
「Undefined variable」が出たコードの一例がこちら。
get_the_terms($post->ID, 'tag');
functions.phpの関数内でこれをやると、状況次第で $post が存在しません。その結果、$post 未定義 → $post->ID 参照不可となってしまいます。
グローバル変数でも常に使えるわけではなく、WordPressは、ループ外・フックの実行順・カスタムクエリ後・管理画面側など、「今の投稿」が決まっていないタイミングがあります。
そこで、必要なところで get_post() を使って “ある/ない” を判定します。get_post() は、null/false/0 などの値が渡された場合、ループ内のグローバルpostを返します。
【これからの書き方】
functions.phpの関数内では $post をしっかりと定義。まず get_post() で取得し、取れなければそのまま return 。
function my_func() {
$post = get_post();
// 早期return:型チェック + ID存在確
if ( ! $post instanceof WP_Post || empty( $post->ID ) ) {
return;
}
$post_id = absint( $post->ID ); // 整数化
// 以降で $post_id を使う
}absint() – Function | Developer.WordPress.org
Warning: Trying to access array offset on value of type null(nullに対して配列アクセス)の原因と直し方
「Trying to access array offset on value of type null」は、「配列じゃないものに配列としてアクセスしようとしている」というエラーです。
今回このエラーが出たのは、ACFを使って画像フィールドを取得しようとした時です。
$screenshot_url = get_field('screenshot')['url'];
このフィールドの返り値は「画像配列(array)」にしています。そのため通常は ['url'] が取れます。
しかし必須項目にはしていなかったため、空欄になっている投稿がありました。フィールドが空欄だと get_field('screenshot') が null/false になることがあります。そのため、「nullなのに配列としてアクセスしようとしている」という警告が出てしまったわけです。
【これからの書き方】
is_array と empty でチェックしてから ['url'] を読む。
<?php
$image = get_field( 'screenshot' );
// 型ガード:配列 + url キーの存在確認
if ( ! is_array( $image ) || empty( $image['url'] ) ) {
return; // または何も出さない
}
// alt属性のフォールバック(ACF配列には alt も入ってる場合が多い)
$alt = ! empty( $image['alt'] ) ? esc_attr( $image['alt'] ) : '';
// 幅・高さも取れるなら出す(レイアウトシフト防止)
$width = ! empty( $image['width'] ) ? absint( $image['width'] ) : '';
$height = ! empty( $image['height'] ) ? absint( $image['height'] ) : '';
$attr = '';
if ( $width && $height ) {
$attr = sprintf( ' width="%d" height="%d"', $width, $height );
}
?>
<img src="<?php echo esc_url( $image['url'] ); ?>" alt="<?php echo $alt; ?>"<?php echo $attr; ?>>ACFのImageフィールドは返り値形式が「array/string/integer」を選べる仕様になっているため、ここの選択も考えておくとこういったコードエラーが減らせるかもです。
2つ(+もう1つ)が同時に出る理由:未定義→null→アクセス
エラーって別々に見えても、実は一つの原因から連鎖してることが多いんですよね。
$postが無い(または期待してる文脈じゃない)- それでも
$post->IDでデータを取ろうとしている - ID前提で処理を書き続ける(terms、サムネ、ACF…)
- 結果として、別々のWarningが同じページに並ぶ
1個目(未定義/取得失敗)を放置したまま次に進むと、nullに対して ->ID や ['url'] といった記述で、警告がセットで出る。
Attempt to read property "ID" on null というエラーも同時に発生していました。
// 悪い連鎖の概念図(functions.php内で起きがち)
$post_tag = get_the_terms($post->ID, 'tag'); // $postが未定義 → Undefined variable
$screenshot_url = get_field('screenshot')['url']; // ACF空欄 → array offset on null
$post_id = $post->ID; // $postがnull扱い → Attempt to read property "ID" on null
WordPressでの改善例(テーマ/プラグイン/テンプレで起きるパターン)
私は get_the_terms($post->ID, 'tag') といったコードが「いつでも使える」と思っていました。
でも get_the_terms() は戻り値が WP_Term[]|false|WP_Error です。termsが無いと false も返るので、処理をしっかり記述しないと別のWarningを呼びます。
get_the_post_thumbnail($post_id, ...) も同じで、$post_id をどこで作ってるかが曖昧だとうまくいかなくなります。
functions.php関数内の $post 前提と、ACF/option/metaの返り値を、必ず配列だとしないコードを考える必要があります。
/**
* ウィジェット的な出力(記事サムネ+タグ表示)
*
* @return void 出力できない場合は何も返さない
*/
function my_widget_like_output() {
// 1) post 取得 + 型ガード + 早期return
$post = get_post();
if ( ! $post instanceof WP_Post || empty( $post->ID ) ) {
return;
}
$post_id = absint( $post->ID );
// 2) タクソノミー取得(tags)+ エラーハンドリング
$terms = get_the_terms( $post_id, 'tag' );
if ( is_wp_error( $terms ) || false === $terms || ! is_array( $terms ) ) {
$terms = array();
}
// 3) ACF 画像(配列返し)の安全な取得
$image = get_field( 'screenshot', $post_id ); // 第2引数で post_id を明示(推奨)
$image_html = '';
if ( is_array( $image ) && ! empty( $image['url'] ) ) {
$url = esc_url( $image['url'] );
$alt = ! empty( $image['alt'] ) ? esc_attr( $image['alt'] ) : '';
$width = ! empty( $image['width'] ) ? absint( $image['width'] ) : '';
$height = ! empty( $image['height'] ) ? absint( $image['height'] ) : '';
$size_attr = '';
if ( $width && $height ) {
$size_attr = sprintf( ' width="%d" height="%d"', $width, $height );
}
$image_html = sprintf(
'<img class="my-img" src="%s" alt="%s"%s>',
$url,
$alt,
$size_attr
);
}
// 4) 出力(画像が無い場合は出さない early return も可)
if ( empty( $image_html ) ) {
return;
}
echo $image_html;
// 5) タグも出すなら(念のためエスケープ)
if ( ! empty( $terms ) ) {
echo '<ul class="tags">';
foreach ( $terms as $term ) {
if ( ! $term instanceof WP_Term ) {
continue; // 念のため型チェック
}
printf(
'<li><a href="%s">%s</a></li>',
esc_url( get_term_link( $term ) ),
esc_html( $term->name )
);
}
echo '</ul>';
}
}再発防止:PHP8時代の書き方(isset / ?? / nullsafe / 初期化)
- 配列を扱う前に –
is_array()で型チェック(配列かどうか確認) +empty()で空チェックを行う - オブジェクトを扱う時 – 一度変数に取得してから、プロパティやメソッドを操作する(パフォーマンスとnullチェックの効率化)
- 未定義変数の対策 – 変数を使う前に初期化しておく
- Null合体演算子(
??、?->) – 便利だが、適切なチェックの代替にはならない。適切なバリデーションと併用する
/**
* 安全版:画像ブロック出力
*
* @return void
*/
function my_safe_block() {
// 1) post 取得 + 早期return
$post = get_post();
if ( ! $post instanceof WP_Post || empty( $post->ID ) ) {
return;
}
$post_id = absint( $post->ID );
// 2) ACF 画像取得 + 早期return(画像が無いなら何も出さない)
$image = get_field( 'screenshot', $post_id );
if ( ! is_array( $image ) || empty( $image['url'] ) ) {
return;
}
// 3) 安全な出力(alt / width / height 対応)
$url = esc_url( $image['url'] );
$alt = ! empty( $image['alt'] ) ? esc_attr( $image['alt'] ) : '';
$width = ! empty( $image['width'] ) ? absint( $image['width'] ) : '';
$height = ! empty( $image['height'] ) ? absint( $image['height'] ) : '';
$size_attr = '';
if ( $width && $height ) {
$size_attr = sprintf( ' width="%d" height="%d"', $width, $height );
}
printf(
'<img src="%s" alt="%s"%s>',
$url,
$alt,
$size_attr
);
}isset / ?? / nullsafe について
isset() は「変数が宣言されていてnullじゃないか」を判定できます。未定義対策の基本として押さえやすいです。
?? は便利だけど、乱用すると「本当は直すべき取得失敗」を隠してしまうため、必要最低限を心がけたいところです。
?->(nullsafe)はオブジェクトチェーンには効くけど、配列の ['url'] には効きません。ACF画像の事故は is_array + empty が王道です。
| 状況 | 使うもの | 理由 |
|---|---|---|
| 変数が未定義かチェック | isset() | 基本。未定義対策の王道 |
| 未定義の時デフォルト値 | ?? | 短く書けるが、取得失敗を隠しやすい |
| オブジェクトチェーン | ?-> | PHP 8 で簡潔に。ただし配列には効かない |
| 配列のキー存在確認 | is_array() + empty() | ACF画像など配列アクセスはこれが堅い |
| 早期return | if (!$post) return; | WordPress 流。取得失敗を明示的に止める |
まとめ(今日から直せるチェックリスト)
- functions.phpの関数内で
$postを当然のように使わない
→get_post()して取れなければreturn $post->IDを読む前に$postが存在するか確認
→Attempt to read property "ID" on nullとならないように- ACF画像(配列返し)は空欄があり得る
→is_array + !empty($image['url'])でチェック
【バージョンごとの変更内容参考】PHP 付録 – Manual
カテゴリー : WordPress