初心者さんが陥りがちなWordPressループのミス:固定ページにブログの新着を取得表示+ページ内容も表示(※情報古いです)

クリックで拡大

#2013.03.25追記
この記事を公開してから2年以上が経ちました。このページに記載している実装方法内には、現在おすすめできないものも含まれています。
今後は「今さら…いや今だから「WordPressのトップページに、新着記事○件を表示する」サンプルコードをあげとく」を参照してください。

#2011.12.12追記 記載内容について、加筆訂正しました。

2年ほど面倒を見ていた、元会社の後輩君からWordPressに関する相談が。
どうやら、サイトのトップページにお知らせとブログの新着記事タイトル5件を出したいけど上手くいかないとのこと。

仕上がりはこんな感じ。(右図)
ブログの新着記事+自由記述でお知らせを掲載したいとのこと。

1.現状把握(後輩君がやっていたこと)

クリックで拡大

  • 固定ページ「HOME」を作り、そこへページテンプレート(toppage.php)を適用。
  • 「ブログ」は、通常の投稿機能を使用。投稿表示のために、「ブログ」という空の固定ページを作成。
  • そして、ダッシュボードの「設定>表示設定>フロントページの表示」で「HOME」を、「投稿ページ」で「ブログ」をそれぞれ選択。

ここまでが設定してありました。

2.症状(何が上手くいっていなかったのか)

クリックで拡大

肝心の症状を書いてませんでした。
こうなっちゃうんです。

「HOME」っていう固定ページの内容を表示させたいのに、上で取得したブログ新着記事1件目が表示されてしまっている状態です。

3.ソースを見てみよう!

問題の部分だけ抜き出してみます。

<h2>新着ブログ一覧</h2>
<dl class="news">
<?php $posts = get_posts('numberposts=5&order=desc');
foreach($posts as $post): ?>
<dt><?php echo date("Y年m月d日", strtotime($post->post_date)); ?></dt>
<dd><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></dd>
<?php endforeach; ?>
</dl>
 
<h2>お知らせ</h2>
<!-- 投稿ここから -->
<?php if(have_posts()): while(have_posts()): the_post(); ?>
<div class="post">
<?php the_content(); ?>
</div><!-- /.post -->
<?php endwhile; endif; ?>
<!-- /投稿ここまで -->

ちなみに、「ブログの新着をTOPに表示させる方法はどれを参考にした?」って訊いたら、
「コレ→『[WordPress]ワードプレスでトップページなどに新着情報を表示する方法』だそうですので貼っておきます。

4.解決法その1 順番を変える

私も同様の経験があるのですぐピンときました。
説明抜きで、最も手っ取り早く解決するなら、通常のループを先に持ってくることですかね。

<h2>お知らせ</h2>
<!-- 投稿ここから -->
<?php if(have_posts()): while(have_posts()): the_post(); ?>
<div class="post">
<?php the_content(); ?>
</div><!-- /.post -->
<?php endwhile; endif; ?>
<!-- /投稿ここまで -->
 
<h2>新着ブログ一覧</h2>
<dl class="news">
<?php $posts = get_posts('numberposts=5&order=desc');
foreach($posts as $post): ?>
<dt><?php the_time('Y年n月j日'); ?></dt>
<dd><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></dd>
<?php endforeach; ?>
</dl>

これだと、ただ順番入れ替えるだけで解決です。
(※日付を出力するタグも、WP標準のthe_timeに変更しています。)
つまりは、上に記述したget_posts() をそのまま引き継いじゃってるんですね。

5.解決法その2 query_posts() 関数を使う ※2013.07.21追記:現在はおすすめしません

いやいや、レイアウト上入れ替えは無理だ、って気持ち分かります。
て、ことで、ちゃんとCodexにも記載があります。

テンプレートタグ/query posts – WordPress Codex 日本語版

query_posts は WordPress ループ で表示される投稿を変更するために使います。

上掲ページの「使い方」のスニペットを参考に、ループ部分を書き換えて

<?php if(have_posts()): while(have_posts()): the_post(); ?>

<?php query_posts(); //コレを追記
if(have_posts()): while(have_posts()): the_post(); ?>

てな感じにしてやればOKです。
あとは念のため、ループ閉じる時にwp_reset_query();を付けるとなおよし。

ついでにCodexページには、新着5件を取得時に使っているget_posts()関数についても説明があります。あわせて参照を!

6.解決法その3 get_posts内で、$postsと$postという変数名を使わない

最後の、この方法が最も良いかと思います。
いつもお世話になってる「まがりんさん」こと@jim0912さんがフォーラムで回答してました。

get_postsを利用されるのであれば、$postsと$postという変数名を使わなければ問題ありません。

WordPress › フォーラム » get_postsでループ処理をした後のthe_contentの内容について

7.解決法その4. setup_postdata($post); を適切に使う 【11/12/12追記】

今まで書いてきた話って、グローバル変数とかそのへんの話をしなくてはいけないので、初心者さんにはちょっとハードルが高いのですよね。
なので今回は割愛するんですが、基本ループの「the_post()」にあたると思われるsetup_postdata($post); の記述を加えることで、投稿データがグローバル変数に設定されるという…
このへんは、もう少しちゃんと噛み砕いて1本記事書きたいところです。今回は不親切に結果だけ記載。
この方法が、Codexにも書いてある書き方なので変数って何?とか、そういうの分からないひとはこれ使っとけばいいと思います。多分。

<h2>新着ブログ一覧</h2>
<dl class="news">
<?php
$news = get_posts('numberposts=5&order=desc');
foreach($news as $post):
setup_postdata($post);
?>
<dt><?php the_time('Y年n月j日(D) H:i'); ?></dt>
<dd><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></dd>
<?php endforeach; ?>
</dl>

以上です。
覚えちゃえば簡単なんですけど、初めてだと焦りますよね。

※引数のnumberposts=5は、query_postsタグに倣ってposts_per_page=5でもOK。

コメントをどうぞ

メールアドレス (必須・公開されません)
コメント本文

  • スパム・迷惑コメント投稿防止のため、メールアドレスの入力が必須ですが、公開はされません。何卒ご協力のほどお願いいたします。
  • 投稿いただいたコメントは管理者のチェック後掲載しておりますので、即時には反映されません。
  • 記載内容に関する批判や間違いの指摘などはそのまま掲載する方針ですが、投稿内容と無関係な誹謗中傷、一方的な罵詈雑言の場合は削除させていただく可能性があります。
  • 通常業務の合間にコメントチェックをしておりますので、すべてのコメントへのお返事が出来ない場合もございます。あらかじめご了承ください。
  • 管理人個人への連絡等は、コメント欄ではなくコンタクトフォームをご利用ください。

書籍を執筆しました

WordPress 標準デザイン講座【Version 4.x対応】


翔泳社さんより、2015/02/27発売しました。2年経ちますのでもう賞味期限切れだとは思いますが、一応実績として...

寄付歓迎(・ω<)☆

当ブログの記事があなたの役に立ったら、気が向いたらでいいのでドネーションいただけると更新の励みになります!
気が向いた方はこちらから

ブログ内検索