Пятнадцать лет назад выбор системы управления контентом был выбором одной программы: движок хранил статьи в базе, сам рисовал страницы по шаблонам и сам же показывал редактору административную панель. Сегодня контент живёт не только на сайте: его читают приложения, письма, виджеты и голосовые интерфейсы, а витрина требует собственного фреймворка и собственной скорости. Ответом на разрыв стал composable подход: хранение контента, логика доставки и внешний вид собираются из независимых частей и общаются через API. Разберём, как WordPress совмещает монолит с открытым интерфейсом, что дают headless системы Strapi и Sanity, чем команда платит за свободу сборки и когда монолит остаётся разумным выбором.

Монолит WordPress с собственной темой и REST API в ядре движка

WordPress появился в 2003 году как движок личного блога на PHP и MySQL и вырос в самую распространённую систему управления контентом: к октябрю 2026 года на нём работает 39.6% всех сайтов мира, а среди сайтов, где система распознаётся, его доля достигает 58.3%. Цифры объясняются простотой входа: хостинг, пять минут установки, тема из каталога и готовый сайт.

Архитектура при этом остаётся классическим монолитом. Страницу рендерит PHP прямо на сервере, записи и страницы лежат в одной таблице wp_posts, произвольные поля - в wp_postmeta, темы состоят из шаблонов и хуков, плагины встраиваются в те же хуки. Всё живёт в одном коде, работает с одной базой и в одном процессе, поэтому расширить можно почти всё, но почти всё связано со всем.

Поворотным стал REST API. Инфраструктура вошла в ядро в версии 4.4, а в декабре 2016 года вышла версия 4.7 с релизным именем Vaughan и контентными эндпоинтами: записи, комментарии, термины таксономий, пользователи, метаданные и настройки стали доступны по отдельным адресам. Движок, построенный вокруг собственного рендера, впервые официально начал отдавать контент наружу в JSON.

Запрос к списку записей с выбором конкретных полей:

GET /wp-json/wp/v2/posts?per_page=5&_fields=id,title,date,link

Ответ приходит в JSON, и витриной может стать что угодно: от мобильного приложения до статического генератора. Плагин WPGraphQL добавляет поверх ядра GraphQL-схему, и WordPress превращается в полноценное headless хранилище с готовой админкой: контент без обязательного рендера, сайт без сайта.

GraphQL-запрос собирает заголовки записей одной рубрики вместе с именами авторов за единственный проход:

{
  posts(first: 5, where: { categoryName: "release" }) {
    nodes {
      title
      date
      author { node { name } }
    }
  }
}

REST экономен и понятен с первого взгляда, GraphQL сокращает число обращений и даёт витрине ровно те поля, что нужны экрану. Внутри монолита оба протокола читают одну и ту же базу, поэтому выбор между ними ничего не меняет в хранении.

В конце 2018 года ядро получило блочный редактор, и статья перестала быть сплошным текстом: контент собирается из блоков. Хранилище при этом осталось прежним, весь набор блоков лежит одним полем в таблице записей, размеченным тегами HTML и комментариями-разделителями. Структура существует внутри редактора, но на уровне базы не читается, и это половинчатый шаг, который наглядно объясняет, почему развитие пошло в сторону отдельных хранилищ.

Headless подход и Strapi с открытым кодом на Node.js

Strapi представляет другой полюс: это open-source headless CMS, у которой витрины не было изначально. Система написана на Node.js, ставится одной командой и разворачивает панель управления с базой данных:

npx create-strapi-app@latest my-project

Модель контента описывается схемой в json-файле, и панель строится из неё автоматически: поля превращаются в форму редактора, роли и права - в настройки доступа.

{
  "kind": "collectionType",
  "displayName": "Article",
  "attributes": {
    "title": { "type": "string", "required": true },
    "slug": { "type": "uid", "targetField": "title" },
    "body": { "type": "richtext" },
    "cover": { "type": "media", "allowedTypes": ["images"] }
  }
}

Сохранение схемы открывает готовые REST и GraphQL эндпоинты, код для них вручную не пишется. Запрос с фильтром и подтягиванием связанного медиа:

