AzureFunctionでWP REST APIを使ってコンテンツを取得する

## はじめに
アプリケーションからWordPressの情報を取得する方法の一つとしてWPRESTAPIがあります。
当記事では、AzureFunctionから定期的にWPRESTAPIをコールして情報を取得する方法を記載します。

## 環境
- WordPress 5.0.3
- Azure function (C#)

## WordPressの準備
### 「WordPress REST API」のインストール
１．「WordPress REST API」をインストールします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/195221/c812a506-f3ca-fcea-d93d-b6bac644040c.png)

２．インストール後、「有効化」します。

３．curlでAPIの動作確認をします。
リファレンスをもとに動作確認を行います。https://ja.wp-api.org/reference/

- 投稿の取得
 - ```curl https://XXXXXXXXXXXXXX.azurewebsites.net/wp-json/wp/v2/posts | jq-win64 .```

```
[
  {
    "id": 1,
    "date": "2019-01-29T13:00:09",
    "date_gmt": "2019-01-29T04:00:09",
    "guid": {
      "rendered": "http://XXXXXXXXXX/?p=1"
    },
    "modified": "2019-01-29T13:00:09",
    "modified_gmt": "2019-01-29T04:00:09",
    "slug": "hello-world",
    "status": "publish",
    "type": "post",
    "link": "https://XXXXXXXXXX/2019/01/29/hello-world/",
    "title": {
      "rendered": "Hello world!"
    },
    "content": {
      "rendered": "\n<p>WordPress へようこそ。こちらは最初の投稿です。編集または削除し、コンテンツ作成を始めてください。</p>\n",
      "protected": false
    },
    "excerpt": {
      "rendered": "<p>WordPress へようこそ。こちらは最初の投稿です。編集または削除し、コンテンツ作成を始めてください。</p>\n",
      "protected": false
    },
    "author": 1,
    "featured_media": 0,
    "comment_status": "open",
    "ping_status": "open",
    "sticky": false,
    "template": "",
    "format": "standard",
    "meta": [],
    "categories": [
      1
    ],
    "tags": [],
    "_links": {
      "self": [
        {
          "href": "https://XXXXXXXXXX/wp-json/wp/v2/posts/1"
        }
      ],
      "collection": [
        {
          "href": "https://XXXXXXXXXX/wp-json/wp/v2/posts"
        }
      ],
      "about": [
        {
          "href": "https://XXXXXXXXXX/wp-json/wp/v2/types/post"
        }
      ],
      "author": [
        {
          "embeddable": true,
          "href": "https://XXXXXXXXXX/wp-json/wp/v2/users/1"
        }
      ],
      "replies": [
        {
          "embeddable": true,
          "href": "https://XXXXXXXXXX/wp-json/wp/v2/comments?post=1"
        }
      ],
      "version-history": [
        {
          "count": 0,
          "href": "https://XXXXXXXXXX/wp-json/wp/v2/posts/1/revisions"
        }
      ],
      "wp:attachment": [
        {
          "href": "https://XXXXXXXXXX/wp-json/wp/v2/media?parent=1"
        }
      ],
      "wp:term": [
        {
          "taxonomy": "category",
          "embeddable": true,
          "href": "https://XXXXXXXXXX/wp-json/wp/v2/categories?post=1"
        },
        {
          "taxonomy": "post_tag",
          "embeddable": true,
          "href": "https://XXXXXXXXXX/wp-json/wp/v2/tags?post=1"
        }
      ],
      "curies": [
        {
          "name": "wp",
          "href": "https://api.w.org/{rel}",
          "templated": true
        }
      ]
    }
  }
]
```

## AzureFunction
１．VisualStudioで「AzureFunctions」のプロジェクトを作成します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/195221/37d5f68b-0291-aa57-7ef9-8d1eaa01f746.png)

２．トリガーの設定
今回は定期的に処理させるため、Timer triggerを選択します。
スケジュールはcronで設定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/195221/98f510b7-c2cc-9604-493c-a900985f2f49.png)

３．実行
５分起きにトリガーが起動され、現在の時間を表示するというシンプルな実行結果になります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/195221/044a9594-91b1-126b-24d5-81fee26e0a40.png)

４．WPから取得するクラスを作成
上記の```curl```の実行結果をコピーして、「JSONをクラスとして貼り付ける」を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/195221/115d5072-e86d-dd0f-6aac-fbfc7feb9f58.png)
下記のようにクラスが自動生成されます。クラス名だけ合わせておきます。

