在之前的文章中我们已经介绍了如何使用polylang对网站启用多语言支持的功能,并描述了使用n8n对文章自动化的进行多语言翻译:
完成后经过一段时间的试用,插件相对完美的达到了我要的需求,但我也发现有一个非常影响使用的点:Polylang插件的免费版本不支持API使用,这严重影响了使用体验,例如以下的几个场景无法自动化的完成:
- 无法获取文章的语言状态,导致webhook自动化完成翻译后,会对已经是英文的文章再翻译一遍创建新文章,从而进入死循环
- 无法自动化关联多语言文章之间的关系,这导致站点的中文和英文文章之间没有关联,无法自动切换内页文章语言
考虑到API是我的强需求,且Polylang的Pro版本相对于我的需求而言性价比并不太高(在1个站点的情况下,需要99欧),于是考虑自行添加相关的功能。
了解插件
对于PHP和Wordpress我相对还比较熟悉,但是我不太希望通过阅读一个非常复杂的代码进行定制化开发,于是我想到了利用AI的辅助:我提供思路,由AI帮助我完成这个需求,以下是相关的记录:
数据库交互
我首先想到,插件一定会在数据库中保存相关的信息,这些信息关系到了文章是什么语言类型,之间的映射关系如何:
基于答案,搜索Polylang插件的相关代码,最终找到pll_save_post
函数,贴入相关的代码:
发现gpt-4o是认识这个插件的,并准确的提示了相关函数的作用,从而我直接问数据保存的结果:
得到答案后,在服务端进行验证,找到关键词post_translations
,序列化后保存了多语言文章之间的相关的映射关系:
找到关键函数
基于gpt-4o给出的提示:
在源代码中对相关关键词进行搜索,找到字段名在程序中的变量名:
了解到变量名后,找对应的调用方法,经过测试,save_translation
从名字和功能上比较贴近相关的实用场景:
找到函数后,寻找看是否有上层函数的传入和调用,最终在api.php
文件中找到一个调用,函数名pll_save_post_translations
适合我们的需求,且经过验证确实可用:
调用函数
找到函数并验证后,接下来就是使用这个函数。考虑到polylang插件未来是有可能升级的,我们尽可能不要对原插件进行编辑,于是我将如下的代码添加到了我的主题的funtions.php
文件的末尾,从而实现我需要添加的功能。
以下代码中值得一提的关键函数是add_action
和add_filter
,这是Wordpress的内置函数,从而使得我们可以对REST的API进行编辑,包括增加端点或对request/response进行数据截获和编辑(编写的时候如果你不会,同样的也可以寻求AI的帮助)。
//基于polylang添加自定义的API
add_action('rest_api_init', 'register_get_language');
function register_get_language() {
register_rest_route('pl', '/language', array(
'methods' => 'GET',
'callback' => 'get_language_by_post_id',
'args' => array(
'id' => array(
'required' => true,
'validate_callback' => function($param, $request, $key) {
return is_numeric($param);
}
),
),
'permission_callback' => '__return_true'
));
}
function get_language_by_post_id($request) {
// 获取请求中的参数 id
$post_id = $request->get_param('id');
// 检查 id 是否有效
if (empty($post_id) || !is_numeric($post_id)) {
return new WP_REST_Response(array(
'success' => false,
'message' => 'Invalid post ID.',
), 400); // 返回 400 错误
}
// 检查 Polylang 函数是否可用
if (!function_exists('pll_get_post_translations')) {
return new WP_REST_Response(array(
'success' => false,
'message' => 'Polylang plugin is not active or not installed.',
), 500); // 返回 500 错误
}
// 获取指定帖子的语言信息
$languages = pll_get_post_translations($post_id);
// 如果未找到语言信息
if (empty($languages)) {
return new WP_REST_Response(array(
'success' => false,
'message' => 'No language information found for the given post ID.',
), 404); // 返回 404 错误
}
// 返回语言信息
return new WP_REST_Response(array(
'success' => true,
'language' => $languages,
), 200); // 返回 200 成功
}
// 设置语言
add_filter('rest_pre_echo_response', 'save_post_translations', 10, 3);
function save_post_translations($response, $server, $request) {
// 检查是否为 /wp/v2/posts 的请求
if ($request->get_route() === '/wp/v2/posts') {
$from_id = $request->get_param('from_id');
if ($from_id){
// 检查 Polylang 函数是否可用
if (!function_exists('pll_save_post_translations')) {
return new WP_REST_Response(array(
'success' => false,
'message' => 'Polylang plugin is not active or not installed.',
), 500); // 返回 500 错误
}
// 检查提交的post语言格式
$languages = pll_get_post_language($response['id']);
pll_save_post_translations(array(
'zh' => $from_id,
$languages => $response['id']
));
}
}
return $response;
}
结果
最终我们在如上的代码中添加了两个API端点,来支持我们的功能,分别是/wp-json/pl/language?id={id}
和/wp-json/wp/v2/posts?from_id={id}
获取文章语言列表 /wp-json/pl/language?id={id}
当传入文章的ID时,服务端会返回这个ID关联的多语言的文章ID列表,从而可以用来判断是否需要进行翻译:
当文章的多语言都已经配置好时,不再进行下一步动作:
创建文章,并关联语言关系 /wp-json/wp/v2/posts?from_id={id}
当使用API创建文章时,带上原文ID,则自动绑定两者之间的语言关系:
发表回复