WordPress 能力 API 简介
自从WordPress 核心 AI 团队正式宣布成立以来,该团队一直在进行的最令人兴奋的项目之一就是全新的能力 API。能力 API 是一个一流的、跨上下文的函数式 API,其他工具和应用程序可以使用它与 WordPress 进行交互。
该 API 旨在为 WordPress 核心、插件和主题定义和暴露其功能(或“能力”)的方式带来统一、可发现且安全的方法。能力 API 的首次实现将包含在 WordPress 6.9 中,为更顺畅的开发工作流程、自动化新可能性和 AI 集成奠定基础。
能力 API 提供了一个中央注册表,WordPress 功能(或能力)以机器可读且对人类友好的格式在其中注册。这意味着能力不仅对开发者可发现,还可以被不同平台(包括AI 代理)的自动化工具以编程方式访问。
该项目的关键目标是:
- 可发现性:通过标准接口列出和检查所有可用能力。
- 互操作性:统一的模式使不相关的组件能够组合工作流。
- 安全优先:对谁或什么可以调用能力进行明确的权限控制。
- 渐进式采用:从Composer包插件开始,计划平滑迁移到 WordPress 核心。
可以将其视为 WordPress 或任何插件/主题能做什么的一站式商店,以一种每个人(和每件事物)都能理解的方式注册。
你可以在这个 GitHub 仓库中找到插件代码的完整副本。
列出所有 URL
该插件本身是极简的。它注册一个工具子菜单项,打开一个管理页面,你可以在其中选择列出 WordPress 站点上所有文章、页面或自定义文章类型的 URL。
有一个主要函数负责获取和显示数据,即 list_all_urls_generate_url_list() 函数。该函数接收两个参数,并生成要在页面上显示的 URL 列表。
/**
* 根据提供的参数生成 URL 列表
* 可选地使它们成为可点击的链接
*
* @param array $arguments 自定义 URL 生成的参数。
* @param bool $makelinks 是否返回可点击链接或纯 URL(已转义)。
*
* @return array 生成的 URL 列表。
*/
function list_all_urls_generate_url_list( array $arguments = array(), bool $makelinks = false ): array {
$default_args = array(
'post_type' => 'post',
'posts_per_page' => - 1,
'post_status' => 'publish',
);
$args = wp_parse_args( $arguments, $default_args );
$posts = get_posts( $args );
$links = array();
foreach ( $posts as $post ) {
$permalink = get_permalink( $post );
if ( $makelinks ) {
$links[] = '<a href="' . esc_url( $permalink ) . '">' . esc_html( $permalink ) . '</a>';
} else {
$links[] = esc_html( $permalink );
}
}
return $links;
}
在内部,此函数调用 WordPress 的 get_posts() 函数来检索实际数据,然后根据是否应显示为可点击链接列表进行格式化。
我想添加几个较小的生活质量改进,例如限制具有大量 URL 站点的结果、按类别或日期范围过滤 URL 以及导出返回的 URL 的选项。
然而,可能有用且较大的两个功能是:
- 一种在 WordPress 外部访问 URL 列表的方法(例如,一个 REST API 端点),以便将数据连接到外部服务。
- 一个允许任何人将 URL 列表添加到块编辑器任何实现(例如,在任何文章或页面中,甚至在模板中)的块。
要实现这一点,你需要设置一些东西。
如果你更喜欢浏览此解决方案的代码,可以通过查看 GitHub 仓库的 rest-blocks 分支来查看完整的实现。
你需要使用 register_rest_route() 注册一个自定义 REST API 路由和关联的 GET 端点,该端点应获取该路由的文章。
这将需要一个回调函数来获取数据,该函数又可以调用不带 $makelinks 参数的 list_all_urls_generate_url_list 来返回数据。
add_action( 'rest_api_init', 'list_all_urls_register_rest_route' );
function list_all_urls_register_rest_route (): void {
register_rest_route(
'list-all-urls/v1',
'/urls',
array(
'methods' => 'GET',
'callback' => 'list_all_urls_rest_fetch_all_urls',
'args' => array(
'type' => array(
'validate_callback' => function( $param ) {
return is_string( $param );
}
),
),
)
);
}
function list_all_urls_rest_fetch_all_urls( $arguments ){
if ( isset($arguments['type'] ) ) {
$post_type = sanitize_text_field( wp_unslash( $arguments['type'] ) );
} else {
$post_type = 'any';
}
$args = array(
'post_type' => $post_type,
);
return list_all_urls_generate_url_list( $args );
}
对于自定义块,你可以使用 create-block 搭建块结构,然后利用自定义 REST API 端点和 api-fetch 包来获取块 Edit 组件的数据并在编辑器中渲染它。
export default function Edit() {
const [urls, setUrls] = useState([]);
useEffect(() => {
apiFetch( { path: '/list-all-urls/v1/urls' } ).then( ( urls ) => {
setUrls( urls );
} );
}, []);
if ( ! urls ) {
return (
<div { ...useBlockProps() }>
<p>{ __(
'Loading...',
'list-all-urls'
) }</p>
</div>
);
}
let urlsList = urls.map( ( url ) => {
return <li><a href={ url }>{ url }</a></li>;
});
return (
<div { ...useBlockProps() }>
<ul>{ urlsList }</ul>
</div>
);
}
将其设为动态块是有意义的,该块在 render.php 文件中调用 list_all_urls_generate_url_list 函数,该文件配置为在前端渲染。
<?php
/**
* 列出所有 URL 块的渲染文件。
*/
$block_attributes = get_block_wrapper_attributes();
$urls = list_all_urls_generate_url_list( array( 'post_type' => 'any' ), true );
$urlList = '';
foreach ( $urls as $url ) {
$urlList .= '<li>' . wp_kses_post( $url ) . '</li>';
}
?>
<div <?php echo $block_attributes; ?>>
<ul>
<?php echo $urlList; ?>
</ul>
</div>
为了使用户能够选择要生成 URL 列表的文章类型,并向列表添加可点击链接,你需要更新块以支持其他属性。
然而,这已经是一段相当多的代码,仅仅是为了使通过 REST API 和块编辑器访问列出 URL 功能成为可能,同时还要维护现有的管理页面。
这是自定义能力的完美示例。你可以在一个地方注册所有内容,然后在需要的地方访问和执行它。
安装能力 API
要开始使用,请确保你使用的是 API 的最新版本。
目前,有三种方法可以安装和测试能力 API:
- 你可以将 GitHub 仓库克隆到你的
wp-content/plugins目录,安装任何依赖项,运行构建步骤,然后激活插件。 - 你可以从 GitHub 仓库的发布页面下载最新版本,然后上传并安装插件 zip 文件。
- 你可以将 Composer 包作为插件或主题的依赖项引入。
测试能力 API 的一种方法是克隆 GitHub 仓库,因为这确保你拥有 trunk 分支上的最新代码。
$ git clone git@github.com:WordPress/abilities-api.git
$ cd abilities-api
$ composer install
$ npm install
$ npm run build
另一个选项是安装 composer 包。这允许你的插件访问能力 API 的最新稳定版本及其可能提供的任何新功能,同时与核心中可用的内容兼容。
$ cd /wp-content/plugins/list-all-urls
$ composer require wordpress/abilities-api
能力来救援
在这种情况下,自定义能力可以处理大部分(如果不是全部)所需的核心功能。PHP 文档包含了你需要了解的关于如何在 PHP 中注册和使用能力的所有信息,但让我们看看“列出所有 URL”需要什么。
和之前一样,如果你更喜欢浏览此实现的完整代码,可以查看 GitHub 仓库的 abilities 分支。
在 PHP 中注册能力可以使用 wp_register_ability() 函数。为确保能力正确注册,此函数应始终在挂钩到 wp_abilities_api_init 操作钩子的回调中调用。
add_action( 'wp_abilities_api_init', 'list_all_urls_register_abilities' );
/**
* 注册列出所有 URL 的能力
*
* @return void
*/
function list_all_urls_register_abilities() {
wp_register_ability(
'list-all-urls/urls',
array(
'label' => __( '获取所有 URL', 'list-all-urls' ),
'description' => __( '从 WordPress 站点检索 URL 列表,可选地作为可点击的锚链接。', 'list-all-urls' ),
'category' => 'site',
'input_schema' => array(
'type' => 'object',
'properties' => array(
'post_type' => array(
'type' => 'string',
'description' => '要从中检索 URL 的文章类型(例如,post、page、自定义文章类型)。',
),
'posts_per_page' => array(
'type' => 'integer',
'description' => '要检索的文章数量。使用 -1 检索所有文章。',
),
'post_status' => array(
'type' => 'string',
'description' => '要检索的文章状态(例如,publish、draft)。',
),
'makelinks' => array(
'type' => 'boolean',
'description' => '是否将 URL 作为可点击的锚链接返回。',
),
),
),
'output_schema' => array(
'type' => 'object',
'properties' => array(
'url' => array(
'type' => 'string',
'description' => 'URL 或指向 URL 的可点击链接'
)
)
),
'execute_callback' => 'list_all_urls_generate_url_list',
'permission_callback' => '__return_true',
)
);
}
深入探讨能力注册
注册能力需要一个唯一标识符(list-all-urls/urls)和一个参数数组。大多数参数是可选的,但必需的是:
label:能力的人类可读名称。description:能力功能的简要描述。category:能力所属的类别。你可以注册自己的能力类别,但在这里,我使用可用的site类别。output_schema:定义能力返回数据结构的模式。execute_callback:执行能力时将调用的函数。permission_callback:确定当前用户是否有权限执行能力的函数。
input_schema 参数是可选的,但如果你的能力需要输入参数,则强烈推荐。在我的例子中,我想传入与 list_all_urls_generate_url_list() 接受的相同的参数。
设置这些模式不仅让能力知道它可以期望和返回什么数据,还支持对该数据的自动验证。例如,如果我尝试在输入中传递一个不计算为整数的 posts_per_page 值,它将自动导致验证错误并阻止能力执行。
你会注意到,我使用原始的 list_all_urls_generate_url_list() 函数作为能力 execute_callback,所以那里不需要任何更改。
在 PHP 中获取和使用能力
下一步是更新内部管理页面以获取和执行能力。
这里真正需要更改的是设置 $input 数组、获取能力并执行它。
$input = array(
'post_type' => $post_type,
'posts_per_page' => - 1,
'post_status' => 'publish',
'makelinks' => $makelinks,
);
$urlsAbility = wp_get_ability( 'list-all-urls/urls' );
$urls = $urlsAbility->execute( $input );
现在,我真正喜欢这个实现的地方在于它的可扩展性。如果我想让其他插件或主题开发者利用此功能,我只需要记录能力标识符、输入模式和输出模式。
还有一些函数可用于检查哪些能力可用——wp_get_abilities()——以及特定能力是否可用——wp_has_ability()。
在开发过程中,你可以使用 WP-CLI 的 shell 命令来获取和检查单个能力。
例如,检查当前有哪些能力可用:
$ wp shell
wp> $abilities = wp_get_abilities();
检查特定能力是否可用:
$ wp shell
wp> $found = wp_has_ability('list-all-urls/urls');
=> bool(true)
获取单个能力:
当获取所有能力和单个能力时,会返回整个能力对象,因此你能够看到能力执行什么功能,以及预期的输入和输出是什么。
$ wp shell
wp> $ability = wp_get_ability('list-all-urls/urls');
=> object(WP_Ability)#2698 (9) {
["name":protected]=>
string(18) "list-all-urls/urls"
["label":protected]=>
string(12) "Get All URLs"
["description":protected]=>
string(87) "Retrieves a list of URLs from the WordPress site, optionally as clickable anchor links."
["category":protected]=>
string(13) "list-all-urls"
["input_schema":protected]=>
array(2) {
["type"]=>
string(6) "object"
["properties"]=>
array(4) {
["post_type"]=>
array(2) {
["type"]=>
string(6) "string"
["description"]=>
string(73) "The post type to retrieve URLs from (e.g., post, page, custom post type)."
}
["posts_per_page"]=>
array(2) {
["type"]=>
string(7) "integer"
["description"]=>
string(58) "Number of posts to retrieve. Use -1 to retrieve all posts."
}
["post_status"]=>
array(2) {
["type"]=>
string(6) "string"
["description"]=>
string(59) "The status of the posts to retrieve (e.g., publish, draft)."
}
["makelinks"]=>
array(2) {
["type"]=>
string(7) "boolean"
["description"]=>
string(49) "Whether to return URLs as clickable anchor links."
}
}
}
["output_schema":protected]=>
array(2) {
["type"]=>
string(6) "object"
["properties"]=>
array(1) {
["url"]=>
array(2) {
["type"]=>
string(6) "string"
["description"]=>
string(32) "URL or clickable link to the URL"
}
}
}
["execute_callback":protected]=>
string(31) "list_all_urls_generate_url_list"
["permission_callback":protected]=>
string(13) "__return_true"
["meta":protected]=>
array(2) {
["annotations"]=>
array(3) {
["readonly"]=>
NULL
["destructive"]=>