鳥山(@sysbird)です、
WordPress Advent Calendar 2012 6日目のブログになります。Adventとは、キリスト降誕を待ち望む期間のことという。その期間、お菓子が隠された小窓を毎日ひとつづつ開けて楽しむのがAdvent Calendarだ。
お菓子にちなんで、本日はお菓子の虜 Web APIの作り方を紹介したい。「お菓子の虜」は、私がコンビニで買って食べたお菓子を記録するブログだ。いままでに食べたお菓子は2134種類。このデータを眠らせるわけにはいくまいと、Web APIとして提供することにした。毎日ただお菓子を食べているだけでないことを、証明するためでもあった。
Web APIはWebサービスのデータを提供したり、Webサービスと連携させたりするためのインタフェースである。Google Maps APIやTwitter APIなど、すでにWordPress上で利用しているユーザも少なくないだろう。今回は、WordPressからWeb APIを提供してみよう。
1.WordPressでWeb API
ブログ「お菓子の虜」は WordPressで運用している。
お菓子ひとつにつき、
・タイトル(お菓子の名前)
・本文(食べた感想)
・更新日
・カテゴリ(スナック、チョコ、クッキー、飴、せんべい)
・タグ(激辛、カレー、ポテトチップ、地域限定など)
・カスタムフィールド(価格、メーカ名、ふりがな)
・添付ファイル(お菓子の写真)
というデータを持っている。
これらのデータをWordPressの外部から取得する方法がある。
WordPressのルートディレクトリにある、wp-load.phpを利用するのだ。このファイルを読み込むことで、WordPressのフロントエンドを介さずして投稿データを取得することができるようになる。
たとえば、
http://example.com
というURLでWordPressを運用している場合に、
http://example.com/api/
というリクエストURLでデータを提供することにしよう。
この場合は、WordPressがインストールされているディレクトリ直下にapiというディレクトリを作成してindex.phpを用意する。
そのなかでまず、
1 |
require_once(dirname(__FILE__) .'/../wp-load.php'); |
と、wp-load.phpのパスを指定して読み込むようにする。設置ディレクトリはここに限らず、wp-load.phpをrequire 可能な位置であればよいだろう。これだけで、WordPressの機能を利用することができる。
あとはおなじみのループ処理で投稿を取得すればよいのだ。
1 2 3 4 5 |
// WordPressのループ処理 $myposts = get_posts(); foreach($myposts as $post){ setup_postdata($post); // 1件の投稿 } |
こうすると最新5件の投稿が取得されるので、決まったフォーマットで出力していけばよい。
2.XMLを生成
Web APIを提供する場合のデータ形式として、代表的なものにXML形式がある。XMLを生成するには、WordPressから取得した投稿をもとにDOM構造を作っていく。
1 2 3 4 |
// DOMの作成 $dom = new DomDocument('1.0', 'utf-8'); $dom->formatOutput = true; $xml = $dom->appendChild($dom->createElement('okashinotoriko')); |
まず”okashinotoriko”というルートの要素を作成している。要素名はなんでもよい。次に、さきほどのループの中で1件の投稿をひとつの子要素として追加していく。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
// WordPressのループ処理 $myposts = get_posts($param); foreach($myposts as $post){ setup_postdata($post); // 1件の投稿 // itemという子要素を作成 $item = $xml->appendChild($dom->createElement('item')); // itemのなかに投稿IDを追加 $item->appendChild($dom->createElement('id', $post->ID)); // タイトル $item->appendChild($dom->createElement('name', get_the_title())); // カスタムフィールド $price = get_post_meta($post->ID , "価格", true); $item->appendChild($dom->createElement('price', $price)); // パーマリンク $item->appendChild($dom->createElement('url', get_permalink())); // 本文 $item->appendChild($dom->createElement('comment', apply_filters('the_content', get_the_content()))); // アイキャッチ $thumbnail = ''; if ((function_exists('has_post_thumbnail')) && (has_post_thumbnail($result->postnumber))) { $thumbnail = get_the_post_thumbnail($post->ID, 'large'); if(!empty($thumbnail)){ if(preg_match_all('/ $thumbnail = $match[2][0]; $item->appendChild( $dom->createElement('image', $thumbnail)); } } } } |
okashinotorikoというルート要素の中に、複数のitemという要素から成るDOM構造ができる。ここでは例として主な要素のみ追加しているが、このほかにもカテゴリやタグ、更新日など投稿に関するデータを好きな要素として追加してよい。
アイキャッチは、WordPressのget_the_post_thumbnail()ではimgタグごと取得されてしまうため、正規表現でsrc属性のみ取り出す。
生成されたDOMをXMLドキュメントとして出力すれば、Web APIとして利用可能となる。
1 2 3 |
// XML出力 header('Content-Type: text/xml;charset=UTF-8'); echo $dom->saveXML(); |
3.検索パラメータに対応
Web APIらしくするには、検索パラメータが必要だろう。
たとえば、
”hoge”というキーワードで30件のデータを取得したい場合は、リクエストURLにパラメータをつなげていく。
http://example.com/api/?keyword=hoge&max=30
この場合、URLのパラメータをPHPの$_GET変数で取得し、get_posts()に渡すパラメータに項目を追加していけばよい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// 検索パラメータを設定 $param = array(); if(isset($_GET['max'])) { // 取得件数が指定されている場合 $param['showposts'] = $_GET['max']; } if(isset($_GET['keyword'])) { // 検索キーワードが指定されている場合 $param['s'] = mb_convert_encoding($_GET['keyword'],'UTF-8','auto'); } // WordPressのループ処理 $myposts = get_posts($param); foreach($myposts as $post){ setup_postdata($post); // 1件の投稿 } |
このようにリクエストURLのパラメータを増やしていくことで、WordPressのループ条件を設定する。ほかにもカテゴリ、年月、開始位置、取得順など、get_posts()に指定できるものが利用できるので、いろいろやっているうちにWeb APIっぽくなる。
» キーワード”カレー”、取得件数10で検索した場合のサンプルレスポンス
4.JSONで出力
Web APIであるからには、JavaScriprからも利用可能なJSON形式にも対応したい。PHPのjson_encode()という関数で変換して出力する。
1 2 3 4 5 |
// XML出力 $xml_obj = simplexml_load_string($dom->saveXML()); $encode = json_encode($xml_obj); header("Content-Type: text/javascript; charset=utf-8"); echo "callback(" .$encode .")"; |
ajaxでcallbackの使えるJSONP形式にしておく。
JSON形式があると、静的ページでもJavaScriptを使ってWordPressの投稿データを表示できるようになるので、利用シーンがぐっと広がる。
» キーワード”カレー”、取得件数10、JSON形式で検索した場合のサンプルレスポンス
まとめ
ごく簡単なREST形式のWeb APIを作例として紹介したものの、リクエストパラメータをPOST変数にしたり、認証を加えたりと、改善の余地はあろう。WordPress同士でも、それ以外のシステムとのやりとりでも、ちょっとしたデータを提供できるとなにかと便利だ。ぜひ試してほしい。
WordPress Advent Calendar 2012 は、まだまだ続きます!
昨日は、
» WordPressのインストールって何? #wacja2012 井村さん
» マルチサイト構築時、油断してて大量のスパムにやられた!一番の脆弱性は自分って話 #wacja2012 #wacja2012 Kさん
のお二人でした。
明日はgrandpawhiteOSAさんです、
おたのしみに!
[…] via. WordPressで提供する Web API #wacja2012 […]
[…] WordPressで提供する Web API #wacja2012 […]
[…] https://sysbird.jp/wptips/2012/12/06/wacja2012/ […]