WordPress.com の投稿を REST API で取得して Vue.js でいい感じに表示してみる

## こんな要件を想定

* 静的 HTML でサイトを運用
* トップページ（index.html）にちょっとしたお知らせ（1 件 1～2 行程度）を表示させたい
* HTML の知識がなくてもお知らせの追加・編集・削除ができるように

わざわざ CMS をセットアップするのはちょっと大仰なので、セキュリティアップデートなどの煩雑さから解放される WordPress.com を使って

* WordPress.com でお知らせコンテンツを管理
* REST API 経由で投稿を取得
* 投稿タイトルの一覧を index.html 上にリスト表示

という解決策をとってみます。Vue.js と axios の組み合わせでわりとすっきり実装できました。

## サーバ要件

* PHPが動作すること（要 cURL）  
  index.html のあるサーバと同一である必要はありません

## ドキュメント

REST API Resources | Developer Resources
https://developer.wordpress.com/docs/api/

## 実装手順

### REST API を使うための API キーを取得

WordPress.com にログインした状態で Developer サイト（ https://developer.wordpress.com/ ）にアクセス。

Developer サイトの「My Apps」メニューをクリックし https://developer.wordpress.com/apps/ に移動。

「Create New Application（新規アプリケーション作成）」ボタンをクリックして下記を入力。

 * Name  
   任意のアプリケーション名
 * Description  
   任意の説明文
 * Website URL  
   自身の公開サイト URL（http://localhost などローカルの URL も可）
 * Redirect URLs  
   リダイレクトURL（開発/ステージング/本番 複数可）
 * Javascript Origins
   JavaScriptを設置するURL（開発/ステージング/本番 複数可）

### アクセストークンを取得

外部のスクリプトから投稿データを取得できるように OAuth の設定をします。

+ ドキュメント  
  OAuth2 Authentication | Developer Resources  
  https://developer.wordpress.com/docs/oauth2/
* アクセストークン発行のエンドポイント  
  https://public-api.wordpress.com/oauth2/authorize?client_id=your_client_id&redirect_uri=your_redirect_uri&response_type=token
* エンドポイントに渡すパラメータ  
  （「Create New Application」で作成したアプリケーションの OAuth Information 欄に情報あり）。
    * your_client_id  
    Auth Information 欄の Client ID
    - your_redirect_uri  
    Auth Information 欄の Redirect URLs （複数あればいずれか）
    - response_type  
    token

> Howdy! {YOUR_APP_NAME} would like to connect to your WordPress.com site.

というようなメッセージが出るはずなので「Approve」ボタンをクリック。

* 「Approve」をクリックして取得できる URL 文字列  
http://example.com/#access_token=YOUR_ACCESS_TOKEN&expires_in=1209600&token_type=bearer&site_id=YOUR_WP_SITE_ID  
   文字列中の YOUR_ACCESS_TOKEN がトークン文字列にあたります

### トークンの自動生成を設定

