[修正]WordPress3.0で子サイトの新着記事一覧を表示するテンプレートを書いてみた

お仕事でマルチサイトで作られたブログ(子サイト)の新着記事を親ブログのHOMEに表示するだけなのに意外と苦労させられたのでメモ。

Twitterで聞いてみたら、め組:デジタルキューブ (digitalcube) on Twitter さんから紹介してもらった「鬼太鼓/Oni Daiko 0.5公開します | Webnistのプラグイン」がまさにドンピシャなプラグイン!
…だったのだけど、今回は見送りました。
「鬼太鼓」自体には全く問題がなく、問題があったのはコアファイルの方で、
get_blog_option()関数にどうも不具合があるみたい。

参考: WordPress MUのget_blog_option関数で問題が! | アイビースター

不具合の現象としては、
複数の子サイト全体の最新記事一覧表示で、最初の記事のサイト名・サイトURLが必ず親サイトになってしまう現象でした。

get_blog_option()関数、Wordpress3.1リリース候補2 (2011/01/12現在)でも特に改修されてるようには見えなかったので、
試行錯誤の末、自分でテーマファイルに書いてみた。
(プラグインにするまでの技量はなかったので、、、)

以下のコードをテーマファイルの、home.php等に書けば動くはずです。(WordPress 3.0.3で確認)

2012/11/19 修正 記事のカテゴリ名・リンクも出力

2011/01/12 一部修正

2011/06/01 大幅に修正。
function.phpで関数化。
引数に除外したいブログIDを指定可能に。
複数ブログの追加・削除していてブログ総数とブログIDのMAXとの不整合からの不具合に対応。

2012/06/08 修正
全サイトのblog_idの取得方法を見直し。
get_blogs_of_user( 1, true); だと、admin(指定ユーザーID:1)が管理してる子サイトらしか取得できませんでした。
(管理者権限を持ってる別ユーザーが作成した子サイトは取得できない)

なので、以下のようにSQLを書いて取得する形に切り替えました。
$blogLists = $wpdb->get_results( $wpdb->prepare( “SELECT blog_id FROM wp_blogs ORDER BY blog_id” ) );

参考:WordPressマルチサイトネットワークから新着記事を取得するコード(修正版) | 神戸のフリーランスWebマスターの日報

このページの目次

function.php

以下の関数をコピペしてください。
[php]

get_results($wpdb->prepare(“SELECT blog_id FROM wp_blogs ORDER BY blog_id”));

