Nuxt.jsからWordPress REST APIで記事を全件取得する

シェアする:

この記事をおすすめしたい人

  • WordPressのREST APIから全記事を取得したい人
  • Nuxt.jsで静的出力する際にAPIから動的ルートを追加したい人
  • つまりオレ

WordPress Nuxt化の一環です。

今回はWordPressのREST APIから記事を全件取得します。

全件取得なんかいらんやろ。

と思っていたんですが、必要になったのでやり方を検討して、実際に取得するところまでやってみたいと思います。

WordPressの上でな!

※ このブログはまだWordPress製です

記事の全件取得が必要なのはgenerateの時

WordPressのNuxt化として、静的HTML出力を考えています。

この際に、動的ルーティングのページ(記事やカテゴリページ)は無視されるので、自分でルートを追加してやらないといけません。

このままだとページをリロードした時に表示されなかったり、HTMLがないせいでSEO的にもあまりよくなさそうな気がするので、全ページ事前に出力します。

WordPressのREST APIは全件取得できないのか?

一度に取得できる記事数は最大100件までです。

記事取得の際に「per_page」をWordPress内で全件指定の「-1」や大きな値(1万とか)を指定すると次のようなエラーがでます。


{
  "code": "rest_invalid_param",
  "message": "無効なパラメーター: per_page",
  "data": {
    "status": 400,
    "params": {
      "per_page": "per_page は1以上、100以下でなければなりません。"
    }
  }
}

つまり100件しばりで全件取得を考えないといけません。

全件取得の考え方

1回のAPIリクエストあたり100件しか取得できないので、全記事の取得が終わるまで複数回APIを叩くことになります。

この時に問題になるのが、「どこで終わるのか」です。

終了判定の違いで3つの方法を考えました。

何も考えずにリクエストを続ける方法

WordPressのREST APIから「次の100件」を取得する場合、「per_page」と「page」でコントロールします。 「次の100件」の場合は「per_page=100」「page=2」になります。

「page」の数を増やしていき、該当記事が1件もなかった場合は次のエラーを返します。


{
  "code": "rest_post_invalid_page_number",
  "message": "リクエストされたページ数は存在するページ数を上回っています。",
  "data": {
    "status": 400
  }
}

このエラーが返った時を終了とする方法です。

ただし、このエラーは上記JSONを正常に受け取れるわけではなく、例外が発生します。

例外処理をしなくてはならないのでちょっと面倒です。

「x-wp-total」から記事数を取得する方法

REST APIを一度リクエストするとレスポンスのヘッダの中に「x-wp-total」という値があります。 これはリクエストしたクエリに該当する「全件」の数です。

詳しくはWordPress公式を見てください。

総記事数が分かるなら、何回リクエストすれば全記事取得できるかが計算できます。

独自APIを使う方法

動的ルーティングを定義するのに必要な最小限の情報(スラッグだけとか)を、全記事分返す独自APIを作ります。

独自APIを実装する手間はありますが、終了判定を気にする必要がなく、APIリクエストも1回で済みます。

独自APIでの実装が一番利便性はいいかなと思いますが、独自APIはなんでもできてしまうし、ここまで独自APIに頼らずにやってきているので、「x-wp-total」を使う方法でコードを考えていきます。

全記事取得のコード

今回はgenerate時のルート追加のために全件取得を行うので、nuxt.config.jsに以下のコードを追加します。


//axiosのインポート
import axios from 'axios'

export default {
  generate: {
    routes: async () => {
      //戻り値用の配列
      let list = []
      
      //1回の取得数
      const per_page = 100
      //APIを取得するURL
      const baseUrl = 'https://dev.ore-shika.com'
      //リクエスト用のクエリ
      const query = baseUrl + '/wp-json/wp/v2/posts' + '?context=embed&per_page=' + per_page + '&page='
      
      //最初の100件を取得
      let res = await axios.get(query + '1')
      //ヘッダから総記事数を取得
      const total = res.headers['x-wp-total']
      //何回取得する必要があるかを計算
      const limit = Math.ceil(total / per_page)
      
      //page番号をiとしてループ
      for ( let i = 1; i <= limit; i++ ) {
        //1回目のレスポンスは受け取り済み
        if ( i > 1 ) {
          res = await axios.get(query + i)
        }
        
        //取得した記事を戻り値配列に追加
        res.data.forEach(post => {
          list.push('/post/' + post.slug + '/')
        })
      }
      
      return list
    },
  },
}

同じ用途で使う場合は、「baseUrl」の部分だけ書き換えればコピペで使えると思います。

「query」に「context=embed」とついていますが、これは簡単に言うと返すデータを必要なものにだけ絞って軽量化するサインです。

他の場所で使う場合は調整が必要ですが、要は以下の4点だけ抑えておけば流用できると思います。

  • 最初の100件を取得
  • ヘッダの「x-wp-total」から総記事数を取得
  • 「page」の最大値を計算
  • 「page」の数だけループして記事を取得

以上、WordPressからお届けしました!

シェアする: