Как использовать WordPress в качестве Headless CMS для Eleventy

Перейдите по адресу Программирование и разработка

В последние несколько лет генерация статических сайтов и концепции Jamstack эволюционировали от нишевых инструментов к основным подходам к разработке.

Преимущества привлекательны:

  • более простое развёртывание и статический хостинг
  • лучшая безопасность; есть несколько серверных систем, которые можно использовать
  • простое резервное копирование и контроль версий документов с помощью Git
  • большой опыт разработки
  • сверхбыстрая производительность.

К сожалению, проекты генерации статических сайтов (SSG) редко передаются клиентам. Такие SSG, как Jekyll, Hugo и Gatsby, созданы для разработчиков. Навигация по ветвям версий, обновление документов Markdown и запуск процессов сборки из командной строки разочаровывают редакторов, пришедших из мира публикации в один клик в системе управления контентом.

В этом руководстве описывается один способ сделать всех счастливыми и мотивированными!

  • редакторы контента могут использовать WordPress для редактирования и предварительного просмотра сообщений
  • разработчики могут импортировать этот контент в Eleventy для создания статического сайта.

Безголовые CMS и слабосвязанные API

Некоторые проиллюстрированные здесь концепции окутаны непонятным жаргоном и терминологией. Я постараюсь избежать этого, но полезно понять общий подход.

Большинство систем управления контентом (CMS) обеспечивают:

  1. Панель управления контентом для управления страницами, сообщениями, медиа, категориями, тегами и т.д.
  2. Системы генерации веб-страниц для вставки контента в шаблоны. Обычно это происходит по запросу, когда пользователь запрашивает страницу.

У этого есть некоторые недостатки:

  1. Сайты могут быть ограничены возможностями CMS и её плагинов.
  2. Контент часто хранится в HTML, поэтому повторное использование затруднено, например, использование того же контента в мобильном приложении.
  3. Процесс рендеринга страницы может быть медленным. CMS обычно предлагают варианты кэширования для повышения производительности, но целые сайты могут исчезнуть при сбое базы данных.
  4. Перейти на альтернативную / лучшую CMS непросто.
Читайте также:  Python Flask — перенаправление и ошибки

Чтобы обеспечить дополнительную гибкость, автономная CMS имеет панель управления контентом, но вместо шаблонов страниц к данным можно получить доступ через API. Тогда любое количество систем может использовать один и тот же контент. Например:

  1. SSG может получить весь контент во время сборки и отобразить весь сайт
  2. другой SSG может создать сайт другим способом — например, с премиальным контентом
  3. мобильное приложение может получать контент по запросу, чтобы показать последние обновления.

Решения Headless CMS включают Sanity.io и Contentful. Они эффективны, но требуют от редакторов изучения новой системы управления контентом.

API REST WordPress

Почти 40% всех сайтов используют WordPress (включая SitePoint.com ). Большинство редакторов контента сталкивались с CMS, и многие будут использовать её ежедневно.

WordPress предоставляет REST API с момента выпуска версии 4.7 в 2016 году. API позволяет разработчикам получать доступ и обновлять любые данные, хранящиеся в CMS. Например, чтобы получить десять последних сообщений, вы можете отправить запрос по адресу:

yoursite.com/wp-json/wp/v2/posts?orderby=date&order=desc

Примечание: этот URL-адрес REST будет работать, только если в настройках WordPress установлены довольно постоянные ссылки, такие как имя сообщения. Если сайт использует URL-адреса по умолчанию, конечной точкой REST будет<yoursite.com/?rest_route=wp/v2/posts?orderby=date&order=desc>.

Это возвращает содержимое JSON, содержащее массив больших объектов для каждого сообщения:

[
  {
    "id": 33,
    "date": "2020-12-31T13:03:21",
    "date_gmt": "2020-12-31T13:03:21",
    "guid": {
      "rendered": "https://mysite/?p=33"
    },
    "modified": "2020-12-31T13:03:21",
    "modified_gmt": "2020-12-31T13:03:21",
    "slug": "my-post",
    "status": "publish",
    "type": "post",
    "link": "https://mysite/my-post/",
    "title": {
      "rendered": "First post"
    },
    "content": {
      "rendered": "<p>My first post. Nothing much to see here.</p>",
      "protected": false
    },
    "excerpt": {
      "rendered": "<p>My first post</p>",
      "protected": false
    },
    "author": 1,
    "featured_media": 0,
    "comment_status": "closed",
    "ping_status": "",
    "sticky": false,
    "template": "",
    "format": "standard",
    "meta": [],
    "categories": [1],
    "tags": []
   }
]

