没有不值得去解决的问题,也没有不值得去学习的技术!

WordPress 经典编辑器代码块无损迁移:批量转换 SyntaxHighlighter 短代码为 Gutenberg 区块

WordPress AI 翻译工程实战

WordPress 经典编辑器代码块无损迁移:批量转换 SyntaxHighlighter 短代码为 Gutenberg 区块

(1) WordPress 经典编辑器代码块无损迁移:批量转换 SyntaxHighlighter 短代码为 Gutenberg 区块

点击翻译按钮后,遇到一个弹窗“神秘”闪退问题及解决方法

(2) 点击翻译按钮后,遇到一个弹窗“神秘”闪退问题及解决方法

图5:DeepL API 注册页面,国家或地区列表中没有中国大陆

(3) 中国大陆 WordPress 博客想提升英文翻译质量,为什么这么麻烦?一次 Polylang + AutoPoly + DeepL API 排查复盘

图5:DeepSeek 的评分结果截图

(4) Chrome Built-in AI、Yandex Translate、ChatGPT Plus 翻译质量对比:我为什么决定重点英文文章改用 ChatGPT Plus

[截图 2:浏览器 Network 中直接请求 translate.yandex.net]

(5) 从 AutoPoly 到 Yandex 网页版:一次 WordPress 英文自动翻译质量验证

【图1:AutoPoly Free 与 Pro 功能对比截图】

(6) AutoPoly Pro + OpenAI API 能否自动化 WordPress 英文翻译?一次从技术到支付的可行性分析

【图2:点击“立即试用”后,ChatGPT 输入框中出现“代理模式”】

(7) ChatGPT Agent 能否替代 ChatGPT Plus 完成 WordPress 英文重译?

【图 7,SlyTranslate 显示翻译完成并创建文章 19426】

(8) SlyTranslate + 智谱 GLM-5.2 长文翻译排障:从 600 秒超时到完整生成英文 WordPress 文章

【图 5,54 个代码块精确匹配、差异数量为 0】

(9) WordPress SlyTranslate + GLM-5.2 长文单次翻译实战:排查 invalid_translation_runaway_output 假失败

【图 2,SlyTranslate 的 Additional Instructions 保持为空】

(10) SlyTranslate + GLM-5.2 翻译质量继续优化:从关闭随机采样、内置提示词到深度思考与模型 A/B 测试

【图6,终端中的完整测试结果】

(11) 在 GLM 5.2 之后测试 DeepSeek:一次面向 WordPress 长文翻译的模型对比与取舍

【图 4,“英文博客翻译质量优化”项目中已经整理完成的会话列表】

(12) 为英文博客翻译质量优化建立独立 ChatGPT 项目:整理历史会话并统一后续评测标准

【图3:Gemini 3.5 Flash 首次成功调用结果】

(13) 暂缓 OpenAI 后,我在本地测试了 Gemini:与 GLM 5.2 的 WordPress 技术文章翻译对比

图3:清理英文 Host 下的对象与术语关系缓存后,英文文章重新显示 SEO Tools、Yoast SEO 和 Blog SEO Log

(14) 为 SlyTranslate 的 GLM 5.2 整篇翻译补上 Plaintext 智能处理,并修复 Code Block Pro 区块失效

图5:英文文章发布后,前台特色图片、分类、标签和 Series 顺序均正常

(15) SlyTranslate + GLM-5.2 翻译 WordPress 长文章后,分类、标签、Series 与特色图片同步问题排查

图1:Codex 输出 Token 校验诊断结果

(16) SlyTranslate 全文翻译报错排查:完善 GLM 5.2 的段落与占位符约束

图1:创建 wordpress-ai-translation-pipeline 私有 GitHub 仓库

(17) 将 WordPress AI 翻译优化项目提交到 GitHub:一次阶段性的收尾

图1:文章列表中因摘要为空而重复出现两个 Post Views

(18) 从空摘要、历史格式混杂到重新翻译:我如何规划 WordPress AI 翻译工程的下一阶段

图4:最终批处理输出 42/42 完成、待处理 0、异常状态 0。

