REST API
WordPress умеет отдавать содержимое не только страницами, но и данными в формате JSON. Через REST API работает сам редактор записей, а ещё мобильные приложения и сайты, где WordPress служит только хранилищем содержимого.
Встроенные адреса
Откройте в браузере адрес сайта с /wp-json/wp/v2/posts — придёт список записей:
| Адрес | Что возвращает |
|---|---|
/wp-json/wp/v2/posts | Записи |
/wp-json/wp/v2/posts/15 | Запись с номером 15 |
/wp-json/wp/v2/pages | Страницы |
/wp-json/wp/v2/categories | Рубрики |
/wp-json/wp/v2/media | Медиафайлы |
/wp-json/wp/v2/books | Свой тип записей с show_in_rest |
Параметры уточняют запрос: ?per_page=5&search=php&_fields=id,title,link.
Свой маршрут
// books.php
add_action('rest_api_init', function () {
register_rest_route('books/v1', '/top', [
'methods' => 'GET',
'callback' => 'books_rest_top',
'permission_callback' => '__return_true',
]);
});
function books_rest_top(WP_REST_Request $request): WP_REST_Response
{
$books = get_posts([
'post_type' => 'book',
'numberposts' => 5,
'meta_key' => 'book_rating',
'orderby' => 'meta_value_num',
]);
$data = array_map(fn (WP_Post $book) => [
'id' => $book->ID,
'title' => $book->post_title,
'link' => get_permalink($book),
], $books);
return rest_ensure_response($data);
}Маршрут откроется по адресу /wp-json/books/v1/top. Первая часть — books/v1 — пространство имён с номером версии.
Параметры
Параметры описывают в маршруте — WordPress сам проверит и очистит их:
register_rest_route('books/v1', '/books/(?P<id>\d+)/rating', [
'methods' => 'POST',
'callback' => 'books_rest_rate',
'permission_callback' => fn () => is_user_logged_in(),
'args' => [
'id' => [
'validate_callback' => fn ($value) => get_post_type((int) $value) === 'book',
],
'rating' => [
'required' => true,
'type' => 'integer',
'minimum' => 1,
'maximum' => 5,
],
],
]);
function books_rest_rate(WP_REST_Request $request): WP_REST_Response
{
$id = (int) $request['id'];
update_post_meta($id, 'book_rating', (int) $request['rating']);
return rest_ensure_response(['id' => $id, 'rating' => (int) $request['rating']]);
}При неверных данных клиент получит ответ с кодом 400 и описанием ошибки.
Ошибки
function books_rest_show(WP_REST_Request $request): WP_REST_Response|WP_Error
{
$book = get_post((int) $request['id']);
if (!$book || $book->post_type !== 'book') {
return new WP_Error('book_not_found', 'Книга не найдена', ['status' => 404]);
}
return rest_ensure_response(['title' => $book->post_title]);
}Свои поля во встроенных ответах
add_action('rest_api_init', function () {
register_rest_field('book', 'price', [
'get_callback' => fn (array $post) => (int) get_post_meta($post['id'], 'book_price', true),
]);
});Теперь в ответе /wp-json/wp/v2/books у каждой книги есть поле price.
Запрос из JavaScript
Для запросов от имени вошедшего пользователя нужен токен в заголовке X-WP-Nonce:
wp_add_inline_script('mytheme-app', 'const booksApi = ' . wp_json_encode([
'root' => esc_url_raw(rest_url('books/v1/')),
'nonce' => wp_create_nonce('wp_rest'),
]) . ';', 'before');// assets/app.js
const response = await fetch(booksApi.root + 'books/15/rating', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': booksApi.nonce,
},
body: JSON.stringify({ rating: 5 }),
});
const result = await response.json();Частая ошибка
permission_callback обязателен. Значение '__return_true' означает «доступно всем» и подходит только для чтения открытых данных. Маршрут, который что-то изменяет, должен проверять права — current_user_can('edit_posts') — иначе менять данные сайта сможет любой посетитель, знающий адрес.