aivec / wordpress-router
WordPress 请求路由器。包含中间件、JWT 和 nonce 检查。
Requires
- aivec/response-handler: ^5.0
- firebase/php-jwt: ^5.0
- nikic/fast-route: ^1.3
Requires (Dev)
- aivec/codecept-docker: ^0.8.1
- aivec/phpcs-wp: ^2.0
- codeception/module-asserts: ^1.3
- codeception/module-cli: ^1.1
- codeception/module-db: ^1.1
- codeception/module-phpbrowser: ^1.0
- codeception/module-rest: ^2.0
- wp-cli/i18n-command: ^2.4
- dev-master
- v7.3.0
- v7.2.1
- v7.2.0
- v7.1.1
- v7.1.0
- v7.0.2
- v7.0.1
- v7.0.0
- v6.0.2
- v6.0.1
- v6.0.0
- v5.1.0
- v5.0.1
- v5.0.0
- v4.1.1
- v4.1.0
- v4.0.6
- v4.0.5
- v4.0.4
- v4.0.3
- v4.0.2
- v4.0.1
- v4.0.0
- v3.1.2
- v3.1.1
- v3.1.0
- v3.0.1
- v3.0.0
- v2.2.0
- v2.1.0
- v2.0.0
- v1.4.0
- v1.3.0
- v1.2.0
- v1.1.1
- v1.1.0
- v1.0.0
- dev-dependabot/composer/guzzlehttp/psr7-2.5.0
- dev-dependabot/composer/firebase/php-jwt-6.0.0
- dev-fix-roles
This package is auto-updated.
Last update: 2024-09-19 22:49:46 UTC
README
本包为 WordPress 提供了路由库,包含针对 WordPress 的特定包装,如 nonce 验证和用户角色检查。本包的核心使用 FastRoute,这是一个小型且简洁的路由解析器。《FastRoute》也是流行的微框架 Slim 所使用的路由解析器。
问题
WordPress 中的路由对插件作者来说是个头疼的问题。如果你采用 WordPress 传统方式通过 admin-ajax.php 注册 AJAX 处理器,它完全依赖于 $_POST 对象的键来解析路由。你可以使用 WordPress 的 REST API,但你无法控制路由何时解析。这对那些为其他插件创建扩展的开发者来说非常重要,因为这些开发者无法控制加载顺序。本包与 WordPress 的实现不同之处在于,它不提供 validate 和 sanitize 回调,而是选择使用通用中间件。
特性
该库提供了许多功能来简化路由的提供,以及一些可选的默认中间件。主要特性如下
- 基于角色的路由注册(编辑者、管理员等)
- 自动 nonce 验证
- URL 参数(非正则表达式 😁)
- 透传路由(非 AJAX 路由)
- 用于生成 HTML 表单的辅助函数
- JWT 路由注册
- JWT 设置页面用于自动生成密钥对
安装
使用 composer 安装
$ composer require aivec/wordpress-router
如果你计划在一个插件中使用此包,我们 强烈 建议使用 mozart 进行命名空间。如果不这样做,可能会出现难以调试的故障。 警告:已警告你。
使用指南
公开路由
公开路由是指不需要 nonce 验证的路由。公开路由任何人都可以从任何地方访问。
use Aivec\WordPress\Routing\Router; use Aivec\WordPress\Routing\WordPressRouteCollector; // First, we declare our routes by extending the `Router` class: class Routes extends Router { /** * This is where we define each route */ public function declareRoutes(WordPressRouteCollector $r) { $r->addPublicRoute('GET', '/hamburger', function () { return 'Here is a public hamburger.'; }); } } // Next, we instantiate the `Routes` class with a unique namespace and listen for requests $routes = new Routes('/mynamespace'); $routes->dispatcher->listen();
调用公开路由
你可以从命令行测试路由,如下所示
$ curl -X GET http://www.my-site.com/mynamespace/hamburger
'Here is a public hamburger.'
或者,你可以使用 jQuery 的 ajax 函数从加载到 WordPress 页面的脚本中发送请求
jQuery.ajax("http://www.my-site.com/mynamespace/hamburger", { success(data) { var response = JSON.parse(data); console.log(response); // Here is a public hamburger. }, });
私有路由
私有路由是指需要 nonce 验证的路由。
use Aivec\WordPress\Routing\Router; use Aivec\WordPress\Routing\WordPressRouteCollector; // First, extend the `Router` class: class Routes extends Router { /** * This is where we define each route */ public function declareRoutes(WordPressRouteCollector $r) { /** * `add` is the default way to register a route with nonce verification */ $r->add('POST', '/hamburger', function () { return 'Here is a private hamburger.'; }); } }
在声明了我们的路由之后,我们使用唯一的命名空间实例化 Routes 类。
这次,我们将 nonce 键和 nonce 名称作为第二个和第三个参数传入。
由于 nonce 处理需要 WordPress 核心函数,因此必须在核心函数加载之后实例化 Routes 类。你可以使用 init 钩子或任何其他适当的钩子来确保核心函数已加载。
$routes = null; add_action('init', function () use ($routes) { $routes = new Routes('/mynamespace', 'nonce-key', 'nonce-name'); $routes->dispatcher->listen(); });
调用私有路由
通常,私有路由是通过从 WordPress 网站上的 JavaScript 文件调用 AJAX 来调用的。为此,我们必须将 nonce 传递给我们要从中调用路由的脚本。
利用 wp_localize_script,我们可以从 Routes 类中调用一个辅助方法来注入 nonce 变量。
add_action('wp_enqueue_scripts', function () use ($routes) { wp_enqueue_script( 'my-script', site_url() . '/wp-content/plugins/my-plugin/my-script.js', [], '1.0.0', false ); wp_localize_script('my-script', 'myvars', $routes->getScriptInjectionVariables()); });
现在,my-script.js 将包含我们需要的 nonce 变量以进行调用。
// my-script.js jQuery.ajax(`${myvars.endpoint}/hamburger`, { method: "POST", data: { [myvars.nonceKey]: myvars.nonce, }, success(data) { var response = JSON.parse(data); console.log(response); // Here is a private hamburger. }, });
URL 参数
花括号用于定义 URL 参数。
URL 参数将被解析,然后插入到 $args 变量中,该变量总是作为处理函数的 第一个 参数传递。
$r->add('POST', '/hamburger/{burgername}', function (array $args) { return 'Here is a ' . $args['burgername'] . ' hamburger.'; });
// my-script.js jQuery.ajax(`${myvars.endpoint}/hamburger/mushroom`, { method: "POST", data: { [myvars.nonceKey]: myvars.nonce, }, success(data) { var response = JSON.parse(data); console.log(response); // Here is a mushroom hamburger. }, });
您可以定义任意多的参数。
$r->add('POST', '/hamburger/{burgername}/{count}', function (array $args) { return 'Here are ' . $args['count'] . ' ' . $args['burgername'] . ' hamburgers.'; });
您还可以限制接受的参数类型,以及提供自己的模式以进行更精细的控制。
// Matches /user/42, but not /user/xyz $r->add('POST', '/user/{id:\d+}', .....); // Matches /user/foobar, but not /user/foo/bar $r->add('GET', '/user/{name}', .....); // Matches /user/foo/bar as well $r->add('GET', '/user/{name:.+}', .....);
路由定义有许多可能性。有关如何解析路由的详细信息,请参考这里。
表单数据
路由器期望以 application/x-www-form-urlencoded 的内容类型发送 POST 请求。表单数据作为 JSON 编码的字符串发送,作为请求体中 payload 键的值。
// $payload contains the decoded JSON key-value array $r->add('POST', '/hamburger', function (array $args, array $payload) { $ingredients = join(' and ', $payload['ingredients']); return 'I want ' . $ingredients . ' on my hamburger.'; });
// my-script.js jQuery.ajax(`${myvars.endpoint}/hamburger`, { method: "POST", data: { [myvars.nonceKey]: myvars.nonce, payload: JSON.stringify({ ingredients: ["pickles", "onion"], }), }, success(data) { var response = JSON.parse(data); console.log(response); // I want pickles and onion on my hamburger. }, });
让一切变得更简单
如我们所见,私有路由需要在 POST 请求体中存在 nonce 键值对。您可能已经注意到我们在那些例子中排除了 GET 请求。这是因为 GET 请求没有请求体内容,这意味着 nonce 变量必须作为 URL 查询参数设置。整个过程很繁琐,我们可以做得更好。
对于正在将 JavaScript 转译的人,我们建议使用 axios 和我们的 辅助库。这完全抽象了 nonce 处理和 JSON 编码,并在请求方法(GET、POST、PUT 等)中自动设置 nonce 变量。
以下是用这些库重写的 表单数据 示例。
// my-script.js import axios from "axios"; import { createRequestBody } from "@aivec/reqres-utils"; axios .post( `${myvars.endpoint}/hamburger`, createRequestBody(myvars, { ingredients: ["pickles", "onion"], }) ) .then(({ data }) => { console.log(data); });