(19) 从只读审计到 42/42 完成:用 GLM 与 SlyTranslate 安全补全 WordPress 历史文章摘要

一、发现问题

最近我在使用 Polylang + AutoPoly 插件对博客进行多语言翻译时,发现一个奇怪的现象:

– 用 Gutenberg 编辑器插入的代码块(SyntaxHighlighter 区块),翻译后的英文文章中代码格式完好无损,缩进、尖括号等都正常。

– 而用经典编辑器通过短代码插入的代码块,例如 `php`,翻译后却出现了严重的问题:尖括号被转义成 `<` 和 `>`,缩进丢失,甚至代码结构被破坏。(如图1、图2)

用经典编辑器通过短代码插入的代码块,例如 `[php]...[/php]`,翻译后却出现了严重的问题:尖括号被转义成 `<` 和 `>`,缩进丢失,甚至代码结构被破坏。(如图1)

用经典编辑器通过短代码插入的代码块,例如 `[php]...[/php]`,翻译后却出现了严重的问题:尖括号被转义成 `<` 和 `>`,缩进丢失,甚至代码结构被破坏。(如图2)

经过对比分析,我找到了根本原因:AutoPoly 翻译插件在解析文章内容时,能够正确识别 Gutenberg 的区块标记(

wp:syntaxhighlighter/code

),从而不对其内部代码进行翻译或转义处理;但对于经典编辑器中的短代码(`php` 等),插件无法准确判断其边界,于是试图翻译短代码内的内容,导致代码被破坏。(如图3)

对于经典编辑器中的短代码(`[php][/php]` 等),插件无法准确判断其边界,于是试图翻译短代码内的内容,导致代码被破坏。(如图3)

二、手动验证替换方案

为了确认解决方案是否可行,我决定先手动对一篇文章进行测试。我选择了一篇包含 `php` 代码块的中文文章,在代码编辑器中将短代码手动替换为 Gutenberg 区块标记。

原始短代码形式:(如图4)

原始短代码形式:(如图4)

替换后的 Gutenberg 区块标记:(如图5)

替换后的 Gutenberg 区块标记:(如图5)

保存文章后,我删除了对应的英文文章,并让 AutoPoly 重新翻译。结果令人满意:新生成的英文文章中,代码块格式与中文完全一致,没有出现任何转义或错乱。(如图7、图9)

保存文章后,我删除了对应的英文文章,并让 AutoPoly 重新翻译。结果令人满意:新生成的英文文章中,代码块格式与中文完全一致,没有出现任何转义或错乱。(如图7)

保存文章后,我删除了对应的英文文章,并让 AutoPoly 重新翻译。结果令人满意:新生成的英文文章中,代码块格式与中文完全一致,没有出现任何转义或错乱。(如图7)

我又用 pythongotext 等短代码分别进行了同样的手动测试,结果全部通过。这证明:将短代码替换为 Gutenberg 区块标记,可以彻底解决翻译时代码块被破坏的问题。

然而,我有数百篇文章使用了经典编辑器,逐个手动替换显然不现实。于是我决定编写一个批量处理方案。经过研究,我实现了“PHP 函数 + WordPress 批量操作”的方法,可以在文章列表页手动勾选需要转换的文章,一键完成替换。

下面将完整方案分享给大家。

三、解决方案概述

将文章中所有 SyntaxHighlighter 短代码(如 phppython)批量转换为 Gutenberg 区块标记,然后让翻译插件重新生成英文文章。该方法支持 30+ 种编程语言,并能自动处理别名映射(如 golang → go、javascript → js)。

四、操作步骤

第一步:备份数据库(非常重要)

在进行任何批量操作前,请务必备份你的 WordPress 数据库。推荐使用 UpdraftPlus 插件,或在主机管理面板的 phpMyAdmin 中导出。

第二步:将以下代码添加到主题的 functions.php

登录 WordPress 后台,进入 外观 → 主题文件编辑器,找到 functions.php 文件,将下面的代码粘贴到文件末尾(注意:如果文件末尾已有 ?> 标记,请把代码放在 ?> 之前)。(如图12)

