TranslatePress Slug 翻译误开启后的清理与跳转方案

TranslatePress Slug 翻译误开启后的清理与跳转方案

现象

前段时间在排查一个 WordPress 多语言站点时,发现了一个比较典型的问题:TranslatePress 的 Slug 翻译功能被误开启了。

起因是用户在使用 TranslatePress 的过程中,不小心在设置里开启了 Slug Translation 功能。这个功能会自动将所有文章(Posts)、页面(Pages)、分类法(Taxonomy)的 URL slug 翻译成目标语言。结果当用户注意到这个问题时,已经有 135 个 slug 被自动翻译 成了西班牙语。

这个站点是英语 → 西班牙语的翻译配置。TranslatePress 默认的数据库表前缀是 trp_,但这个站点因为使用了自定义表前缀,实际表名为 test_trp_

虽然用户后来关闭了这个功能,但那 135 个翻译后的 slug 仍然残留在数据库中。这时候就面临一个问题:如果把翻译后的 slug 直接删掉,访问这些西语 URL 的用户会看到 404 吗?

TranslatePress 的数据存储

TranslatePress 使用以下数据库表来管理 slug 翻译:

主要表结构

表名 用途 记录数
`{prefix}_trp_slug_originals` 存储原始 slug(所有需要翻译的 slug) 136
`{prefix}_trp_slug_translations` 存储翻译后的 slug 135
`{prefix}_trp_dictionary_{lang_from}_{lang_to}` 存储内容翻译(页面文字等) 14,787
`{prefix}_trp_original_strings` 存储原始字符串 14,782
`{prefix}_trp_gettext_{lang}` 存储 gettext 翻译 274

Slug 翻译表结构

test_trp_slug_originals 表结构:

字段 类型 说明
id int 自增 ID
original varchar 原始 slug
type varchar 类型:post / taxonomy / other

test_trp_slug_translations 表结构:

字段 类型 说明
id int 自增 ID
original_id int 关联 originals 表的 ID
translated varchar 翻译后的 slug
language varchar 目标语言代码(如 es_ES)
status int 状态(1=已翻译)

查询已翻译的 Slug


global $wpdb;

// 查询所有原始 slug 及其翻译
$results = $wpdb->get_results("
  SELECT o.id, o.original, o.type, t.translated, t.language
  FROM {$wpdb->prefix}trp_slug_originals o
  LEFT JOIN {$wpdb->prefix}trp_slug_translations t
    ON o.id = t.original_id
  ORDER BY o.id
");

// 查看 TranslatePress 设置
$settings = get_option('trp_settings');

测试:删除翻译 slug 后会不会自动跳转

在决定怎么处理之前,先做一个关键测试:只删除一条翻译记录,看看 TranslatePress 有没有内置的自动跳转机制。

测试步骤

第 1 步:删除一条翻译记录


global $wpdb;
$deleted = $wpdb->delete(
  "test_trp_slug_translations",
  ['id' => 1]  // ventanas-abatibles-de-aluminio → aluminum-casement-windows
);

第 2 步:用 curl 测试西语 URL


curl -sI -o /dev/null -w "%{http_code} %{redirect_url}" \
  "https://example.com/ventanas-abatibles-de-aluminio/"

第 3 步:观察结果

返回结果:404 — 没有跳转,直接 404。

这说明 TranslatePress 没有内置的 301 自动回退机制。删除翻译 slug 后,对应的西语 URL 直接 404,必须手动创建跳转。

对比测试(跳转配置完成后)

等所有跳转规则配置好之后(详见下文),重新测试同样的 URL:


curl -sI -o /dev/null -w "%{http_code} %{redirect_url}" \
  "https://example.com/ventanas-abatibles-de-aluminio/"

此时返回:301 https://example.com/aluminum-casement-windows/

再测试另一个还在翻译表中的西语 slug:


curl -sI -o /dev/null -w "%{http_code} %{redirect_url}" \
  "https://example.com/ventanas-correderas-de-aluminio/"

同样返回 301,说明走的是手动配置的跳转规则,与翻译记录无关。

结论

TranslatePress 没有内置 slug 跳转机制。 删除翻译记录后必须自己配好 301,否则西语 URL 直接 404。正确的顺序是:先配跳转、再删记录、最后验证。

301 Redirects 插件的数据存储与使用

在排查过程中,顺便研究了 301 Redirects 插件的数据存储方式。如果你需要用插件来管理一对一跳转(而不是 .htaccess),这些信息会很有用。

301 Redirects 插件数据存储

这个免费插件(v2.84,来自 WebFactory Ltd)将跳转规则存储在自定义数据库表中,而不是 WordPress 的 options 表。

表名: {prefix}_redirects

字段 类型 说明
id mediumint (auto_increment) 主键
url_from varchar(1024) 来源 URL(要跳转的路径)
url_to varchar(1024) 目标 URL
status varchar(12) HTTP 状态码,默认 “301”
type varchar(12) 类型,”url” 表示 URL 跳转
count mediumint 跳转计数

相关 options:

option_name 说明
eps_redirects_redirects 跳转规则数组(旧版存储方式)
eps_redirects_404_log 404 错误日志
eps_redirects_404s 404 统计
eps_redirects_version 插件版本

注意: 免费版 不支持正则匹配(regex)。正则支持是 PRO 版的功能。

如何批量写入跳转规则

用 SQL 直接 INSERT:


global $wpdb;

$table = $wpdb->prefix . 'redirects';
$wpdb->insert($table, [
  'url_from' => 'ventanas-abatibles-de-aluminio',
  'url_to'   => '/aluminum-casement-windows/',
  'status'   => '301',
  'type'     => 'url',
  'count'    => 0,
]);

批量插入多条:


INSERT INTO wp_redirects (url_from, url_to, status, type, count)
VALUES
  ('ventanas-abatibles-de-aluminio', '/aluminum-casement-windows/', '301', 'url', 0),
  ('ventanas-correderas-de-aluminio', '/aluminium-sliding-windows/', '301', 'url', 0),
  ...

删除一条跳转规则:


global $wpdb;
$wpdb->delete($wpdb->prefix . 'redirects', ['id' => 123]);

查看现有跳转规则:


global $wpdb;
$redirects = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}redirects");

.htaccess 中的正则跳转

当免费版 301 Redirects 不支持正则时,可以用 .htaccess 的 RewriteRule 来处理需要正则匹配的跳转。

哪些场景需要正则跳转

slug 翻译中有几种类型不是一对一的,而是 base slug 的翻译:

原始 base slug 翻译后 影响范围
`author` → `autor` 所有作者归档页 `/autor/kimmy/` → `/author/kimmy/`
`category` → `categoria` 所有分类归档页 `/categoria/blog/` → `/category/blog/`
`page` → `pagina` 所有分页 URL `/post/pagina/2/` → `/post/page/2/`

.htaccess 规则写法


# 放在 # BEGIN WordPress 之前(优先级最高)

  RewriteEngine On
  
  # Author base slug: /autor/xxx → /author/xxx
  RewriteRule ^autor/(.+)$ /author/$1 [R=301,L]
  
  # Category base slug: /categoria/xxx → /category/xxx  
  RewriteRule ^categoria/(.+)$ /category/$1 [R=301,L]
  
  # Page base slug: /xxx/pagina/N → /xxx/page/N
  RewriteRule ^(.+)/pagina/(\d+)$ /$1/page/$2 [R=301,L]

注意: 这些规则要放在 WordPress 的 # BEGIN WORDDDRESS ... # END WordPress 区块之前。因为 WordPress 的规则是 fallthrough 到 index.php,如果放后面可能永远不会匹配到。

规则解释

  • ^autor/(.+)$ — 匹配以 /autor/ 开头的 URL,捕获后面的路径部分
  • $1 — 正则中的第一个捕获组
  • [R=301,L] — R=301 表示 301 重定向,L 表示这是最后一条规则(不再继续匹配)

通过 PHP 写入 .htaccess


// 在 WordPress 的 rewrite 规则之前插入自定义规则
add_action('generate_rewrite_rules', function($wp_rewrite) {
  $new_rules = [
    '^autor/(.+)$' => 'index.php?author_name=$matches[1]',
  ];
  $wp_rewrite->rules = $new_rules + $wp_rewrite->rules;
});

不过更直接的方式是用 file_get_contents + file_put_contents 编辑 .htaccess 文件。

完整处理流程总结

  1. 发现阶段:用 SHOW TABLES LIKE '%trp%'get_option('trp_settings') 检查 slug 翻译状态
  2. 评估阶段:查询 trp_slug_translations 统计有多少 slug 被翻译,区分出”一对一”的页面 slug 和”一对多”的 base slug
  3. 测试阶段:删一条记录 → curl 验证是否自动跳转(实测返回 404,TranslatePress 无内置跳转)
  4. 配置跳转阶段:先配置好所有需要的 301 跳转——base slug 走 .htaccess RewriteRule,其他走 301 Redirects 插件
  5. 验证阶段:curl 确认跳转生效
  6. 清理阶段:DELETE 所有 trp_slug_translations 记录

关键经验

  • TranslatePress 没有 slug 自动跳转,删除记录后西语 URL 直接 404,必须手动配跳转
  • 免费版 301 Redirects 不支持正则,base slug 类的跳转需要 .htaccess
  • 先测跳转机制、再配规则、再删记录、最后验证,这个顺序不能乱
  • 操作前备份数据库永远是好的习惯
发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

或许还会想看: