WP_Query()を使い、異なるテーブルからデータを取り出す方法

[2011.3.10追記]
よりシンプルな方法を書いたエントリーを追加しました。たぶんこっちの方がおすすめ。

先月末に納品したWordPressベースのサイトについて、客先から追っかけでリクエストが寄せられた。実は設計段階で調整可能だった要件であり自らの調整不足が露呈した機能追加なのだが、ひとまずそれは措いておく(泣き笑い)。

サイトの概要は以下のとおり。

  • 客先は三つの店舗(仮に shop1・shop2・shop3 とする)を持っている。
  • 各店ごとにWordPressをインストール、管理画面を別個に持たせている(実は納品後、一つのWordPressで複数サイトを持たせる方法があることが分かったのだが……しかも、WPMUでなく通常版のWPでだ)。
  • 投稿のカテゴリーは二つ(仮に foo と bar とする)。
  • データベースは共通で、各店ごとに異なるテーブル接頭辞($table_prefix)を wp-config.php 内で設定。

いったんは、shop1・shop2・shop3がそれぞれに投稿を管理する、つまり店舗ごとに違った投稿を掲載できるという仕様で納品したものの……

「shop1での投稿をshop2・shop3と共有したい」

というリクエストがぴょーんと飛んできたのだ。

サイトのデザイン(特にヘッダまわり)は店舗ごとに異なっており、shop2・shop3から単純にshop1へリンクをはって解決する問題ではない。「グローバル変数である $wpdb を使い $wpdb -> get_results でshop1のテーブルから拾えばいけるのでは?」 経験則からそう考え、いったんはコードを書き起こして完成したのだが、これでは根本的に解決しなかった。

メッセージループのテンプレートタグが使えないのだ。

『Ktai Style』という、WP界隈では有名なケータイ表示用プラグインも併用しているので、プラグインとの整合性をとるためにもメッセージループのテンプレートタグを使えるように作らないといけない。

そこで悩んだ末、このようなコードを書いた。あくまでこのサイト向けに特化したコードで汎用性に乏しいため、例によって「ご利用は計画的に」の情報なのでご了承を。

function my_get_query ( $prefix, $query = '' ) {
	global $wpdb, $wp_query;
	$uri = $_SERVER['REQUEST_URI'];
 
	$wpdb = new wpdb ( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
	$wpdb -> set_prefix ( $prefix );
	$wpdb -> wpdb ( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
 
	// 個別記事
	if ( preg_match ( "/archives/d+/", $uri ) ) {
		preg_match ( "/archives/(d+)/", $uri, $array );
		if ( $array[1] ) { $post_id = $array[1]; }
 
		$wp_query = new WP_Query ( $query. '&p=' . $post_id );
	}
 
	// カテゴリーアーカイブ
	if ( preg_match ( "/archives/category/", $uri ) ) {
		$str = preg_split ( "/page\//", $uri );
		if ( $str[1] ) {
			$page = $str[1];
			$offset = ( $page - 1 ) * get_option ( 'posts_per_page' );
		}
 
		$wp_query = new WP_Query ( $query . '&offset=' . $offset );
		$wp_query -> query_vars['paged'] = $page;
		$wp_query -> is_paged = is_paged ();
	}
 
	return $wp_query;
}

メッセージループの直前で、この関数を

$wp_query = my_get_query ( 'テーブル接頭辞' , 'クエリー文字列' );

という形で読み込んで使う(クエリー文字列についてはテンプレートタグ/query posts – WordPress Codex 日本語版を参照のこと)。

$wp_query はWPのコアファイルで定義され、ページ生成時の鍵となるオブジェクトなので、言うなればここに手を加えるのはご法度。そこをあえて上書きすることで、メッセージループやページ遷移系のテンプレートタグ(posts_nav_link() など)を使えるようにしている。自分で言うのもなんだが裏技的使い方といえるだろう。

ちなみに上記のようなコードだと、以下のような制限や問題点がある。

  1. query_posts() では使える category_name という引数が使えない(=cat_IDで指定しないといけない)。
  2. パーマリンク設定が「数字ベース」となっている場合のみ有効。
  3. アーカイブページから個別記事に遷移したときに single.php が読み込まれない(index.php もしくは 404.php が読み込まれる)。

3.については single.php 内の記述を index.php にコピペするか、404.php の冒頭に以下のように記述して回避可能だった(わたしの場合、後者を選んだ)。

<?php my_is_single ( 'テーブル接頭辞' ); ?>

my_is_single 関数は以下のように記述。

function my_is_single ( $prefix ) {
	global $wpdb;
 
	$uri = $_SERVER ['REQUEST_URI'];
	$posts_table = $prefix . 'posts';
 
	if ( preg_match ( "/archives/d+/", $uri ) ) {
		preg_match ( "/archives/(d+)/", $uri, $array );
		$post_id = $array[1];
		$array   = $wpdb -&gt; get_results ( "SELECT ID FROM $posts_table WHERE post_type = 'post' AND post_status = 'publish'" );
 
		foreach ( $array as $value ) {
			if ( $post_id = $value ) {
				include ( TEMPLATEPATH . '/single.php' );
				exit ();
			}
		}
	}
 
	return;
}

以上、何かのご参考になれば。「ここをこうするとより汎用性が増すよ」というアドバイスもお待ちしてます。

WordPressによる複数blog運用。(10行追加+α) | まつぼっくりんご
http://www.tymy.net/~matsu/blog/2008/02/05/wordpress%E3%81%AB%E3%82%88%E3%82%8B%E8%A4%87%E6%95%B0blog%E9%81%8B%E7%94%A8%E3%80%82%EF%BC%8810%E8%A1%8C%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%E3%81%A0%E3%81%91%EF%BC%89/


WP_Query()を使い、異なるテーブルからデータを取り出す方法” への1件のコメント

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <img localsrc="" alt=""> <pre lang="" line="" escaped="" highlight="">