Help us understand the problem. What is going on with this article?

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

はじめに

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

検証した環境

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

インストール

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

インストールするプラグイン

  • wp-graphql
    • WordPressを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

GraphiQLからGraphQLを実行します
メニューに、GraphiQLが表示されていますので、クリックします
image.png

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

{ 
  posts{ 
    edges { 
      node { postId title link date }
      }
    } 
}

上の矢印ボタンをクリックすると実行されます。

image.png

ウィンドウの右側にクエリの結果が表示されれば動作しています。
このIDEですが、かなり賢く補完してくれるので重宝すると思います。
image.png

クエリのサンプル

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

1件の投稿を取得する

{
  postBy(postId:1){
    title date link
  }
}

1件の固定ページを取得する

{
  pageBy(pageId:2){
    title date link
  }
}

直近5件の投稿を取得する

{ 
  posts(first:5) { 
    edges { 
      node { postId title link date }
    } 
  }
}

直近5件の投稿をカテゴリ付きで取得する

{ 
  posts(first:5) { 
    edges { 
      node { postId title link date 
        categories {
          edges { node { id name } }            
        }
      }
    } 
  }
}

カテゴリID:2の直近5件の投稿を取得する

{ 
  posts(first:5,where:{categoryId: 2}) { 
    edges { 
      node { postId title link date 
        categories {
          edges { node { id name } }            
        }
      }
    } 
  }
}

1件と投稿と1件の固定ページを取得する

{ 
  postBy(postId:1) { 
        postId title link date
  },
  pageBy(pageId:2){
    title date link
  }
}
  • REST APIだと2回APIをコールしないといけないが、GraphQLだと1回ですみますね:rocket:

curlからアクセスする場合

  • curlからアクセスする場合、パーマリンク設定が基本になっていると、/graphqlが404エラーになります。基本以外の設定に変更します
  • httpクライアントであるcurlからGraphQLを実行する場合はこのようなシェルを用意しておきます
curl.sh
#!/bin/sh
curl \
-X POST \
-H 'content-type: application/json' \
--data @- \
http://localhost/graphql

次にクエリ部分を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 

レスポンス

{
    "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 }}" }'

レスポンス

{"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なら初回アクセス時に1回のAPIで必要なデータを取得しておき、それをローカルストレージに格納して使い回すなんてこともできると思います。

WordPressをGraphQL+Headless CMSで使う

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

最後に

  • 今回はセキュリティまわりに触れていません。GraphQLを使ってデータの登録や削除もできますので、本番環境に適用する場合にはセキュリティには注意しましょう。さすがに認証が必要と思われますが、未検証です。
  • 今回使ったプラグインは、まだ1.0として公開されていません。そのあたりにも注意しましょう
  • 登録や削除のクエリは別の機会に試してみたいと思います
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away