WordPress как на ладони

register_rest_route()WP 4.4.0

Регистрирует маршрут REST API и его эндпоинты (конечные точки). Говоря проще регистрирует URL по которому будет срабатывать указанная PHP функция.

Функцию нужно вызывать на хуке rest_api_init.

C версии WP 5.5.0 параметр permission_callback стал обязательным! Если его не указать, то вы получите следующее уведомление в debug.log:

PHP Notice: register_rest_route was called incorrectly. В регистрации маршрута REST API для /foo отсутствует обязательный аргумент permission_callback. Для публичных маршрутов REST API, используйте __return_true в качестве коллбэк функции.

Подробнее читайте здесь: https://developer.wordpress.org/rest-api/extending-the-rest-api/routes-and-endpoints/#permissions-callback.

Читайте также: Учебник по WordPress REST API.

Хуков нет.

Возвращает

true|false. True в случае успеха и false при ошибке.

Шаблон использования

add_action( 'rest_api_init', function () {

	register_rest_route( 'myplugin/v1', '/my_slug/(?P<param_name>.+)', array(
		'methods'             => 'GET',            // метод запроса: GET, POST ...
		'callback'            => 'function_name',  // функция обработки запроса. Должна вернуть ответ на запрос
		'permission_callback' => 'function_name',  // функция проверки доступа к маршруту. Должна вернуть true/false
		// описание передаваемых параметров
		'args' => array(
			'param_name' => array(
				'default'           => null,           // значение параметра по умолчанию
				'required'          => null,           // является ли параметр обязательным. Может быть только true
				'validate_callback' => 'function_name', // функция проверки значения параметра. Должна вернуть true/false
				'sanitize_callback' => 'function_name', // функция очистки значения параметра. Должна вернуть очищенное значение
			),
			'param_name2' => array(
				...
			)
			...
		),
	) );

} );

Использование

register_rest_route( $namespace, $route, $args, $override );
$namespace(строка) (обязательный)
Первая часть маршрута (URL), которая идет после REST префикса (/wp-json/). Должна быть уникальной, обычно тут используется уникальное название вашего плагина или темы, например myplugin/v1. Подробнее смотрите пространства имен в REST.
$route(строка) (обязательный)
Вторая часть маршрута (URL). Поддерживает регулярные выражения, к примеру /author/(?P<id>\d+).
$args(массив)

Массив параметров для конечной точки.
С помощью этих параметров можно тонко настроить обработку запроса конечной точки.

Если нужно создать несколько конечных точек, то массив должен содержать вложенные массивы, в которых описывается каждая конечная точка.

Массив для одной конечной точки по умолчанию выглядит так:

$args = [
	'methods'  => 'GET',
	'callback' => null,
	'permission_callback' => null,
	'args'     => array(),
];

Пример как можно указать несколько конечных точек (методов):

$args = [
	// common args
	'args' => [
		'id' => [
			'description' => __( 'Unique identifier for the term.' ),
			'type'        => 'integer',
		],
	],
	// GET
	[
		'methods'  => 'GET',
		'callback' => null,
		'permission_callback' => null,
		'args'     => [],
	],
	// POST
	[
		'methods'  => 'POST',
		'callback' => null,
		'permission_callback' => null,
		'args'     => [],
	],
]

Описание всех возможных аргументов смотрите ниже.

Созданный тут массив, как есть попадают в свойство объекта WP_REST_Server::$endpoints.

$override(логический)

Определяет нужно ли переписать данные, если такой маршрут уже существует:

  • true - переопределить
  • false - объединить с помощью функции array_merge().

По умолчанию: false

Аргументы параметра $args

methods(строка/массив)

Определяет по какому методу запроса, будет доступна конечная точка: GET (по умолчанию), POST, PUT, PATCH, DELETE. Несколько методов можно указать строкой через запятую или массивом.

Можно использовать предопределенные константы класса WP_REST_Server:

WP_REST_Server::READABLE    // GET
WP_REST_Server::CREATABLE   // POST
WP_REST_Server::EDITABLE    // POST, PUT, PATCH
WP_REST_Server::DELETABLE   // DELETE
WP_REST_Server::ALLMETHODS  // GET, POST, PUT, PATCH, DELETE
callback(коллбэк функция)

