別のWordPressの投稿をget_posts()とかnew WP_Query()で取得する方法

とりあえず動かす方法

投稿を取得したい WordPress のデータベースの設定

一般的に、データベースはセキュリティの観点から限られた接続元からしか接続を受け付けないように設定してあります。例えば、localhostとか2inc.orgのように自サーバーからの接続しか受け付けませんよ、のように。なので、そのまま外部から投稿を取得しようとしても接続を拒否されてしまうので、まずはデータベースの方で、外部接続用のユーザーを作成し、そのユーザーが WordPress のデータベースを使用できるように設定してください。権限はなるべく少ないほうが良いので、selectだけにしたほうが良いと思います。

レンタルサーバーだとデータベースユーザーが用意されている1つしか使えなかったり、設定の変更ができないことが多いと思いますので RSS をパースしたりするしかないかなと…。

functions.php

/**
 * switch_blog 用に wp_upload_dir() の返り値を書き換え
 * 多分 path、basedir も多分必要そうだけど今回は割愛
 *
 * @param array $upload_dir
 * @return array
 */
function _habakiri_switch_blog_upload_dir( $upload_dir ) {
	$pattern = '/^(https?:\/\/[^\/]+)/';
	$replacement = home_url();
	$upload_dir['url'] = preg_replace( $pattern, $replacement, $upload_dir['url'] );
	$upload_dir['baseurl'] = preg_replace( $pattern, $replacement, $upload_dir['baseurl'] );
	return $upload_dir;
}

/**
 * 別のブログに切り替え
 */
function habakiri_switch_blog() {
	global $wpdb, $backup_wpdb;
	$backup_wpdb = $wpdb;
	$wpdb = new wpdb( 'データベースユーザー名', 'データベースパスワード', 'データベース名', 'データベースホスト名' );
	wp_set_wpdb_vars();
	wp_cache_init();
	add_filter( 'upload_dir', '_habakiri_switch_blog_upload_dir', 10 );
}

/**
 * 本サイト用に設定を戻す
 * habakiri_switch_blog した後は必ずこのメソッドでリセットが必要
 */
function habakiri_restore_current_site() {
	global $wpdb, $backup_wpdb;
	$wpdb = $backup_wpdb;
	wp_cache_init();
	remove_filter( 'upload_dir', '_habakiri_switch_blog_upload_dir', 10 );
}

テンプレート

<?php if ( !empty( $_SERVER['SERVER_ADDR'] ) && $_SERVER['SERVER_ADDR'] === 'ホストのIP' ) : ?>
	<?php habakiri_switch_blog(); ?>
	<?php $blog_posts = get_posts( ... ); ?>
	<?php if ( $blog_posts ) : ?>
		<?php foreach ( $blog_posts as $post ) : setup_postdata( $post ); ?>
		
<h2><?php the_title(); ?></h2>

		<?php the_excerpt(); ?>
		<?php endforeach; wp_reset_postdata(); ?>
	<?php endif; ?>
	<?php habakiri_restore_current_site(); ?>
<?php endif; ?>

詳しく知りたい方向けに解説

global $wpdb; $wpdb = new wpdb( … ) だけで良いと思っていた時代が私にもありました

投稿データの取得には wp_set_wpdb_vars() が必要

WordPress のデータベース接続を一手に担っている$wpdbというグローバル変数があります。こいつが全て管理しているならglobal $wpdb; $wpdb = new wpdb( ... )すればええやん!と思ってやってみたのですが、全然投稿データが取得できませんでした。

なんでかなと実行されている SQL を見てみるとFROMが空になってる!それじゃ取得できるわけがない…。で、コアのコードを読んでみると、$wpdb = new wpdb( ... )したあとにテーブル名とかの初期化が必要みたいです。それを行う関数がwp_set_wpdb_vars()になります。

これで投稿データが取得できるようになります。が…

パーマリンクの取得には wp_cache_init() が必要

タイトルや本文は取得できるのですが、the_permalink()でパーマリンクを取得すると、なぜかドメインの部分が元サイトのままになっていました。またコアのコードを探ってみると、the_permalinkはオプション値(get_option( 'siteurl' ))を参照していることがわかりました。WordPress は基本的に、起動時にオプションテーブルのオプション値をドカッと一括で取得してキャッシュするようになっています。なので、このキャッシュ(オプション値)を参照している関数を使用する場合はwp_cache_init()でキャッシュのリセットが必要になります。

これで正しいパーマリンクが取得できるようになります。が…

アイキャッチの取得には wp_upload_dir() の書き換えが必要

アイキャッチを表示しようとthe_post_thumbnail()すると、またしてもドメイン部分が元サイトのままになっていました。当然404…。またまたコアのコードを探ってみると、the_post_thumbnail()wp_upload_dir()で upload ディレクトリの URL を取得してそれを使用しているということがわかりました。

wp_upload_dir() は upload ディレクトリのパスや URL を返す関数ですが、内部では WP_CONTENT_DIRWP_CONTENT_URLのような WordPress の起動時に設定される定数が使用されているため、データベースを切り替えたとしてもこの値は切り替えることができません。そこで、wp_upload_dir()の返り値を変更するフィルターフックupload_dirを使って URL 部分を書き換えました。僕のサンプルコードでは、元サイトも取得先ブログのほうもアップロードディレクトリのパスが同じ設定だったので特にパス部分を書き換える処理はいれていませんが、違う場合はそこも書き換えが必要かもしれません。

テンプレート側では必ず接続元のチェックが必要

外部ブログに接続する前には必ず、必ず、接続元のチェックが必要です!これしないと接続エラーで落ちます。

僕のサンプルコードだと<?php if ( !empty( $_SERVER['SERVER_ADDR'] ) && $_SERVER['SERVER_ADDR'] === 'ホストのIP' ) : ?> として IP でチェックしていますが、ホスト名でも多分大丈夫だと思います。要は、最初に外部ブログのデータベースで接続元の設定をしたと思いますが、それと同じ接続元以外からの接続の場合は$wpdbの上書きを行わないようにすれば良いということです。

取得が終わったら諸々リセットが必要

$wpdbwp_upload_dir()の返り値を変更しているため、そのままにしていると取得部分のコードより後ろが全て外部ブログのデータを持ってこようとしてしまいおかしなことになってしまいます。なので、取得が終わったら必ず設定のリセットが必要です。僕のサンプルコードでは、habakiri_restore_current_site()がリセットを行っています。

  • ブックマーク
  • Feedly

この記事を書いた人

キタジマタカシ

長崎在住、フリーランスのWordPress テーマ / プラグインデベロッパー。 多数のプロダクトをオープンソースで開発・公開しています。現在は WordPress 有料テーマ Snow Monkey を開発・販売しています。