По умолчанию WordPress возвращает десять сообщений. Заголовок HTTP x-wp-totalвозвращает общее количество сообщений и x-wp-totalpagesобщее количество страниц.

Примечание: для чтения общедоступных данных аутентификация WordPress не требуется, потому что… они общедоступны! Аутентификация необходима только при попытке добавить или изменить контент.

Таким образом, можно использовать WordPress в качестве автономной CMS и импортировать данные страницы в генератор статических сайтов, например Eleventy. Ваши редакторы могут продолжать использовать известный им инструмент независимо от процессов, которые вы используете для публикации на сайте.

Предупреждения WordPress

В разделах ниже описывается, как импортировать сообщения WordPress на сайт, созданный Eleventy.

В идеальном мире ваш шаблон WordPress и тема Eleventy были бы похожи, поэтому предварительный просмотр страниц отображался бы идентично окончательному сайту. Это может быть сложно: WordPress REST API выводит HTML, и этот код может быть значительно изменён плагинами и темами. Карусель, товар из магазина или контактная форма могут оказаться на вашем статическом сайте, но не работать из-за отсутствия ресурсов на стороне клиента или запросов Ajax к API на стороне сервера.

Мой совет: чем проще настроить WordPress, тем проще будет использовать его в качестве автономной CMS. К сожалению, эти 57 основных плагинов, установленных вашим клиентом, могут вызвать некоторые проблемы.

Установить WordPress

В приведённом ниже демонстрационном коде предполагается, что на вашем компьютере работает WordPress по адресу http: // localhost: 8001 /. Вы можете установить Apache, PHP, MySQL и WordPress вручную, использовать универсальный установщик, такой как XAMPP, или даже получить доступ к живому серверу.

Кроме того, вы можете использовать Docker для управления установкой и настройкой. Создайте новый каталог, например wpheadless, содержащий docker-compose.yml файл:

version: '3'

services:

  mysql:
    image: mysql:5
    container_name: mysql
    environment:
      - MYSQL_DATABASE=wpdb
      - MYSQL_USER=wpuser
      - MYSQL_PASSWORD=wpsecret
      - MYSQL_ROOT_PASSWORD=mysecret
    volumes:
      - wpdata:/var/lib/mysql
    ports:
      - "3306:3306"
    networks:
      - wpnet
    restart: on-failure

  wordpress:
    image: wordpress
    container_name: wordpress
    depends_on:
      - mysql
    environment:
      - WORDPRESS_DB_HOST=mysql
      - WORDPRESS_DB_NAME=wpdb
      - WORDPRESS_DB_USER=wpuser
      - WORDPRESS_DB_PASSWORD=wpsecret
    volumes:
      - wpfiles:/var/www/html
      - ./wp-content:/var/www/html/wp-content
    ports:
      - "8001:80"
    networks:
      - wpnet
    restart: on-failure

volumes:
  wpdata:
  wpfiles:

networks:
  wpnet:

Запустите docker-compose upиз своего терминала, чтобы запустить WordPress. При первом запуске это может занять несколько минут, так как все зависимости должны быть загружены и инициализированы.

На wp-contentхосте будет создан новый подкаталог, содержащий установленные темы и плагины. Если вы используете Linux, macOS или Windows WSL2, вы можете обнаружить, что этот каталог был создан rootпользователем. Вы можете запустить, sudo chmod 777 -R wp-contentчтобы предоставить права чтения и записи всем пользователям, чтобы вы и WordPress могли управлять файлами.

Примечание: chmod 777не идеально. sudo chown -R www-data: wp-contentДалее следует чуть более безопасный вариант sudo chmod 774 -R wp-content. Это даёт права на запись Apache и всем участникам вашей группы.

Перейдите по адресу http: // localhost: 8001 / в своём браузере и следуйте процессу установки WordPress:

Перейдите по адресу

При необходимости измените настройки своего сайта, не забывая установить красивые постоянные ссылки, такие как название сообщения, в меню » Настройки» > » Постоянные ссылки». Затем добавьте или импортируйте несколько сообщений, чтобы у вас были данные для тестирования в Eleventy.

