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 有没有内置的自动跳转机制。

删掉第一条翻译记录(ventanas-abatibles-de-aluminioaluminum-casement-windows):


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

然后用 curl 测一下西语 URL:


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

返回结果: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),这些信息会很有用。

这个免费插件(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 之前(优先级最高)
<IfModule mod_rewrite.c>
  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]
</IfModule>

注意: 这些规则要放在 WordPress 的 # BEGIN WORDPRESS ... # 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
  • 先测跳转机制、再配规则、再删记录、最后验证,这个顺序不能乱
  • 操作前备份数据库永远是好的习惯
发表回复

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

或许还会想看: