wordpress:マルチサイトで複数の子サイトの記事をまとめて親サイトに日付順表示させる
前回、wordpressをマルチサイト化する手順を書きましたが、今回はタイトル通り「子サイトの記事をまとめて親サイトに表示する」方法を書いていこうかと思います。
子サイトを1つ指定してやる場合は簡単なのですが、複数ある子サイトをまとめてとなると多少厄介です。
ではやっていきましょう。
準備
まずは表示確認のための下準備をします。
サイトの作成とか記事の投稿とかです。
こんな感じで作成しました。
-
子サイト1
記事テスト1
記事テスト2
記事テスト3
記事テスト4
記事テスト5
-
子サイト2
記事テスト1
記事テスト2
記事テスト3
記事テスト4
記事テスト5
-
子サイト3
記事テスト1
記事テスト2
記事テスト3
記事テスト4
記事テスト5
■カテゴリ
3サイトとも共通で。
カテゴリで絞り込まない場合はバラバラでも大丈夫。
- お知らせ/information
- 更新情報/update
- イベント情報/event
■画像サイズ
3サイトとも共通で。
画像を出力しない場合はバラバラでも大丈夫。
- サムネイル/150*150
- 中サイズ/300*300
- 大サイズ/1024*1024
関数「get_multisite_posts」を作る
オリジナルの関数を「get_multisite_posts」とし、作成します。
functions.phpに追記してください。
function get_multisite_posts( $args ) { //サイトの取得 $site = ( !$args['site'] ) ? array( 'site__not_in' => array( 1 ) ) : array( 'site__in' => $args['site'] ); $blogs = get_sites( $site ); //カテゴリー $category = ( !$args['category'] ) ? false : $args['category']; //取得件数 $limit = ( !$args['limit'] ) ? false : $args['limit']; global $wpdb; $sql = ''; foreach( $blogs as $blog ){ //blog切り替え switch_to_blog( $blog->blog_id ); $str = "(SELECT posts.*,%d as blog_id,%s as blog_name".PHP_EOL; $str .= "FROM {$wpdb->posts} AS posts".PHP_EOL; $sql .= $wpdb->prepare( $str, $blog->blog_id, get_blog_option( $blog->blog_id, 'blogname') ); //termテーブルをjoin if( $category ) { $sql .= "INNER JOIN {$wpdb->term_relationships} AS term1 ON posts.ID = term1.object_id".PHP_EOL; $sql .= "INNER JOIN {$wpdb->term_taxonomy} AS term2 ON term1.term_taxonomy_id = term2.term_taxonomy_id".PHP_EOL; $sql .= "INNER JOIN {$wpdb->terms} AS term3 ON term2.term_id = term3.term_id".PHP_EOL; } $sql .= "WHERE posts.post_type = 'post'".PHP_EOL; //category if( $category ) { $str = "AND term3.slug = %s".PHP_EOL; $sql .= $wpdb->prepare( $str, $category ); $sql .= "AND term2.taxonomy = 'category'".PHP_EOL; } $sql .= "AND posts.post_status = 'publish')".PHP_EOL; //次のblogがあるか next( $blogs ); if( current( $blogs ) !== false){ $sql .= "UNION".PHP_EOL; } restore_current_blog(); } $limit = ( !$limit ) ? null : $wpdb->prepare( 'LIMIT %d', $limit); $sql .= "ORDER BY post_date DESC {$limit}"; $posts = $wpdb->get_results( $sql ); return $posts; }
出力する
<?php $args = array( 'site' => false, 'category' => false, 'limit' => 8 ); $posts = get_multisite_posts( $args ); foreach( $posts as $post ) : switch_to_blog( $post->blog_id ); setup_postdata( $post ); ?> <div> サイト名:<?php echo esc_html( $post->blog_name ); ?><br> タイトル:<?php the_title(); ?><br> 日付:<?php the_date(); ?><br> <a href="<?php the_permalink(); ?>" target="_blank"><?php the_post_thumbnail('thumbnail'); ?></a> </div> <?php restore_current_blog(); endforeach; wp_reset_postdata(); ?>
説明
get_multisite_postsの引数
引数にはサイト、カテゴリ、取得件数を指定できるようにしました。
並び順は投稿日順です。
- 「site」がfalseの場合は親サイト(id=1)を除いたすべてのサイト(子サイトすべて)から抽出します。
指定する場合は配列でブログIDを入れます。 - 「category」がfalseの場合は投稿全てから。
指定する場合は文字列でカテゴリスラッグDを入れます。複数指定は対応していません。 - 「limit」がfalseの場合は全記事を取得。
取得数を指定する場合は数字で。
例1) $args = array( site => false, category => false, limit => false );
例1) $args = array( site => array(2,3), category => false, limit => 10 );
例1) $args = array( site => false, category => 'information', limit => 3 );
中身は以下のようなものとなってます。
[0] => stdClass Object ( [ID] => 21 [post_author] => 1 [post_date] => 2019-01-19 17:38:32 [post_date_gmt] => 2019-01-19 08:38:32 [post_content] => テキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト [post_title] => テスト5 [post_excerpt] => [post_status] => publish [comment_status] => open [ping_status] => open [post_password] => [post_name] => test5 [to_ping] => [pinged] => [post_modified] => 2019-01-20 15:44:38 [post_modified_gmt] => 2019-01-20 06:44:38 [post_content_filtered] => [post_parent] => 0 [guid] => https://securavita.net/demo2/child1/?p=21 [menu_order] => 0 [post_type] => post [post_mime_type] => [comment_count] => 0 [blog_id] => 2 [blog_name] => 子サイト1 )
通常の返り値に「blog_id」と「blog_name」が追加されたものになっています。
get_multisite_postsの説明
//サイトの取得
wordpress関数「get_sites」を使用します。
get_multisite_postsの引数「site」がfalseだった場合、親サイトを除くすべてなのでsite__not_inを。
指定されてる場合はsite__inを。
//blog切り替え
wordpress関数「switch_to_blog(blog_id)」でブログを切り替えます。。
$str = “(SELECT~
SELECTの返り値にblog_idとblog_nameを指定しておきます。
//termテーブルをjoin
get_multisite_postsの引数「category」に指定があった場合のみtermテーブルをjoinします。
カテゴリーのスラッグから判別するには3つのテーブルをjoinさせる必要があります。
- wp_terms
- wp_term_taxonomy
- wp_term_relationships
//category
get_multisite_postsの引数「category」に指定があった場合、ANDにカテゴリー部分を追加します。
//次のblogがあるか
配列「blogs」を次に進め、値がある場合は「UNION」でSQL文を連結します。
UNIONは複数のSELECT文の実行結果をまとめて1つの結果として処理します。
補足
$wpdb->prepare
prepareは不正な操作や不正な文字を処理しないために用意されているものです。
値が変動するものはこのやり方でエスケープさせてください。
X $sql = "SELECT * FROM wp_posts WHERE post_type = 'post' AND ID = {$post_id}"; ○ $sql = $wpdb->prepare( "SELECT * FROM wp_posts WHERE post_type = 'post' AND ID = %d", $post_id );
PHP_EOL
SQL文にいちいちPHP_EOLを書いて改行させてますが、これは確認するときに見やすいからやってるだけでなくてもOKです。
ただ、SQL文が連結しないよう、半角スペースなどできちんと分割させておいてください。
X SELECT * FROM wp_posts WHERE post_type = 'post'AND ID = 1; ○ SELECT * FROM wp_posts WHERE post_type = 'post' AND ID = 1;
今回は簡易版
一応、カスタム投稿やカスタム分類、カスタムフィールド、ページ送りに対応したものもできるんですがかなりややこしくなるため今回は簡易版です。
時間があればやってみます。
マルチサイトで同様のことをしたく、この記事を見つけました。
丁寧なご説明で子サイトの投稿情報を無事取得することができました。
たとえばこの一覧にページ送りを設けたい場合どのような
記述を追加すればよいでしょうか。。
コメントありがとうございます。
単純なページ送り(次・前のページ)をつけるだけなら、URLクエリにpaged(現在のページ)をもたせてその分SELECT文にoffsetを追加して調整してやればいけます。
次のページがあるかどうか調べないといけないので表示したい数+1件取得し、その数が表示したい数よりも大きい場合は次のページがあるという判断にしますかね。
よくあるページ数のボタンつけたい場合は全件数を取得しないといけないので、その処理が先にいりますね。
全件取得後その数を表示したい数で割れば総ページ数がでますので。