node-wpapi で WordPress の REST-API をごにょごにょするためのまとめ

WordPress の REST-API を扱うには、WP-API チームがメンテナンスしている `node-wpapi` モジュールを利用すると便利です。

https://github.com/WP-API/node-wpapi

ささっと例を見せるとこんな感じ。

```javascript
wp.posts().perPage(10).orderby('date').order('asc').then((posts) => {
  console.log(posts);
});
```

PHP で WP_Query を書く際に使うパラメータをチェーンメソッドでつないでいくので、いろいろ分かりやすいです。

ちなみにリード開発者の [K.Adam White](https://twitter.com/kadamwhite) さんは、とても紳士的な素晴らしい人で、さらにご夫婦で日本語が話せます。

以下 `node-wpapi` の使い方を紹介します。なお、現在 v2 を開発中ですが、ここでの解説は v1 をベースにします。（あまり大きな変更はなさそう。）

## インストール

```
$ npm install node-wpapi
```

そして

```javascript
const wpapi = require('node-wpapi');
```

## エンドポイントの設定

まずみなさんの WordPress の API エンドポイントを設定します。

```javascript
const wp = new WPAPI({endpoint: "https://example.com/wp-json"});
```

* `/wp-json` で終わっていること。
* 間違ってないか念の為ブラウザで確認してね。
* `/wp-json` の部分をカスタマイズしている場合は、それに合わせてください。

## 投稿を取得する

WordPress にデフォルトで設定されている「投稿」を取得するには以下のような感じです。

```javascript
wp.posts().then((posts) => {
  console.log(posts);
});
```

ID:1234 の投稿を取得するには:

```javascript
const posts = wp.posts().id(1234).then((posts) => {
  console.log(posts);
});
```

他にも `wp.pages()` とか `wp.tags()` などいろいろあります。

以下 [README](https://github.com/WP-API/node-wpapi/blob/master/README.md) より引用。

* `wp.posts()...`: Request items from the `/posts` endpoints
* `wp.pages()...`: Start a request for the `/pages` endpoints
* `wp.types()...`: Get Post Type collections and objects from the `/types` endpoints
* `wp.comments()...`: Start a request for the `/comments` endpoints
* `wp.taxonomies()...`: Generate a request against the `/taxonomies` endpoints
* `wp.tags()...`: Get or create tags with the `/tags` endpoint
* `wp.categories()...`: Get or create categories with the `/categories` endpoint
* `wp.statuses()...`: Get resources within the `/statuses` endpoints
* `wp.users()...`: Get resources within the `/users` endpoints
* `wp.search()...`: Find resources of any [REST-enabled] post type matching a `?search=` string
* `wp.media()...`: Get Media collections and objects from the `/media` endpoints
* `wp.themes()...`: Read information about the active theme from the `/themes` endpoint (always requires authentication)
* `wp.settings()...`: Read or update site settings from the `/settings` endpoint (always requires authentication)
* `wp.blocks()...`: Create queries against the `blocks` endpoint

## カスタム投稿タイプを取得する

カスタム投稿タイプを取得するには、以下のように `registerRoute()` を使用する必要があります。

```javascript
wp.myPostType = wp.registerRoute('wp/v2', '/my-post-type/(?P<id>[0-9]+)');
```

この `registerRoute()` にわたす引数は、1つ目が namespace、2つ目が restbase と呼ばれています。

ドキュメントを読むときにこれら2つの単語は頻出しますので覚えておくといいかもです。

もしみなさんのカスタム投稿タイプの restbase がわからない場合は、`https://example.com/wp-json/wp/v2` の `routes` 以下に出ているはずなので探してください。([WordPress.org の例](https://wordpress.org/wp-json/wp/v2)) 

上述の例では、`my-post-type` というカスタム投稿タイプを取得するための `wp.myPostType()` というメソッドを定義しています。

こうすることで

```javascript
wp.myPostType().then((data) => {
  console.log(posts);
});
```

のように投稿を取得することができます。

あとは前述の「投稿」のようにチェーンメソッドでクエリーを追加していく感じです。

```javascript
// ID 1234 の記事を取得
wp.myPostType().id(1234).then((data) => {
  console.log(posts);
});
```

以上はカスタムタクソノミーでも同じです。

あっ、そうそう、WordPress 側でカスタム投稿タイプを登録する際に、`show_in_rest` の値を `true` にするのをお忘れなく。

```php
register_post_type( 'my-post-type', array(
  (中略) 
  'show_in_rest'          => true,
) );
```

ちなみに JetPack を使っていると、`show_in_rest`が `true` の場合に WordPress.com の統合ダッシュボードで記事を編集できるようになってしまいます。

カスタム投稿タイプの場合、独自なメタボックス等があると思いますが、そういうのはデータがぶっ壊されるので要注意です。（`public`が false でも吸い込むのマジにやめてほしい。あいつほんと嫌い。笑）

## フィルターを使う

### WordPress 側でフィルター機能を有効化

WordPress の REST-API は、開発中は WP_Query のパラメータをクエリー文字列として渡すことで、取得する投稿のリストにフィルターをかけることができましたが、コアにマージされるとともにその機能は削除されました。
（誰もが必要としているわけではない＆サードパーティのプラグイン等による意図しないセキュリティリスクを避けた。）

WP-APIチームでは、このフィルター機能を有効化するためのプラグインを配布しています。

後述するフィルターを使うには、WordPress にこのプラグインをオウンリスクでインストールしてください。

https://github.com/WP-API/rest-filter

このプラグインは公式ディレクトリにもありますが、このオリジナルの作者さんとは違う人が登録したっぽいんですよね。どっちをインストールするべきかはちょっとよくわからないです。

### Node 側の処理

`node-wpapi` でフィルターを利用できるようにするには、パラメータを追加して上げる必要があります。

```javascript
wp.myPostType = wp.registerRoute('wp/v2', '`/my-post-type/(?P<id>[0-9]+)`', {
  params: ['filter']
});
```

これで、以下のように WP_Query っぽいことができるようになります。

```javascript
// 投稿者の ID が 1 で「hello」にマッチする記事を取得
wp.myPostType().filter({
  author: 1,
  s: "hello"
}).then((posts) => {
  console.log(posts);
});
```

## カスタム投稿タイプの記事をカスタムタクソノミーで検索する

REST-API でカスタムタクソノミーを使用して投稿を検索するには、カスタムタクソノミーを定義するための `register_taxonomy()` のパラメータに以下のように指定されている必要があります。

```php
// WordPress の `register_taxonomy()` のパラメータに以下が含まれていること。
$tax_args = array(
  (中略)
  'public'            => true,
  'query_var'         => true,
  'show_in_rest'      => true,
);
```

以上で、以下のように検索することができます。

```javascript
wp.myPostType().filter({
  author: 1,
  "my-custom-taxonomy": "orange"
}).then((posts) => {
  console.log(posts);
});
```

## その他のTips

### アイキャッチ画像を取得する

デフォルトの API のレスポンスはパフォーマンスを改善するためにやや省略された内容で帰ってきます。

アイキャッチ画像についてもデフォルトのレスポンスでは ID しか含まれていないので、以下のようチェーンメソッドに `embed()` を追加して画像の URL を取得します。

```javascript
wp.myPostType().embed().id(1234).then((posts) => {
  console.log(posts[0]._embedded['wp:featuredmedia'][0]['media_details']['sizes']['post-thumbnail']);
});
```

オブジェクトの階層が深いのでめんどくさいですが実際の値を見てみると、サイズごとのURLをすべて返してくれるので便利といえば便利です。

### 一部のクエリーパラメータが使用できない。

パフォーマンスに配慮するため、一部のクエリーに制限があります。

たとえば、`ordeby` にはかなり制限があって、`rand` とかは使用できません。

どうしても使いたい場合は、プラグインで自己責任で許可してねということのようですが、やりかたは調べてません。