概要説明
別の WordPress サイトの新しい記事を、自分のサイトに一覧で出すショートコード。パスワードの要らない REST API で取る方法と、同じサーバーのデータベースから取る方法を、キャッシュ・エスケープ付きで。前のコードの問題点も。
~ 目次 ~
REST API で取る(おすすめ・パスワードは要らない)
運営しているほかのサイトの新しい記事を、サイドバーや記事の下に並べたいことがあります。取る先が公開している WordPress なら、REST API(/wp-json/wp/v2/posts)で記事の一覧を取れます。データベースのパスワードは要りません。
まず、取ってきた記事を一覧の HTML にする関数です(下の 2 つのやり方で共通に使います)。
functions.php
/*----------------------------------------------------
取ってきた記事を一覧の HTML にする(下の 2 つのやり方で共通)
----------------------------------------------------*/
if ( ! function_exists( 'fs_render_remote_posts' ) ) {
function fs_render_remote_posts( $posts ) {
if ( ! $posts ) {
return '';
}
$html = '<ul class="fs-remote-posts">';
foreach ( $posts as $p ) {
$html .= '<li><a href="' . esc_url( $p['url'] ) . '">';
if ( $p['image'] ) {
$html .= '<img src="' . esc_url( $p['image'] ) . '" alt="" loading="lazy">';
}
$html .= '<span class="fs-remote-date">' . esc_html( mysql2date( 'Y.m.d', $p['date'] ) ) . '</span>';
$html .= '<span class="fs-remote-title">' . esc_html( $p['title'] ) . '</span>';
$html .= '</a></li>';
}
return $html . '</ul>';
}
}
functions.php
/*----------------------------------------------------
別の WordPress の新しい記事を出す(REST API で取る・1 時間ためておく)
使い方:[fs_remote_posts url="https://example.com" count="5"]
----------------------------------------------------*/
if ( ! function_exists( 'fs_remote_posts_shortcode' ) ) {
function fs_remote_posts_shortcode( $atts ) {
$atts = shortcode_atts( array( 'url' => '', 'count' => 5 ), $atts, 'fs_remote_posts' );
$base = untrailingslashit( esc_url_raw( $atts['url'] ) );
$count = max( 1, min( 20, (int) $atts['count'] ) );
if ( '' === $base ) {
return '';
}
$cache_key = 'fs_remote_posts_' . md5( $base . '|' . $count );
$posts = get_transient( $cache_key );
if ( false === $posts ) {
$res = wp_remote_get( $base . '/wp-json/wp/v2/posts?_embed=wp:featuredmedia&per_page=' . $count, array( 'timeout' => 5 ) );
if ( is_wp_error( $res ) || 200 !== wp_remote_retrieve_response_code( $res ) ) {
set_transient( $cache_key, array(), 10 * MINUTE_IN_SECONDS ); // 取れなかったときは 10 分取りに行かない
return '';
}
$posts = array();
foreach ( (array) json_decode( wp_remote_retrieve_body( $res ), true ) as $p ) {
$posts[] = array(
'title' => isset( $p['title']['rendered'] ) ? wp_strip_all_tags( $p['title']['rendered'] ) : '',
'url' => isset( $p['link'] ) ? $p['link'] : '',
'date' => isset( $p['date'] ) ? $p['date'] : '',
'image' => isset( $p['_embedded']['wp:featuredmedia'][0]['source_url'] ) ? $p['_embedded']['wp:featuredmedia'][0]['source_url'] : '',
);
}
set_transient( $cache_key, $posts, HOUR_IN_SECONDS );
}
return fs_render_remote_posts( $posts );
}
add_shortcode( 'fs_remote_posts', 'fs_remote_posts_shortcode' );
}
- 取った結果は 1 時間ためておく(transient)ので、ページを開くたびに相手のサイトへ取りに行きません。
- 相手のサイトが止まっているときは、5 秒で諦めて何も出しません。10 分は取りに行かないので、自分のサイトが遅くなりません。
- タイトル・URL・画像の URL は、出す前に esc_html・esc_url で安全な形にします。
- 相手のサイトで REST API を止めている(401 などが返る)ときは、この方法では取れません。
データベースから取る(REST API が使えないとき)
相手のサイトの REST API が使えず、同じサーバー(または接続できるサーバー)にデータベースがあるときは、データベースから直接取ります。接続の情報は functions.php に書かず、wp-config.php に書きます。
wp-config.php
// 取る先のデータベースの接続情報(functions.php ではなく wp-config.php に書く) define( 'FS_REMOTE_DB', array( 'host' => 'localhost', 'name' => 'データベース名', 'user' => 'ユーザー名', 'pass' => 'パスワード', 'prefix' => 'wp_', 'url' => 'https://example.com', // 取る先のサイトの URL ) );
functions.php
/*----------------------------------------------------
別の WordPress の新しい記事を出す(データベースから取る・1 時間ためておく)
使い方:[fs_remote_posts_db count="5"]
----------------------------------------------------*/
if ( ! function_exists( 'fs_remote_posts_db_shortcode' ) ) {
function fs_remote_posts_db_shortcode( $atts ) {
if ( ! defined( 'FS_REMOTE_DB' ) ) {
return '';
}
$atts = shortcode_atts( array( 'count' => 5 ), $atts, 'fs_remote_posts_db' );
$count = max( 1, min( 20, (int) $atts['count'] ) );
$cache_key = 'fs_remote_posts_db_' . $count;
$posts = get_transient( $cache_key );
if ( false === $posts ) {
$c = FS_REMOTE_DB;
$remote = new wpdb( $c['user'], $c['pass'], $c['name'], $c['host'] );
$p = preg_replace( '/[^A-Za-z0-9_]/', '', $c['prefix'] );
$url = untrailingslashit( $c['url'] );
$rows = $remote->get_results( $remote->prepare(
"SELECT p.ID, p.post_title, p.post_date, f.meta_value AS file
FROM {$p}posts AS p
LEFT JOIN {$p}postmeta AS t ON t.post_id = p.ID AND t.meta_key = '_thumbnail_id'
LEFT JOIN {$p}postmeta AS f ON f.post_id = t.meta_value AND f.meta_key = '_wp_attached_file'
WHERE p.post_status = 'publish' AND p.post_type = 'post'
ORDER BY p.post_date DESC
LIMIT %d",
$count
) );
$posts = array();
foreach ( (array) $rows as $r ) {
$posts[] = array(
'title' => $r->post_title,
'url' => $url . '/?p=' . (int) $r->ID,
'date' => $r->post_date,
'image' => $r->file ? $url . '/wp-content/uploads/' . $r->file : '',
);
}
set_transient( $cache_key, $posts, HOUR_IN_SECONDS );
}
return fs_render_remote_posts( $posts );
}
add_shortcode( 'fs_remote_posts_db', 'fs_remote_posts_db_shortcode' );
}
- 新しい順に、指定した数だけ取ります(LIMIT)。全部の記事は読みません。
- アイキャッチ画像は、画像の情報(_wp_attached_file)からアドレスを作ります。
- 接続の情報が間違っていると、表示のたびにエラーになることがあります。作業環境で確かめてから本番に入れてください。
ショートコードの使い方
[fs_remote_posts url=”https://example.com” count=”5″] REST API で、https://example.com の新しい記事を 5 件出す
[fs_remote_posts_db count=”5″] wp-config.php の FS_REMOTE_DB のデータベースから、新しい記事を 5 件出す
見た目は CSS で整えます(例)。
style.css(例)
.fs-remote-posts { list-style: none; margin: 0; padding: 0; }
.fs-remote-posts li { border-bottom: 1px solid #ddd; }
.fs-remote-posts a { display: flex; gap: 12px; align-items: center; padding: 10px 0; }
.fs-remote-posts img { width: 80px; height: 80px; object-fit: cover; }
.fs-remote-date { color: #888; font-size: 12px; }
前に載せていたコードの問題と、確かめた結果
以前この記事に載せていたコードには、次の問題がありました。
- 本文を $post->content で取っていた(正しくは post_content)ので、本文はいつも空だった。
- 件数の上限も並び順もなく、ページを開くたびに相手のサイトの公開記事を全部読んでいた(記事が多いと重い)。
- タイトルや URL を、エスケープせずにそのまま HTML に入れていた。
- データベースのパスワードを functions.php に書いていた。
- アイキャッチ画像のアドレスに guid を使っていた(サイトを引っ越すと古いアドレスのままになる)。
確かめた結果
作業環境(WordPress 7.1)で確かめました。
| やり方 | 結果 |
|---|---|
| REST API(make.wordpress.org/core から 3 件) | 3 件出た。1 回目 1.28 秒、2 回目はためておいた分で 0 秒 |
| データベース(別の WordPress のデータベースから 3 件) | 3 件・画像 3 枚が出た。1 回目 0.07 秒、2 回目 0 秒 |
| REST API で、ないサイトを指定 | 何も出さずに終わる(自分のページは表示される) |
このサイトのフッターの「運営サイトの一覧と記事数」も、同じように別の WordPress から取って、1 日ためておく作りにしています。


