この記事は ここのえ Advent Calendar 2023 Day 7 の記事です。
Wordpressのブログ記事をトップページに乗せたい
Laravel + Vue環境のホームページをメインで置いているのですが、それとは別のところで動いているWordpressへの導線が欲しく、トップページに新着記事を載せてみました。
Wordpressから新着情報を取ること自体は、JSON形式で取得できるため、データ構造さえ分かっていれば必要に応じてデータ取得が可能です。
LPとかに新着情報を載せる……とかそういう需要も多いと思うので、必要に応じて試してみてください。
環境
今回サンプルに使うのはこんな感じの構成です。
- Laravel 10.x
- PHP 8.2
- Vue 3 (Composition API)
- Typescript
実装
前提の環境を構築済みとします。
また各ライブラリ・フレームワークの解説は省略します。
例として、今回のサイトのWordpressが動作しているアドレスは https://example.com/blog と仮定します。
今回の実装の目的としては、Vue側で
- 記事タイトル
- URL
- 投稿日時
- サムネイル画像
を表示することを目指します。
バックエンド
LaravelのController
Wordpress REST APIを叩いて、必要なデータを取得します。
エンドポイントは、GET /wp/v2/posts
です。
https://example.com/blog/wp-json/wp/v2/posts
加えてper_page
のクエリパラメータを付けることで取得数を制限することができます。
新着記事を表示するだけなら全体を取得する必要もないので、無駄がなくて良いです (デフォルトでper_page=10なので、速度的にはあまり変わらないかも) 。
https://example.com/blog/wp-json/wp/v2/posts?per_page=5
Controllerの実装は以下の通りです。
public function index() {
// 記事の一覧を取得
$posts_raw = file_get_contents("https://example.com/blog/wp-json/wp/v2/posts?per_page=5");
$posts = json_decode($posts_raw, true);
// Viewに返すデータをまとめたArray
$recent = [];
foreach ($posts as $post) {
// サムネイル画像の情報を取得
$thumb_raw = file_get_contents($post["_links"]["wp:featuredmedia"][0]["href"]);
$thumb_data = json_decode($thumb_raw, true);
// 必要な情報を配列にまとめる
$recent[] = [
"title" => $post["title"]["rendered"],
"url" => $post["link"],
"date" => $post["date"],
"thumbnail" => $thumb_data["guid"]["rendered"]
];
}
return view("index", ["recent" => $recent]);
}
サムネイルのみ、GET /wp/v2/posts
で返ってくるJSONでは取得することができません。
JSON内の_links -> wp:featuredmedia[0] -> href
のリンクに GET /wp/v2/media
のエンドポイントへのリンクが入っているので、サムネイル画像の情報を取得するために file_get_contents
を再度回しています。
APIの詳細については、公式のHandbookを参照してください。
フロントエンド
Blade
Controllerで取得したデータがBladeに飛んで来たら、Vueに渡します。
@js
ディレクティブを使って、Vueのpropsとして飛ばします。
<div id="app">
<index-page :recent="@js($recent)" />
</div>
Vue (Typescript, Composition API)
propsを適宜storeに保存したり、使いやすいように取り扱ってください。サンプルでは最小構成にしています。
Typescriptで記述しているため型定義が多めですが、jsの場合は適宜読み替えてください。
date
がstringになってしまうため、JSのDate型に変換したほうが取り扱い易いです。
<!-- IndexPage.vue -->
<script setup lang="ts">
// 記事のinterface
interface Post {
title: string
url: string
date: Date
thumbnail: string
}
// propsの定義
const props = defineProps<{
recent: {
title: string
url: string
date: string
thumbnail: string
}[]
}>()
// 記事の一覧を保持したref
const posts: ref<Post[]> = ref([])
// propsからの変換処理
onBeforeMount(() => {
for(const p of props.recent) {
posts.value.push({
title: p.title,
url: p.url,
date: new Date(p.date),
thumbnail: p.thumbnail,
})
}
})
// 日付をyyyy/mm/dd形式に変更
const getDateString = (date: Date): string => {
return date.toLocaleDateString('ja-JP', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
}
</script>
<template>
<a v-for="post of posts" :key="post.url" :href="post.url">
<img :src="post.thumbnail" :alt="post.title" />
<p>{{ post.title }}</p>
<p>{{ getDateString(post.date) }}</p>
</a>
</template>
まとめ
PHPの方である程度整形してあげれば、フロント側で取り扱うのは容易です。
Wordpressで取得できるのは記事情報に限らないので、アイデア次第で色々できそうです。