WordPress REST API возвращает максимум 100 постов за один запрос. Попытка получить все публикации сразу через параметр per_page=-1 либо не сработает, либо создаст критическую нагрузку на сервер. API работает через пагинацию: запрашиваете страницу за страницей, пока данные не закончатся. Игнорирование этого механизма приводит к неполной выборке — получите первые 10–100 записей и упустите остальное.
- WordPress REST API ограничивает выборку максимум 100 постами за один запрос — параметр per_page=-1 не работает и приводит к неполной выборке данных
- Для получения всех постов необходимо использовать пагинацию: запрашивать страницы по очереди (page=1, 2, 3…) и контролировать заголовки X-WP-Total и X-WP-TotalPages для расчета количества итераций
- Оптимизация запросов достигается параметром _fields (сокращает размер ответа в 10–15 раз), фильтрацией по категориям/авторам/датам и кешированием результатов через Transients API или плагины кеша
- Для продакшена рекомендуется создавать кастомные эндпоинты через register_rest_route(), настраивать CORS-заголовки и использовать аутентификацию через Application Passwords или JWT для доступа к приватным данным
В статье разберем, как правильно собрать все посты через endpoint /wp-json/wp/v2/posts: настроим параметры per_page и page, напишем циклы на JavaScript и PHP, проверим заголовки X-WP-Total и X-WP-TotalPages. Покажем, как оптимизировать запросы через параметр _fields, фильтровать по категориям и авторам, кешировать результаты и создавать кастомные эндпоинты для боевого сервера.

WordPress REST API: как это работает и где кроются подвохи
WordPress REST API открывает доступ к контенту сайта через HTTP-запросы: вы обращаетесь к специальному URL вида /wp-json/wp/v2/posts и получаете JSON с данными постов, страниц, категорий, пользователей. Система построена на архитектуре REST — каждая сущность живет по своему маршруту, поддерживает методы GET (чтение), POST (создание), PUT/PATCH (обновление), DELETE (удаление). Базовый endpoint /wp-json/wp/v2/posts возвращает список публикаций, но по умолчанию отдает только 10 записей за раз. Главный подвох: API жестко ограничивает размер страницы параметром per_page — максимум 100 постов за один запрос, и обойти этот лимит напрямую нельзя.
Основы REST API: маршруты и эндпоинты
Маршрут /wp-json/wp/v2/posts — основной endpoint для работы с публикациями. Он принимает GET-запросы и возвращает массив объектов постов в формате JSON. Каждый объект содержит поля: id, title, content, excerpt, date, author, categories, featured_media и другие. Полный список маршрутов доступен по адресу /wp-json — там увидите /wp/v2/pages, /wp/v2/categories, /wp/v2/users.
Протокол REST строг к архитектуре. Попытка вытянуть весь массив данных из базового эндпоинта за один вызов — это прямое нарушение стандартов, которое неизбежно приведет к отказу базы данных.
Эндпоинты поддерживают параметры фильтрации: per_page (количество постов на странице, от 1 до 100), page (номер страницы), categories (ID категории), author (ID автора), search (текстовый поиск), orderby и order (сортировка). Параметры передаются в строке запроса: /wp-json/wp/v2/posts?per_page=50&page=2&categories=5. Без параметров API вернет первые 10 постов в порядке убывания даты публикации.
Почему нельзя получить все посты одним запросом
Ограничение per_page=100 зашито в ядро WordPress (файл wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php). Попытка указать per_page=-1 или per_page=99999 игнорируется или обрезается до 100. Это защита от перегрузки: если на сайте 10 000 постов, запрос всех записей сразу заставит PHP собрать гигантский массив данных, выполнить десятки JOIN-запросов к базе, сформировать JSON объемом несколько мегабайт и отдать его клиенту за 5–30 секунд, что убьет сервер при параллельных запросах.
В старых версиях WordPress (до 4.7) параметр per_page=-1 работал для внутренних WP_Query, но в REST API это никогда не было допустимо. Единственный корректный способ — запрашивать данные страницами: сначала page=1, затем page=2, page=3 и так до конца. Количество страниц сообщает заголовок X-WP-TotalPages в HTTP-ответе, общее число постов — X-WP-Total. Игнорирование пагинации даст неполную выборку: получите только первые 10 или 100 записей.

