#WordPress マルチサイトネットワーク内の各ブログから最新の投稿1件を取得し時系列で並べる方法

2011.8.28:別サイトにて修正版をアップしました。

 

WordPress3.0以降で標準で使える様になった、複数のブログをひとつのWordPressで管理できるネットワーク機能。ネットワーク内のブログの新着記事は普通トップページに表示したいと思うので、表題の機能は需要がありそうだからテンプレートタグがあってもいいのになぁと思うのですが、見つからなかったので自作。いや、ほんとに探したらあるのかもしれないけど!

方針

functions.phpに、ネットワーク内の全ブログから最新1件の投稿を取得し、時系列で並び替える関数を用意する。表示はお好みで。

関数(functions.phpに入れるととりあえず使えます)

// $startを1以上にすると最新のn件を飛ばして取得できます
// $numで取得する件数を指定。
function get_recentposts_from_network( $start = 0, $num = 10 ) {
 $recent_posts = get_site_option("network_recentposts");

 // データが残っていない場合、60秒以上経過している場合はアップデートする
 if( is_array( $recent_posts ) ) {
 if( ( $recent_posts['time'] + 60 ) < time() ) { // cache for 60 seconds.
 $update = true;
 }
 } else {
 $update = true;
 }

 if( $update == true ) {
 unset( $recent_posts );
 // 全ブログのIDを取得
 $blogs = get_blog_list( 0,'all' );

 if( is_array( $blogs ) ) {
 reset( $blogs );
 // 各ブログの最新1件を取得する
 foreach( $blogs as $blog ) {
 switch_to_blog( $blog['blog_id'] );
 $posts = get_posts( 'numberposts=1' );
 if( $posts ) {
 foreach( $posts as $post ) {
 $recent_posts[$blog['blog_id']] = $post->post_date;
 $post_list[$blog['blog_id']] = $post;
 } // endforeach
 unset( $posts );
 } // endif ( $posts )
 restore_current_blog();
 } // endforeach
 // 投稿日時で並べ替える
 arsort( $recent_posts );
 reset( $recent_posts );
 foreach( (array) $recent_posts as $key => $details ) {
 $t[$key] = $post_list[$key];
 } // endforeach
 unset($recent_posts);
 $recent_posts = $t;
 update_site_option( "network_recentposts", $recent_posts );
 } //endif ( is_Array( $blogs ) )
 } // endif ( $update == true )

 if( $recent_posts )
 return array_slice( $recent_posts, $start, $num, true );

 return array();
}

表示

関数からの返り値には、ブログIDをキーとした配列に、各投稿のデータが入っています。switch_to_blog()でブログをスイッチしてからsetup_postdata()で投稿データをセットアップすると、テンプレートタグが普通に使える様になります。あとはお好みでどうぞ!

<?php
$network_posts = get_recentposts_from_network( 0, 5 );
if( $network_posts ) :
?>
<ul>
 <?php
 foreach( (array) $network_posts as $blog => $post ) {
 switch_to_blog( $blog );
 setup_postdata( $post );
 ?>
 <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
 <?php
 restore_current_blog();
 }
 wp_reset_query();
 ?>
 </ul>
<?php endif; ?>

これでフィードも作ろうと思ったらかなり面倒…。

WPMUをずっと使ってこられた方なら、何かいい方法を知ってるのかもしれない 😉

