Когда-то давно, примерно лет 12 назад, я много работал с WordPress. Хотя он всегда позиционировал себя CMS для блогов, многие делали на нем не только блоги, потому что WordPress предоставлял удобную админку. Темы и плагины писать тоже было удобно. Но с развитием фронтенда со всеми сборщиками, реактами и полной сепарацией от бэкенда, возникла проблема: темы WP всегда были неотделимы от него, а фронтенд становился сложнее. В результате верстать и писать логику на js стало неудобно.
Спустя много лет, я решил посмотреть как же развивается WordPress и с удивлением обнаружил, что он теперь у него есть api. Более того, теперь можно запрашивать данные не только через REST API, но из GraphQL.
Изменилось все, даже способ установки. Так, к примеру, для установки WordPress на локальной машине можно использовать Docker образ для WordPress. Появились решения вроде LocalWP, Kinsta позволяющие запускать WordPress на локальной машине в один клик.
И это очень здорово, потому что команда WordPress решила ту самую проблему разработки тем и адаптировала свою систему под современные задачи.
По url https://yourdomain/wp-json/
доступен список всех роутов.
С помощью плагина WPGraphQL можно добавить поддержку GraphQL.
Ниже опишу пример создания блога на WordPress + Nextjs.
Установим wordpress. Я использовал LocalWP.
Выбираем Create a new site и прокликиваем опции, оставляя все настройки по умолчанию. В результате, работающий на локальной машине WordPress должен выглядеть вот так. Нам нужен адрес сайта: notes.local
.
Если хотите использовать сразу production сервер, могу посоветовать railway.app. Для простого пет-проекта подойдет бесплатный тариф.
После развертывания проекта, нам потребуется url, по которому будет доступен WordPress. В моем случае это dailynotes.up.railway.app
.
Этот адрес сайта потребуется нам для запросов. Его следует вынести в .env файл, а сам файл добавить в .gitignore, чтобы этот файл не попал на github. Одна из причин по которой так следует делать: чтобы разные настройки не перемешивались. Например, на локальной машине у вас может быть один адрес сайта, а на продакшене другой. Другая причина — в .env файлах можно хранить ключи доступа, которые не должны быть доступны публично.
Следующим шагом устанавливаем nextjs: npx create-next-app@latest
.
В корневой директории проекта я сделал файл .env.local и добавил туда url сайта:
NEXT_PUBLIC_WORDPRESS_API_URL=https://dailynotes.up.railway.app
В этом примере я использую сразу путь к сайту на railway. Потому что кроме установки плагина я не планирую никаких изменений в WordPress и хочу сразу получать настоящие данные со своего блога.
Для получения данных мы создадим в корневой файл ./helpers/api.js
:
const API_URL = `${process.env.NEXT_PUBLIC_WORDPRESS_API_URL}/graphql
async function fetchAPI(query = '', { variables } = {}) {
const headers = { 'Content-Type': 'application/json' }
const res = await fetch(API_URL, {
headers,
method: 'POST',
body: JSON.stringify({
query,
variables,
}),
})
const json = await res.json()
if (json.errors) {
console.error(json.errors)
throw new Error('Failed to fetch API')
}
return json.data
}
export async function fetchNotes() {
const data = await fetchAPI(`
query FetchNotes {
posts(where: {status: PUBLISH}) {
nodes {
id
title
content
date
}
}
}
`)
return data?.posts
}
fetchAPI
предназначена для выполнения асинхронных запросов к API с использованием метода POST. Она принимает два аргумента: query
(по умолчанию пустая строка) и объект параметров с именем variables
(по умолчанию пустой объект).
Для получения постов мы будем использовать fetchNotes()
, которая в свою очередь будет использовать функцию fetchApi()
. На странице ./page.js
можно будет вызвать fetchNotes()
, чтобы запросить данные:
import { fetchNotes } from '@/app/helpers/api'
export default async function Home() {
const notes = await fetchNotes()
return (
<section>
{notes.nodes.map((note) => {
return (
<article className="note" key={note.id}>
<h2>{note.title}</h2>
<div className="note-content" dangerouslySetInnerHTML={{ __html: note.content }}></div>
</article>
)
})}
</section>
)
}
Это очень базовый пример, его цель дать примерное представление как это работает. В будущем его можно усложнить, дополнив запрос другой информацией.