こんな要件を想定
- 静的 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
- your_client_id
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」 内に
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>
投稿データ取得のための 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 ディレクティブを付加したので、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 アカウントの通知設定もよしなに済ませるとよいでしょう。