GET /api/articles?filters[slug][$eq]=hello-world&populate=cover

Проект живёт активной веткой пятой мажорной версии: за октябрь 2026 года вышли релизы от v5.57.0 до v5.59.0, последний датируется 21 октября. Еженедельный ритм исправлений означает, что экосистема не заморожена и ошибки не висят в списках задач годами.

Структурированный контент Sanity и язык запросов GROQ

Sanity смотрит на контент ещё жёстче: не как на страницы, а как на документы в Content Lake, real-time базе структурированного контента. Редакторы работают в Sanity Studio, настраиваемом интерфейсе, который собирается как приложение на React и меняется вместе с задачами редакции, а разработчики запрашивают данные собственным языком GROQ.

Схема документа описывает сразу и форму редактора, и структуру ответов:

{
  name: "article",
  title: "Статья",
  type: "document",
  fields: [
    { name: "title", type: "string" },
    { name: "slug", type: "slug" },
    { name: "body", type: "array", of: [{ type: "block" }] },
    { name: "author", type: "reference", to: [{ type: "author" }] }
  ]
}

Поле reference создаёт связь между документами, которую GROQ потом проходит стрелкой, массив с типом block подключает Portable Text, а строковое поле превращается в простое поле ввода Studio. Одна схема обслуживает и редактора, и разработчика, и это прямое следствие принципа "контент как данные": форма описания не хранится отдельно от смысла.

Расшифровка звучит как Graph-Relational Object Queries, и формулировка создателей передаёт идею: описать ровно ту информацию, которая нужна приложению, при необходимости соединяя несколько наборов документов и собирая ответ из конкретных полей. Типичный запрос:

*[_type == "article" && defined(publishedAt)] | order(publishedAt desc) {
  title,
  "slug": slug.current,
  "authorName": author->name
}[0...9]

В одной строке собраны фильтр по типу документа и наличию даты публикации, сортировка по убыванию, проекция трёх полей, один из которых - переименованный текущий слаг, а другой - имя из связанного документа автора через стрелку author->name. В SQL то же самое потребовало бы JOIN и псевдонимов таблиц.

Текст в Sanity хранится блоками Portable Text, где абзац и заголовок различаются полем style, а выделение задаётся массивом marks, а не тегами HTML:

{
  "_type": "block",
  "style": "h2",
  "children": [
    { "_type": "span", "text": "Заголовок раздела", "marks": [] }
  ],
  "markDefs": []
}

Такой текст - данные, а не разметка: приложение отрисует блок ссылкой, сайт - тегом h2, письмо - собственными стилями, и исходный документ при этом останется прежним.

Сборка витрины на Next.js и границы статической генерации

Когда хранилище перестало рендерить страницы, место витрины заняли фреймворки: Next.js для React, Nuxt для Vue, Astro для быстрой статики. Типовая сборка строится на статической генерации: страницы собираются заранее и раздаются с CDN, а свежий контент подтягивается по расписанию.

export async function getStaticProps() {
  const res = await fetch(`${process.env.CMS_URL}/api/articles`);
  const posts = await res.json();
  return { props: { posts }, revalidate: 60 };
}

Параметр revalidate со значением 60 разрешает пересобрать страницу не чаще раза в минуту: правки доходят быстро, а нагрузка на API ограничена. В свежих версиях Next.js в App Router тот же результат даёт кеширование fetch с полем next.revalidate, а публикацию ускоряет webhook из CMS, который дергает пересборку в момент нажатия кнопки.

Вызов пересборки принимает отдельный обработчик, который CMS дергает при публикации:

export default async function handler(req, res) {
  if (req.query.secret !== process.env.WEBHOOK_SECRET) {
    return res.status(401).end();
  }
  await res.revalidate('/articles');
  return res.status(200).end();
}

Обработчик сверяет секрет, просит каркас пересобрать конкретный адрес и молчит до следующей публикации. Дальше включается раздача: готовые страницы лежат на CDN-узлах рядом с читателем и отдаются за десятки миллисекунд, тогда как PHP-монолит отвечает от собственного сервера, и его скорость упирается в хостинг, кеш плагинов и базу. Статическая витрина выигрывает и на уровне архитектуры, и на уровне скорости первой отрисовки.

