Статья A.S Groups

WordPress REST API: пагинация без пропущенных записей и лишней нагрузки

Пагинация WordPress REST API с page, per_page и X-WP-TotalPages

Навигация по статье

Услуги A.S Groups

Нужен сайт, магазин или автоматизация?

Помогаю бизнесу запускать и дорабатывать WordPress-проекты: от посадочной страницы до WooCommerce, CRM и Telegram-уведомлений.

Обсудить проект Telegram
WordPress под ключ Лендинги, корпоративные сайты и структура под заявки. WooCommerce Интернет-магазины, каталог, оплата, доставка и интеграции. Доработка сайта Правки, скорость, формы, баги и развитие текущего проекта. CRM / Telegram / AI Автоматизация заявок, уведомлений и ручных процессов.

Интеграция с WordPress REST API часто отлично работает на тестовом сайте и начинает терять данные после роста проекта. Причина простая: коллекции возвращаются страницами, а клиент ошибочно считает первый ответ полным списком.

Для импорта статей, товаров, категорий, пользователей или кастомных сущностей нужно корректно обходить pagination, учитывать лимит per_page, читать заголовки X-WP-Total/X-WP-TotalPages и не создавать лишнюю нагрузку запросами «до пустого ответа» без контроля.

Почему REST API не возвращает всё сразу

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

Поэтому запрос вида /wp-json/wp/v2/posts — это первая страница, а не «все записи сайта».

Основные параметры pagination

  • page — номер страницы;
  • per_page — количество элементов на странице, максимум 100;
  • offset — смещение относительно начала выборки.
GET /wp-json/wp/v2/posts?per_page=100&page=1

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

X-WP-Total и X-WP-TotalPages

WordPress возвращает два ключевых HTTP-заголовка: X-WP-Total содержит общее количество элементов, а X-WP-TotalPages — количество страниц при текущих параметрах запроса.

Правильный клиент делает первую страницу, читает X-WP-TotalPages, затем запрашивает страницы от 2 до указанного значения. Не нужно заранее угадывать число записей.

Пример на JavaScript

async function fetchAllPosts(baseUrl) {
  const all = [];
  const perPage = 100;

  const first = await fetch(`${baseUrl}/wp-json/wp/v2/posts?per_page=${perPage}&page=1`);
  if (!first.ok) throw new Error(`HTTP ${first.status}`);

  all.push(...await first.json());
  const totalPages = Number(first.headers.get('X-WP-TotalPages') || 1);

  for (let page = 2; page <= totalPages; page++) {
    const response = await fetch(`${baseUrl}/wp-json/wp/v2/posts?per_page=${perPage}&page=${page}`);
    if (!response.ok) throw new Error(`Page ${page}: HTTP ${response.status}`);
    all.push(...await response.json());
  }

  return all;
}

Для production-кода добавьте timeout, retry только для временных ошибок и журнал последней успешно обработанной страницы.

Не запрашивайте поля, которые не используете

Глобальный параметр _fields позволяет ограничить набор возвращаемых полей. Если интеграции нужны только ID, slug, modified и title, нет смысла передавать полный content, links и лишние метаданные.

GET /wp-json/wp/v2/posts?per_page=100&page=1&_fields=id,slug,modified,title

Это уменьшает размер JSON, время сериализации и сетевой трафик. Особенно заметно на больших текстах и кастомных REST-полях.

Почему параллельно запрашивать сотни страниц опасно

После получения X-WP-TotalPages легко запустить все страницы одновременно через Promise.all. На большом сайте это может создать всплеск PHP workers и SQL-запросов.

Для интеграции обычно лучше ограниченная concurrency: например, несколько запросов одновременно, а не десятки. Точное число зависит от VPS, endpoint и сложности запросов.

Стабильная сортировка важна

Если во время выгрузки редакторы публикуют новые материалы, выборка может сдвинуться. При сортировке по дате новый объект попадает в начало, а элементы на границе страниц меняют позиции. Результатом могут стать дубль одной записи и пропуск другой.

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

Pagination и изменяющиеся данные

Номер страницы — транспортный механизм, а не курсор состояния бизнеса. Если выгрузка занимает долгое время, данные между page 1 и page 20 могут измениться.