Как устроены запросы: HTTP-методы, структура ответа и заголовки пагинации
GET-запрос к /wp-json/wp/v2/posts?per_page=100 возвращает массив JSON-объектов в теле ответа и служебные заголовки в HTTP-headers: X-WP-Total (общее количество постов, например 457), X-WP-TotalPages (количество страниц, например 5 при per_page=100), Link (ссылки на первую, следующую, предыдущую и последнюю страницы в формате RFC 5988). Заголовки критичны для автоматического обхода: парсите X-WP-TotalPages, чтобы знать, сколько итераций нужно выполнить.
Структура ответа: массив объектов, каждый содержит id (число), date (строка ISO 8601), title.rendered (HTML заголовка), content.rendered (HTML контента), excerpt.rendered (анонс), author (ID автора), categories (массив ID категорий), featured_media (ID изображения). Для сокращения объема данных используйте параметр _fields: /wp-json/wp/v2/posts?_fields=id,title,date — API вернет только указанные поля, что уменьшит размер ответа в 5–10 раз и ускорит обработку.
| Заголовок / Параметр | Тип данных | Описание и применение |
|---|---|---|
| X-WP-Total | Integer | Общее количество записей в базе данных, соответствующих вашему запросу. |
| X-WP-TotalPages | Integer | Количество страниц для пагинации (зависит от переданного лимита per_page). |
| _fields | String (через запятую) | Жестко ограничивает JSON-ответ, возвращая только запрошенные ключи объекта. |
🚀 Тексты, которые нравятся поисковикам
ТЗМонстр — умный нейропомощник для SEO и блогов. Автоматически собирает LSI-фразы, генерирует детальное ТЗ и пишет экспертные статьи лучше обычного ChatGPT. От 15₽ за готовый план работы.
Собираем все посты: Практическое руководство по работе с пагинацией
WordPress REST API делит публикации на страницы по 10 постов (по умолчанию) или по заданному значению per_page (максимум 100). Чтобы собрать полный список, запустите цикл: сделайте запрос к странице 1, затем к странице 2, 3 и так далее, пока API не вернет пустой массив или количество элементов станет меньше per_page. Заголовки ответа X-WP-Total и X-WP-TotalPages сообщают общее число постов и страниц — используйте их, чтобы заранее рассчитать количество итераций. Без такого подхода получите неполные данные: API отдаст лишь первую порцию, остальные записи останутся за кадром.
Эндпоинт /wp/v2/posts: начинаем работать с публикациями
Базовый URL для получения постов: https://example.com/wp-json/wp/v2/posts. По умолчанию возвращает 10 последних публикаций со статусом publish, отсортированных по дате в обратном порядке. В ответе приходит массив объектов: каждый содержит id, date, title, content, excerpt, author, categories, tags и ссылки на вложенные ресурсы.

