Headless WordPress: интеграция WP REST API с React и Next.js

Headless WordPress: интеграция WP REST API с React и Next.js

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Headless WordPress: интеграция WP REST API с React и Next.js
Средний
~3-5 дней

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1414
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1285
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    982
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1241
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    982
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    994

Headless WordPress: интеграция WP REST API с React и Next.js

Типичная проблема: бизнесу нужен управляемый контент в WordPress, но готовые темы не обеспечивают нужную производительность или кастомизацию. Решение — headless CMS, где WordPress остаётся бэкендом, а фронтенд строится на React, Vue, Next.js или Svelte. Это избавляет от монолитных тем, ускоряет загрузку страниц (LCP снижается на 30–50%) и упрощает поддержку. За 5+ лет мы реализовали более 50 таких проектов — от интернет-магазинов до корпоративных порталов. Бюджет интеграции сопоставим со стоимостью одного месяца работы фронтенд-разработчика, но окупается за счёт снижения затрат на хостинг и ускорения вывода новых страниц.

Какие задачи решает headless WordPress?

  • Отделение контента от представления: редакторы работают в знакомой админке WordPress, а разработчики используют современный стек (React, Next.js, Vue). Больше не нужно подгонять шаблоны под дизайн — API отдаёт чистые данные.
  • Повышение производительности: статические страницы (SSG) и ISR сокращают TTFB до 200 мс, а LCP — до 2 с. Экономия на серверных ресурсах достигает 40% за счёт кеширования.
  • Единое API для всех клиентов: один WordPress может обслуживать SPA, мобильное приложение и телеграм-бота — через REST или GraphQL.

Базовая интеграция: получение данных

WordPress REST API по умолчанию доступен по /wp-json/wp/v2/. Получение последних постов:

// lib/wordpress.ts const WP_API_URL = process.env.NEXT_PUBLIC_WP_URL + '/wp-json/wp/v2'; export interface WPPost { id: number; slug: string; title: { rendered: string }; content: { rendered: string }; excerpt: { rendered: string }; date: string; featured_media: number; _embedded?: { 'wp:featuredmedia'?: [{ source_url: string; alt_text: string }]; 'wp:term'?: Array<Array<{ id: number; name: string; slug: string }>>; }; } export async function getPosts(params: { perPage?: number; page?: number; category?: number; search?: string; } = {}): Promise<{ posts: WPPost[]; total: number; totalPages: number }> { const qs = new URLSearchParams({ per_page: String(params.perPage ?? 12), page: String(params.page ?? 1), _embed: 'wp:featuredmedia,wp:term', ...(params.category && { categories: String(params.category) }), ...(params.search && { search: params.search }), }); const res = await fetch(`${WP_API_URL}/posts?${qs}`, { next: { revalidate: 60 }, // ISR в Next.js 13+ }); if (!res.ok) throw new Error(`WP API error: ${res.status}`); return { posts: await res.json(), total: Number(res.headers.get('X-WP-Total')), totalPages: Number(res.headers.get('X-WP-TotalPages')), }; } export async function getPostBySlug(slug: string): Promise<WPPost | null> { const res = await fetch(`${WP_API_URL}/posts?slug=${slug}&_embed=wp:featuredmedia,wp:term`); const posts = await res.json(); return posts.length ? posts[0] : null; } 

Next.js App Router: динамические маршруты

// app/blog/[slug]/page.tsx import { getPostBySlug, getPosts } from '@/lib/wordpress'; import { notFound } from 'next/navigation'; export async function generateStaticParams() { const { posts } = await getPosts({ perPage: 100 }); return posts.map(post => ({ slug: post.slug })); } export async function generateMetadata({ params }: { params: { slug: string } }) { const post = await getPostBySlug(params.slug); if (!post) return {}; return { title: post.title.rendered, description: post.excerpt.rendered.replace(/<[^>]+>/g, '').slice(0, 160), }; } export default async function PostPage({ params }: { params: { slug: string } }) { const post = await getPostBySlug(params.slug); if (!post) notFound(); const media = post._embedded?.['wp:featuredmedia']?.[0]; return ( <article className="post-single"> {media && ( <img src={media.source_url} alt={media.alt_text} className="post-single__cover" /> )} <h1 dangerouslySetInnerHTML={{ __html: post.title.rendered }} /> <div className="post-content" dangerouslySetInnerHTML={{ __html: post.content.rendered }} /> </article> ); } 

dangerouslySetInnerHTML здесь допустим — контент от доверенного сервера, но если источник под вашим контролем, добавьте DOMPurify для безопасности.

Кастомный хук для React SPA