登录 WordPress 后台,进入 外观 → 主题文件编辑器,找到 functions.php 文件,将下面的代码粘贴到文件末尾(注意:如果文件末尾已有 ?> 标记,请把代码放在 ?> 之前)。(如图12)
// 添加批量操作选项
function add_bulk_operation_convert_shortcode( $bulk_actions ) {
    $bulk_actions['convert_shortcode_to_block'] = '转换短代码为区块';
    return $bulk_actions;
}
add_filter( 'bulk_actions-edit-post', 'add_bulk_operation_convert_shortcode' );

function handle_bulk_operation_convert_shortcode( $sendback, $action, $post_ids ) {
    if ( $action !== 'convert_shortcode_to_block' ) return $sendback;
    global $wpdb;
    
    $languages = ['bash','shell','cpp','c','css','go','golang','java','js','javascript','perl','pl','php','plain','text','ps','powershell','python','ruby','sql','xml','xhtml','html','yaml','lua'];
    $converted_count = 0;
    $skipped_count = 0;
    
    foreach ( $post_ids as $post_id ) {
        $post = get_post( $post_id );
        if ( ! $post ) continue;
        
        $old_content = $post->post_content;
        $new_content = $old_content;
        $changed = false;
        
        foreach ( $languages as $lang ) {
            $open  = '[' . $lang . ']';
            $close = '[/' . $lang . ']';
            $pos = 0;
            while ( ($open_pos = strpos( $new_content, $open, $pos )) !== false ) {
                $close_pos = strpos( $new_content, $close, $open_pos );
                if ( $close_pos === false ) break;
                
                $code_start = $open_pos + strlen( $open );
                $code = substr( $new_content, $code_start, $close_pos - $code_start );
                $code = html_entity_decode( $code, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
                
                if ( in_array( $lang, ['text','plain'] ) ) {
                    $block = "<!-- wp:syntaxhighlighter/code -->\n<pre class=\"wp-block-syntaxhighlighter-code\">\n{$code}\n</pre>\n<!-- /wp:syntaxhighlighter/code -->";
                } else {
                    $alias = $lang;
                    if ( $alias === 'golang' )    $alias = 'go';
                    if ( $alias === 'javascript' ) $alias = 'js';
                    if ( $alias === 'pl' )        $alias = 'perl';
                    $block = "<!-- wp:syntaxhighlighter/code {\"language\":\"{$alias}\"} -->\n<pre class=\"wp-block-syntaxhighlighter-code\">\n{$code}\n</pre>\n<!-- /wp:syntaxhighlighter/code -->";
                }
                
                $new_content = substr_replace( $new_content, $block, $open_pos, $close_pos + strlen( $close ) - $open_pos );
                $changed = true;
                $pos = $open_pos + strlen( $block );
            }
        }
        
        if ( $changed ) {
            $wpdb->update( $wpdb->posts, ['post_content' => $new_content], ['ID' => $post_id], ['%s'], ['%d'] );
            $converted_count++;
        } else {
            $skipped_count++;
        }
    }
    
    $sendback = add_query_arg( ['converted_count' => $converted_count, 'skipped_count' => $skipped_count], $sendback );
    return $sendback;
}
add_filter( 'handle_bulk_actions-edit-post', 'handle_bulk_operation_convert_shortcode', 10, 3 );

function bulk_operation_convert_shortcode_notices() {
    if ( isset( $_REQUEST['converted_count'] ) || isset( $_REQUEST['skipped_count'] ) ) {
        $converted = intval( $_REQUEST['converted_count'] ?? 0 );
        $skipped   = intval( $_REQUEST['skipped_count'] ?? 0 );
        echo '<div class="notice notice-success is-dismissible"><p>' .
             sprintf( '转换完成!%d 篇文章已更新,%d 篇文章无需更新。', $converted, $skipped ) .
             '</p></div>';
    }
}
add_action( 'admin_notices', 'bulk_operation_convert_shortcode_notices' );

更新文件。

第三步:在文章列表页执行批量转换

1. 刷新 WordPress 后台的“所有文章”页面。

2. 勾选你需要转换的文章(可以多选)。(如图13)

3. 在顶部的“批量操作”下拉菜单中,选择“转换短代码为区块”。

4. 点击“应用”按钮。

勾选你需要转换的文章(可以多选)。(如图13)

系统会自动处理,完成后会在页面顶部显示转换结果(例如:转换完成!1 篇文章已更新,0 篇文章无需更新。)。

第四步:排坑记录:反斜杠丢失与 `>` 双重转义

在实现批量转换的过程中,我遇到了三个典型的“陷阱”,花了不少时间才彻底解决。记录下来,希望能帮助遇到类似问题的读者。

坑一:反斜杠 `\` 神秘失踪

我的测试文章中有一段 PowerShell 路径:`PS E:\wwwroot\object> bash test.sh`。执行批量转换后,反斜杠全部消失了,变成了 `PS E:wwwrootobject> bash test.sh`。

经过反复排查,原因出在两个方面:

1. 正则表达式:使用 `preg_replace_callback` 配合 `(.*?)` 捕获代码内容时,PHP 的正则引擎会对反斜杠进行转义处理。如果原始内容中包含 `\w` 这类组合,可能会被解释为转义序列而丢失。

2. WordPress 自动转义:使用 `wp_update_post` 保存文章时,WordPress 会自动调用 `wp_slash` 对内容中的反斜杠再次转义,导致保存后变成双反斜杠或直接丢失。

解决方案:放弃正则表达式,改用 `strpos` + `substr_replace` 进行字符串查找替换。同时,使用 `$wpdb->update` 直接写入数据库,完全绕过 `wp_update_post` 的自动转义机制。

坑二:`>` 变成 `&gt;`

代码块中常见的 `>`(表示大于号)在转换后变成了 `&gt;`,浏览器显示为 `>` 文本而不是 `>`。

原因是:原始文章内容中的 `>` 是 HTML 实体,在保存到数据库时,WordPress 或浏览器会将 `&` 字符转义为 `&`,从而导致双重转义。

解决方案:在生成 Gutenberg 区块之前,对捕获到的代码内容执行一次 `html_entity_decode`,将所有 HTML 实体还原为原始字符。这样保存后,`>` 就变成了 `>`,浏览器能正确显示为 `>`。

最终代码要点:
– 字符串查找替换(避免正则反斜杠问题)
– `html_entity_decode`(解决实体双重转义)
– `$wpdb->update`(绕过 WordPress 自动斜杠处理)

经过以上修正,批量转换后的代码块格式完整,反斜杠和特殊符号均能正确保留。

坑三:批量转换后的代码块格式符合预期,但是在网页中的一些代码块中会显示 `wp-block-syntaxhighlighter-code`。在代码编辑器中查看,未发现问题。如图16

批量转换后的代码块格式符合预期,但是在网页中的一些代码块中会显示 `wp-block-syntaxhighlighter-code`。在代码编辑器中查看,未发现问题。如图16

在 可视化编辑器 中查看 。提示:区块包含未预料的或无效的内容。点击 尝试恢复,恢复后的代码与原始代码不一致。

原始代码如下:

<?php
 
use yii\db\Migration;
 
/**
 * Class m180620_105204_update_table_options_to_log
 */
class m180620_105204_update_table_options_to_log extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function safeUp()
    {
        $tableOptions = null;
        if ($this->db->driverName === 'mysql') {
            // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
            $tableOptions = 'CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE=InnoDB';
            $this->execute('ALTER TABLE {{%user}} ROW_FORMAT=DYNAMIC');
            $this->execute('ALTER TABLE {{%user}} CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci');
            $this->execute('ALTER TABLE {{%log}} ROW_FORMAT=DYNAMIC');
            $this->execute('ALTER TABLE {{%log}} CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci');
        }
 
        $this->addCommentOnTable('{{%user}}', '用户', $tableOptions);
        $this->addCommentOnTable('{{%log}}', '日志', $tableOptions);
    }
 
    /**
     * {@inheritdoc}
     */
    public function safeDown()
    {
        echo "m180620_105204_update_table_options_to_log cannot be reverted.\n";
 
        return false;
    }
 
    /*
    // Use up()/down() to run migration code without a transaction.
    public function up()
    {
 
    }
 
    public function down()
    {
        echo "m180620_105204_update_table_options_to_log cannot be reverted.\n";
 
        return false;
    }
    */
}

恢复后的代码如下,一些代码丢失:


db->driverName === 'mysql') {
            // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
            $tableOptions = 'CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE=InnoDB';
            $this->execute('ALTER TABLE {{%user}} ROW_FORMAT=DYNAMIC');
            $this->execute('ALTER TABLE {{%user}} CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci');
            $this->execute('ALTER TABLE {{%log}} ROW_FORMAT=DYNAMIC');
            $this->execute('ALTER TABLE {{%log}} CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci');
        }

        $this->addCommentOnTable('{{%user}}', '用户', $tableOptions);
        $this->addCommentOnTable('{{%log}}', '日志', $tableOptions);
    }

    /**
     * {@inheritdoc}
     */
    public function safeDown()
    {
        echo "m180620_105204_update_table_options_to_log cannot be reverted.\n";

        return false;
    }

    /*
    // Use up()/down() to run migration code without a transaction.
    public function up()
    {

    }

    public function down()
    {
        echo "m180620_105204_update_table_options_to_log cannot be reverted.\n";

        return false;
    }
    */
}




临时解决方案为 从网页源代码中复制原始代码至 可视化编辑器 中,保存。

第五步:移除临时代码

批量转换完成后,请务必回到 functions.php,删除刚才添加的所有代码。这样做有两个好处:

– 避免日后误操作;

– 保持主题文件的整洁。

第六步:重新生成翻译文章

如果你使用了 Polylang + AutoPoly:

1. 删除之前因短代码问题导致的英文文章(或将其移至回收站)。

2. 重新执行翻译(AutoPoly 会自动根据新的中文文章内容生成英文版本)。

3. 此时你会发现,英文文章中的代码块格式与中文完全一致,不会再出现转义或错乱问题。

五、支持的语言列表

代码中已包含以下语言(可根据需要自行增删):

bash, shell, cpp, c, css, go, golang, java, js, javascript, perl, pl, php, plain, text, ps, powershell, python, ruby, sql, xml, xhtml, html, yaml, lua

注意:plain 和 text 会转换为不指定 language 属性的纯文本块;golang 自动映射为 go,javascript 映射为 js,pl 映射为 perl。

六、常见问题

Q1:执行批量操作后,文章内容没有变化?

可能文章本身没有使用短代码,或者短代码的语言标签不在支持列表中。可以检查代码中的 $languages 变量,确保已包含你使用的所有标签。

Q2:转换后代码块的语法高亮失效?

请确保你仍然安装了 SyntaxHighlighter Evolved 插件,并且版本支持 Gutenberg 区块。该插件从 3.x 版本开始已经兼容区块编辑器。

Q3:我的代码块是 code 这种无语言标签的形式,怎么办?

你可以将代码中的语言列表改为 code,然后在替换回调中统一处理为不带 language 属性的区块。

Q4:能不能只替换特定分类下的文章?

可以。在第三步“勾选文章”时,你可以先通过分类筛选,然后全选当前分页,再执行批量操作。

七、总结

通过 PHP 函数 + WordPress 原生批量操作,我们实现了对经典编辑器中 SyntaxHighlighter 短代码的精准、批量转换。整个过程无需安装额外插件,安全可控,完美解决了多语言翻译时代码块格式错乱的问题。

点击翻译按钮后,遇到一个弹窗“神秘”闪退问题及解决方法

需要长期技术维护或远程问题排查?

我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。

如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:

  • ✅ PHP / Laravel / Yii2 老项目无人维护
  • ✅ Go / Gin 后端接口需要排查或优化
  • ✅ WordPress 网站访问慢、报错或插件冲突
  • ✅ Nginx / MySQL / Redis / Linux 服务器异常
  • ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
  • ✅ 需要长期远程技术支持或兼职维护

更多介绍请查看:关于我 & 合作

微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan

评论

发表回复

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

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理