Здесь указывается имя функции, которая будет срабатывать при переходе (запросе) на URL (rest маршрут). В функции нужно сформировать и вернуть данные. Возвращаемые данные будут преобразованы в json формат и выведены на экран.

В этом параметре, например, можно использовать свою функцию или любую другую, которая возвращает результат, например get_posts().

Функция указанная в этом параметре в качестве параметра получает объект класса WP_REST_Request, в нём содержатся параметры запроса и благодаря им можно сформировать точный ответ. К примеру, если просто вызвать get_posts(), то она вернет результат согласно её дефолтным настройкам, но если её обернуть в свою функцию и передать в вызов get_posts() полученный параметр ID автора, то можно отфильтровать посты по автору (смотрите первый пример).

Так как в функцию передаётся объект класса WP_REST_Request, то нам доступны методы для получения различной информации:

// Регистрирует маршрут
add_action( 'rest_api_init', function () {
	register_rest_route( 'myplugin/v1', '/author/(?P<id>\d+)', array(
		'methods'  => 'GET',
		'callback' => 'my_rest_api_func',
	) );
} );

// Обратимся по адресу http://wp-test.ru/wp-json/myplugin/v1/author/1

function my_rest_api_func( WP_REST_Request $request ) {
	// Можно получить доступ к параметрам через прямой доступ к массиву объекта:
	$param = $request['id']; // 1

	// Или с помощью метода:
	$param = $request->get_param( 'id' ); // 1

	// Массив из всех параметров
	$parameters = $request->get_params(); // Array([id] => 1)

	// При необходимости также доступны отдельные параметры параметров:
	$parameters = $request->get_url_params(); // Array([id] => 1)

	$parameters = $request->get_query_params(); // Array()
	// Если запросить http://wp-test.ru/wp-json/myplugin/v1/author/1?post=1
	$parameters = $request->get_query_params(); // Array( [post] => 1 )

	$parameters = $request->get_body_params(); // Array()
	$parameters = $request->get_json_params(); // null - не было запроса с заголовком Content-type: application/json
	$parameters = $request->get_default_params(); // Array()

	// Данные о загрузках не объединены, но могут быть доступны отдельно:
	$parameters = $request->get_file_params();

	// варианты возврата данных

	return new WP_REST_Response( true, 200 );

	return new WP_Error( 'no_author', 'Invalid author', array( 'status' => 404 ) );

	return 'строка';

	return array( 'foo'=>'bar' );

	// получим объект WP_REST_Response
	$response = rest_ensure_response( array( 'foo'=>'bar' ) );
	$response->set_status( 401 );
	$response->set_headers( [
		'X_REAL_IP'      => '54.15.124.126',
	] );
	return $response;
}
permission_callback(коллбэк функция) (обязательный)

Позволяет проверить права пользователя, который запрашивает маршрут. Доступ будет разрешен, если вернуть true, и запрещен, если false.

С версии WordPress 5.5 данную функцию нужно указывать обязательно!

Пример, как разрешить доступ всем пользователям:

register_rest_route( 'myplugin/v1', '/awesome-route', array(
	'methods'             => WP_REST_Server::READABLE,
	'callback'            => 'my_awesome_func',
	'permission_callback' => '__return_true'
) );

Пример, как проверить возможности пользователя:

register_rest_route( 'myplugin/v1', '/author/(?P<id>\d+)', array(
	'methods'             => WP_REST_Server::READABLE,
	'callback'            => 'my_awesome_func',
	'permission_callback' => 'my_awesome_permission_callback'
) );

function my_awesome_permission_callback ( WP_REST_Request $request ) {
	return current_user_can( 'edit_others_posts' );
}

Пусть функция my_awesome_func() возвращает посты указанного пользователя. Если пользователь имеет право изменять чужие посты (к примеру, редактор), то нужные данные вернуться. Если же таких прав у текущего пользователя нет, то вернется ошибка:

{
	"code": "rest_forbidden",
	"message": "Извините, вам не разрешено выполнять данное действие.",
	"data": {
		"status": 401
	}
}

Такая же ошибка вернётся, если не передать nonce, подробнее читайте в разделе Авторизация в WP REST API.

show_in_index(true/false)
Нужно ли показывать роут в схеме всех роутов.
args(массив)

Возможные параметры эндпоинта. Каждый элемент массива описывает один параметр. Ключ элемента это название параметра запроса, а значение это вложенный массив описывающий этот параметр.

