Wordpress (REST API) в качестве Headless CMS для сайта на Eleventy
Почему Wordpress
Wordpress был выбран в качестве примера Headless CMS для Eleventy только потому, что он достаточно распространён и многим знаком. С таким же успехом, в связке с Eleventy, можно использовать любую CMS, поддерживающую интерфейс REST API
.
Почему Eleventy
Практически все генераторы сайтов Jamstack умеют запрашивать информацию из удалённых источников и вставлять эти данные в страницы сайта. Но далеко не все из них умеют создавать страницы на основе коллекций, полученных по REST API
. Страницы обычно создаются только опираясь на файловую структуру и конфигурацию генератора, а данные из удалённых источников могут размещаться на уже созданных страницах.
Eleventy, на текущий момент, один из немногих движков, умеющий не только размещать на страницах данные, полученные из Headless CMS по REST API
, но и генерировать страницы сайта на их основе. Это одно из основных условий, позволяющих осуществлять полноценное управление контентом Jamstack сайта при помощи Headless CMS.
Настройка Wordpress
В настройках Wordpress не требуется специально включать интерфейс REST API
, т.к. он уже включён по умолчанию, при условии, что его явно не отключили при помощи плагина или фильтра:
// functions.php
<?php
add_filter("rest_authentication_errors", function ($access) {
...
}, 999);
Страницы Wordpress в формате JSON
доступны по адресу:
# url
https://example.com/wp-json/wp/v2/pages
Записи Wordpress в формате JSON
доступны по адресу:
# url
https://example.com/wp-json/wp/v2/posts
Тем не менее, вероятно, потребуется дополнительная настройка количества отдаваемых страниц и постов, т.к. по умолчанию, через REST API
, Wordpress отдаёт коллекции постранично, по 10 постов на страницу. Без дополнительной настройки это количество можно увеличить максимум до 100 постов при помощи параметра ?per_page=100
в запросе. Подробная документация по настройке REST API
Wordpress доступна по ссылке.
Настройка Eleventy
1. Инсталлируем в проект модуль eventy-fetch
, позволяющий запрашивать удалённые данные:
# terminal
npm install @11ty/eleventy-fetch
Надеюсь, не нужно напоминать, что эту команду необходимо выполнить из папки проекта.
2. В системной папке _data
проекта Eleventy создаём файл posts.js
со следующим содержимым:
// _data/posts.js
const fetch = require("@11ty/eleventy-fetch");
const url = "https://example.com/wp-json/wp/v2/posts?per_page=100";
module.exports = async (data) => {
return await fetch(url, { duration: "10m", type: "json" });
};
Здесь мы запрашиваем 100 последних постов Wordpress в формате JSON
c 10-минутным кэшированием, чтобы не нагружать CMS слишком частыми обращениями во время разработки. Аналогичным образом можно создать файл pages.js
в папке _data
для получения страниц Wordpress.
Теперь, в любом шаблоне проекта Eleventy, нам доступна коллекция постов, полученных по REST API
из Wordpress, с именем posts
:
// posts.njk
{% for post in posts %}
...
{% endfor %}
Проверить наличие постов в коллекции можно с помощью следующего кода:
// posts.njk
<ul>
{% for post in posts %}
<li>{{ post.title.rendered }}</li>
{% endfor %}
</ul>
3. Чтобы не выводить все посты коллекции одним большим списком, в Eleventy предусмотрен механизм разбивки коллекций на страницы - pagination
, с настраиваемым количеством постов на каждой странице:
// posts.njk
---
pagination:
data: posts
size: 10
---
<ul>
{% for post in pagination.items %}
<li>{{ post.title.rendered }}</li>
{% endfor %}
</ul>
Здесь мы разбиваем коллекцию posts
на страницы по 10 постов. А в цикле перебираем не всю коллекцию posts
, а коллекцию pagination.items
, в которой только 10 постов текущей страницы. Сами страницы постраничной разбивки включёны в коллекцию pagination.pages
и имеют следующие адреса:
- /posts/
- /posts/1/
- /posts/2/
- и т.д.
4. До сих пор мы публиковали посты из коллекции, полученной по REST API
из Wordpress, на странице, сгенерированной из шаблона posts.njk
. Но нам ещё нужно научить Eleventy генерировать отдельную страницу для каждого поста из коллекции. Для этого воспользуемся тем же механизмом разбивки на страницы pagination
, с той лишь разницей, что на каждой странице будет всего один пост:
// post.njk
---
pagination:
data: posts
size: 1
alias: post
permalink: "/posts/post-{{ post.id }}/"
---
<h1>{{ post.title.rendered }}</h1>
{{ post.content.rendered | safe }}
Здесь появилось два новых параметра - alias
, позволяющий получить прямой доступ к единственному посту объекта pagination
, и permalink
, позволяющий настроить ссылку для каждого поста.
Теперь для всех постов в коллекции, полученной по REST API
из Wordpress, будут генерироваться отдельные страницы с адресами:
- /posts/post-347/
- /posts/post-568/
- и т.п.
5. Последним штрихом подкорректируем шаблон posts.njk
, чтобы он не только выводил постраничный список постов, полученных по REST API
из Wordpress, но и позволял открывать каждый пост по ссылке.
// posts.njk
---
pagination:
data: posts
size: 10
---
<ul>
{% for post in pagination.items %}
<li><a href="/posts/post-{{ post.id }}">{{ post.title.rendered }}</a></li>
{% endfor %}
</ul>