WEBOPIXEL

WordPressからデータベースに直接アクセスする

Posted: 2010.08.08 / Category: WordPress / Tag: 

Wordpressにはさまざまな関数が用意されていますので、ちょっとしたテンプレートの作成だけなら基本的には問題ないと思います。
ただ、複雑な条件でデータを読み込みたいときや、このデータを使いたいんだけど、どの関数を使っていいかわからないよ! なんて経験が少なからずあるはずです。
SQL文を使用してデータベースに直接アクセスすれば自由にデータを扱うことができるはずです。

Sponsored Link

なおこの記事はWordpress3.01を使用しています。

WordPressのデータベースを見てみる。

まずは「phpMyAdmin」で読み込むべきデータを確認してみましょう。
「phpMyAdmin」にログインしたら左カラムからWordpressで使用しているデータベースを選択します。
次の画面のには「wp_commentmeta」や「wp_comments」というテーブルが11個表示されるはずです。
プラグインが入ってればもっと多いかもしれませんし、接頭辞の「wp_」はインストールの設定によっては違う文字列になっているかもしれません。

WordPressテーブル一覧

wp_commentmeta コメント・トラックバックのメタデータ
wp_comments コメント・トラックバックのデータ
wp_links リンク作成で入力したデータ
wp_options 設定で入力したデータ
wp_postmeta カスタムフィールドなどのデータ
wp_posts 投稿記事およびページデータ
wp_terms カテゴリ・タグなどのデータ
wp_term_relationships 投稿記事・ページとカテゴリ・タグなどの関連情報
wp_term_taxonomy カテゴリ・タグなどの情報
wp_usermeta 各ユーザのメタデータ
wp_users 登録ユーザ情報

wpdbオブジェクトを使用して投稿記事のタイトルを取り出す。

テーブル構造もなんとなくわかったところで、これらのデータを取り出してみましょう。
「wpdb」というクラスを使用すると面倒な設定なしでデータベースにアクセスすることができます。
ためしに投稿記事のタイトルを取り出してリスト表示してみましょう。

もう一度phpMyAdminで確認してみましょう。
投稿記事のデータは「wp_posts」というテーブルです。
主なフィールドをまとめてみました。詳しくはWordPress Codexを参照してください。

wp_postsフィールド一覧

ID 自動的に割り振られた投稿ID
post_date 投稿日時
post_content 本文
post_title タイトル
post_status 投稿ステータス
guid 記事のURL
post_type 投稿種別

タイトルを取り出したいので「post_title」というフィールドですね。
複数行のレコードを取り出す場合は「get_results」関数を使用します。
SQL文は「get_results」の引数に記述します。
通常のMySQLのように「FROM テーブル名」と記述してもいいのですが、テーブル名の「wp_」という接頭辞はインストール時に変更できるため柔軟なテンプレートを作成するなら直接指定しない方が良いようです。
Wordpressでは代わりに各テーブルに対応したプロパティ名で指定します。
プロパティ名は基本的にテーブル名から接頭辞(デフォルトではwp_)を除いたものになります。「wp_posts」なら「posts」ですね。
では、テンプレートの適当なファイルに下記を記述して実行してください。

WordPress テンプレートファイル

		$results = $wpdb->get_results("SELECT post_title FROM $wpdb->posts");
		foreach ($results as $value) {
			print('<li>'.$value->post_title.'</li>');
		}
	

ずらーっとタイトルが表示さたら成功です。

条件を設定して必要なデータだけ表示する。

一応タイトル一覧は表示できましたが、もこれだとページのタイトルも表示されるし、下書きとか予約記事とかも問答無用に表示されちゃってるので、あまりよろしくありません。
もうすこし細かい設定をして投稿された記事だけ表示するようにしてみましょう。
条件として投稿記事(ページじゃない)であることと、公開済な記事を新しい順に5件表示してみます。
投稿記事のフィールド名は「post_type」、公開済の記事は「post_status」です。
SQL文はWHEREを使いさらに条件を絞る場合はANDでつなげていきます。

