You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPML自动复制次要语言至其他次要语言:经典编辑器失效排查

WPML多语言内容自动同步问题

背景

我们通过WPML实现域名与独立语言绑定:.at域名对应德语AT版本,.de域名对应德语DE版本,英文设为默认回退语言(需保留该设置,其他语言域名依赖其作为回退)。但WPML不支持为次要语言设置不同回退语言,仅能手动复制内容,操作耗时,因此编写了自动同步代码。

现有代码

function duplicate_wpml_language_on_update( $post_id, $post ) {
    global $sitepress;
    if ( defined( 'ICL_LANGUAGE_CODE' ) && $sitepress->is_translated_post_type( $post->post_type ) ) {
        switch (ICL_LANGUAGE_CODE) {
            case 'fr':
                wp_schedule_single_event( time(), 'duplicate_post', array( $post_id, $post, 'frbe' ) );
                break;
            case 'de':
                wp_schedule_single_event( time(), 'duplicate_post', array( $post_id, $post, 'deat' ) );
        }
    }
}
add_action( 'save_post', 'duplicate_wpml_language_on_update', 10, 2 );
add_action( 'woocommerce_update_product', 'duplicate_wpml_language_on_update', 10, 2 );
add_action( 'wpml_pro_translation_completed', 'duplicate_wpml_language_on_update', 10, 2 );
add_action( 'icl_pro_translation_completed', 'duplicate_wpml_language_on_update', 10, 2 );
add_action( 'wpml_save_translation_data', 'duplicate_wpml_language_on_update', 10, 2 );

function duplicate_post( $post_id, $post, $lang ) {
    global $sitepress;
    $trid = $sitepress->get_element_trid( $post_id, 'post_' . $post->post_type );
    $translations = $sitepress->get_element_translations( $trid, 'post_' . $post->post_type );

    if ( isset( $translations[$lang] ) ) {
        $target_post_id = $translations[$lang]->element_id;
        $duplicate_of = get_post_meta( $target_post_id, '_icl_lang_duplicate_of', true );
        if ( $duplicate_of ) {
            // Duplicate to $lang
            $target_post_id = $sitepress->make_duplicate( $post_id, $lang );
        }
    } 
}
add_action( 'duplicate_post', 'duplicate_post', 10, 3 );

问题

代码在WordPress默认编辑器中正常工作,可将内容同步至目标次要语言;但使用WPML经典翻译编辑器时完全失效。推测是钩子未触发,已尝试多个钩子仍未解决。若钩子已触发,未发现代码逻辑问题——同一文章的所有语言版本应共享相同trid,_icl_lang_duplicate_of功能也保持一致。需确认:

  1. 代码是否存在错误?
  2. 若代码无问题,是否有其他实现方式,或可触发WPML经典编辑器保存操作的钩子?

解答

一、代码逻辑问题排查

  1. ICL_LANGUAGE_CODE取值偏差:WPML经典翻译编辑器中,ICL_LANGUAGE_CODE指向当前编辑的翻译语言,而非原始文章语言。例如编辑法语翻译时,该常量为fr,但代码仅在fr时触发同步至frbe,若编辑的是frbe的翻译则不会触发,逻辑应调整为监听原始语言文章的更新。
  2. 定时任务的不可靠性:wp_schedule_single_event依赖WP Cron,后台编辑器操作时可能因Cron未及时运行导致同步失败,建议直接调用同步函数而非延迟执行。
  3. 同步触发条件过严:代码仅在目标语言文章已是副本(存在_icl_lang_duplicate_of元数据)时执行同步,首次创建目标语言文章时无法触发,应改为只要原始文章更新,就同步目标语言内容(无论目标文章是否为副本)。

修改后的核心代码示例:

function duplicate_wpml_language_on_update( $post_id, $post ) {
    global $sitepress;
    // 排除自动保存和修订版
    if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
        return;
    }
    if ( !defined( 'ICL_LANGUAGE_CODE' ) || !$sitepress->is_translated_post_type( $post->post_type ) ) {
        return;
    }
    // 获取当前文章的实际语言代码
    $current_lang = $sitepress->get_element_language_code( $post_id, 'post_' . $post->post_type );
    // 定义语言映射规则
    $lang_mappings = array(
        'fr' => 'frbe',
        'de' => 'deat'
    );
    if ( isset( $lang_mappings[$current_lang] ) ) {
        // 直接调用同步函数,取消定时任务
        duplicate_post( $post_id, $post, $lang_mappings[$current_lang] );
    }
}

function duplicate_post( $post_id, $post, $target_lang ) {
    global $sitepress;
    $trid = $sitepress->get_element_trid( $post_id, 'post_' . $post->post_type );
    $translations = $sitepress->get_element_translations( $trid, 'post_' . $post->post_type );
    
    $target_post_id = null;
    // 检查目标语言是否已有翻译
    if ( isset( $translations[$target_lang] ) ) {
        $target_post_id = $translations[$target_lang]->element_id;
    } else {
        // 无翻译则创建新副本
        $target_post_id = $sitepress->make_duplicate( $post_id, $target_lang );
    }
    if ( $target_post_id ) {
        // 同步核心文章内容
        $post_data = array(
            'ID' => $target_post_id,
            'post_title' => $post->post_title,
            'post_content' => $post->post_content,
            'post_excerpt' => $post->post_excerpt,
            'post_status' => $post->post_status
        );
        wp_update_post( $post_data );
        // 同步自定义字段(排除WPML专属字段)
        $custom_fields = get_post_custom( $post_id );
        foreach ( $custom_fields as $key => $values ) {
            if ( strpos( $key, '_icl_' ) !== false ) {
                continue;
            }
            delete_post_meta( $target_post_id, $key );
            foreach ( $values as $value ) {
                add_post_meta( $target_post_id, $key, $value );
            }
        }
    }
}

二、适配WPML经典编辑器的钩子

若需通过钩子触发同步,以下钩子适配经典翻译编辑器的保存流程:

  • wpml_translation_saved:WPML翻译保存时触发,传递翻译后文章ID和原始文章ID。
  • icl_after_save_translation:翻译保存完成后触发,包含翻译元素详情。
  • wpml_post_translation_updated:文章翻译更新时触发,适合监听翻译内容变更。

示例使用wpml_translation_saved钩子:

add_action( 'wpml_translation_saved', 'handle_wpml_classic_editor_save', 10, 2 );
function handle_wpml_classic_editor_save( $translation_id, $original_post_id ) {
    global $sitepress;
    $original_post = get_post( $original_post_id );
    $current_lang = $sitepress->get_element_language_code( $original_post_id, 'post_' . $original_post->post_type );
    $lang_mappings = array(
        'fr' => 'frbe',
        'de' => 'deat'
    );
    if ( isset( $lang_mappings[$current_lang] ) ) {
        duplicate_post( $original_post_id, $original_post, $lang_mappings[$current_lang] );
    }
}

三、其他实现思路

  1. 调用WPML内置函数:使用wpml_copy_post函数直接执行复制操作,提升兼容性。
  2. 添加手动同步按钮:在WPML翻译编辑器中添加AJAX触发的同步按钮,适合需要手动控制的场景。

内容的提问来源于stack exchange,提问作者Digital Lion

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 03:09:27