マルチサイトでは、switch_to_blog()で一時的に別サイトへ切り替えて投稿を取得できます。「本部サイトのお知らせを支店サイトに出す」「全サイトの新着をトップにまとめる」といった横断表示の基本です。
<?php
switch_to_blog(1); // ← 対象サイトのID(1はメインサイト)
$query = new WP_Query([
'posts_per_page' => 5,
]);
$items = [];
while ($query->have_posts()) {
$query->the_post();
$items[] = [
'title' => get_the_title(),
'url' => get_permalink(), // ← 切り替え中に取るのが大事
'date' => get_the_date('Y.m.d'),
];
}
wp_reset_postdata();
restore_current_blog(); // ← 必ず戻す
?>押さえるのは2つ——restore_current_blog()を必ず呼ぶこと、URLや画像は切り替え中に取得すること。
出力は「戻したあと」に
上のコードのようにデータを配列に集めてから表示すると、テンプレート側がすっきりします。
<?php if ($items) : ?>
<ul class="cross-site-news">
<?php foreach ($items as $item) : ?>
<li>
<time><?php echo esc_html($item['date']); ?></time>
<a href="<?php echo esc_url($item['url']); ?>"><?php echo esc_html($item['title']); ?></a>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>アイキャッチのHTMLも切り替え中に文字列として作っておくのがコツです(URLがそのサイトのものになります)。
$items[] = [
'title' => get_the_title(),
'url' => get_permalink(),
'thumb' => get_the_post_thumbnail(get_the_ID(), 'medium'), // HTMLごと保持
];サイトの一覧を取得する(get_sites)
<?php
$sites = get_sites([
'number' => 100, // 取得件数(既定100)
'public' => 1, // 公開サイトのみ
'archived' => 0,
'deleted' => 0,
]);
foreach ($sites as $site) {
echo esc_html($site->blog_id) . ' / ';
echo esc_html($site->domain) . esc_html($site->path) . ' / ';
echo esc_html(get_blog_option($site->blog_id, 'blogname')) . '<br>';
}
?>get_sites()が返すのはWP_Siteオブジェクトの配列で、blog_id domain pathが入っています。サイト名や設定値はget_blog_option()で取れます(切り替え不要)。
実例:全サイトの新着をまとめる
<?php
/**
* ネットワーク全体の新着記事を集める。
* 重い処理なので結果をキャッシュする。
*/
function mynet_network_recent_posts($limit = 6) {
$cache_key = 'mynet_network_recent_' . $limit;
$cached = get_site_transient($cache_key);
if ($cached !== false) {
return $cached;
}
$items = [];
foreach (get_sites(['number' => 50, 'public' => 1, 'archived' => 0, 'deleted' => 0]) as $site) {
switch_to_blog((int) $site->blog_id);
$q = new WP_Query(['posts_per_page' => $limit, 'ignore_sticky_posts' => true]);
while ($q->have_posts()) {
$q->the_post();
$items[] = [
'title' => get_the_title(),
'url' => get_permalink(),
'timestamp' => get_the_time('U'),
'site_name' => get_bloginfo('name'),
];
}
wp_reset_postdata();
restore_current_blog();
}
// 日付の新しい順に並べて上位だけ返す
usort($items, fn($a, $b) => $b['timestamp'] <=> $a['timestamp']);
$items = array_slice($items, 0, $limit);
set_site_transient($cache_key, $items, 10 * MINUTE_IN_SECONDS);
return $items;
}ポイントは3つです。
- サイトごとに
switch→取得→restoreを1組で回す - 並べ替えは集め終わってから(サイトをまたぐ並び替えはPHP側で行う)
- 結果をキャッシュする(
set_site_transient()はネットワーク共通のキャッシュ)
メインサイト(親サイト)を参照する
<?php
$main_id = get_main_site_id(); // メインサイトのID
$is_main = is_main_site(); // 今メインサイトを表示しているか
if (!$is_main) {
switch_to_blog($main_id);
$notices = get_posts(['numberposts' => 3, 'category_name' => 'important']);
$data = array_map(fn($p) => [
'title' => get_the_title($p),
'url' => get_permalink($p),
], $notices);
restore_current_blog();
}
?>「本部の重要なお知らせを全支店サイトのトップに出す」——マルチサイトでいちばん需要のあるパターンです。
切り替えずに取れるもの
1つの値を取るだけならswitch_to_blog()は不要です。こちらのほうが軽くなります。
<?php
echo esc_html(get_blog_option(3, 'blogname')); // サイト3のサイト名
echo esc_url(get_site_url(3)); // サイト3のURL
echo esc_url(get_home_url(3, '/contact/')); // サイト3の任意のパス
$details = get_blog_details(3); // ドメイン・パスなどまとめて
?>| やりたいこと | 切り替え | 使う関数 |
|---|---|---|
| 投稿を取得する | 必要 | switch_to_blog()+WP_Query |
| サイト名・設定値を取る | 不要 | get_blog_option() |
| URLを作る | 不要 | get_site_url() / get_home_url() |
| サイトの一覧 | 不要 | get_sites() |
| ネットワーク共通の設定 | 不要 | get_site_option() |
画像URLの注意
画像はuploads/sites/<ID>/にサイトごとに保存されるため、URLもサイトごとに違います。切り替えていない状態でwp_get_attachment_image()にIDを渡すと、今のサイトの画像を探して見つからないという結果になります。
画像のHTMLは切り替え中に作って持ち回る——これを守れば事故りません。
べんりワザアイキャッチ画像の出し方と代替画像アイキャッチの出し方の基本はこちら集計・全サイト横断の処理をするとき
「全サイトの投稿数を数える」ような処理は、サイト数×クエリになるため負荷が高いです。
- 管理画面の画面表示では避ける——WP-Cronや手動実行のバッチで集計し、結果を
site_optionに保存する - 表示側は保存済みの値を読むだけにする
まとめ
- 他サイトの投稿は
switch_to_blog($id)→取得→restore_current_blog()の1組で取る - URL・画像のHTMLは切り替え中に作る。表示は戻したあとで
- サイト一覧は
get_sites()、値を1つ取るだけならget_blog_option()で切り替え不要 - サイト横断の集計は重い——
set_site_transient()でキャッシュする
横断表示ができるようになると、マルチサイトの「まとめて運営できる」利点を活かしきれます。