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>
AG & Dev © 2020 Moscow