Skip to content

WPML Compatibility

The Remote Sync plugins are compatible with WPML, but there are a few important details to keep in mind for correct operation.

Product Mapping: Only Main Language

  • Sync table connections must be made only for products in the site's main language.
  • Translations should be created using WPML's "duplicate/copy" feature. WPML will automatically keep translated products in sync with changes made to the main language product.
  • The lock icon in the WPML UI indicates that only the main language product is editable, and all changes will be propagated by WPML.

WPML lock icon showing main language sync

WPML product translation table

Required Setting for Order Sync

To ensure order synchronization works correctly, you must set the following option in WPML, exactly as shown in the screenshot below:

WPML order sync setting

If this setting is not enabled, order sync may not function as expected across languages.

Syncing Translations via Hooks

In some cases, you may want to automatically sync translated content (like English titles) directly from the remote database during the import process. This can be achieved using the import_products hooks.

Example: Syncing English titles to WPML

This example uses a name_en meta value from the remote product data to update or create the WPML English translation.

/**
 * Sync English titles to WPML English translation.
 */
add_action( 'plugandpay_woocommerce_remote_sync_{remote_slug}_import_products_simple_end', 'my_prefix_sync_wpml_translation_simple', 10, 2 );
add_action( 'plugandpay_woocommerce_remote_sync_{remote_slug}_import_products_variable_end', 'my_prefix_sync_wpml_translation_variable', 10, 2 );

/**
 * Handler for Simple Products.
 *
 * @param int $wc_product_id WooCommerce product ID.
 * @param \PlugandPay\Remote_Sync\DTOs\Importable_Product_Data $remote_product Remote product data.
 */
function my_prefix_sync_wpml_translation_simple( int $wc_product_id, $remote_product ): void {

    $name_en = $remote_product->meta['name_en'] ?? '';

    if ( ! empty( $name_en ) ) {
        my_prefix_update_wpml_title_and_slug( $wc_product_id, $name_en );
    }

}

/**
 * Handler for Variable Products (fires once per group).
 *
 * @param int $wc_parent_product_id WooCommerce parent product ID.
 * @param \PlugandPay\Remote_Sync\DTOs\Importable_Product_Data[] $group The full remote product group.
 */
function my_prefix_sync_wpml_translation_variable( int $wc_parent_product_id, array $group ): void {

    // Parent translation uses the name_en meta from the first variation in the group.
    $name_en = $group[0]->meta['name_en'] ?? '';

    if ( ! empty( $name_en ) ) {
        my_prefix_update_wpml_title_and_slug( $wc_parent_product_id, $name_en );
    }

}

/**
 * Logic to update or create the WPML English translation.
 */
function my_prefix_update_wpml_title_and_slug( int $original_id, string $title_en ): void {

    $trid = apply_filters( 'wpml_element_trid', null, $original_id, 'post_product' );

    $translations = apply_filters( 'wpml_get_element_translations', null, $trid, 'post_product' );

    $en_id = $translations['en']->element_id ?? null;

    // If EN translation does not exist, create it
    if ( ! $en_id ) {

        $original_post = get_post( $original_id );

        if ( ! $original_post ) {
            return;
        }

        $en_id = wp_insert_post([
            'post_type'   => 'product',
            'post_status' => $original_post->post_status,
            'post_title'  => $title_en,
            'post_name'   => sanitize_title( $title_en ),
            'post_author' => $original_post->post_author,
        ]);

        if ( ! $en_id ) {
            return;
        }

        do_action( 'wpml_set_element_language_details', [
            'element_id'           => $en_id,
            'element_type'         => 'post_product',
            'trid'                 => $trid,
            'language_code'        => 'en',
            'source_language_code' => $translations[array_key_first($translations)]->language_code
        ]);
    } else {
        // Update title + slug only if it already existed
        wp_update_post([
            'ID'         => $en_id,
            'post_title' => $title_en,
            'post_name'  => sanitize_title( $title_en ),
        ]);
    }

}