Оставьте WordPress работающим, но, как только вы будете готовы всё выключить, запустите его docker-compose downиз каталога проекта.

Установить Eleventy

Eleventy — популярный генератор статических сайтов на Node.js. В руководстве «Приступая к работе с Eleventy» описывается полная установка, но в приведённых ниже инструкциях показаны основные шаги.

Убедитесь, что у вас установлен Node.js версии 8.0 или выше, затем создайте каталог проекта и инициализируйте package.json файл:

mkdir wp11ty
cd wp11ty
npm init

Установите Eleventy и Fetch-совместимую библиотеку node-fetch в качестве зависимостей разработки:

npm install @11ty/eleventy node-fetch --save-dev

Затем создайте новый.eleventy.jsфайл конфигурации, который устанавливает подкаталоги source ( /content) и build ( /build):

// .eleventy.js configuration
module.exports = config => {

  return {

    dir: {
      input: 'content',
      output: `build`
    }

  };

};

Получение данных сообщений WordPress

Eleventy может получать данные откуда угодно. Файлы JavaScript, содержащиеся в _dataкаталоге содержимого, выполняются автоматически, и любые данные, возвращаемые экспортированной функцией, доступны в шаблонах страниц.

Создайте content/_data/posts.jsфайл в каталоге проекта. Начните с определения конечной точки API сообщений WordPress по умолчанию и node_fetch модуля:

// fetch WordPress posts
const
  wordpressAPI = 'http://localhost:8001/wp-json/wp/v2/posts?orderby=date&order=desc',
  fetch = require('node-fetch');

За этим следует wpPostPages()функция, которая определяет, сколько вызовов REST необходимо выполнить для получения всех сообщений. Он вызывает URL-адрес WordPress API, но добавляет &_fields=idтолько идентификаторы сообщений — минимально необходимые данные.

Затем x-wp-totalpagesможно проверить заголовок, чтобы получить количество страниц:

// fetch number of WordPress post pages
async function wpPostPages() {

  try {

    const res = await fetch(`${ wordpressAPI }&_fields=id&page=1`);
    return res.headers.get('x-wp-totalpages') || 0;

  }
  catch(err) {
    console.log(`WordPress API call failed: ${err}`);
    return 0;
  }

}

wpPosts() Функция извлекает один набор ( стр ) постов, где каждый имеет свой идентификатор, пули, дата, название, выдержку и содержание возвращены. Строка анализируется в JSON, затем удаляются все пустые и защищённые паролем сообщения (где content.protectedустановлено true).

Примечание: по умолчанию черновики и личные сообщения WordPress. Которые могут просматривать только редакторы контента, не возвращаются /wp-json/wp/v2/postsконечной точкой.

Содержимое сообщения отформатировано для создания дат и чистых строк. В этом примере из полностью определённых URL-адресов WordPress удалён домен http: // localhost: 8001, чтобы гарантировать, что они указывают на отображаемый сайт. При необходимости вы можете добавить дополнительные модификации:

// fetch list of WordPress posts
async function wpPosts(page = 1) {

  try {

    const
      res = await fetch(`${ wordpressAPI }&_fields=id,slug,date,title,excerpt,content&page=${ page }`),
      json = await res.json();

    // return formatted data
    return json
      .filter(p => p.content.rendered && !p.content.protected)
      .map(p => {
        return {
          slug: p.slug,
          date: new Date(p.date),
          dateYMD: dateYMD(p.date),
          dateFriendly: dateFriendly(p.date),
          title: p.title.rendered,
          excerpt: wpStringClean(p.excerpt.rendered),
          content: wpStringClean(p.content.rendered)
        };
      });

  }
  catch (err) {
    console.log(`WordPress API call failed: ${err}`);
    return null;
  }

}


// pad date digits
function pad(v = '', len = 2, chr = '0') {
  return String(v).padStart(len, chr);
}


// format date as YYYY-MM-DD
function dateYMD(d) {

  d = new Date(d);
  return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate());

}

// format friendly date
function dateFriendly(d) {

  const toMonth = new Intl.DateTimeFormat('en', { month: 'long' });
  d = new Date(d);
  return d.getDate() + ' ' + toMonth.format(d) + ', ' + d.getFullYear();

}