#WordPress マルチサイトネットワーク内の各ブログから最新の投稿1件を取得し時系列で並べる方法」への53件のフィードバック

  1. この記事に助けられました。ありがとうございます!
    ひとつ教えて欲しいのですが、親サイト(サイトid=1)のブログの更新情報もリストに含まれるのですが、それを表示させないようにするにはどうしたら良いでしょうか?
    functions.php の
    // 全ブログのIDを取得
    $blogs = get_blog_list( 0,’all’ );
    の書き方を変えれば良いですか?
    phpが全然わからずどうしたら良いかわかりません。
    何卒宜しくお願い致します!

    1. コメントありがとうございます。
      id1のブログを含めない方法ですが、関数の方をいじってあげてください。
      「foreach( $blogs as $blog ) {」の後ろに「if( $blog[‘blog_id’] != 1 ){」と追加すればid1以外のデータを取得します。if文を閉じるのもお忘れなく。

      1. こんなに早く返信いただけるとは。
        早速入れてみたら無事に親ブログが表示されなくなりました。
        ありがとうございました!

  2. ネットワーク機能についての記事がなかなか見つからず、悩んでいたのでとても助かりました。
    質問があるのですが、各ブログの記事数を1件ではなく、すべて表示させるにはどの様にすればいいでしょうか。
    numberpostsを-1にしてみたりしたのですが、うまくいかず悩んでいます。
    よろしくお願いいたします!

    1. WordPressのデータベース構造はそれぞれのブログが独立しているので、すべての投稿の新着順を表示するのは非現実的です。この方法も無理矢理なので。

      1. 上の方も書いてましたが、こんなに早く返信いただけるとは!
        上記の件、了解いたしました。何か他の見せ方を考えてみます。
        ありがとうございました!
        ちなみにカヒミ・カリィのアルバム、僕もびっくりして買ってしまいましたよ!

        1. 単に複数サイトのRSSをまとめるという手段もありますし、サイト内のブログの数が限られている場合はそれで十分かもしれませんね。
          カヒミのアルバムはよいですね! ;-D

  3. この記事を見つけることができてとても助かりました。ありがとうございます。
    そして実際に上記のソースを使ってテストをしていたところ、
    現状のブログ数全ての新着1件を表示させていますが、
    表示する件数を指定することはできますでしょうか?
    functions内の3行目( $start = 0, $num = 10 )の”$num = 10”を指定したい数に
    変更をしたのですが、変わらず悩んでいます。
    教えて頂けると幸いです。
    よろしくお願いいたします。

    1. functions内の3行目は初期値の設定ですので、利用する際に数値を指定してください。

      get_recentposts_from_network( 0, 5 );

      でこの数値指定の意味は全ブログから新着1件を取ってきて新着順に並べたあと、最新から5件を表示しているという意味です。

      1. ご返信ありがとうございます!
        上の方々のとおり、こんなに早く返信をいただいていたとは、、
        そしてご丁寧な説明までありがたいです。
        get_recentposts_from_network( 0, 5 );のところだったんですね。
        勉強になります。本当に助かりました。

  4. 初めまして。
    皆さんと同じ悩みをもつものです。
    最新の投稿1件とは何処で定義していますか?
    いろいろ調整してみたのですが変化しません。
    どうかご教授ねがいます。
    よろしくお願い致します。

    1. 各ブログの最新n件にするには下記部分の1を変更してみてください。
      $posts = get_posts( ‘numberposts=1’ );

      未検証ですが、たぶん大丈夫だと思います。あまり多くすることはおすすめしません。

  5. 返信ありがとうございます。
    件数は増えませんでした。
    解ったことがあります。

    numberposts=XのXは各ブログの最新からX番目でした。

    頑張ってみたのですが最新n件を解析できませんでした。

    申し訳ないのですがもう少し力を貸していただけないでしょうか?

    よろしくお願い致します。

    1. > numberposts=XのXは各ブログの最新からX番目でした。
      その通りです。どんな仕様をご希望ですか?

      1. 各ブログから5件ずつ新しいエントリーを抽出(3ブログ合った場合15件)し、その中で最新の10件を表示するというような仕様を考えております。

        よろしくお願い致します。

        1. 下記2箇所、修正ください。
          ————
          $posts = get_posts(‘numberposts=1’);

          $posts = get_posts(‘numberposts=5’);
          ————
          get_recentposts_from_network( 0, 5 );

          get_recentposts_from_network( 0, 10 );
          ————
          この記事、意外と需要ありますね〜。お仕事でWordPressを使われているのですか?

          1. はい。仕事でWordpressを主に使っています。
            今までマルチブログの案件が無かったので今回のような要件がありませんでした。
            これから試してみます。
            後ほどご報告いたします。

          2. ダメでした。
            $posts = get_posts(‘numberposts=1′);

            $posts = get_posts(‘numberposts=5′);
            こっちはfunctions.phpへ

            get_recentposts_from_network( 0, 5 );

            get_recentposts_from_network( 0, 10 );
            こっちはindex.phpへ

            4ブログつくってあって3つのエントリーなので12件。
            そのうちの最新なので10件表示されてないといけないのに4件しか表示されてないのです。
            その4件は各ブログの最古記事。

            分かりません・・・

            よろしくお願いいたいします。

          3. 単一ブログならなんとかなる関数もマルチブログにだとわからない事だらけでした。
            いろいろ我侭な仕様に対応していただき今回は大変感謝しております。
            ありがとうございました。

  6. はじめまして、先日こちらの記事を拝見し、とても参考にさせていただきました。
    お仕事の方のページには、
    >よく更新するブログばかりトップページに出てくるのを防ぐため。
    と記載があったのですが、逆にそのような形式で表示を行いたいと考えています。
    (更新のあったブログが順番に表示される形式)
    どちらの箇所を変更すれば可能か、ご教示頂けないでしょうか?

    1. こんにちは。その件はyossy44さんの質問への回答で修正したのですが、ブログにアップするのを忘れていました。しばらくお待ちください!

    1. ↑の件、すみません、私の勘違いでした・・・。
      標準で、更新された順にblogが並べ替えられるようになっていたのですね。

      上の方でコメントにあった、

      「foreach( $blogs as $blog ) {」の後ろに「if( $blog[‘blog_id’] != 1 ){」と追加すればid1以外のデータを取得します。if文を閉じるのもお忘れなく。」

      これの閉じる箇所を、if文の直後ではなく、

      return array();
      }

      より後に記載してしまった為、id順に並べ替えられたままとなっていました。
      お手数をおかけし申し訳ありませんでした。

  7. 最近wordpressを始めたのですが、今までphpなんて扱ったことも無かったので、非常に参考にさせていただいています。

    差し支えなければ教えていただきたいのですが、マルチサイトからの新着投稿記事取得で、”最新の投稿記事にmeta_key=〇〇を含むブログだけをピックアップしたい”場合はどのようにすればよいのでしょうか?

    どうぞ宜しくお願いします。

  8. いち早くご返答いただき、ありがとうございました。
    教えていただいた方法で試したところ、バッチリ動いてくれました。感動ものです。
    サイトが完成しましたら、またご報告させていただきますね。

  9. 甘えついでに、もう1つ教えてください。
    最新記事をランダムに抽出しようと思っています。
    arsort( $recent_posts ); を  shuffle( $recent_posts );
    に変えてみるなど、いろいろ試しましたがうまく行きません。
    すみませんが教えていただけるとありがたいです。

  10. すみません。もう少しヒントをお願いします。

    $network_posts = get_recentposts_from_network_rand(0,5);

    $network_posts = get_recentposts_from_network_rand(‘posts_per_page=5&orderby=rand’);
    としましたが、Warning: array_slice() expects parameter 2 to be long, string given in…というエラーが出てしまいます。

    “各ブログからランダムに記事を取得し、それを新しいものから表示する”ではなく、”各ブログから最新記事を取得し、そのうちのいくつかをランダムに表示する”ということをしたいので、
    ” arsort( $recent_posts );”以降の変更が必要かと解釈していますが、いかがなものでしょうか?

    1. ああなるほど、そのタイミングですか。PHPにはshuffleというその名の通り配列をシャッフルする関数がありますので、それを突っ込みましょう。

      if( $recent_posts ) {
      shuffle( $recent_posts );
      return array_slice( $recent_posts, $start, $num, true );
      }

      http://www.phppro.jp/phpmanual/php/function.shuffle.html

      さてこのコード、一部問題ありなのでyossy44さんとのやりとりの時から修正中で、新しくブログ記事をアップする予定です。またよかったら見てください。動作に問題はないのですが、一部余計な処理があるのと、get_blog_listがすでに非推奨に変わったので将来のバージョンでは使えなくなります。

  11. 色々とありがとうございます。
    shuffleだけだとkeyが削除されて、アドレスが崩れてしまうため、Programming Magicさんの記事も合わせて参考にさせていただきながら、何とかできました。
    if( $recent_posts ) {
    { $keys = array_keys($recent_posts);
    shuffle($keys);
    foreach($keys as $key){
    $result[$key] = $recent_posts[$key];}
    return $result; }
    return array_slice( $recent_posts, $start, $num, true );
    マルチサイトのランダムブログリングに活用させていただきます。
    また次の記事も楽しみにしております。

    1. > shuffleだけだとkeyが削除されて、アドレスが崩れてしまう
      うっ、そうか…。となるとキーだけばらけさせてソートするしかないですね。書いてある方法でバッチリだと思います!すいません。

  12. とても参考にさせていただいております。
    親ブログの記事を反映させない方法が以前出ておりました。
     → if( $blog[‘blog_id’] != 1 ){

    反映させないブログを複数指定できますでしょうか
    if( $blog[‘blog_id’] != 1 || 2 || 3 ){
    などやってみましたが、逆にすべて表示されてしまいました。

    ご確認いただければと思います。

    1. この記事ホント需要ありますね…。
      get_blog_listが非推奨になったので、バージョンアップする予定ですのでまた見に来てください。

      とりあえず、条件分岐の書き方が間違っているので、下記でOKです。
      if( ($blog[‘blog_id’] != 1) || ($blog[‘blog_id’] != 2) || ($blog[‘blog_id’] != 3) ){

      1. 早速のお返事ありがとうございました。
        希望通りの動作になりました。(ちなみに || は && でした(^_^;))

        バージョンアップ予定とのこと。
        期待しておりますのでよろしくお願い致します。

  13. KtaiStleで使いたいので組み込んでみたのですが、
    何故かテンプレート側の
    the_title()が 1(ネットワーク管理人)のタイトル名
    the_permalink()が、1の投稿日時、タイトル名になっちゃいます。
     サイト名は正常
     URL: http://www.****/サイト名/2011/06/29/hello-world/

    WP3.1.4 

    KtaiStleに組み込んだ方いますか??

    1. switch_to_blogが効かないってことでしょうね。回避する手段はあると思いますがぱっと思いつきません。

  14. 理由はよく判らないのですが、
    テンプレート側 の foreachの前で global $post; を宣言したら動作しました。

    $post ) {
    switch_to_blog( $blog );
    setup_postdata( $post );

    ↓↓↓↓↓↓↓↓

    $post ) {
    switch_to_blog( $blog );
    setup_postdata( $post );

  15. 全角で投稿します~

     <?php
      foreach( (array)     ・・・・ {
      switch_to_blog( $blog );
      setup_postdata( $post ); 

     ↓↓↓↓↓↓↓↓↓

     <?php
      global $post; 
      foreach( (array)     ・・・・ {
      switch_to_blog( $blog );
      setup_postdata( $post );

  16. はじめまして!
    こちらのソースを大変参考にさせて頂いております。
    不明点が出てきてつまずいてしまったので、もしよろしければご教授ください。

    現在5つの子ブログを運営しており、親ブログの固定ページに子ブログの最新記事一覧のページを作成しております。
    例えば、20件の最新記事があり、10件の最新記事を表示した場合、wp_pagenaviなどのプラグインを使用して、残りの10ページ次へをクリックして表示する。といったような事は可能でしょうか。

    どうぞよろしくお願い致します。

    1. 可能です、というか実際にページ送り対応のために、最新のn件を飛ばして取得出来るようにしています。ただし、プラグインを使用することはできません。自前でページ送りの処理を書く必要があります。

      また、この関数は別サイトにて修正版をアップしていますので、よろしければこちらをお使いください。
      http://notnil-creative.com/blog/archives/774

      1. umbrella_process様
        ご返信ありがとうございます。
        重ねての質問で申し訳ございませんが、お教えいただいたURLから修正版を反映し、ソース下部にページ送りようのコードを追加したのですが、実際のページでページ送りようのコードが出てきません。。

        <?php $network_posts = get_recentposts_from_network(‘num=30’);
        if( $network_posts ) :
        foreach( (array) $network_posts as $key => $post ) {
        switch_to_blog( $post->blog_id );
        setup_postdata( $post );
        ?>
        <div class=”clearfix”>
        <a href=”<?php the_permalink() ;?>”><?php the_title(); ?> post_content), 0, 60); ?>
        </div>
        <?php restore_current_blog(); } wp_reset_query(); endif; ?>

        <?php previous_posts_link(‘< Previous Page’); ?>
        <?php next_posts_link(‘Next Page >’); ?>

        上記のように書いたのですが、なにか根本的に間違っているのでしょうか。。
        どうぞよろしくお願い致します。

        1. previous_posts_linkとnext_posts_linkは、WordPressのコアで実装されているページ送りですよね。上で書いているように、自前でページ送りの処理を書く必要があります。1ページ目は0件目から9件目、2ページは10件目から11件目、分かりますでしょうか?
          あと、このページは古い内容です。できればリンク先の方に質問などは書いてください。

  17. はじめまして、今ポータル系を作ろうとしてるので、こちらの情報が非常にありがたいです!
    ひとつだけ質問されていただいてよろしいでしょうか?

    今回のコードで「記事内の一番目の画像を一覧表示」しようと思い「記事の画像の取得」までは以外とすんなりできたのですが、その後画像から各ブログ記事にリンクをさせようとしたところ、どうしても1番目の記事にしか飛びませんでした。
    そもそもPHPの知識に乏しく、みなさんの情報の寄せ集めで動かしているのがいけないと思うのですが、こちらのコードの場合、ベストな記述というのはあるのでしょうか?

    初心者の質問ですみませんが、もしよい方法があれば是非お聞かせ下さいm(_ _)m

      1. 失礼しました(汗
        早速そちらを拝見させて頂きます。
        早急なお返事有り難うございました。

コメントを残す

メールアドレスが公開されることはありません。