register_rest_route()
云策文档标注
概述
register_rest_route() 函数用于在 WordPress REST API 中注册自定义路由,是扩展 API 功能的核心方法。它允许开发者定义命名空间、路由路径、端点参数,并支持多种 HTTP 方法和回调函数。
关键要点
- 必须在 'rest_api_init' Hook 之后调用,否则会触发 _doing_it_wrong() 警告。
- 参数包括:$route_namespace(命名空间,必填,不能为空或包含首尾斜杠)、$route(路由路径,必填)、$args(端点选项数组,可选,默认空数组)、$override(是否覆盖现有路由,可选,默认 false)。
- 从 WordPress 5.5.0 开始,$args 中必须包含 'permission_callback' 参数,否则会触发警告;对于公共路由,建议使用 '__return_true'。
- 函数返回布尔值:成功时返回 true,错误时返回 false(如命名空间或路由为空)。
- 支持通过正则表达式在路由中定义参数,并可在回调函数中通过 WP_REST_Request 对象访问。
代码示例
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',
'args' => array(
'id' => array(
'validate_callback' => function($param, $request, $key) {
return is_numeric( $param );
}
),
),
) );
} );注意事项
- 命名空间应唯一,通常包含插件或主题名称及版本号,避免使用非命名空间路由(除非直接调用 WP_REST_Server::register_route)。
- 路由路径中的参数需使用正则表达式正确匹配,否则可能导致 404 错误。
- permission_callback 返回 false、null 或 WP_Error 时拒绝访问,其他值(包括空字符串)均允许访问。
- 回调函数接收 WP_REST_Request 对象作为参数,可用于获取请求数据。
原文内容
Registers a REST API route.
Description
Note: Do not use before the ‘rest_api_init’ hook.
Parameters
$route_namespacestringrequired-
The first URL segment after core prefix. Should be unique to your package/plugin.
$routestringrequired-
The base URL for route you are adding.
$argsarrayoptional-
Either an array of options for the endpoint, or an array of arrays for multiple methods.
Default:
array() $overridebooloptional-
If the route already exists, should we override it? True overrides, false merges (with newer overriding if duplicate keys exist).
Default:
false
Source
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(
__FUNCTION__,
sprintf(
/* translators: 1: string value of the namespace, 2: string value of the route. */
__( 'Routes must be namespaced with plugin or theme name and version. Instead there seems to be an empty namespace '%1$s' for route '%2$s'.' ),
'<code>' . $route_namespace . '</code>',
'<code>' . $route . '</code>'
),
'4.4.0'
);
return false;
} elseif ( empty( $route ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: string value of the namespace, 2: string value of the route. */
__( 'Route must be specified. Instead within the namespace '%1$s', there seems to be an empty route '%2$s'.' ),
'<code>' . $route_namespace . '</code>',
'<code>' . $route . '</code>'
),
'4.4.0'
);
return false;
}
$clean_namespace = trim( $route_namespace, '/' );
if ( $clean_namespace !== $route_namespace ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: string value of the namespace, 2: string value of the route. */
__( 'Namespace must not start or end with a slash. Instead namespace '%1$s' for route '%2$s' seems to contain a slash.' ),
'<code>' . $route_namespace . '</code>',
'<code>' . $route . '</code>'
),
'5.4.2'
);
}
if ( ! did_action( 'rest_api_init' ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: rest_api_init, 2: string value of the route, 3: string value of the namespace. */
__( 'REST API routes must be registered on the %1$s action. Instead route '%2$s' with namespace '%3$s' was not registered on this action.' ),
'<code>rest_api_init</code>',
'<code>' . $route . '</code>',
'<code>' . $route_namespace . '</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;
}
Skip to note 9 content
alordiel
Since WP 5.5.0 there is a notice if your registration of REST API route is not including the `
permission_callback`. You may get some notice in debug.log like the following one:PHP Notice: register_rest_route was called incorrectly. The REST API route definition for
/foois missing the requiredpermission_callbackargument. For REST API routes that are intended to be public, use__return_trueas the permission callback.To solve this problem you will need to add the `
permission_callback` in arguments like the example from the “Routes and Endpoints Handbook”: https://developer.wordpress.org/rest-api/extending-the-rest-api/routes-and-endpoints/#permissions-callbackSkip to note 10 content
Lance Cleveland
Args is a named array that usually includes the keys ‘methods’ and ‘callback’.
‘method’ defines which HTTP methods are to be processed by the function defined by ‘callback’.
‘method’ can be a string of comma-separated HTTP methods or an array of strings of HTTP methods.
A common practice is to use the WP_REST_Server constants to set the ‘method’.
WP_REST_Server::READABLE = ‘GET’
WP_REST_Server::EDITABLE = ‘POST, PUT, PATCH’
WP_REST_Server::DELETABLE = ‘DELETE’
WP_REST_Server::ALLMETHODS = ‘GET, POST, PUT, PATCH, DELETE’
Example
<br />
// Get a list of locations.<br />
// Method GET via wp-json/store-locator-plus//locations/<br />
//<br />
// Calls the get_locations method of the current class when the route is matched.<br />
//<br />
register_rest_route( 'my-plugin-slug/v2' , '/locations/', array(<br />
'methods' => 'GET',<br />
'callback' => array(<br />
$this,<br />
'get_locations'<br />
)<br />
) );<br />
WP_REST_Server::CREATABLE= ‘POST’Skip to note 11 content
abellowins
//The Following registers an api route with multiple parameters. add_action( 'rest_api_init', 'add_custom_users_api'); <pre class="wp-block-code"><code lang="php" class="language-php ">function add_custom_users_api(){
register_rest_route( ‘mmw/v1’, ‘/users/market=(?P[a-zA-Z0-9-]+)/lat=(?P[a-z0-9 .-]+)/long=(?P[a-z0-9 .-]+)’, array(
‘methods’ => ‘GET’,
‘callback’ => ‘get_custom_users_data’,
));
}
Make sure that your regex expressions are fine. If the data does not match then the URL will return a 404.
Some examples are:
(?P[a-zA-Z0-9-]+) for slug (you can change slug for your custom name)
(?Pd+) for id
(?P[a-z0-9 .-]+) for longitude or latitude
//Customize the callback to your liking function get_custom_users_data($data){ //get users by market $users = mmw_get_custom_users(); foreach ($users as $key => $user) { $market = $user['Market']; $long = $user['long']; $lat = $user['lat']; if( intval($market) === intval(trim($data['market'])) ){ $result[] = array( 'user_login' => $user->user_login, 'avatar_url' => get_avatar_url($user->ID), 'lat' => $lat, 'long' => $long ); } } return $result; }Edited to remove an extra
)in one of the regexes. – DevHub Team// Pass this action in your __construct of your class. add_action( 'rest_api_init', array( $this, 'action__rest_api_init' ) ); /** * [action__rest_api_init description] * * @return {[type]} [description] */ function action__rest_api_init() { register_rest_route( 'licences', // $namespace '/removed', // $route array( 'callback' => array( $this, 'api__removed' ), 'permission_callback' => '__return_true', ) ); } /** * [api__removed description] * * @return {[type]} [description] */ function api__removed() { // do you code }Note: – licences and /removed only use for example.
Skip to note 12 content
derhans
In case you are a friend of type hinting and are wondering what is being passed to your
callbackmethod, it’s aWP_REST_Requestobject. It might help you with autocompletion and discovering other methods provided.public function wpdocs_get_lineitems( WP_REST_Request $data ) { $params = $data->get_url_params(); // etc. }Skip to note 13 content
Lance Cleveland
Args , the named array cited above, can also contain an optional ‘args’ array of its own.
The second args array contains the default arguments, required arguments, validation callback, and sanitization callback that are in place for each argument passed in with the REST request. The key name of this array is the name of the parameter being passed.
See http://v2.wp-api.org/extending/adding/ under the “Arguments” section for more information and examples.
Example
<br />add_action( 'rest_api_init', function () {<br />
register_rest_route( 'myplugin/v1', '/author/(?Pd+)', array(<br />
'methods' => 'GET',<br />
'callback' => 'my_awesome_func',<br />
'args' => array(<br />
'id' => array(<br />
'validate_callback' => function($param, $request, $key) {<br />
return is_numeric( $param );<br />
}<br />
),<br />
),<br />
) );<br />
} );<br />
Skip to note 14 content
Keramot UL Islam
1. You can not use
/(slash) at the beginning or end of the namespace, for example:plugin_name/api/.2.
permission_callbackis required argument ofregister_rest_route.function plugin_name_create_route() { add_action( 'rest_api_init', function() { register_rest_route( 'plugin_name/api', '/token/', array( 'methods' => 'POST', 'callback' => 'plugin_name_route_api', ‘permission_callback' => function() { return ''; } ) ); } ); }1. Callback takes the request object as a parameter.
2. You can set the response headers with
WP_Errorclass.function plugin_name_route_api( WP_REST_Request $req ) { $token = get_option('bearer_token'); $headers = $req->get_headers(); $auth_token = $headers['authorization'][0]; if ( $token != $auth_token ) { return new WP_Error( '401', esc_html__( 'Not Authorized', 'text_domain' ), array( 'status' => 401 ) ); } return json_encode(["message" => "Authorized"]); }permission_callbackis equivalent to granting access. Using'__return_true'is preferred if the intention is to make an API public.Skip to note 15 content
Mustafa Uysal
for the non-namespaced routing, call
WP_REST_Server::register_routedirectly.Example
add_action( 'rest_api_init', function ( $server ) { $server->register_route( 'foo', '/foo', array( 'methods' => 'GET', 'callback' => function () { return 'baz'; }, ) ); } );will register
fooendpoint without namespace. You can accesshttp://example.com/wp-json/fooAs a reminder, please ensure before registering non-namespaced routes. They can be useful for backward compatibility only.
Skip to note 16 content
Roy Orbitson
The
permission_callbackshould return one offalse,null, or aWP_Errorif access is to be disallowed. Anything else, including other “falsey” values, will grant access.