```C#:wpinfo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WPbat
{

    public class wpinfo
    {
        public Class1[] Property1 { get; set; }
    }

    public class Class1
    {
        public int id { get; set; }
        public DateTime date { get; set; }
        public DateTime date_gmt { get; set; }
        public Guid guid { get; set; }
        public DateTime modified { get; set; }
        public DateTime modified_gmt { get; set; }
        public string slug { get; set; }
        public string status { get; set; }
        public string type { get; set; }
        public string link { get; set; }
        public Title title { get; set; }
        public Content content { get; set; }
        public Excerpt excerpt { get; set; }
        public int author { get; set; }
        public int featured_media { get; set; }
        public string comment_status { get; set; }
        public string ping_status { get; set; }
        public bool sticky { get; set; }
        public string template { get; set; }
        public string format { get; set; }
        public object[] meta { get; set; }
        public int[] categories { get; set; }
        public object[] tags { get; set; }
        public _Links _links { get; set; }
    }

    public class Guid
    {
        public string rendered { get; set; }
    }

    public class Title
    {
        public string rendered { get; set; }
    }

    public class Content
    {
        public string rendered { get; set; }
        public bool _protected { get; set; }
    }

    public class Excerpt
    {
        public string rendered { get; set; }
        public bool _protected { get; set; }
    }

    public class _Links
    {
        public Self[] self { get; set; }
        public Collection[] collection { get; set; }
        public About[] about { get; set; }
        public Author[] author { get; set; }
        public Reply[] replies { get; set; }
        public VersionHistory[] versionhistory { get; set; }
        public WpAttachment[] wpattachment { get; set; }
        public WpTerm[] wpterm { get; set; }
        public Cury[] curies { get; set; }
    }

    public class Self
    {
        public string href { get; set; }
    }

    public class Collection
    {
        public string href { get; set; }
    }

    public class About
    {
        public string href { get; set; }
    }

    public class Author
    {
        public bool embeddable { get; set; }
        public string href { get; set; }
    }

    public class Reply
    {
        public bool embeddable { get; set; }
        public string href { get; set; }
    }

    public class VersionHistory
    {
        public int count { get; set; }
        public string href { get; set; }
    }

    public class WpAttachment
    {
        public string href { get; set; }
    }

    public class WpTerm
    {
        public string taxonomy { get; set; }
        public bool embeddable { get; set; }
        public string href { get; set; }
    }

    public class Cury
    {
        public string name { get; set; }
        public string href { get; set; }
        public bool templated { get; set; }
    }
}
```

５．APIで投稿のタイトルと内容を取得
最初で作成されたテンプレートに下記のように処理を追記します。

```C#:function1.cs
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Web;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;

namespace WPbat
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async System.Threading.Tasks.Task RunAsync([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer, TraceWriter log)
        {
            var client = new HttpClient();

            string wpurl = "https://XXXXXXXXXX/wp-json/wp/v2/posts?/";

            var queryString = HttpUtility.ParseQueryString(string.Empty);

            var uri = wpurl + queryString;

            var response = await client.GetAsync(uri);

            List<Class1> jres = await response.Content.ReadAsAsync<List<Class1>>(new[] { new JsonMediaTypeFormatter() });

            foreach (Class1 contents in jres)
            {
                log.Info($"タイトル：{contents.title.rendered}");
                log.Info($"内容：{contents.content.rendered}");
            }

        }
       
    }
}

```

６．実行して確認
WordPressの情報を取得できました！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/195221/dbba4e43-8970-a6f2-05f6-842266ba1246.png)


## 応用編：投稿編集日で範囲指定をして投稿を取得
編集日で指定するには、filter引数を使用する必要があります。

１．WPにrest-filterをインストールします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/195221/e611ecc6-5f0f-4b71-ae4e-1f3dccb3e434.png)

２．編集日で範囲指定をする
filterを引数を使用して、期間指定を行います。[WP_query](https://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/WP_Query)のように使うことができます。
例えば、2019/01/30 ~ 2019/01/31の間に編集された投稿を取得するには下記のようなデータをクエリ文字列として送信します。

```
{
  "filter": {
    "date_query": [
      {
        "column": "post_modified",
        "after": "2019-01-30",
        "before": "2019-01-31",
        "inclusive": true
      }
    ]
  }
}
```

３. AzureFunctionに実装
先ほどのソースに追記します。

```C#:function1.cs
            queryString.Add("filter[date_query][0][column]", "post_modified");
            queryString.Add("filter[date_query][0][after]", "2019-01-30");
            queryString.Add("filter[date_query][0][before]", "2019-01-31");
            queryString.Add("filter[date_query][0][inclusive]", "1");
```

４．filterプラグインの修正
現状では一部のクエリが正しく動作しないので、```class-wp-rest-filter.php``` 内の 53行目を下記のように修正します。

```class-wp-rest-filter.php
$vars = apply_filters(
'query_vars',
array_merge(
$wp->public_query_vars,
array_values(array_diff($wp->private_query_vars, array('post_status'))),
array('date_query')
)
);
```

５．実行
正しく取得することができました！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/195221/9c83fd96-f3bf-89d3-ea55-a099002efb66.png)