WordPress テンプレートファイル

		$results = $wpdb->get_results("
			SELECT post_title
			FROM $wpdb->posts
			WHERE post_type = 'post'		/* 投稿記事である */
			AND post_status = 'publish'		/* かつ公開済の記事 */
			ORDER BY post_date DESC			/* 新しい順に並び替え */
			LIMIT 5							/* 表示記事5 */
		");
		foreach ($results as $value) {
			print('<li>'.$value->post_title.'</li>');
		}
	

記事へのリンクを付ける

最後に一覧表示したタイトルへ各記事へのリンクを付けてみましょう。
リンクのデータは「guid」フィールドに入っています。
新たに取り出す値を追加する場合はSQL文のSELECTにカンマで区切って追加していきます。

WordPress テンプレートファイル

		$results = $wpdb->get_results("
			SELECT post_title, guid		/* post_titleとguidの値を取り出す */
			FROM $wpdb->posts
			WHERE post_type = 'post'	/* 投稿記事である(ページじゃない) */
			AND post_status = 'publish'	/* かつ公開済の記事 */
			ORDER BY post_date DESC		/* 新しい順に並び替え */
			LIMIT 5						/* 表示記事5 */
		");
		foreach ($results as $value) {
			print('<li><a href="'.$value->guid.'">'.$value->post_title.'</a></li>');
		}
	

これでも基本的に動作すると思いますが、guidフィールドには素のままのURLが入っているため、パーマリンクをカスタマイズしていると表示されるURLが違うのでちょっと気持ち悪いですね。
そこで「get_permalink」関数を使用して実際のURLに変換してみます。
「get_permalink」は引数に記事のIDを指定することで、パーマリンクを返してくれます。
なので、新たに「ID」フィールドから値を取り出す必要がありそうです。この値を引数に指定すれば完成ですね。

WordPress テンプレートファイル

		$results = $wpdb->get_results("
			SELECT post_title, guid, ID	/* post_titleとguidとIDの値を取り出す */
			FROM $wpdb->posts
			WHERE post_type = 'post'	/* 投稿記事である(ページじゃない) */
			AND post_status = 'publish'	/* かつ公開済の記事 */
			ORDER BY post_date DESC		/* 新しい順に並び替え */
			LIMIT 5						/* 表示記事5 */
		");
		foreach ($results as $value) {
			print('<li><a href="'.get_permalink($value->ID).'">'.$value->post_title.'</a></li>');
		}
	

SQLインジェクション対策

たとえばユーザーがIDを入力してデーターを表示したいとします。
その場合SQL文の中に変数を入れることになると思いますが、そのまま変数を入れてしまうと自由にSQL文を埋め込まれてしまいます。
「prepare」メソッドを使用すればSQLクエリをエスケープすることができます。

 
	$num = 2;
	$results = $wpdb->get_results($wpdb->prepare("
		SELECT post_title
		FROM $wpdb->posts p
		WHERE p.ID = %d
	", $num));
	

変数を入れる箇所に、変数が文字列の場合は「%s」を、整数の場合は「%d」を入れます。
変数は「prepare」の第2引数以降に順番に入れます。

WordPressデータベースの詳しい解説は下記を参考にしてみてください。

参照元 : データベース概要 – WordPress Codex 日本語版

COMMENTS

ボンディー 2011-08-25 05:53 

はじめまして。。。

投稿者一覧ページで、各投稿者をクリックすると「最新記事」へジャンプする…というものが作りたかったのですが、なかなかどうしてやり方が分からず困っておりました。

こちらのサイトでは、「wpdb」をゼロから分かりやすく解説して頂いており、大変勉強になりました。
引っぱり出したいデータが、引っぱり出せずに今まで諦めていたことが沢山ありましたが、これからはなんとかなりそうです!
ありがとうございます!

jQueryなどのコンテンツも勉強になます。そして面白いですね。。。

webOpixel 2011-08-25 21:53 

わざわざコメントを残していただきましてありがとうございます。
少しでも参考になったようで嬉しいです。

てくの 2012-05-24 09:59 

大変参考になりました。
ありがとうございました。

sato 2012-12-31 13:23 

こんにちは、参考にさせてもらっております。
fetch_feed関数で取得したRSSを、wp_insert_post関数を使って、記事として投稿しているのですが、その点について聞かせていただいてもよろしいでしょうか。

—————————
foreach($rss_items as $item2){
// 投稿オブジェクトの作成
$my_post = array();
$my_post[‘post_title’] = $item2->get_title();
$my_post[‘post_content’] =’PICK UP!!:<a href=”‘ .$item2->get_permalink(). ‘” target=”_blank”>’. $item2->get_title() . ‘</a>’;
$my_post[‘post_status’] = ‘publish’;//下書き状態にすることも可能だ
$my_post[‘post_author’] = 1;
$my_post[‘post_category’] = array(2);
// データベースに投稿を追加
wp_insert_post( $my_post );
}//foreach
—————————

ただ、このままだと同じRSSが何度も投稿されてしまうので、「同様の記事タイトルを持つ投稿は、1度のみ投稿されるようする」ということを実現したいと思っています。
wp_insert_post( $my_post );の部分で、if文を使えば良いのだと思いますが、条件式として何を利用するのが良いでしょうか。
解説されているwpdb関数でタイトルを取り、それを利用するという点についてはわかりましたが、、、。

ご存知でしたら、アドバイスいただけると有難いです。

riiti 2016-03-14 14:18 

初めまして
いつも参考にさせてもらっています。
すごく基本的なところだったらすいません。上記のSQLインジェクション対策の部分でprepareメソッドが出たあとにSQL文のWHEREのあとにp.IDと書いてあるのはどういう意味なのでしょうか?
「p.」がなぜ急に出てきたのかがわからなくて質問させていただきました。どうぞよろしくお願いいたします。

$results = $wpdb->get_results($wpdb->prepare(”
SELECT post_title
FROM $wpdb->posts p
WHERE p.ID = %d
“, $num));

LEAVE A REPLY

コードを書く場合は<pre>で囲んでください。