foreach ($blogLists as $blog) {
$blog_id = $blog->blog_id;
if (in_array($blog_id, $denyBlogs))
continue; //指定ブログはスキップ

//ブログ切替
switch_to_blog($blog->blog_id);
//ブログのサイト名とURLを取得
$siteurl = get_site_url();
$blog_name = get_option(‘blogname’);

$my_posts = get_posts(“showposts=3&post_status=publish”); //公開記事のみ
if (have_posts()) {
//タイムスタンプをキーに記事情報を格納
foreach ($my_posts as $post) {
setup_postdata($post);

$get_post_time = $post->post_date;
//同時更新への対応(タイムスタンプの末尾にブログIDとPostIDを付加)
$unix_time = strtotime($get_post_time) . ‘:’ . $blog_id . ‘-‘ . $post->ID;
$entryAry[$unix_time][‘quid’] = $post->guid;
$entryAry[$unix_time][‘ID’] = $post->ID;
$entryAry[$unix_time][‘title’] = $post->post_title;
$entryAry[$unix_time][‘date’] = date(‘Y/m/d’, strtotime($post->post_date));
//ブログのサイト名とURLを格納
$entryAry[$unix_time][‘siteurl’] = $siteurl;
$entryAry[$unix_time][‘blogname’] = $blog_name;
$entryAry[$unix_time][‘blog_id’] = $blog_id;

//カテゴリ情報保存
$entryAry[$unix_time][‘categories’] = get_the_category($post->ID);

//カテゴリリンクはマルチblog内でしか取得できないので、このループ上で生成
$categories_link = ”;
$categories = get_categories();
foreach ($categories as $category) {
$categories_link .= ‘

  • テンプレート

    こんな感じ。
    [php]

      

       $v ) :
        if( $j < get_option('posts_per_page')):   ?>
        

        

          “>
        

        

          

        
        

          子サイト2のお知らせ記事です
    子サイト2
    2011/01/09
    子サイト3のお知らせ記事です
    子サイト3
    2010/12/27
    子サイト2のお知らせ記事です
    子サイト2
    2010/12/17
    子サイト1のお知らせ記事です
    子サイト1
    2010/11/18
    親サイトのお知らせです

    [/html]

    肝は get_blogs_of_user() でした。
    この関数で全てのマルチサイトのブログの情報を取得できました。
    (パッと見ではブログのユーザーの情報を取得できるように思えたけど全然違った)

    [php]
    $blogLists = get_blogs_of_user( 1, true);
    [/php]

    関連記事:自力でページング:Wordpress3.0のマルチサイトの全てのブログの記事に対応 | 我流天性 がらくた屋

    参考にしたサイト:
    WordPress: get_blog_list() の代用処理について | ブレン | 神戸のホームページ制作/システム開発/PC管理
    WordPress MUのトップページに各ブログの新着記事を表示する | WordPress maaguu (^^; com 北海道札幌でホームページ制作を楽しむ

  • [修正]WordPress3.0で子サイトの新着記事一覧を表示するテンプレートを書いてみた” への23件のフィードバック

    1. はじめまして。
      現在WPのマルチサイトを研究してましてこの記事にたどり着きました。

      ブログIDに縛られずに、時系列に記事を取得できるこのソースは素晴らしいと思い便利に使わせて頂いております。

      貴ソースを見ていてさらに記事内1番目の画像サムネイルまで取得できたら最高だなぁと思いゴリゴリとカスタマイズをやっていたのですが、サムネイルのパスが “wp-content/uploads/yyyy/mm/ファイル名” となってしまい本来やりたい “/ブログスラッグ/wp-content/blogs.dir/ブログID/files/yyyy/mm/ファイル名” にさせるのにどうにも煮詰まってしまいました・・

      下記のソースは追加してやってみているのですが、気をつけるポイント等はありますでしょうか?

      //投稿内のサムネイルを取得
      $dat = get_posts(‘post_type=attachment&orderby=rand&order=ASC&numberposts=1&post_parent=’.get_the_ID());
      if (count($dat)> 0) {
      $image = wp_get_attachment_image_src($dat[0]->ID);
      $desc = $image[0];
      }
      $entryAry[$unix_time][‘image’] = $desc;

    2. こんにちわ。
      ソースが少しは役に立ったみたいで嬉しい限りです。
      ご質問の件は、実証するのに少しお時間ください><

    3. 早速のお返事ありがとうございます。

      色々と調べて見たのですが、他の方のTipsを参考に問題を解決致しました。

      ■最新記事取得
      #WordPress マルチサイトネットワーク内の各ブログから最新の投稿1件を取得し時系列で並べる方法
      http://www.umbrellaprocess.com/archives/503

      ■サムネイル取得/表示
      サムネイル画像を取得する関数 wordpress
      http://mmb.glow-g.net/2010/0730/145415.html

      合わせ技で解決という感じなのですが何とかやりたい挙動をしてくれています。
      (カスタマイズしてもなぜか最新1件しか表示されないのですが・・)
      引き続き、調べていきます。

      また何か進展ありましたら共有させて下さい。

    4. 初めまして、今回いくつか質問がありコメントさせていただきました。
      早速ですが・・・
      各ブログ内のカテゴリーを表示させたいのですが、
      どのような書き方をしたらいいでしょうか?

      また、現在除外したいブログを指定する形になっていますが、
      その逆で表示させたいブログを指定する形に変更する場合、
      どの部分を変更したらいいでしょうか?

      私の方で調べながら、いくつか行ったのですが
      上記二つがどうしても解決出来なかったので、ご教示いただけないでしょうか。
      お手数ですが、宜しくお願い致します。

    5. たけるさんへ

      >各ブログ内のカテゴリーを表示させたいのですが、
      >どのような書き方をしたらいいでしょうか?
      全く考えていませんでした…
      少し見なおして修正しています。

      肝は、カテゴリ関係の関数で、リンクを生成する類は、
      ブログの切り替えが必要だということです。

      なのでfunction.phpの記事を取得して変数に格納する段階で、先にカテゴリのリンクの一覧を文字列として格納する方法にしています(汗
      たぶん、もっとスマートな方法もあると思いますが、取り急ぎということでm(__)m

      出力するHTMLを調整したい場合は、function.phpの該当箇所を調整してください。

      >また、現在除外したいブログを指定する形になっていますが、
      >その逆で表示させたいブログを指定する形に変更する場合、
      >どの部分を変更したらいいでしょうか?

      20行目の
      > if( in_array( $blog_id , $denyBlogs )) continue; //指定ブログはスキップ

      > if( !in_array( $blog_id , $denyBlogs )) continue; //指定ブログ以外はスキップ

      とすれば動くと思います(動作未確認)

    6. >我流@CGFMさん
      お礼がが遅くなり申し訳ございません。
      お忙しい中ご回答、ありがとうございます。
      早速、参考にさせていただきました。

    7. はじめまして。
      子ブログの任意のカステムフィールドの値を持っている投稿記事だけを時系列で取得する方法を探していてこちらのページを見つけました。
      とても参考になっており、便利に使わせていただいております。ありがとうございます。

      ひとつ自力では解決できていない問題がありましたので、質問させてください。
      このコードを利用してページネーションを行おうとしているのですが、うまくできていません。

      コードとしては、以下のようになっています。

      (上の部分は省略しています)
      $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
      $max_page = $wp_query->max_num_pages;
      (途中省略)

      該当記事はありません。

      <?php if(function_exists('wp_pagenavi')) {
      echo $paged."";
      echo $max_page."";
      wp_pagenavi();
      } else {
      vicuna_paging_link('next_label=Newer Entries&prev_label=Older Entries&indent=2');
      } ?>

      echo $paged :結果:1
      echo $max_page:結果:0

      と出ており、max_num_pages が取得できていないようです。
      考えてみれば、functions.phpでは、各子ブログに対して、get_postsをしているので、その結果を配列に格納している状態で、データを利用している場合、max_num_pagesはあるわけがないのかな、と思っています。
      ※そもそも上記の理解で合っているのかも自信はありませんが・・・。

      子ブログから抽出したデータを格納した配列を利用して、ページネーションがなんとかできないかと色々調べてはいるのですが、実力不足で解決できていません。

      よろしければお知恵を拝借できないかと思い、コメントさせていただきます。

      もし、何か良い方法をご存知であればご教示いただけないでしょうか。
      お手数おかけいたしますが、よろしくお願いいたします。

    8. ピンバック: Mylogs
    9. 我流@CGFMさん、はじめまして。

      現在、マルチサイトを使ってwordpressを構築しております。
      /blog/の中をマルチサイトにし、静的トップページの新着情報を子ブログ単位を表示させたく、このブログを拝見させて頂きました。上記の方法でためてしているのですが、うまく記事判定がいかず「記事がありません」と表示されてしまいます。

      バージョンは、WordPress 3.6

      今、やろうとしているのが、
      ブログID 2~29 が表示される 新着情報枠
      ブログID 30~34 が表示される 新着情報枠
      トップページに子ブログを振り分けて表示させたいと思っております。

      なにか、良い方法などご存知であればご教授いただけないでしょうか。
      よろしくお願い致します。m(__)m

    10. モグラさん、コメントどうも。

      >ブログID 2~29 が表示される 新着情報枠
      >ブログID 30~34 が表示される 新着情報枠

      実際にはどんなPHPコードを書かれているのでしょうか??
      (さすがに現象だけ書かれても何が原因かは僕にはどこが悪いかわかりません)

      僕のコードでは、 get_blog_all_entry(array(1,4)); と”除外したいサイトのblog_id”を指定する考え方なので、
      get_blog_all_entry()内の分岐処理なところを数字の範囲指定に書き換えてもらうのが一番ベストです。

      動作確認はしてないですが以下の考え方ではどうでしょうか?

      ---------------------------
      function get_blog_all_entry($denyBlogs, $blogIdStart, $blogIdEnd) { //←引数追加:blogIDの始まりと終わり

      (中略)

      foreach ($blogLists as $blog) {
      $blog_id = $blog->blog_id;
      //blog IDの判別
      if ( in_array($blog_id, $denyBlogs)
      || $blog_id < $blogIdStart || $blog_id > $blogIdEnd
      ) //指定範囲外のblogIDだったら
      continue; //スキップ

      (中略)
      ---------------------------
      //テンプレートの指定方法
      get_blog_all_entry(array(1,4) , 1, 29);
      get_blog_all_entry(array() , 30, 39);

    11. 我流@CGFM

      早速のご返信ありがとうございます。
      現象だけ記載してしまい、申し訳ございません。

      PHPのソースコードは、上記書いている内容をそのまま使わせて頂いております。
      ディレクトリ構成から説明致しますと、少し複雑なのですが下記のような形になっております。

      index.php トップページ 静的ページ
        /blog/ wordpress格納ディレクトリ(各IDごとにマルチサイト化)
      → /01/
      → /02/
      → /01/
      中略・・・・
      → /30/

      /ブログID/home.php フロントページは、カスタムフィールドで表示させるインデックスページ
      (記事投稿ではなく、カスタム投稿で表示するページになります。)

      (ブログ投稿ページ)
      /ブログID/blog/インデックスページ.php
      → page-all.php 固定ページでブログ記事一覧表示
      /ブログID/ブログ詳細ページ.php
      → single.php ブログ詳細ページ

      home.phpがブログの一覧ではないため表示ができないのでしょうか。
      構築経験が少なく、文章が拙いコメントで書いてしまい申し訳ございません。。。

    12. モグラさんへ

      詳細ありがとうございます。

      >静的トップページの新着情報を子ブログ単位を表示させたく
      >index.php トップページ 静的ページ
      ここで「静的トップページ」は、上記の「静的ページ」と同じページでいいでしょうか?

      > /blog/ wordpress格納ディレクトリ(各IDごとにマルチサイト化)
      ということは、静的トップページは、WordPress外にあるということですね?

      それであるならば、すいませんが僕のコードは動きませんよ。
      前提条件はWordPress内のテーマ内で動作するコードです。
      テーマ内で使うWordpress独自の関数と同じように、Wordpress内だけで使える処理や呼び出しを使ってます。

      なので外から切り離した中では記事取得も何もできないので、僕のコードを実行しても
      「該当記事はありません。」
      と出力されてるはずです。

      根本的な解決としてサイト構成を見なおしてWordoressで統一する形にした方が早いと思います。

    13. モグラさんへ

      おそらく、ルートディレクトリもWordpressの領域にすればいいと思います。

      参考)
      Wordpress Codex「WordPress を専用ディレクトリに配置する > 既存のサブディレクトリをルートディレクトリとして表示する場合」
      http://goo.gl/ysfFP

      ◯ /index.php をWordpress で表示する(マルチサイトの親サイトとして)

      ◯ 親サイトのHOME専用テーマファイルに静的トップページだったPHPの内容を移植

      ◯記事内PHPコードを貼り付ける → 新着ブログ記事一覧を取得&表示

      頑張ってみてください。

    14. 我流@CGFMさん

      ご返信ありがとうございます。

      >>静的トップページの新着情報を子ブログ単位を表示させたく
      >>index.php トップページ 静的ページ
      >ここで「静的トップページ」は、上記の「静的ページ」と同じページでいいでしょうか?
      そうですね。ここは静的ページになります。

      >> /blog/ wordpress格納ディレクトリ(各IDごとにマルチサイト化)
      >ということは、静的トップページは、WordPress外にあるということですね?
      >
      >それであるならば、すいませんが僕のコードは動きませんよ。
      >前提条件はWordPress内のテーマ内で動作するコードです。
      >テーマ内で使うWordpress独自の関数と同じように、Wordpress内だけで使える処理や呼び出しを使ってます。
      色々とご教授頂きありがとうございました。

      今回、ある案件のリニューアルでして、
      仕様というしがらみがあり、配下にwordpressインストールしなければいけませんでした。
      (元々、過去wordpressなどがあったり等)

      部分的改修もあり、中々難しい状態ではあります。
      他の方法を模索してみます。m(__)m

      1つ勉強になりましたので、他で記事内ソースを使わせて頂きます。。
      ありがとうございました。m(__)m

    15. モグラさんへ

      なるほど。index.phpがwordpress外に置くしかないならいくつか泥臭い力技があります。

      A: WordPress上で該当記事の出力記事をPHPファイルで出力 → 静的トップPHPでinclude
      B: WordPress上の該当記事表示をiframeで読み込む
      C: 各ブログのRSSを読み込んで自前で処理(PHP or JavaScript + Google Feed API)

      個人的にはGoogle Feed APIで複数RSS読込→時系列表示が一番お手軽かと。

      参考になれば幸いです→ http://news.7zz.jp/ajax/2447.html

    16. 我流@CGFMさん

      返信遅れました。ありがとうございます。

      きれいなソースではないですが、Aの方法で力技で解決してみました。
      色々と記事出力部分で苦戦してしまったのですが、なんとかうまく動作しました。

      = $kiji){
      break;
      }else{
      switch_to_blog($value);
      $posts = get_posts();
      $blog_name = get_option(‘blogname’);

      if( $posts ) {
      foreach( $posts as $post ){
      $blog_date = get_the_time(‘Y/m/d’);
      $post_date[] = $post->post_date;
      $post_list[] = array(
      “link”=>$post->guid,
      “title”=>$post->post_title,
      “name”=>$blog_name,
      “date”=>$blog_date
      );
      }
      }
      restore_current_blog();
      }
      arsort($post_date);
      $i++;
      }
      foreach($post_date as $key => $value) :
      ?>

      <a href="”>

      PHPのははじめてだったので、まだまだ綺麗にかける方法があると思いますが、
      なんとか意図した形で出力できました。

      色々とご相談に乗って頂きありがとうございました。m(__)m

    17. <?php
      $blogs = array(2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30);
      $i = 0;
      $kiji = 6;
      foreach($blogs as $value){
      if($i >= $kiji){
      break;
      }else{
      switch_to_blog($value);
      $posts = get_posts();
      $blog_name = get_option(‘blogname’);

      if( $posts ) {
      foreach( $posts as $post ){
      $blog_date = get_the_time(‘Y/m/d’);
      $post_date[] = $post->post_date;
      $post_list[] = array(
      “link”=>$post->guid,
      “title”=>$post->post_title,
      “name”=>$blog_name,
      “date”=>$blog_date
      );
      }
      }
      restore_current_blog();
      }
      arsort($post_date);
      $i++;
      }
      foreach($post_date as $key => $value) :
      ?>

      <a href="”>

      <?php
      endforeach;
      ?>

    18. 失礼しました。
      タグがうまく貼れなく、2回程送信してしまいました。。。。m(__)m

    19. 我流@CGFMさん、はじめまして。
      他サイトを探しても「ブログごとに各1件づつ」最新情報を取得というものしか探せず、困っておりました。

      ただ、事情があり、全てカスタム投稿タイプで作成しております。
      何分初心者で、それだとどこをどう直せばいいのかわからず、質問させていただきました。
      もしよろしければ、教えていただけないでしょうか?

      ■Aサイト(親)→「Aサイトのお知らせ」
              「Bの施工実例・お知らせ、Cの施工実例・お知らせを日付順で最新5件表示」
      ■Bサイト(子)→施工事例、Bサイトのお知らせ
      ■Cサイト(子)→施工実例、Cサイトのお知らせ

      はなはだあつかましいお願いとは存じますが、よろしくお願いいたします。

    コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

    CAPTCHA


    *