WP REST APIは、全件取得しようと思ってもper_pageが100までしかきいてくれないので、何も考えなければ100件しか取得することができません。

そのため、全件取得しようと思ったら、下記の2通りが一般的になります。

  • php側で全件取得したものをエンドポイントに追加
  • jsで全件取得

ですがphp側で処理してしまうと、そもそもREST APIの概念って何だっけ?的な感じになります。

また、今まではper_pageをループさせていたのですが、疑問を感じ始めたので、今回はjsを使用した別の方法で取得します。

jsといっても、Vue2でSFC構文を用いてコンポーネントで使い回せるようにするのがゴールです。

根本的な取得方法は変わらないので、Vue3勢もReact勢も楽しめる内容になっている。。。はずです!

また、今回は長くなりますので下記の3部に分けてお届けします。

  • post取得編 ← 今回はココ
  • pagination機能追加編(WPライクな普通のpaginationです)
  • taxonomy選択機能追加編

ではやっていきましょう。

# この記事で解決すること

  • WP REST APIで投稿(カスタム投稿)の全件取得ができる

 

手順

  1. 事前準備
    • 構造の確認
    • 使用するライブラリ
    • フォルダ・ファイル構成の確認
    • 使用するデータの決定
    • 使用するデータの入れ込み
  2. 情報の取得
    • 投稿のheader情報取得
    • 投稿の取得
    • 投稿の全件取得
  3. 表示データの確定
  4. templateの設定
    • html設定(最小限)
    • styleの設定(最小限)
  5. 実装
    • Vueコンポーネントの読み込み
    • htmlへの実装
    • 動作確認

            事前準備

            構造の確認

            まずは取得に際する構造確認です。

            WP REST APIは、per_pageを使用した場合、1度に100件までしか投稿データを取得することできません。

            per_pageは無駄な記述が多いので、今回はパラメーターのpageを使用します。

            例えば120件の投稿があった場合、1page=10件なのでpageの合計は12となります。

            それをpage=1からpage=12まで繰り返し取得することで全件取得することができます。

            使用するライブラリ

            今回は下記のライブラリを使用します。

            ライブラリが違っても根本は変わりませんので、よしなにしてください。

            • axios@1.1.1
            • vue@2.6.14
            • vue-loader@15.9.8
            • vue-style-loader@4.1.3
            • vue-template-compiler@2.6.14

            フォルダ・ファイル構成の確認

            • theme folder
              • src
                • js
                  • components
                    • archive.vue
                  • app.js
              • page-test.php

            使用するデータの決定

            html側で大方設定できるようにしておきたいので、propsも踏まえて説明していきます。

            また、今回は投稿全件取得編ですので、paginationやtaxonomy関連のデータはあえて記載しません。

            props

            name type remark
            postFetchUrl String 取得するREST APIのURL
            require: true
            postQuery Object postFetchUrlに送るパラメータ
            default: () => ({
            ‘_embed’: ”, // アイキャッチ情報の取得
            })
            perPage Number 1回(ページ)で表示させる件数
            default: 10

            data

             

            name type remark
            dataOrigin Array 都度リクエストを送る必要がないよう、
            全投稿データを格納しておくための配列
            dataBase Array タクソノミーなどの範囲指定が入った場合に、
            現在必要な投稿データを入れておくための配列
            totalPages Number 合計ページ数
            totalPosts Number 合計投稿数
            pager Number props:perPageを踏まえた現在のページ
            default: 1

            使用するデータの入れ込み

            今回はコンポーネント化しますので、archive.vueにガシガシ書いていきます。

            前項のデータを踏まえると現状のarchive.vueは下記の内容となります。

            archive.vue

            <template>
            </template>
            
            <style lang="scss" scoped>
            </style>
            <script>
              import axios from 'axios'
              export default {
                props: {
                  postFetchUrl: {
                    type: String,
                    require: true
                  },
                  postQuery: {
                    type: Object,
                    default: () => ({
                      '_embed': '', // アイキャッチ情報の取得
                    })
                  },
                  perPage: {
                    type: Number,
                    default: 10,
                  },
                },
                data() {
                  return {
                    dataOrigin: [],
                    dataBase: [],
                    totalPages: 0,
                    totalPosts: 0,
                    pager: 1,
                  }
                },
            </script>

            情報の取得

            投稿のheader情報取得

            asyncawaitを使用してpostFetchUrlの情報をaxiosで取得してきます。

            axiosを使用している理由としては、何も考えずにheader情報を取得できるからです。

            archive.vue: methods

            async getPostInfo() {
              await axios.get(this.postFetchUrl)
              .then((res) => {
                this.totalPages = Number(res.headers['x-wp-totalpages']) // 合計ページ数
                this.totalPosts = Number(res.headers['x-wp-total'])      // 合計投稿数
              })
              .catch(error => console.log(error))
            },

            投稿の取得

            props:postQueryで指定したパラメータを踏まえた上で投稿を取得してきます。

            archive.vue: methods

            async getPostData(num, postQuery = this.postQuery) {
              
              // パラメータを追加できるようにしておく
              const params = { page: num }                    // ページの指定
              insertParams = await {...postQuery, ...params}  // postQueryとparamsを結合
              
              // 投稿を取得してdataOriginに追加
              await axios.get(this.postFetchUrl, {params: insertParams})
              .then((res) => {
                this.dataOrigin = this.dataOrigin.concat(res.data)  // データをdataOriginに結合
                this.dataBase   = this.dataOrigin                   // 範囲指定などがあった場合のための保存用データ
              })
              .catch(error => console.log(error))
            },

            この関数はページ数分のループを回すので、numで取得ページの管理を行います。

            リクエストURLは/wp-json/wp/v2/posts?page=num&postQuery...となります。

            あとは、返ってきたデータをdataOrigindataBaseに追加していくという流れです。

            投稿の全件取得

            先ほど作成したgetPostData()を使用して投稿を全件取得します。

            archive.vue: methods

            async getPostDatas() {
              
              // 投稿のheader情報取得
              await this.getPostInfo()
              
              // 投稿のページ数分の配列を作成
              const numPostAry = [...Array(this.totalPages).keys()].map( i => ++i )
              
              // 投稿のページ数分ループを回す
              for (let num of numPostAry) {
                await this.getPostData(num)
              }
            },

            文言で書くと、下記となります。
            合計ページ数と合計投稿数を取得し終わったら、合計ページ数回、情報を取得しに行く

            先程から出てきているasyncawaitはこの終わったらを担っています。

            7行目

            this.totalPages = 5だと仮定した場合、[1, 2, 3, 4, 5]という配列を作成してくれます。

            ちなみに、.map( i => ++i )しなかった場合は[0, 1, 2, 3, 4]となります。

             

             

            あとはmountedgetPostDatasを呼び出せば、投稿の全件取得は内部的に完了しています。

            archive.vue: mounted

            mounted() {
              this.getPostDatas()
            },

            表示データの作成

            さて、ここまでで取得したデータは、あくまで保存用のデータです。

            ですが表示する件数を指定したいので、表示用のデータを作成します。

            表示するデータはpropsの設定により切り替わるのでcomputedに登録することにします。

            archive.vue: computed

            datas() {
              return this.dataBase.slice(0, this.perPage)
            },

            pagination実装前なのですごく簡素ですが、これでperPageで設定した分の投稿数を表示してくれます。

            templateの設定

            archive.vueにhtmlとstyleを書いていきます。

            html設定

            実装後にVueファイルを変更することは極力避けたいのでslotを使用します。

            archive.vue: template

            <template>
              <div class="my-post-archive">
                <article class="archive" v-if="datas">
                  <section class="archive__item" v-for="data in datas" :key="data.id">
                    <slot :data="data" name="post" />
                  </section>
                </article>
              </div>
            </template>

            先程computedで作成したdatasv-forで回します。

            あとはsection内の構造をhtml側で設定できるようslotを設置しています。

            styleの設定

            サンプルですので、すごく簡単な3カラムにしました。

            archive.vue: style

            .archive {
              display: flex;
              flex-wrap: wrap;
              justify-content: center;
              gap: .5rem 1rem;
              margin-top: 1rem;
              &__item {
                width: calc((100% / 3) - ( 1rem * (3 - 1) ));
                text-align: center;
              }
            }

            実装

            Vueコンポーネントの読み込み

            app.js

            import Archive from './components/archive.vue'
            
            if (document.getElementById('archive')) {
              new Vue({
                el: "#archive",
                components: {
                  Archive,
                },
              })
            }

            htmlへの実装

            page-test.php

            <div id="archive">
              <archive
                :post-fetch-url="'/wp-json/wp/v2/posts'"
                :per-page="10"
                :post-query="{
                  '_fields': 'id,content,title,categories,_links,_embedded',
                  '_embed': '',
                }"
                #post="{ data }"
              >
                <span v-text="data.id"></span>
              </archive>
            </div>

            6行目

            あまり多くを読み込みたくないので、post-queryで読み込むフィールドを設定しておきます。

            10行目

            slotの受け取りをしています。

            #v-slotの省略です。

            <slot :data="data" name="post" />
            #post="{ data }"

            11行目

            サンプルなので、ひとまず投稿のIDだけ表示することにします。

            これで実装は完了です。

            動作確認

            上記のコードで投稿が取得できているのがわかると思います。

            また、:per-page=”10″で表示件数を10件としていますが、:per-page=”30″に変更すれば30件取得することができます。

             

            最後に

            皆さんもお気付きの通り、今のままだと「per_pageで取得してくればいいでしょ」という状況になっています。

            ですが、これまでの内容はあくまで投稿を全件取得するという名目でした。

            次回以降のpagination機能とtaxonomy選択機能を追加することで意味をなしてきますので、気長にお付き合いいただければと思います。

            また、infinit scrollを実装される方はここまでで十分かなと思います。

            お付き合いありがとうございました!

            では、よいWPライフを!

            あわせて読みたい記事

            【ページネーション編】WP REST APIで投稿を非同期で全件取得した話
            【ページネーション編】WPRESTAPIで投稿を非同期で全件取得した話
            前記事【投稿全件取得編】で取得してきた投稿に対して、スタンダードなページネーションを子コンポーネントとして追加する方法です。
            【タクソノミーフィルター編】WP REST APIで投稿を非同期で全件取得した話
            【タクソノミーフィルター編】WPRESTAPIで投稿を非同期で全件取得した話
            前記事にてWPRESTAPIで取得した投稿全件に対し、チェックの入ったタームのみ表示させ、ページネーションと連携します。