Изменение ответов рабочих эндпоинтов

Иногда могут возникнуть ситуации, когда нужно изменить ответы уже рабочих эндпоинтов. Например, добавить или удалить данные в них. Логика работы WP API позволяет сделать это без особых сложностей.

В этом руководстве описывается, как добавить дополнительные данные в ответы эндпоинтов. А также описывается, как дополнить ключ _links и как создать свой компактный URL (CURIE) в таком _links ключе.

Добавление своего поля в ответ REST API

Важное замечание об изменении ответов REST API

Изменение данных ответа опасно! А добавление данных в ответ безопасно!

API выдает много полей в ответах и многие из них вам могут быть не нужны. Отсюда может появится соблазн изменить или удалить поля из ответов REST API. Но делать этого нельзя, потому что другие Клиенты ожидают стандартных ответов. И одним из таких Клиентов является сама админка WordPress.

Поэтому изменение или удаление данных ответа конечной точки ядра WordPress запрещено!

Как же изменить ответ если очень надо?

Если вам все же очень нужно изменить какие-то данные ответа, то вариантов может быть несколько:

  • Можно дублировать поле с измененными данными.
  • Или можно создать параметр запроса, при указании которого, ненужные поля будут удаляться из ответа.
  • Или можно работать с контекстами, например создать свой контекст, который будет возвращать только нужные вам поля.

Как видите, есть много вариантов изменить данные ответа, не навредив общей работе API, пользуйтесь ими!

Существуют две функции, которые позволяют добавить данные (поля) в ответ REST API:

Подробнее о том как работают функции читайте в их описании и ниже смотрите примеры добавления полей.

Обе эти функции подойдут для любого ресурса REST API (пост, термин ...) и любого метода запроса (GET POST).

Недостаток register_meta() в том, что функция понимает только скалярные значения, а register_rest_field() может обработать и объекты.

register_rest_field( $object_type, $attribute, $args )

register_rest_field() добавляет произвольное поле для указанного ресурса REST API.

$object_type(строка/массив) (обязательный)
Название ресурса REST для которого регистрируется поле. Несколько ресурсов можно можно указать в массиве. Возможные ресурсы из ядра: post, term, meta, user, comment. Также может быть название произвольного ресурса, например при регистрации типа записи или таксономии.
$attribute(строка) (обязательный)
Название поля. Это поле будет использовано как ключ в объекте REST ответа.
$args(массив)

Параметры обработки указанного поля во время REST запроса.

  • $get_callback(строка/массив/null)
    Функция для получения значения поля.
    По умолчанию: null - значение не будет показано в ответе

  • $update_callback(строка/массив/null)
    Функция, используемая для установки и обновления значения поля.
    По умолчанию: null - значение не может быть установлено или обновлено

  • $schema(строка/массив/null)
    Функция, используемая для создания схемы этого поля.
    По умолчанию: null - схема не будет показана

По умолчанию: array()

Пример

Создадим возможность читать и записывать метаполе в REST запросе для комментариев.

Этот пример показывает как добавить поле karma в ответ для комментариев. Работает на основе существующего, но неиспользуемого ядром, поля comment_karma в таблице wp_comments. Обратите внимание, что реальная реализация comment_karma должна использовать отдельный эндпоинт.

Это демонстрационный пример, который показывает какие проверки разрешений или обработка ошибок могут потребоваться для поля.

// регистрировать поле нужно во время события 'rest_api_init'!
add_action( 'rest_api_init', function () {

	// регистрируем REST поле
	register_rest_field( 'comment', 'karma', array(

		// функция вывода значения поля при ответе
		'get_callback' => function( $comment_arr ) {
			$comment_obj = get_comment( $comment_arr['id'] );
			return (int) $comment_obj->comment_karma;
		},

		// функция обновления поля
		'update_callback' => function( $karma, $comment_obj ) {
			$ret = wp_update_comment( array(
				'comment_ID'    => $comment_obj->comment_ID,
				'comment_karma' => $karma
			) );

			if ( false === $ret ) {
				return new WP_Error( 'rest_comment_karma_failed', __( 'Failed to update comment karma.' ), array( 'status' => 500 ) );
			}
			return true;
		},

		// описание поля в схеме
		'schema' => array(
			'description' => __( 'Comment karma.' ),
			'type'        => 'integer'
		),

	) );

} );

register_meta( $object_type, $meta_key, $args )

register_meta() регистрирует метаполе. Если при регистрации метаполя указать параметр show_in_rest = true, то это поле будет доступно в REST API и будет показываться в ответе в ключе meta. Также это метаполе можно будет создавать/обновлять через REST запросы.

$object_type(строка) (обязательный)
Тип объекта для которого регистрируется метаполе: post, user, comment, term. Параметр $meta_type из функций {add/get/update/delete}_metadata( $meta_type, ...)
$meta_key(строка) (обязательный)
Название ключа, который регистрируется.
$args(массив) (обязательный)

Данные описывающие метаполе. По умолчанию такие:

$args = array(
	'object_subtype'    => '',
	'type'              => 'string',
	'description'       => '',
	'single'            => false,
	'sanitize_callback' => null,
	'auth_callback'     => null,
	'show_in_rest'      => false,
);

register_meta() это общая функция, для нее есть обертки, чтобы удобно регистрировать метаполя для записей и элементов таксономий:

