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功能也保持一致。需确认:
- 代码是否存在错误?
- 若代码无问题,是否有其他实现方式,或可触发WPML经典编辑器保存操作的钩子?
解答
一、代码逻辑问题排查
ICL_LANGUAGE_CODE取值偏差:WPML经典翻译编辑器中,ICL_LANGUAGE_CODE指向当前编辑的翻译语言,而非原始文章语言。例如编辑法语翻译时,该常量为fr,但代码仅在fr时触发同步至frbe,若编辑的是frbe的翻译则不会触发,逻辑应调整为监听原始语言文章的更新。- 定时任务的不可靠性:
wp_schedule_single_event依赖WP Cron,后台编辑器操作时可能因Cron未及时运行导致同步失败,建议直接调用同步函数而非延迟执行。 - 同步触发条件过严:代码仅在目标语言文章已是副本(存在
_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] ); } }
三、其他实现思路
- 调用WPML内置函数:使用
wpml_copy_post函数直接执行复制操作,提升兼容性。 - 添加手动同步按钮:在WPML翻译编辑器中添加AJAX触发的同步按钮,适合需要手动控制的场景。
内容的提问来源于stack exchange,提问作者Digital Lion
相关产品推荐
相关产品推荐