Граница подхода - предпросмотр. Редактору нужно видеть правку до публикации, значит витрина обязана показывать черновик по временной ссылке, а это отдельный маршрут с проверкой токена. Монолит даёт такую кнопку из коробки, composable стек собирает её руками.

Composable стек и принципы MACH для архитектуры контента

Методологию отрасли описывает аббревиатура MACH: Microservices, API-first, Cloud-native, Headless. Отраслевой альянс, основанный в 2020 году, закрепил её как общий язык описания современной сборки, и идея проста: каждая способность системы - отдельный сервис, обмен только через открытые интерфейсы, работа в облаке, хранилище контента без привязки к витрине.

Composable - ступень над headless: не одна CMS, а сборка независимых компонентов. Поиск, персонализация, коммерция, аналитика подключаются каждый своим API, и витрина становится тонким слоем сборки. Выгоды прикладные: релиз витрины не трогает хранилище, нагрузка сервисов масштабируется порознь, падение поиска не роняет статьи, а замена одного компонента не требует пересборки всего стека.

Пример прикладной сборки для медиа: редакция пишет в Sanity, витрина собирается на Next.js, полнотекстовый поиск работает отдельным сервисом со своими индексами, изображения отдаются через сервис трансформации, который режет один исходник под размеры экранов. Каждый слой заменяется отдельно, и выпуск витрины не требует доступа к хранилищу.

Цена свободы от монолита для команды и бюджета проекта

Свобода стоит денег, и счёт выставляется той же команде. В монолите новый тип контента - это плагин за вечер; в composable стеке - модель, интерфейс редактора, запрос, верстка, кеширование и миграция старых записей. Мелкая правка "добавить поле к событию" касается уже четырёх мест вместо одного.

Точек отказа становится больше: у каждой системы своя версия, свои токены, свои лимиты запросов, и деплои нужно синхронизировать. Безопасность тоже распадается: права, ключи API и списки CORS настраиваются в каждой части стека, а утечка одного ключа открывает ровно тот сервис, к которому он подходит.

Миграция тоже ложится на команду. Записи выгружаются из старой системы постранично через REST, поля приводятся к новой схеме, вложения переносятся в новое хранилище медиа, а редиректы со старых адресов прописываются вручную. Перенос честнее разбивать на этапы: новый раздел сначала запускается на composable витрине, старые страницы остаются на монолите, и система переезжает кусками без остановки работы сайта.

Монолит держится, когда сайт один, контент простой, дизайн собирается из готовой темы, а в штате нет разработчика. Сайт на WordPress поднимается за вечер, обновляется кнопкой и переживает смену подрядчиков. Composable окупается там, где каналов несколько, дизайн нестандартный, а релизы витрины идут каждую неделю.

Критерии выбора между монолитом и композицией на живых задачах

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

  1. сколько каналов одновременно потребляет один и тот же контент;
  2. есть ли в команде frontend разработчик на постоянной поддержке;
  3. нужен ли дизайн, который не собирается из готовой темы;
  4. как часто выходят правки и как быстро они должны появляться на витрине;
  5. какие требования предъявляются к нагрузке и скорости отрисовки страниц;
  6. кто отвечает за обновления и безопасность каждого компонента.

Один канал и простые материалы отвечают на первые два вопроса в пользу монолита, и спорить здесь не о чем. Несколько каналов, приложение вдобавок к сайту и нестандартный интерфейс склоняют выбор к композиции. Гибрид остаётся легитимным ответом: WordPress как админка и репозиторий при витрине на Next.js - проверенный путь, когда редакторам привычна одна панель, а продукту нужны скорость и свобода.

Эволюция не отменила монолит: 39.6% сайтов мира не дадут этого сделать. Она добавила выбор там, где раньше выбора не было: хранить контент там, где он не привязан к чужой теме, и менять витрины поколениями, не трогая само содержание. Композиция - не мода и не догма, а расчёт, который окупается ровно тогда, когда число витрин и скорость релизов переходят порог, за которым монолит начинает тормозить.