// clean WordPress strings
function wpStringClean(str) {

  return str
    .replace(/http:\/\/localhost:8001/ig, '')
    .trim();

}

Наконец, одна экспортированная функция возвращает массив всех отформатированных сообщений. Он вызывает wpPostPages()определение количества страниц, а затем запускается wpPosts()одновременно для каждой страницы:

// process WordPress posts
module.exports = async function() {

  const posts = [];

  // get number of pages
  const wpPages = await wpPostPages();
  if (!wpPages) return posts;

  // fetch all pages of posts
  const wpList = [];
  for (let w = 1; w <= wpPages; w++) {
    wpList.push( wpPosts(w) );
  }

  const all = await Promise.all( wpList );
  return all.flat();

};

Возвращённый массив пост-объектов будет выглядеть примерно так:

[
  {
    slug: 'post-one',
    date: new Date('2021-01-04'),
    dateYMD: '2021-01-04',
    dateFriendly: '4 January 2021',
    title: 'My first post',
    excerpt: '<p>The first post on this site.</p>',
    content: '<p>This is the content of the first post on this site.</p>'
  }
]

Рендеринг всех постов в Eleventy

Функция разбивки на страницы Eleventy может отображать страницы из сгенерированных данных. Создайте content/post/post.njk файл шаблона Nunjucks со следующим кодом для извлечения posts.jsданных ( posts) и вывода каждого элемента (’post’) в каталог, названный в соответствии с названием сообщения:

---
pagination:
  data: posts
  alias: post
  size: 1
permalink: "/{{ post.slug | slug }}/index.html"
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ post.title }}</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<style>
  body { font-size: 100%; font-family: sans-serif; }
</style>
</head>
<body>

<h1>{{ post.title }}</h1>

<p><time datetime="{{ post.dateYMD }}">{{ post.dateFriendly }}</time></p>

{{ post.content | safe }}

</body>
</html>

Запустите npx eleventy —serveиз терминала в корневом каталоге проекта, чтобы сгенерировать все сообщения и запустить сервер разработки.

Если сообщение со слагом post-oneбыло создано в WordPress, вы можете получить к нему доступ на своём новом сайте Eleventy по адресу http: // localhost: 8080 / post-one / :

вы можете получить к нему доступ на своём новом сайте Eleventy по адресу

Создание индексных страниц

Чтобы упростить навигацию, можно создать аналогичную страницу с разбивкой на страницы content/index.njk. Это отображает пять элементов на странице со ссылками на «новые» и «старые» публикации:

---
title: WordPress articles
pagination:
  data: posts
  alias: pagedlist
  size: 5
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ post.title }}</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<style>
  body { font-size: 100%; font-family: sans-serif; }
  ul, li {
    margin: 0;
    padding: 0;
  }
  ul {
    list-style-type: none;
    display: flex;
    flex-wrap: wrap;
    gap: 2em;
  }
  li {
    flex: 1 1 15em;
  }
  li.next {
    text-align: right;
  }
  a {
    text-decoration: none;
  }
  a h2 {
    text-decoration: underline;
  }
</style>
</head>
<body>

<h1>
  {% if title %}{{ title }}{% else %}{{ list }} list{% endif %}
  {% if pagination.pages.length > 1 %}, page {{ pagination.pageNumber + 1 }} of {{ pagination.pages.length }}{% endif %}
</h1>

<ul class="posts">
  {%- for post in pagedlist -%}
    <li>
      <a href="/{{ post.slug }}/">
        <h2>{{ post.title }}</h2>
        <p><time datetime="{{ post.dateYMD }}">{{ post.dateFriendly }}</time></p>
        <p>{{ post.excerpt | safe }}
      </a>
    </li>
  {%- endfor -%}
</ul>

<hr>

{% if pagination.href.previous or pagination.href.next %}
<ul class="pages">
  {% if pagination.href.previous %}
    <li><a href="{{ pagination.href.previous }}">&laquo; newer posts</a></li>
  {% endif %}

  {% if pagination.href.next %}
    <li class="next"><a href="{{ pagination.href.next }}">older posts &raquo;</a></li>
  {% endif %}
</ul>
{% endif %}

</body>
</html>

Выполненный npx eleventy —serveвами выше должен оставаться активным, но при необходимости запустите его снова. В index.htmlкаталоге создаётся файл build, который ссылается на первые пять сообщений. Дополнительные страницы содержатся в build/1/index.htmlи build/2/index.html т.д.

