WordPressのGraphQLプラグインを試してみた

# はじめに
今後流行するであろう、GraphQL+Headless CMSについて調べていたところ、WordPressでもGraphQLを実現できるプラグインがあることを知り、試してみました。まだ、日本語のドキュメントが少ないので、ここに記事にしました。

# 検証した環境

- macOS 10.13.16
- Docker
- WordPress5.2.2
     - Dockerのコンテナを使っています

# インストール
- `wp-graphql`はプラグインディレクトリからインストールすることができません（07/30時点）
- プラグインのソースコードがGitHubに公開されていますので、それを使います

## インストールするプラグイン
- [wp-graphql](https://github.com/wp-graphql/wp-graphql)
    - WordPressをGraphQLサーバにするプラグイン
- [wp-graphiql](https://github.com/wp-graphql/wp-graphiql)
    - WordPressの管理画面上で、GraphQLを実行できるプラグイン
　　

## 手順
**WordPressのプラグインディレクトリに移動します**

```
cd html/wp-content/plugins
``` 
ディレクトリは各自の環境に応じて読み替えてください

**git cloneします**

``` 
git clone https://github.com/wp-graphql/wp-graphql.git
git clone https://github.com/wp-graphql/wp-graphiql.git
```
- ReleasesからZIPをダウンロードしたほうがよいと思いますが、ローカル環境だし、今後のバージョンアップ時にgit pullの方が簡単なので、git cloneにしました

**WordPress にログインして、プラグインを有効化します**

- プラグイン画面では、このように表示されています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77333/464485af-02e0-780c-82bb-b95527b3d08b.png)

**GraphiQLからGraphQLを実行します**
メニューに、**GraphiQL**が表示されていますので、クリックします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77333/e504681b-992e-efd8-963a-897ddec36ec4.png)

ウィンドウの左側に以下のクエリを貼り付けます。

``` json
{ 
  posts{ 
    edges { 
      node { postId title link date }
      }
    } 
}
```
上の矢印ボタンをクリックすると実行されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77333/cbeb0e38-8dcb-75b2-1e86-d5166f297e9c.png)

ウィンドウの右側にクエリの結果が表示されれば動作しています。
このIDEですが、かなり賢く補完してくれるので重宝すると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77333/10bd63f4-5227-be8b-8b56-9464dc3cd62b.png)


 
## クエリのサンプル
- 投稿と固定ページのデータを取得するためのクエリサンプルです

### 1件の投稿を取得する
``` json
{
  postBy(postId:1){
    title date link
  }
}
```
### 1件の固定ページを取得する
``` json
{
  pageBy(pageId:2){
    title date link
  }
}
```
### 直近5件の投稿を取得する
``` json
{ 
  posts(first:5) { 
    edges { 
      node { postId title link date }
    } 
  }
}
```
### 直近5件の投稿をカテゴリ付きで取得する
``` json
{ 
  posts(first:5) { 
    edges { 
      node { postId title link date 
        categories {
          edges { node { id name } }            
        }
      }
    } 
  }
}
```
### カテゴリID:2の直近５件の投稿を取得する
``` json
{ 
  posts(first:5,where:{categoryId: 2}) { 
    edges { 
      node { postId title link date 
        categories {
          edges { node { id name } }            
        }
      }
    } 
  }
}
```
### １件と投稿と１件の固定ページを取得する
```
{ 
  postBy(postId:1) { 
        postId title link date
  },
  pageBy(pageId:2){
    title date link
  }
}
```
- **REST APIだと２回APIをコールしないといけないが、GraphQLだと1回ですみますね**:rocket:

# curlからアクセスする場合
- curlからアクセスする場合、パーマリンク設定が**基本**になっていると、**/graphql**が404エラーになります。**基本**以外の設定に変更します
- httpクライアントであるcurlからGraphQLを実行する場合はこのようなシェルを用意しておきます

``` sh:curl.sh
#!/bin/sh
curl \
-X POST \
-H 'content-type: application/json' \
--data @- \
http://localhost/graphql

```

次にクエリ部分をjsonファイルにしておきます

``` json:get-posts.json
{ 
    "query":"{ posts { edges { node {postId title} } } }" 
}
```

jsonファイルを標準入力でシェルに渡します

```
sh curl.sh < get-posts.json
```
クエリ部を別ファイル化しておくことで、いろんなクエリを楽に実行することができると思います

# REST API との比較
## REST API
- WordPressにはREST APIが搭載されています。そのAPIで投稿を取得するとこのようになります。レスポンスはフォーマットかけてます。レスポンスが長いですね〜:ramen:

**リクエスト**

```
curl http://localhost/wp-json/wp/v2/posts/1 
```

**レスポンス**