Некоторые данные параметра автоматически попадают в схему маршрута (например description, type, required ...). См. rest_get_allowed_schema_keywords().

Возможные аргументы массива:

description
default
required
sanitize_callback
validate_callback

// проверка и очистка
type
	string
		minLength / maxLength
		pattern
		format
	null
	boolean
	number / integer
		minimum / maximum
		exclusiveMinimum / exclusiveMaximum
		multipleOf
	array
		items
		minItems / maxItems
		uniqueItems
	object
		properties
		additionalProperties
		patternProperties
		minProperties / maxProperties
enum
oneOf / anyOf

Типы данных REST. Проверка и очистка — тут смотрите полный список возможных параметров и их описание.

  • description(строка) (попадает в схему)
    Описание параметра.

  • default(разное) (попадает в схему)
    Значение по умолчанию для аргумента, если он не указан.

    register_rest_route( 'myplugin/v1', '/author/(?P<key>\d+)', array(
    	'methods'  => WP_REST_Server::READABLE,
    	'callback' => 'my_awesome_func',
    	'args'     => array(
    		'key' => array(
    			'default' => 1
    		),
    	),
    ) );
  • required(true/false) (попадает в схему)
    Если в значении указать true и указанный параметр не будет определен (не будет указан в запроса), то будет возвращена ошибка.

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

    required не имеет смысла, если установлен параметр default, поскольку аргумент всегда будет иметь значение.

    register_rest_route( 'myplugin/v1', '/author/(?P<key>\d+)', array(
    	'methods'  => WP_REST_Server::READABLE,
    	'callback' => 'my_awesome_func',
    	'args'     => array(
    		'key' => array(
    			'required' => false // или true - обязательный параметр
    		),
    	),
    ) );
  • validate_callback(строка/callback)
    Функция проверки данных. Функция должна возвращать true, если проверка прошла, и false в противном случае.

    Функция также может вернуть объект WP_Error, тогда сообщение будет добавлено в объект ответа. Например, если вернуть такой объект:

    new WP_Error( 'err', 'Must match `^[a-zA-Z0-9:_-]+$` regex.' )

    То в ответе получим:

    {
    	"code": "rest_invalid_param",
    	"message": "Неверный параметр: name",
    	"data": {
    		"status": 400,
    		"params": {
    			"name": "Must match `^[a-zA-Z0-9:_-]+$` regex."
    		},
    		"details": {
    			"name": {
    				"code": "err",
    				"message": "Must match `^[a-zA-Z0-9:_-]+$` regex.",
    				"data": null
    			}
    		}
    	}
    }

    Пусть функция my_awesome_func() возвращает список постов указанного автора, тогда:

    register_rest_route( 'myplugin/v1', '/author/(?P<id>\d+)', [
    	'methods'  => 'GET',
    	'callback' => 'my_awesome_func',
    	'args'     => [
    		'id' => [
    			'validate_callback' => function( $param, $request, $key ) {
    				return is_numeric( $param );
    			},
    		],
    	],
    ] );

    Запросим записи автора с ID = 1 по адресу (предполагаем, что записи есть):

    http://wp-test.ru/wp-json/myplugin/v1/author/1

    Вернется массив с записями. Но если обратится по адресу:

    http://wp-test.ru/wp-json/myplugin/v1/author/vasya

    То вернется ошибка:

    {
    	"code": "rest_no_route",
    	"message": "Подходящий маршрут для URL и метода запроса не найден",
    		"data": {
    		"status": 404
    	}
    }

    Потому что параметр id не прошёл проверку функций is_numeric(), так как значение vasya не является числом.

    Казалось бы, почему просто не указать функцию is_numeric() вот так:

    register_rest_route( 'myplugin/v1', '/author/(?P<id>\d+)', array(
    	'methods'  => WP_REST_Server::READABLE,
    	'callback' => 'my_awesome_func',
    	'args'     => array(
    		'id' => array(
    			'validate_callback' => 'is_numeric'
    		),
    	),
    ) );
    

    Но, как можно заметить из примера выше, в указанную функцию будут переданы три параметра $param, $request, $key и, если всех их передать функции is_numeric() - будет ошибка уровня warning.

    [29-May-2018 12:07:54 UTC] PHP Warning:  is_numeric() expects exactly 1 parameter,
    3 given in \sites\example.com\wp-includes\rest-api\class-wp-rest-request.php on line 858

    Есть тикет, по этой теме.

  • sanitize_callback(строка/callback)
    Функция очистки данных. Аналогична validate_callback, только вместо true/false нужно возвратить очищенное входящее значение. Или можно вернуть WP_Error объект.

    register_rest_route( 'myplugin/v1', '/author/(?P<id>\d+)', array(
    	'methods'  => WP_REST_Server::READABLE,
    	'callback' => 'my_awesome_func',
    	'args'     => array(
    		'id' => array(
    			'sanitize_callback' => function ( $param, $request, $key ) {
    				return (int) $param;
    			}
    		),
    	),
    ) );
  • type(строка) (попадает в схему)
    Тип значения параметра. Возможные значения: array, object, string, number, integer, boolean, null. Если указан другой тип, то в ответ выдаст ошибку 400. Подробнее про этот параметр.

  • minimum / maximum(число) (используется в схеме)
    Минимальное или Максимальное значение параметра. Только для type = integer.

  • format(строка) (используется в схеме)
    Дополнительный формат строки. Значения будут проверятся на соответствие указанному формату. Подробнее.

  • enum(массив) (используется в схеме)
    Список возможных значения параметра (когда у параметра ограниченный список возможных значений).