Параметры в строке запроса управляют выборкой: per_page задает количество постов на странице (1–100), page — номер страницы, _embed подгружает связанные данные (автора, изображения, категории) одним запросом, _fields ограничивает список полей и уменьшает размер ответа. Комбинируйте эти параметры, чтобы получить нужный срез данных без лишнего трафика.
Пагинация в деле: используем per_page (до 100) и page для полной выборки
Установите per_page=100, чтобы за один запрос получить максимальное количество постов. Первый запрос отправьте с параметром page=1, затем увеличивайте page до тех пор, пока массив в ответе не станет пустым. Заголовок X-WP-TotalPages покажет точное число страниц: например, при 350 постах понадобится 4 запроса (100+100+100+50).
Проверяйте длину массива: когда она упадет ниже 100 или станет равна нулю, цикл останавливается. Не полагайтесь на фиксированное число итераций — контент на сайте меняется, и жесткий лимит приведет к пропуску новых постов. Храните все собранные объекты в общем массиве, который станет финальным списком публикаций.
Итерации парсинга не должны быть жестко запрограммированы. Специалисты TzMonster отмечают, что контент динамичен, и надежный подход — прерывать цикл динамически, когда длина массива становится меньше лимита, а не полагаться на фиксированный счетчик.
Примеры кода: создаем циклический запрос на JavaScript и PHP
На JavaScript используйте async/await и цикл while: инициализируйте page=1, внутри цикла делайте fetch к /wp-json/wp/v2/posts?per_page=100&page=${page}, добавляйте результат в общий массив и увеличивайте page. Цикл прерывается, когда response.json() возвращает пустой массив. Заголовки X-WP-Total и X-WP-TotalPages извлекайте через response.headers.get() — это позволит вывести прогресс загрузки.
На PHP применяйте wp_remote_get в цикле: $page = 1; do { $response = wp_remote_get(«https://example.com/wp-json/wp/v2/posts?per_page=100&page=$page»); $posts = json_decode(wp_remote_retrieve_body($response)); $all_posts = array_merge($all_posts, $posts); $page++; } while(count($posts) === 100);. Такой код продолжает запросы, пока массив содержит ровно 100 элементов, затем останавливается.

Оптимизация и частые ошибки: Эффективная работа с данными
REST API возвращает посты со всеми полями: заголовок, содержимое, метаданные, автор, таксономии. Это создает избыточную нагрузку при больших выборках. Одна страница из 100 постов с полным контентом весит несколько мегабайт и грузится секундами. WordPress предлагает параметры для оптимизации: _fields ограничивает выборку нужными полями, _embed добавляет связанные данные без дополнительных запросов, фильтры по категориям и датам сокращают объем результатов.
Контроль над контентом: Параметры _fields для выбора и _embed для встраивания
Параметр _fields уменьшает размер ответа, указывая API вернуть только перечисленные поля. Запрос /wp-json/wp/v2/posts?per_page=100&_fields=id,title,date вернет только ID, заголовок и дату публикации — размер ответа уменьшится в 10–15 раз. Это критично для мобильных приложений и SPA, где лишний трафик замедляет загрузку. Поля задаются через запятую: _fields=id,slug,link,excerpt.rendered. Полное содержимое (content.rendered) весит больше всего — исключайте его, если нужен только список.
Параметр _embed добавляет в ответ связанные объекты: избранные изображения, категории, авторов. Без него для получения картинки поста нужен отдельный запрос к /wp-json/wp/v2/media/{id}. Запрос /wp-json/wp/v2/posts?_embed&per_page=100 вернет посты с блоком _embedded, где находятся wp:featuredmedia (изображение), wp:term (категории и теги), author (данные автора). Это экономит HTTP-запросы, но увеличивает размер ответа — используйте _embed только когда нужны связанные данные сразу.

Типичные ошибки: Игнорирование пагинации, per_page=-1 и их последствия
Частая ошибка — запрос всех постов через per_page=-1 или per_page=9999. В старых версиях WordPress (до 4.7) per_page=-1 работал и возвращал весь список, но создавал огромную нагрузку на базу данных и мог вызвать таймаут сервера. С версии 4.7 API игнорирует значения больше 100 и возвращает максимум 100 записей. Если на сайте 500 постов, запрос с per_page=-1 вернет только первые 100, и остальные 400 останутся незамеченными. Проверить это можно по заголовку X-WP-Total в ответе.
Вторая ошибка — игнорирование заголовков пагинации. Разработчики делают один запрос, получают 100 постов и считают это полной выборкой. На самом деле сервер возвращает X-WP-Total (общее количество постов) и X-WP-TotalPages (количество страниц) — их нужно считывать и организовывать цикл. Без этого выборка всегда будет неполной. Третья ошибка — игнорирование кеширования: каждый запрос к API вызывает запросы к базе данных. Если получаете все посты каждые несколько секунд, сервер упадет под нагрузкой. Используйте Transient API или плагины кеширования (WP Rocket, W3 Total Cache) для хранения результатов на 10–60 минут.
Отказ от кеширования — это гарантированный способ уронить сервер. Каждый запрос к REST API без сохраненного транзиента инициирует десятки SQL-вызовов, что при высокой посещаемости моментально исчерпает лимиты СУБД.
Управление доступом: Аутентификация и решение проблем с CORS
REST API возвращает только публичные данные: опубликованные посты, страницы, категории. Черновики, приватные записи и данные пользователей требуют аутентификации. Для доступа используйте Application Passwords (WordPress 5.6+): создайте пароль приложения в профиле пользователя и передавайте его в заголовке Authorization: Basic base64(username:app_password). Альтернатива — OAuth через плагины WP OAuth Server или JWT Authentication for WP REST API. JWT выдает токен после авторизации, который затем передается в заголовке Authorization: Bearer token.
При запросах с внешних доменов (например, из React-приложения на другом хосте) браузер блокирует ответ из-за политики CORS. WordPress не настраивает CORS по умолчанию — API возвращает данные, но браузер их отбрасывает с ошибкой ‘No Access-Control-Allow-Origin header’. Решение: добавьте в functions.php хук для отправки заголовков CORS. Код: add_action(‘rest_api_init’, function() { remove_filter(‘rest_pre_serve_request’, ‘rest_send_cors_headers’); add_filter(‘rest_pre_serve_request’, function($value) { header(‘Access-Control-Allow-Origin: *’); header(‘Access-Control-Allow-Methods: GET’); return $value; }); });. Для продакшена замените * на домен фронтенда и настройте методы.

Продвинутые сценарии и кеширование: Производительность в продакшене
Множественные запросы к REST API на проектах с тысячами постов создают задержки 2–5 секунд на странице — пользователи уходят, сервер перегружается. Стандартные endpoint’ы не оптимизированы для массовых выборок: отдают избыточные метаданные, выполняют SQL-запросы на каждый вызов и не используют кеш по умолчанию. Решение — фильтрация, кеширование и кастомные эндпоинты. REST API предоставляет параметры для сужения выборки по категориям, авторам, датам и статусам публикаций — сокращаете объем передаваемых данных в 3–10 раз. Кеш на уровне сервера или Transients API снижает нагрузку на базу данных до нуля при повторных обращениях.
Расширенные запросы: Фильтрация по категориям, тегам, авторам и датам
API принимает GET-параметры для точечных выборок: categories — массив ID категорий, tags — ID тегов, author — ID автора, before/after — ISO 8601 даты. Запрос /wp-json/wp/v2/posts?categories=5&per_page=100 вернет только посты категории 5. Параметр author=3 фильтрует по конкретному автору. Дата задается через after=2024-01-01T00:00:00 для публикаций новее указанной точки. Все параметры комбинируются: categories=5,8&author=3&per_page=50 — посты категорий 5 или 8 от автора 3.
Параметр _fields сокращает размер ответа: _fields=id,title,link вернет только указанные поля вместо полного объекта. Для постов без контента используйте _fields=id,title,date,author — экономите до 80% трафика. Статус публикации контролирует status=publish (только опубликованные) или status=draft,pending для черновиков. Параметр orderby=dateℴ=desc сортирует по дате. Связка _fields + categories + per_page=100 создает оптимальный запрос для списков.
Грамотное использование фильтров способно сократить объем передаваемого трафика на 80%. Вы не просто ускоряете отдачу контента, но и экономите драгоценные ресурсы на десериализации JSON на стороне клиента.
Кеширование данных API: Стратегии для повышения производительности
WordPress Transients API хранит результаты запросов в базе данных: set_transient(‘all_posts’, $data, 3600) сохраняет на 1 час, get_transient(‘all_posts’) извлекает. При следующем обращении проверяете наличие кеша — если есть, отдаете без запроса к API. Transient автоматически удаляется по истечении времени или при обновлении контента через хук save_post. Для внешних приложений применяйте localStorage в браузере или Redis/Memcached на сервере — храните ответ с меткой времени, обновляйте раз в N минут.
Плагины WP REST Cache и REST API Cache автоматизируют кеширование: устанавливаете TTL 300–3600 секунд, плагин перехватывает запросы и отдает сохраненные данные. Настройка инвалидации по событию: при публикации нового поста кеш очищается, API возвращает актуальную выборку. Для тяжелых проектов используйте CDN с кешированием JSON-ответов — Cloudflare или KeyCDN хранят результаты на edge-серверах, задержка падает до 50–100 мс. Связка Transients + CDN снижает нагрузку на WordPress на 90%.

Создаем свои эндпоинты: Расширяем функционал API
Кастомный эндпоинт обходит ограничения стандартного API и возвращает данные в нужном формате. Регистрируете через register_rest_route() в functions.php: создаете маршрут /wp-json/custom/v1/all-posts, привязываете callback-функцию. Внутри функции выполняете WP_Query с параметрами posts_per_page=-1 или большим числом, формируете массив нужных полей (ID, заголовок, ссылка), возвращаете через WP_REST_Response. Endpoint доступен по прямому URL без пагинации — одним запросом получаете весь список.
Пример: register_rest_route(‘custom/v1’, ‘/all-posts’, array(‘methods’=>’GET’, ‘callback’=>’get_all_posts_callback’)). В функции get_all_posts_callback() пишете $query = new WP_Query(array(‘posts_per_page’=>-1, ‘fields’=>’ids’)), извлекаете ID, дополняете данными через get_post(). Добавляете проверку прав через permission_callback для защиты — ограничиваете доступ авторизованными пользователями. Кастомные эндпоинты подходят для внутренних инструментов, мобильных приложений или интеграций с внешними сервисами, где нужна полная выборка без циклов.

Тимур (Команда TzMonster) — Эксперт по контент-маркетингу и SEO.