取得したトークン文字列を JS ファイルにベタ書きしてもいいのですが、ドキュメント[「OAuth2 Authentication | Developer Resources」](https://developer.wordpress.com/docs/oauth2/) 内に

> Tokens currently last two weeks and users will need to authenticate with your app once the token expires. Tokens are returned via the hash/fragment of the URL.

トークンは 2 週間で無効になるという一文が！

そこでドキュメントの教えに沿って、PHP を使ってトークンを自動生成するように設定します。ファイル名は get-token.php としました。

**get-token.php**

```
<?php

// JavaScript の実行ドメインと PHP スクリプトを置くドメインが違う場合は Access-Control-Allow-Origin を設定する必要あり


// cURL を使ってトークンを取得
$curl = curl_init( 'https://public-api.wordpress.com/oauth2/token' );
curl_setopt( $curl, CURLOPT_POST, true );
curl_setopt( $curl, CURLOPT_POSTFIELDS, [
        
	// YOUR_CLIENT_ID に My Apps で作成したアプリケーションの Client ID を記述
	'client_id' => YOUR_CLIENT_ID,

	// YOUR_CLIENT_SECRET に My Apps で作成したアプリケーションの Client Secret を記述
	'client_secret' => 'YOUR_CLIENT_SECRET',

	'grant_type' => 'password',

	// YOUR_WP_USERNAME に WordPress.com サイトのユーザー名を記述        
	'username' => 'YOUR_WP_USERNAME',

	// YOUR_WP_PASSWORD に WordPress.com サイトのパスワードを記述                
	'password' => 'YOUR_WP_PASSWORD',
] );
curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1);
$auth = curl_exec( $curl );
$auth = json_decode( $auth );
$access_key = $auth->access_token;

echo $access_key;
```

get-token.php をリモートにアップロードし http://example.com/get-token.php をたたいてトークン文字列が表示されれば OK。

URL 直打ちでトークン文字列が丸裸になるので、作成したアプリケーションの「Javascript Origins」や、get-token.php の「Access-Control-Allow-Origin」の設定を適切に行ってください。

### Vue.js と axios の読み込み

ここはさくっと CDN の力を借りましょう（Vue.js のバージョンは本記事執筆時点のもの）。

**index.html**

```
<script src="//cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script src="//unpkg.com/axios/dist/axios.min.js"></script>
```

* 公式ドキュメント
   * [インストール — Vue\.js](https://jp.vuejs.org/v2/guide/installation.html)
   * [axios/axios: Promise based HTTP client for the browser and node\.js](https://github.com/axios/axios#installing)

### 投稿データ取得のための JS ファイルを設置

WordPress.com から投稿を取得する JS ファイル（get-posts.js）の例です。

定数 wpUrl 内の example.wordpress.com は投稿を取得したい WordPress.com サイトのドメイン、同 phpPath 内の example.com は get-token.php を設置したドメインにそれぞれ書き換えてください。

**get-posts.js**

```
'use strict';

const wpUrl   = 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.com/posts/';
const phpPath = 'https://example.com/get-token.php';


// REST API 経由で投稿データを取得
const getWpPosts = function(data) {	
	axios.get(wpUrl, {
		headers: {'Authorization': 'BEARER ' + data}
	})
	.then(function (response) {
		initVue(response.data);
	})
	.catch(function (error) {
		initVue(error);
	});	
};


// アクセストークン文字列を取得
const getWpToken = function() {	
	axios.get(phpPath, {
		responseType: 'text'
	})
	.then(function (response) {
		getWpPosts(response.data);
	})
	.catch(function (error) {
		console.log(error);
	});	
};


// Vue インスタンスの生成
function initVue(data) {
	if (data.hasOwnProperty('posts')) {
		if (data.posts.length > 0) {
			new Vue({
				el: '#posts',
				data: {
					posts: data.posts,
					type: 'posts'
				}
			});
		}
		else {
			new Vue({
				el: '#posts',
				data: {
					type: 'no-posts'
				}
			});
		}
	}
	else {
		new Vue({
			el: '#posts',
			data: {
				type: 'errored'
			}
		});
	}
}


window.onload = function () {
	getWpToken();
}
```

get-posts.js ができたら index.html に読み込みます。ここでは index.html と同階層にある js ディクレトリ内に get-posts.js を置くような設定にしました。

**index.html**

```
<script src="//cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script src="//unpkg.com/axios/dist/axios.min.js"></script>
<script src="./js/get-posts.js"></script>
```

### Vue.js でページ内にレンダリング

取得結果を表示させたい箇所を ``<div id="posts">...</div>`` とマークアップした例です。

**index.html**

```
<div id="posts">
	<ul v-if="type === 'posts'" v-cloak>
		<li v-for="post in posts">{{ post.title }}<br> 
		（{{ post.date }}）</li>
	</ul>	
	<p v-if="type === 'no-posts'" v-cloak>現在公開中のお知らせはありません。</p>
	<p v-if="type === 'errored'" v-cloak>何らかの原因でお知らせのデータが取得できませんでした。</p>
</div>
```

[v-cloak ディレクティブ](https://jp.vuejs.org/v2/api/#v-cloak)を付加したので、index.html が読み込む CSS ファイルに下記を追記しておきます。

```
[v-cloak] {
	display: none;
}
```

### 日付表示もいい感じにする

これでひととおり実装できましたが ``{{ post.date }} `` で示した投稿日の日付が

> 2019-01-01T00:00:00+09:00

というような表示になってしまうので、日付処理ライブラリ Moment.js を使っていい感じに変換することにします。Moment.js も CDN でさくっと読み込みましょう（バージョンは本記事執筆時点のもの）。

* Moment.js  
  https://momentjs.com/

**index.html** の JS 読み込み箇所

```
<script src="//cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script src="//unpkg.com/axios/dist/axios.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.23.0/moment.js"></script>
<script src="./js/get-posts.js"></script>
```

**index.html** の ``<div id="posts">...</div>`` 内

【変更前】

```
<div id="posts">
	<ul v-if="type === 'posts'" v-cloak>
		<li v-for="post in posts">{{ post.title }}<br> 
		（{{ post.date }}）</li>
	</ul>	
	<p v-if="type === 'no-posts'" v-cloak>現在公開中のお知らせはありません。</p>
	<p v-if="type === 'errored'" v-cloak>何らかの原因でお知らせのデータが取得できませんでした。</p>
</div>
```

【変更後】

```
<div id="posts">
	<ul v-if="type === 'posts'" v-cloak>
		<li v-for="post in posts">{{ post.title }}<br> 
		（{{ post.date | moment }}）</li>
	</ul>	
	<p v-if="type === 'no-posts'" v-cloak>現在公開中のお知らせはありません。</p>
	<p v-if="type === 'errored'" v-cloak>何らかの原因でお知らせのデータが取得できませんでした。</p>
</div>
```

**get-posts.js** の function initVue() 内

【変更前】

```
if (data.posts.length > 0) {
	new Vue({
		el: '#posts',
		data: {
			posts: data.posts,
			type: 'posts'
		}
	});
}
```

【変更後】

```
if (data.posts.length > 0) {
	new Vue({
		el: '#posts',
		filters: {
			moment: function(date) {
				if (!date) return ''
				return moment(date).format('YYYY/M/D');
			}
		},
		data: {
			posts: data.posts,
			type: 'posts'
		}
	});
}
```

``moment(date).format('YYYY/M/D');`` が文字列を指定している箇所です。表示例は Moment.js のドキュメントを参照してください。

## 運用にあたっての tips 的なもの

WordPress.com はお知らせコンテンツ管理のためだけに使うので、WordPress.com サイト自体は非公開の運用とするのがおすすめです。

また、WordPress.com アカウントの通知設定もよしなに済ませるとよいでしょう。