Примеры

1

#1 Получение записей указанного автора

В WordPress для этой цели есть дефолтные методы, но давайте для примера создадим свой простой вариант:

// Регистрирует маршрут
add_action( 'rest_api_init', function () {

	register_rest_route( 'myplugin/v1', '/author/(?P<id>\d+)', array(
		'methods'  => 'GET',
		'callback' => 'my_awesome_func',
		'permission_callback' => '__return_true'
	) );
} );

// Обрабатывает запрос
function my_awesome_func( WP_REST_Request $request ) {

	$posts = get_posts( array(
		'author' => (int) $request['id'],
	) );

	if ( empty( $posts ) )
		return new WP_Error( 'no_author_posts', 'Записей не найдено', array( 'status' => 404 ) );

	return $posts;
}

Теперь получим записи автора с ID = 1 с помощью GET запроса по адресу:

http://wp-test.ru/wp-json/myplugin/v1/author/1

Получим ответ в формате json, если записи нашлись:

[
	{
		"ID": 280,
		"post_author": "1",
		"post_date": "2018-04-10 21:06:29",
		"post_date_gmt": "2018-04-10 18:06:29",
		"post_content": "Привет! Эта статья должна стать исключением.\r\n\r\n[smr_slider id='1']",
		"post_title": "Ещё статья",
		"post_excerpt": "",
		"post_status": "publish",
		"comment_status": "open",
		"ping_status": "open",
		"post_password": "",
		"post_name": "eshhyo-statya",
		"to_ping": "",
		"pinged": "",
		"post_modified": "2018-05-25 11:34:03",
		"post_modified_gmt": "2018-05-25 08:34:03",
		"post_content_filtered": "",
		"post_parent": 0,
		"guid": "http://wp-test.ru/?p=280",
		"menu_order": 0,
		"post_type": "post",
		"post_mime_type": "",
		"comment_count": "0",
		"filter": "raw"
	},
	{
		"ID": 273,
		...
	}
	...
]

Получим ответ в формате json, если записей у автора нет:

{
	"code": "no_author_posts",
	"message": "Записей не найдено",
	"data": {
		"status": 404
	}
}

Можно доработать функцию, чтобы получать только нужные нам значения:

// Обрабатываем запрос
function my_awesome_func( WP_REST_Request $request ) {

	// Получим записи указанного автора
	$posts = get_posts( array(
		'author' => (int) $request['id'],
	) );

	if( empty( $posts ) )
		return new WP_Error( 'no_author_posts', 'Записей не найдено', array( 'status' => 404 ) );

	// Создадим свои данные для возврата
	$posts = array_map( function ( $post ) {
		$post_data['title']    = esc_html( $post->post_title );
		$post_data['url']      = esc_url( get_the_permalink( $post ) );
		$post_data['comments'] = (int) $post->comment_count;
		$post_data['likes']    = (int) get_post_meta( $post->ID, 'likes', true );

		return $post_data;
	}, $posts );

	return $posts;
}

Если записи есть, получим ответ:

