by ryou

[WordPress]get_postsを使うときにはグローバル変数$postを自前で上書きする必要がある

get_postsを使用して、固定ページ内で投稿情報を取得しようとした際にハマったので覚書。

今までしていた勘違い

setup_postdataは、グローバル変数$postを引数によって上書きする処理も内部で行っている。

(「フレームワークのコア変数を、使用者によって直接書き換える必要があるような設計してるわけないじゃん。」という思い込み)

実際

setup_postdataは投稿に関わるグローバル変数の設定を行うが、その設定に$post自身は含まれない。(!?)

$postに関しては開発者自身がグローバル変数$postに対して代入を行うことで書き換えなければならない。(!?!?)

詳細

WordPress Codexのsetup_postdataの関数リファレンスページの用例には以下のように書かれている。

<ul>
<?php


$args = array( 'posts_per_page' => 5, 'offset'=> 1, 'category' => 1 );

$myposts = get_posts( $args );
foreach ( $myposts as $post ) : setup_postdata( $post ); ?>
    <li>
        <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
    </li>
<?php endforeach;
wp_reset_postdata();?>

</ul>

今まで何の気なしに見ていたが、foreach内で使用されている「$post」という変数名が非常に重要で、ここを別の名前に変更すると動作しなくなってしまう。(具体的には、the_titleとか投稿情報を表示する関数が意図しないデータを返すようになってしまう。)

というのも改めて考えれば当然なのだが、この位置はグローバルスコープである。そのため、foreachのループ毎にグローバル変数$postが表示したいpostデータで上書きされており、その処理が必須となっている。(the_titleとかが変な情報を返すようになるのは、それらがグローバル変数$postを元にデータを返却しているため。)

setup_postdataはグローバル変数$postの設定処理はやらない。$post以外の投稿に関わるグローバル変数の設定をするだけ。(軽く見た中では、setup_postdataを実行しないとthe_authorが正常に動作しなかった)

前述した「フレームワークのコア変数を、使用者によって直接書き換える必要があるような設計してるわけないじゃん。」という思い込みにより別の変数名を使用してしまい、ドハマりしてしまった。ハック的なテクニックでなく、Codexに書いてあるようなコードでまさかそんな手法が書かれているとは思いもよらなかった…

結論

つまり、投稿データを表示する際に必要な処理は

  • グローバル変数$postに、表示させたいpostデータを代入
  • setup_postdataにグローバル変数$postを渡して実行

また、表示処理が完了したら、

  • wp_reset_postdataを実行し、上書きしたグローバル変数$postを元に戻す。

が必要となる。

イメージ的に、setup_postdata内でグローバル変数$postの上書きも行っているかと思っていたが、そんなことは全く無かったので注意しないといけない。