Надёжная интеграция хранит собственную контрольную точку: например, последнее подтверждённое modified_gmt и ID. Следующий запуск запрашивает только изменённые записи с небольшим overlap и дедупликацией по ID.

Не используйте page как idempotency key

Страница 3 сегодня и страница 3 завтра — разные наборы объектов. В CRM, индексе поиска или локальной базе сущность нужно связывать по WordPress ID либо по другому стабильному бизнес-идентификатору.

Тогда повторный импорт страницы обновит существующую запись, а не создаст дубль.

Что делать с HTTP 400 на последней странице

Если клиент запрашивает номер страницы больше доступного, WordPress может вернуть ошибку вроде invalid page number. Поэтому лучше ориентироваться на X-WP-TotalPages, а не бесконечно увеличивать page до первого сбоя.

Если общее количество страниц изменилось во время синхронизации, завершите текущий проход по понятному snapshot-плану и затем сделайте reconciliation изменённых сущностей.

Retry только для временных ошибок

HTTP 429, 502, 503 или сетевой timeout часто допускают повтор с backoff. Ошибка 400 из-за неверного параметра не исправится после десяти повторов. 401/403 требует проверки авторизации и прав.

Для защищённых endpoint способ авторизации нужно проектировать отдельно. Для WordPress Application Passwords есть отдельная инструкция.

CORS не связан с pagination

Если запрос работает через curl, но блокируется в браузере, увеличение per_page не поможет. Это другая проблема — политика origin и разрешённых заголовков. Её я разбирал в статье про CORS WordPress REST API.

Как синхронизировать категории и теги

Taxonomy endpoints также являются коллекциями. Если категорий или тегов больше одной страницы, нужно читать те же pagination headers и обходить все страницы. Нельзя считать первые 10 или 100 терминов полным справочником.

При импорте сохраняйте numeric ID и slug, но учитывайте, что ID относятся к конкретному WordPress-сайту. ID категории 15 на staging не обязан означать ту же категорию на production.

Пагинация WooCommerce и WordPress

WooCommerce REST API построен поверх WordPress REST API и многие collection endpoints используют аналогичную модель страниц. Но параметры конкретного ресурса всегда нужно сверять с его актуальной схемой, а не автоматически переносить все фильтры от wp/v2/posts.

Практическая схема большого импорта

  1. Сделать первый запрос с нужными фильтрами, сортировкой и _fields.
  2. Прочитать X-WP-Total и X-WP-TotalPages.
  3. Последовательно или с ограниченной concurrency пройти страницы.
  4. Дедуплицировать объекты по ID.
  5. Фиксировать прогресс после успешно сохранённой страницы.
  6. Повторять только временные ошибки с backoff.
  7. После полного прохода выполнить reconciliation изменившихся объектов.
  8. Для следующих запусков перейти на инкрементальную синхронизацию.

Типовые ошибки

  • обработать только первую страницу;
  • поставить per_page=1000 и ожидать, что WordPress примет значение;
  • не читать response headers;
  • запускать все страницы одновременно без ограничения;
  • качать полный content, когда нужны три поля;
  • считать page стабильным идентификатором;
  • не учитывать изменения коллекции во время долгой выгрузки;
  • повторять любую 4xx ошибку бесконечно.

Когда нужна кастомная интеграция

Если нужно синхронизировать тысячи записей с CRM, поисковым индексом, мобильным приложением или внешним каталогом, простой цикл по страницам — только начало. Нужны checkpoint, idempotency, ограничение нагрузки, безопасная авторизация и повторяемая обработка ошибок.

В A.S Groups можно заказать API/CRM-интеграцию или доработку WordPress REST endpoint под конкретную структуру данных. Для оценки пришлите тип сущностей, пример ответа API и объём записей без секретных ключей. Связь — через контакты.

Официальные источники

Следующий шаг

Нужно решить похожую задачу?

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

Обсудить задачу

Источники

Обсуждение

Вопросы и комментарии

Можно уточнить детали статьи или поделиться своим опытом. Первый комментарий проходит проверку.

Оставить комментарий

Email не публикуется. Ссылки и HTML в тексте удаляются.

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

Используем необходимые cookies, аналитику и данные форм, чтобы сайт работал корректно и заявки доходили.