[
	{
		"title": "Ещё статья",
		"url": "http://wp-test.ru/eshhyo-statya",
		"comments": 3,
		"likes": 11
	},
	{
		"title": "Моя статья",
		...
	},
	...
]
0

#2 Еще примеры

Смотрите в Учебнике REST API в разделе Создание маршрутов. Там например, вы найдете, пример создания маршрутов на основе Класса контроллера (ООП).

Список изменений

С версии 4.4.0 Введена.
С версии 5.1.0 Added a _doing_it_wrong() notice when not called on or after the rest_api_init
С версии 5.5.0 Added a _doing_it_wrong() notice when the required permission_callback argument is not set.

Код register_rest_route() WP 6.5.2

function register_rest_route( $route_namespace, $route, $args = array(), $override = false ) {
	if ( empty( $route_namespace ) ) {
		/*
		 * Non-namespaced routes are not allowed, with the exception of the main
		 * and namespace indexes. If you really need to register a
		 * non-namespaced route, call `WP_REST_Server::register_route` directly.
		 */
		_doing_it_wrong( 'register_rest_route', __( 'Routes must be namespaced with plugin or theme name and version.' ), '4.4.0' );
		return false;
	} elseif ( empty( $route ) ) {
		_doing_it_wrong( 'register_rest_route', __( 'Route must be specified.' ), '4.4.0' );
		return false;
	}

	$clean_namespace = trim( $route_namespace, '/' );

	if ( $clean_namespace !== $route_namespace ) {
		_doing_it_wrong( __FUNCTION__, __( 'Namespace must not start or end with a slash.' ), '5.4.2' );
	}

	if ( ! did_action( 'rest_api_init' ) ) {
		_doing_it_wrong(
			'register_rest_route',
			sprintf(
				/* translators: %s: rest_api_init */
				__( 'REST API routes must be registered on the %s action.' ),
				'<code>rest_api_init</code>'
			),
			'5.1.0'
		);
	}

	if ( isset( $args['args'] ) ) {
		$common_args = $args['args'];
		unset( $args['args'] );
	} else {
		$common_args = array();
	}

	if ( isset( $args['callback'] ) ) {
		// Upgrade a single set to multiple.
		$args = array( $args );
	}

	$defaults = array(
		'methods'  => 'GET',
		'callback' => null,
		'args'     => array(),
	);

	foreach ( $args as $key => &$arg_group ) {
		if ( ! is_numeric( $key ) ) {
			// Route option, skip here.
			continue;
		}

		$arg_group         = array_merge( $defaults, $arg_group );
		$arg_group['args'] = array_merge( $common_args, $arg_group['args'] );

		if ( ! isset( $arg_group['permission_callback'] ) ) {
			_doing_it_wrong(
				__FUNCTION__,
				sprintf(
					/* translators: 1: The REST API route being registered, 2: The argument name, 3: The suggested function name. */
					__( 'The REST API route definition for %1$s is missing the required %2$s argument. For REST API routes that are intended to be public, use %3$s as the permission callback.' ),
					'<code>' . $clean_namespace . '/' . trim( $route, '/' ) . '</code>',
					'<code>permission_callback</code>',
					'<code>__return_true</code>'
				),
				'5.5.0'
			);
		}

		foreach ( $arg_group['args'] as $arg ) {
			if ( ! is_array( $arg ) ) {
				_doing_it_wrong(
					__FUNCTION__,
					sprintf(
						/* translators: 1: $args, 2: The REST API route being registered. */
						__( 'REST API %1$s should be an array of arrays. Non-array value detected for %2$s.' ),
						'<code>$args</code>',
						'<code>' . $clean_namespace . '/' . trim( $route, '/' ) . '</code>'
					),
					'6.1.0'
				);
				break; // Leave the foreach loop once a non-array argument was found.
			}
		}
	}

	$full_route = '/' . $clean_namespace . '/' . trim( $route, '/' );
	rest_get_server()->register_route( $clean_namespace, $full_route, $args, $override );
	return true;
}
campusboy 4754youtube.com/c/wpplus
Создатель YouTube канала wp-plus, на котором делюсь своим опытом. Активный пользователь wp-kama.ru. WordPress-разработчик. Разработка сайтов и лендингов. Доработка существующих проектов. Сопровождение ресурсов.
Редакторы: Kama 9621
1 комментарий
    Войти