Пример

Этот пример показывает как создать поле, которое можно будет читать, создавать и обновлять в REST API.

Обновление поля будет доступно по запросу: POST wp-json/wp/v2/posts/{id}, а создание по запросу POST wp-json/wp/v2/posts/.

Заметка: если при регистрации типа записи в параметре supports не указано свойство custom-fields, то мета-поля не будут отображаться в rest API.

// Регистрация метаполя для типа записи 'post' с поддержкой REST API
register_post_meta( 'post', 'my_meta_key', array(
	// тип поля, может быть: 'string', 'boolean', 'integer', 'number'.
	// указанный тип используется для очистки поля при записи и выводе.
	'type'         => 'string',
	// описание будет показано в схеме ключа.
	'description'  => 'A meta key associated with a string meta value.',
	// метаполе может иметь только одно значение.
	'single'       => true,
	// использовать поле в WP REST API
	'show_in_rest' => true,
) );

WordPress генерирует список ссылок, связанных с запрашиваемым ресурсом, чтобы упростить навигацию к связанным ресурсам. Подробнее здесь.

{
 "_links": {
	"self": [
	  {
		"href": "https://make.wordpress.org/core/wp-json/wp/v2/posts/28312"
	  }
	],
	"collection": [
	  {
		"href": "https://make.wordpress.org/core/wp-json/wp/v2/posts"
	  }
	],
	"author": [
	  {
		"embeddable": true,
		"href": "https://make.wordpress.org/core/wp-json/wp/v2/users/8670591"
	  }
	],
	"replies": [
	  {
		"embeddable": true,
		"href": "https://make.wordpress.org/core/wp-json/wp/v2/comments?post=28312"
	  }
	],
	"wp:term": [
	  {
		"taxonomy": "category",
		"embeddable": true,
		"href": "https://make.wordpress.org/core/wp-json/wp/v2/categories?post=28312"
	  },
	  {
		"taxonomy": "post_tag",
		"embeddable": true,
		"href": "https://make.wordpress.org/core/wp-json/wp/v2/tags?post=28312"
	  }
	]
  }
}

Ключ _links в JSON объекте не содержится в WP_REST_Response::$data и к нему нет доступа через WP_REST_Response::get_data(), потому что этот ключ добавляется прямо перед тем как вернуть ответ.

Произвольная ссылка может быть добавлена через метод:

WP_REST_Response::add_link( $rel, $href, $attributes )

$rel(строка)
Связь ссылки. Должна быть строка из доступного списка IANA. Или можно указать URL адрес зарегистрированный как «Компактынй URL (CURIE)». Пример CURIE: https://api.w.org/term превратиться в wp:term при генерации ответа API.
$href(строка)
URL ссылки.
$attributes(массив)

Список атрибутов ссылки. Здесь могут быть разные параметры (зависит от контроллера ресурса).

  • embeddable - включает поддержку встраивания (_embedded), при включенном параметре _embed. Если несколько ссылок добавляются с одинаковой связью, то встраивания будут в том же порядке, в котором были добавлены ссылки.

Примеры добавления ссылки:

$response->add_link( 'author', rest_url( "/wp/v2/users/{$post->post_author}" ) );

$response->add_link( 'https://api.w.org/term', add_query_arg( 'post', $post->ID, rest_url( "/wp/v2/{$tax_base}" ) ) );

$response->add_link( 'author', rest_url( "/wp/v2/users/{$post->post_author}" ), array(
	'embeddable' => true,
) );

$response->add_link( 'author', rest_url( "/wp/v2/users/{$additional_author}" ), array(
	'embeddable' => true,
) );

Пример реализации ссылок на публикации с несколькими авторами. Порядок добавления ссылок сохраняется.

{
  "_links": {
	"author": [
	  {
		"embeddable": true,
		"href": "https://yourwebsite.com/wp-json/wp/v2/users/1"
	  },
	  {
		"embeddable": true,
		"href": "https://yourwebsite.com/wp-json/wp/v2/users/2"
	  }
	]
  },
  "_embedded": {
	"author": [
	  {
		"id": 1,
		"name": "Primary Author"
	  },
	  {
		"id": 2,
		"name": "Secondary Author"
	  }
	]
  }
}

Регистрация своего Компактного URL (CURIE)

CURIEs - «Compact URIs» - URL записывается в компактном виде, чтобы понятно и универсально выглядеть в ответе API. Понятие было введено с версии WP 4.5.

Пример CURIE: https://api.w.org/term превратиться в wp:term при генерации ответа API.

Все варианты:

https://api.w.org/items          =  wp:items
https://api.w.org/featuredmedia  =  wp:featuredmedia
https://api.w.org/attachment     =  wp:attachment
https://api.w.org/term           =  wp:term
https://api.w.org/post_type      =  wp:post_type

Свои CURIEs можно добавить через фильтр rest_response_link_curies.

Например, сделаем преобразование ссылки https://api.mypluginurl.com/my_link в my_plugin:my_link в ответе API.

add_filter( 'rest_response_link_curies', 'my_plugin_prefix_register_curie' );
function my_plugin_prefix_register_curie( $curies ) {

	$curies[] = array(
		'name'      => 'my_plugin',
		'href'      => 'https://api.mypluginurl.com/{rel}',
		'templated' => true,
	);

	return $curies;
}