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で投稿(カスタム投稿)の全件取得ができる
手順
- 事前準備
- 構造の確認
- 使用するライブラリ
- フォルダ・ファイル構成の確認
- 使用するデータの決定
- 使用するデータの入れ込み
- 情報の取得
- 投稿のheader情報取得
- 投稿の取得
- 投稿の全件取得
- 表示データの確定
- templateの設定
- html設定(最小限)
- styleの設定(最小限)
- 実装
- 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
- components
- js
- page-test.php
- src
使用するデータの決定
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情報取得
async
await
を使用して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...
となります。
あとは、返ってきたデータをdataOrigin
とdataBase
に追加していくという流れです。
投稿の全件取得
先ほど作成した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)
}
},
文言で書くと、下記となります。
「合計ページ数と合計投稿数を取得し終わったら、合計ページ数回、情報を取得しに行く」
先程から出てきているasync
await
はこの終わったらを担っています。
7行目
this.totalPages = 5
だと仮定した場合、[1, 2, 3, 4, 5]という配列を作成してくれます。
ちなみに、.map( i => ++i )
しなかった場合は[0, 1, 2, 3, 4]となります。
あとはmounted
でgetPostDatas
を呼び出せば、投稿の全件取得は内部的に完了しています。
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
で作成したdatas
をv-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ライフを!