```json
{
    "id": 1,
    "date": "2019-07-30T16:38:46",
    "date_gmt": "2019-07-30T07:38:46",
    "guid": {
        "rendered": "http:\/\/localhost\/?p=1"
    },
    "modified": "2019-07-31T15:47:50",
    "modified_gmt": "2019-07-31T06:47:50",
    "slug": "hello-world",
    "status": "publish",
    "type": "post",
    "link": "http:\/\/localhost\/2019\/07\/30\/hello-world\/",
    "title": {
        "rendered": "Hello world!"
    },
    "content": {
        "rendered": "\n<p>WordPress \u3078\u3088\u3046\u3053\u305d\u3002\u3053\u3061\u3089\u306f\u6700\u521d\u306e\u6295\u7a3f\u3067\u3059\u3002\u7de8\u96c6\u307e\u305f\u306f\u524a\u9664\u3057\u3001\u30b3\u30f3\u30c6\u30f3\u30c4\u4f5c\u6210\u3092\u59cb\u3081\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n",
        "protected": false
    },
    "excerpt": {
        "rendered": "<p>WordPress \u3078\u3088\u3046\u3053\u305d\u3002\u3053\u3061\u3089\u306f\u6700\u521d\u306e\u6295\u7a3f\u3067\u3059\u3002\u7de8\u96c6\u307e\u305f\u306f\u524a\u9664\u3057\u3001\u30b3\u30f3\u30c6\u30f3\u30c4\u4f5c\u6210\u3092\u59cb\u3081\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n",
        "protected": false
    },
    "author": 1,
    "featured_media": 0,
    "comment_status": "open",
    "ping_status": "open",
    "sticky": false,
    "template": "",
    "format": "standard",
    "meta": [],
    "categories": [
        2,
        1
    ],
    "tags": [],
    "_links": {
        "self": [
            {
                "href": "http:\/\/localhost\/wp-json\/wp\/v2\/posts\/1"
            }
        ],
        "collection": [
            {
                "href": "http:\/\/localhost\/wp-json\/wp\/v2\/posts"
            }
        ],
        "about": [
            {
                "href": "http:\/\/localhost\/wp-json\/wp\/v2\/types\/post"
            }
        ],
        "author": [
            {
                "embeddable": true,
                "href": "http:\/\/localhost\/wp-json\/wp\/v2\/users\/1"
            }
        ],
        "replies": [
            {
                "embeddable": true,
                "href": "http:\/\/localhost\/wp-json\/wp\/v2\/comments?post=1"
            }
        ],
        "version-history": [
            {
                "count": 1,
                "href": "http:\/\/localhost\/wp-json\/wp\/v2\/posts\/1\/revisions"
            }
        ],
        "predecessor-version": [
            {
                "id": 9,
                "href": "http:\/\/localhost\/wp-json\/wp\/v2\/posts\/1\/revisions\/9"
            }
        ],
        "wp:attachment": [
            {
                "href": "http:\/\/localhost\/wp-json\/wp\/v2\/media?parent=1"
            }
        ],
        "wp:term": [
            {
                "taxonomy": "category",
                "embeddable": true,
                "href": "http:\/\/localhost\/wp-json\/wp\/v2\/categories?post=1"
            },
            {
                "taxonomy": "post_tag",
                "embeddable": true,
                "href": "http:\/\/localhost\/wp-json\/wp\/v2\/tags?post=1"
            }
        ],
        "curies": [
            {
                "name": "wp",
                "href": "https:\/\/api.w.org\/{rel}",
                "templated": true
            }
        ]
    }
}
```
## GraphQL

**リクエスト**

```
curl http:/localhost/graphql -X POST -H 'content-type: application/json' --data '{ "query" : "{ postBy(postId:1) { postId title link date }}" }'
```

**レスポンス**

``` json
{"data":{"postBy":{"postId":1,"title":"Hello world!","link":"http:\/\/localhost\/2019\/07\/30\/hello-world\/","date":"2019-07-30T16:38:46"}}}
```

こんなにシンプルなレスポンスになります。すっきりできそうだ:sunny:

# WordPressのGraphQLプラグインの使い所
- WordPressで構築したサイトでテンプレート(function.phpあたり）を作れる人がいない。または、時間が取れない
- WordPressで管理しているデータを別サイトで使いたい

このような状況であれば、このプラグインを使って、JSからGraphQLを使ってデータを取得すれば実装がすぐにできると思います。まあ、REST APIでもいいですが、GraphQLなら初回アクセス時に１回のAPIで必要なデータを取得しておき、それをローカルストレージに格納して使い回すなんてこともできると思います。

## WordPressをGraphQL+Headless CMSで使う
最初からHeadless CMSと使うなら、私なら別のCMSを選択すると思います。ただし、国産でそのようなCMSがないので、海外のCMSを採用することになります。そうした場合、CMS管理画面のメニューが英語になったり、サポートも日本語では受けれなくなると思います。そういった状況では導入が困難になると話は変わってきます。
WordPressの知名度と無償、検索すればなんかしら情報が出てくる、使える人が多いことを考慮に入れると、選択肢に入ってきますね。

# 最後に
- 今回はセキュリティまわりに触れていません。GraphQLを使ってデータの登録や削除もできますので、本番環境に適用する場合にはセキュリティには注意しましょう。さすがに認証が必要と思われますが、未検証です。
- 今回使ったプラグインは、まだ1.0として公開されていません。そのあたりにも注意しましょう
- 登録や削除のクエリは別の機会に試してみたいと思います