Перейдите по адресу http: // localhost: 8080 /, чтобы просмотреть индекс:

Создание индексных страниц

Пресса Ctrl| Cmd+ Cдля выхода с сервера Eleventy. Выполните npx eleventyсамостоятельно, чтобы создать полный сайт, готовый к развертыванию.

Решения о развёртывании

В результате ваш сайт Eleventy содержит статический HTML и ресурсы. Его можно разместить на любом веб-сервере без серверных сред выполнения, баз данных или других зависимостей.

Вашему сайту WordPress требуются PHP и MySQL, но он может быть размещён где угодно для редакторов контента. Сервер в сети частной компании является наиболее безопасным вариантом. Но вам может потребоваться общедоступный веб-сервер для удалённых сотрудников. Любой из них можно защитить с помощью ограничений IP-адреса, дополнительной аутентификации и т.д.

Ваши сайты Eleventy и WordPress могут размещаться на разных серверах, возможно, доступ к ним осуществляется из разных поддоменов, таких как www.mysite.comи editor.mysite.com соответственно. Ни один из них не будет конфликтовать с другим, и будет легче управлять всплесками трафика.

Однако вы можете предпочесть оставить оба сайта на одном сервере, если:

  • у вас есть статические страницы (услуги, информация, контакты и т. д.) и некоторые страницы WordPress (магазин, форумы и т. д.), или
  • статический сайт получает доступ к данным WordPress, таким как загруженные изображения или другие API REST.

PHP инициирует рендеринг WordPress только в том случае, если URL-адрес не может быть разрешён другим способом. Например, предположим, что у вас есть сообщение WordPress с постоянной ссылкой /post/my-article. Он будет обслуживаться при доступе пользователя, mysite.com/post/my-article если только статический файл с именем /post/my-article/index.htmlне был сгенерирован Eleventy в корневом каталоге сервера.

К сожалению, редакторы контента не смогут просматривать статьи из WordPress, поэтому вы можете рассмотреть возможность условной перезаписи URL. Эта.htaccessконфигурация Apache загружает все /post/URL-адреса из соответствующего /static/каталога, за исключением случаев, когда IP-адрес пользователя 1.2.3.4:

RewriteEngine OnRewriteCond %{REMOTE_HOST} !^1.2.3.4RewriteRule «^/post/(.*)» «/static/post/$1/index.html» [R]

Для более сложных сайтов вы можете использовать Eleventy для рендеринга файлов конфигурации сервера на основе созданных вами страниц.

Наконец, вы можете захотеть представить процесс, который автоматически запускает процесс сборки и развёртывания Eleventy. Вы могли бы рассмотреть:

  1. Сборка каждые N часов независимо от изменений.
  2. Предоставьте большую кнопку «РАЗВЕРТИТЬ» для редакторов контента. Это может быть интегрировано в панели администрирования WordPress.
  3. Используйте WordPress REST API, чтобы часто проверять modifiedдату самой последней публикации. Перестройку можно начать, когда она позже даты последней сборки.

Более простые статические сайты

Этот пример иллюстрирует основы использования WordPress в качестве автономной CMS для создания статических сайтов. Это обнадёживает просто, хотя для более сложного содержимого потребуется более сложный код.

Предложения по дальнейшему улучшению:

  • Попробуйте импортировать сообщения с существующего сайта WordPress, который использует сторонние темы и плагины.
  • Измените возвращённый HTML, чтобы удалить или адаптировать виджеты WordPress.
  • Импортируйте дополнительные данные, такие как страницы, категории и теги ( комментарии также возможны, хотя и менее полезны).
  • Извлеките изображения или другие носители в локальную файловую систему.
  • Подумайте, как вы можете кэшировать записи WordPress в локальном файле для более быстрой визуализации. Можно проверить _fields=modifiedдату, чтобы убедиться, что новые и обновлённые сообщения импортируются.

WordPress вряд ли будет лучшим вариантом для управления статическим контентом сайта. Однако, если вы уже используете WordPress и думаете о переходе на генератор статических сайтов, его REST API предоставляет возможный путь миграции без полного отказа от CMS. от CMS.

 

Оцените статью
bestprogrammer.ru
Добавить комментарий