// hooks/usePosts.ts import useSWR from 'swr'; const fetcher = (url: string) => fetch(url).then(r => r.json()); export function usePosts(category?: string, page = 1) { const params = new URLSearchParams({ per_page: '12', page: String(page), _embed: '1' }); if (category) params.set('categories', category); const { data, error, isLoading } = useSWR<WPPost[]>( `/wp-json/wp/v2/posts?${params}`, fetcher, { revalidateOnFocus: false } ); return { posts: data ?? [], isLoading, error }; } 

Используйте этот хук с пагинацией и скелетонами. Пример компонента — в документации SWR.

Как настроить on-demand ISR для мгновенного обновления контента?

Next.js поддерживает перестройку страниц по триггеру. Когда пост публикуется в WordPress, PHP-код отправляет POST-запрос на эндпоинт /api/revalidate в Next.js:

// WordPress: save_post hook и CORS filter add_action('save_post', function (int $post_id, WP_Post $post): void { if ($post->post_status !== 'publish') return; $next_url = get_option('nextjs_revalidate_url'); $secret = get_option('nextjs_revalidate_secret'); if (!$next_url || !$secret) return; wp_remote_post("{$next_url}/api/revalidate", [ 'body' => json_encode([ 'secret' => $secret, 'path' => '/' . $post->post_type . '/' . $post->post_name, ]), 'headers' => ['Content-Type' => 'application/json'], 'blocking'=> false, ]); }, 10, 2); add_filter('rest_pre_serve_request', function ($value) { $origin = $_SERVER['HTTP_ORIGIN'] ?? ''; $allowed = ['https://mysite.com', 'https://www.mysite.com', 'http://localhost:3000']; if (in_array($origin, $allowed)) { header('Access-Control-Allow-Origin: ' . $origin); header('Access-Control-Allow-Credentials: true'); header('Access-Control-Allow-Methods: GET, POST, OPTIONS'); header('Access-Control-Allow-Headers: Authorization, Content-Type'); } return $value; }); 

А на стороне Next.js обрабатываем:

// Next.js: app/api/revalidate/route.ts import { revalidatePath } from 'next/cache'; export async function POST(req: Request) { const { secret, path } = await req.json(); if (secret !== process.env.REVALIDATE_SECRET) { return Response.json({ error: 'Invalid secret' }, { status: 401 }); } revalidatePath(path); return Response.json({ revalidated: true, path }); } 

Этот пайплайн обеспечивает обновление страниц за секунды без полной перестройки сайта. Экономия трафика — до 40% по сравнению с полной регенерацией.

Производительность: что кешировать

Данные Стратегия
Список постов ISR, revalidate: 60s
Одиночный пост ISR + on-demand revalidate при save_post
Меню навигации Static (revalidate: false)
Поисковые результаты SSR (без кеша, параметры меняются)
ACF-поля настроек сайта Static или revalidate: 3600s

Сравнение REST и GraphQL

Критерий REST GraphQL
Гибкость запросов Фиксированные поля Выбор только нужных данных
Количество запросов Часто несколько Один
Сложность настройки Минимальная Требуется плагин и схема
Производительность Высокая для простых страниц Лучше для сложных вложений

Как проходит интеграция headless WordPress

  1. Аудит — разбираем текущую архитектуру WordPress, плагины, объём контента, нагрузку.
  2. Проектирование — определяем необходимые endpoint’ы, поля, стратегию кеширования (ISR, SSG, SSR).
  3. Настройка API — расширяем REST или устанавливаем WPGraphQL, добавляем custom fields (ACF).
  4. Разработка фронтенда — создаём типизированный клиент (TypeScript), компоненты, маршрутизацию.
  5. Интеграция — подключаем CORS, on-demand revalidation, деплоим WordPress и фронтенд.
  6. Тестирование — проверяем производительность (Core Web Vitals), кросс-доменные запросы, обработку ошибок.
  7. Документация и передача — записываем видео-консультацию для команды, передаём репозиторий.

Сроки: базовая интеграция — от 5 до 7 рабочих дней, сложные сценарии (GraphQL, ACF, on-demand ISR) — до 15 дней. Точную оценку даём после аудита.

Детали настройки CORS

При разных доменах WordPress и фронтенда добавляем фильтр rest_pre_serve_request, который устанавливает заголовки для разрешённых источников. Это стандартная практика, описанная в документации REST API. Если нужна нестандартная конфигурация — мы подстроим под ваш проект.

Сколько стоит интеграция headless WordPress?

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

Хотите получить точную оценку? Закажите аудит вашего проекта — мы проанализируем архитектуру и предложим оптимальное решение. Свяжитесь с нами через форму на сайте или напишите в Telegram.