【WordPress】別のWordPressサイトの投稿をREST APIで取得して表示する方法|キャッシュ・安全な出力

別のWordPressサイトの投稿を取得して自分のサイトに表示したいとき、REST API/wp-json/wp/v2/posts)を使うのが基本です。サーバー側で wp_remote_get() を使い、安全な出力とキャッシュまで含めて実装するのが実用的です。

この記事でわかること

  • REST APIのエンドポイントと wp_remote_get() での取得
  • content.rendered安全に出力する(二重エスケープを避ける)
  • トランジェントでキャッシュして毎回叩かないようにする
  • タイムアウト・取得件数の指定
REST APIは「有効化」不要(デフォルトで有効)
REST APIはWordPress 4.7以降、標準で有効です。「設定 → パーマリンク」で有効化する、といった操作は不要で、そのような設定項目もありません。対象サイトのエンドポイント(https://example.com/wp-json/wp/v2/posts)にアクセスしてJSONが返れば利用できます(セキュリティプラグインでREST APIを制限しているサイトは取得できないことがあります)。
スポンサーリンク

REST APIで投稿を取得して表示する

テーマの functions.php やテンプレートで、wp_remote_get() を使って取得します。件数(per_page)とタイムアウトを指定し、is_wp_error() でエラーを確認します。

PHP:外部サイトの投稿を取得して表示
$api_url = 'https://example.com/wp-json/wp/v2/posts?per_page=5'; // 件数を指定

$response = wp_remote_get($api_url, array(
  'timeout' => 10, // 外部が遅いとき固まらないように
));

if (is_wp_error($response)) {
  echo '<p>記事を取得できませんでした。</p>';
} else {
  $posts = json_decode(wp_remote_retrieve_body($response));

  foreach ((array) $posts as $post) {
    echo '<h3><a href="' . esc_url($post->link) . '">'
      . esc_html($post->title->rendered) . '</a></h3>';

    // content.rendered は整形済みHTML → esc_html ではなく wp_kses_post
    echo '<div>' . wp_kses_post($post->content->rendered) . '</div>';
  }
}
本文は esc_html ではなく wp_kses_post で出す
REST APIの content.renderedtitle.renderedすでにHTMLとして整形済みです。本文を esc_html() で囲むと <p> などのタグが文字としてそのまま表示され、本文が壊れますwpautop も不要)。本文は許可タグだけ通す wp_kses_post()、タイトル文字は esc_html()、リンクは esc_url() と使い分けてください。

トランジェントでキャッシュする(実用上ほぼ必須)

外部APIをページ表示のたびに毎回叩くと、表示が遅くなり相手サーバーにも負担をかけます。トランジェント(set_transient / get_transientで一定時間キャッシュしましょう。次の例は1時間キャッシュします。

PHP:取得結果を1時間キャッシュする
function get_external_posts() {
  $cache_key = 'external_posts';
  $cached = get_transient($cache_key);
  if ($cached !== false) {
    return $cached; // キャッシュを返す
  }

  $response = wp_remote_get('https://example.com/wp-json/wp/v2/posts?per_page=5', array(
    'timeout' => 10,
  ));
  if (is_wp_error($response)) {
    return array();
  }

  $posts = json_decode(wp_remote_retrieve_body($response));
  set_transient($cache_key, $posts, HOUR_IN_SECONDS); // 1時間キャッシュ
  return $posts;
}

あとは get_external_posts() でループするだけです。サイト全体の表示速度対策はWordPressサイトを高速化する7つのステップも参考になります。

クリック時に読み込む場合(Ajax)

「ボタンを押したら読み込む」「無限スクロールで追加する」など非同期で取得したい場合はJavaScript(fetch/Ajax)を使います。ただしブラウザから外部サイトのAPIを直接叩くとCORSで弾かれることがあるため、自サイトのPHP(上記)を経由して中継するのが確実です。Ajaxの基本はAjaxを使用する方法、スクロールでの追加読み込みはAjaxを使った無限スクロールを実現する方法を参照してください。

よくある質問(FAQ)

Q取得した本文にHTMLタグが文字で表示されてしまいます。
Acontent.rendered は整形済みHTMLなので、esc_html() で囲むとタグが文字として表示されます。本文は wp_kses_post() で許可タグだけ通して出力してください。wpautop() も基本は不要です。
Q取得に失敗する・表示が固まる場合は?
Ais_wp_error() でエラーを確認し、wp_remote_get() の第2引数にarray('timeout' => 10) を渡してタイムアウトを調整します。毎回APIを叩かないようトランジェントでキャッシュすると安定します。対象サイトがREST APIを制限している場合は取得できません。
QRSSフィードから取得する方法もありますか?
Aあります。fetch_feed('https://example.com/feed/') でフィードを取得し、$feed->get_items(0, 5) でループします。タイトルとリンクだけ表示したい軽い用途に向いています。RSSの投稿者名を隠す設定はRSSフィードの投稿者名を非表示にする方法を参照してください。

まとめ

  • 取得wp_remote_get()per_pagetimeout 指定)+is_wp_error()
  • 出力:本文は wp_kses_post()、タイトルは esc_html()、リンクは esc_url()
  • キャッシュset_transient / get_transient で毎回叩かない
  • 前提:REST APIはデフォルト有効(有効化操作は不要)

「安全な出力」と「キャッシュ」の2点を押さえれば、外部サイトの投稿を速く・崩さず表示できます。