Search code examples
phpwordpresswoocommerceproductwpml

Change Woocommerce products sale price programatiaclly syncing WPML translations


I want to change discounts (sale price) for products in certain category, but no matter what i try the code:

  1. works well only in the parent category
  2. unfortunately for translations of the same category sets discounts for completely different products
  3. applies discounts in translations multiplied by the exchange rate (example: for exchange rate 4:1 a 10% discount becomes 40% discount for a product valued 100)

How to make it change the same products and keep the same price among WPML/WCML translations? thank you for any advice

///automatic randomized discounts 
// Define a custom 1-minute interval
function custom_1_minute_interval($schedules) {
    $schedules['1minute'] = array(
        'interval' => 60, // 1 minute in seconds
        'display'  => __('Every 1 Minute'),
    );
    return $schedules;
}
add_filter('cron_schedules', 'custom_1_minute_interval');

// Schedule the event to run the custom function every 1 minute
add_action('init', 'schedule_custom_function');

function schedule_custom_function() {
    if (!wp_next_scheduled('every_1_minute_custom_function')) {
        wp_schedule_event(time(), '1minute', 'every_1_minute_custom_function');
    }
}

add_action('every_1_minute_custom_function', 'custom_function_to_manage_discounts');

function custom_function_to_manage_discounts() {
    // Define the log file
    $log_file = WP_CONTENT_DIR . '/promo.log';

    // Open the log file for writing (creates a new file if it doesn't exist)
    $log_handle = fopen($log_file, 'a');

    // Check if the log file was successfully opened
    if ($log_handle) {
        // Log a timestamp indicating the start of the custom function
        fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function started." . PHP_EOL);

        // Get all products in category ID 29 for the original language version
        $category_id = 29;
        $args = array(
            'post_type' => 'product',
            'posts_per_page' => -1,
            'tax_query' => array(
                array(
                    'taxonomy' => 'product_cat',
                    'field'    => 'id',
                    'terms'    => $category_id,
                    'include_children' => true,
                ),
            ),
        );

        $products = get_posts($args);

        if ($products) {
            // Log the product IDs retrieved from the category
            $product_ids_list = array();
            foreach ($products as $product) {
                $product_ids_list[] = $product->ID;
            }
            fwrite($log_handle, date('[d-M-Y H:i:s]') . " Product IDs Retrieved from Category ID {$category_id}: " . implode(', ', $product_ids_list) . PHP_EOL);

            // Calculate the number of products to apply discounts to (25% of total)
            $discount_count = ceil(0.25 * count($products));

            // Shuffle the products array randomly
            shuffle($products);

            // Iterate through products to clear discounts for all
            foreach ($products as $product) {
                // Get the product object
                $product_obj = wc_get_product($product->ID);

                // Clear discount price (sale price)
                $product_obj->set_sale_price('');
                $product_obj->set_date_on_sale_from('');
                $product_obj->set_date_on_sale_to('');

                // Log the action in the log file
                fwrite($log_handle, date('[d-M-Y H:i:s]') . " Cleared discount for Product ID: {$product->ID}" . PHP_EOL);

                // Save the product to trigger WooCommerce cache refresh
                $product_obj->save();
            }

            // Apply discounts to a random 25% of products
            for ($i = 0; $i < $discount_count; $i++) {
                $product = $products[$i];

                // Get the regular price
                $regular_price = get_post_meta($product->ID, '_regular_price', true);

                // Calculate the new discount price (90% of the regular price)
                $new_discount_price = $regular_price * 0.9;

                // Get the product object
                $product_obj = wc_get_product($product->ID);

                // Set the new discount price (sale price)
                $product_obj->set_sale_price($new_discount_price);
                $product_obj->set_date_on_sale_from(time());

                // Calculate the new price as a separate variable
                $new_price = $regular_price * 0.9;

                // Log the action in the log file with the new price
                fwrite($log_handle, date('[d-M-Y H:i:s]') . " Applied discount for Product ID: {$product->ID}, New Price: {$new_price}" . PHP_EOL);

                // Save the product to trigger WooCommerce cache refresh
                $product_obj->save();
            }
        }

        // Log a timestamp indicating the completion of the custom function
        fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function completed." . PHP_EOL);

        // Close the log file
        fclose($log_handle);
    }
}

Update: Code which works on my staging but not production:

// Define a custom 1-minute interval
function custom_1_minute_interval($schedules) {
    $schedules['1minute'] = array(
        'interval' => 60, // 1 minute in seconds
        'display'  => __('Every 1 Minute'),
    );
    return $schedules;
}
add_filter('cron_schedules', 'custom_1_minute_interval');

// Schedule the event to run the custom function every 1 minute
add_action('init', 'schedule_custom_function');

function schedule_custom_function() {
    if (!wp_next_scheduled('every_1_minute_custom_function')) {
        wp_schedule_event(time(), '1minute', 'every_1_minute_custom_function');
    }
}

add_action('every_1_minute_custom_function', 'custom_function_to_manage_discounts');

function custom_function_to_manage_discounts() {
    // Define the log file
    $log_file = WP_CONTENT_DIR . '/promo.log';

    // Open the log file for writing (creates a new file if it doesn't exist)
    $log_handle = fopen($log_file, 'a');

    // Check if the log file was successfully opened
    if ($log_handle) {
        // Log a timestamp indicating the start of the custom function
        fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function started." . PHP_EOL);

        // Get all products in category ID 29 for the original language version
        $category_id = array(2465); // <== Changed variable as an array

        $posts_ids = get_posts( array(
            'post_type'      => 'product',
            'post_status'    => 'publish', // <== Added (published products only)
            'posts_per_page' => -1,
            'fields'         => 'ids', // <== Get an array of product IDs
            'orderby'        => 'rand', // <== Random order (replace shuffle)
            'tax_query'      => array(
                array(
                    'taxonomy' => 'product_cat',
                    'field'    => 'term_id', // <== Mistake corrected (not 'id')
                    'terms'    => $category_id,
                    'include_children' => true,
                ),
            ),
        ) );

        if ( count($posts_ids) > 0 ) {
            fwrite($log_handle, date('[d-M-Y H:i:s]') . " Product IDs Retrieved from Category ID {$category_id}: " . implode(', ', $posts_ids) . PHP_EOL);

            // Calculate the number of products to apply discounts to (25% of total)
            $discount_count = ceil(0.25 * count($posts_ids));

            // Loop through product Ids
            foreach ($posts_ids as $post_id) {
                $product = wc_get_product($post_id); // Get the product object

                // Reset sale price from discounted products only
                if ( $product->get_sale_price() > 0 ) {
                    $reg_price = $product->get_regular_price(); // get regular price
                    $product->set_price($reg_price); // Set back the regular price
                    // Clear sale price
                    $product->set_sale_price('');
                    $product->set_date_on_sale_from('');
                    $product->set_date_on_sale_to('');

                    $product->save(); // Save the product to trigger WooCommerce cache refresh

                    do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // refresh price for translations
                    do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // refresh sale price for translations
                    do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // refresh field for translations
                    do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // refresh field for translations

                    // Log the action in the log file
                    fwrite($log_handle, date('[d-M-Y H:i:s]') . " Cleared discount for Product ID: {$post_id}" . PHP_EOL);
                }
            }

            // Apply discounts to a random 25% of products
            for ($i = 0; $i < $discount_count; $i++) {
                $post_id    = $posts_ids[$i];
                $product    = wc_get_product($posts_ids[$i]); // Get the product object
                $reg_price  = $product->get_regular_price(); // get regular price
                $sale_price = $reg_price * 0.9; // Calculate 10% discount

                // Set the new discount price (sale price)
                $product->set_price($sale_price);
                $product->set_sale_price($sale_price);
                $product->set_date_on_sale_from(time());

                $product->save(); // Save the product to trigger WooCommerce cache refresh

                do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // refresh price for translations
                do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // refresh sale price for translations
                do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // refresh field for translations
                do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // refresh field for translations

                // Log the action in the log file with the new price
                fwrite($log_handle, date('[d-M-Y H:i:s]') . " Applied discount for Product ID: {$post_id}, New Price: {$sale_price}" . PHP_EOL);
            }
        }
        // Log a timestamp indicating the completion of the custom function
        fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function completed." . PHP_EOL);
        fclose($log_handle); // Close the log file
    }
}

Update 2 Issue narrowed down to be casued by different product default language version vs page default language version. My failed attempt to fix it below

// Define a custom 1-minute interval
function custom_1_minute_interval($schedules) {
    $schedules['1minute'] = array(
        'interval' => 60, // 1 minute in seconds
        'display'  => __('Every 1 Minute'),
    );
    return $schedules;
}
add_filter('cron_schedules', 'custom_1_minute_interval');

// Schedule the event to run the custom function every 1 minute
add_action('init', 'schedule_custom_function');

function schedule_custom_function() {
    if (!wp_next_scheduled('every_1_minute_custom_function')) {
        wp_schedule_event(time(), '1minute', 'every_1_minute_custom_function');
    }
}

add_action('every_1_minute_custom_function', 'custom_function_to_manage_discounts');

function custom_function_to_manage_discounts() {
    // Define the log file
    $log_file = WP_CONTENT_DIR . '/promo.log';

    // Open the log file for writing (creates a new file if it doesn't exist)
    $log_handle = fopen($log_file, 'a');

    // Check if the log file was successfully opened
    if ($log_handle) {
        // Log a timestamp indicating the start of the custom function
        fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function started." . PHP_EOL);

        // Get all products in category ID 29 for the original language version (Polish)
        $category_id = 2465; // Set the correct category ID for Polish products

        $original_language = apply_filters('wpml_current_language', 'pl'); // Set the original language to Polish

        // Switch to the original language
        do_action('wpml_switch_language', $original_language);

        $posts_ids = get_posts( array(
            'post_type'      => 'product',
            'post_status'    => 'publish', // Published products only
            'posts_per_page' => -1,
            'fields'         => 'ids', // Get an array of product IDs
            'orderby'        => 'rand', // Random order
            'tax_query'      => array(
                array(
                    'taxonomy' => 'product_cat',
                    'field'    => 'term_id', // Use "term_id" as per your comment
                    'terms'    => $category_id,
                    'include_children' => true,
                ),
            ),
        ) );

        // Switch back to the site's default language
        do_action('wpml_switch_language', ICL_LANGUAGE_CODE);

        if ( count($posts_ids) > 0 ) {
            fwrite($log_handle, date('[d-M-Y H:i:s]') . " Product IDs Retrieved from Category ID {$category_id}: " . implode(', ', $posts_ids) . PHP_EOL);

            // Calculate the number of products to apply discounts to (25% of total)
            $discount_count = ceil(0.25 * count($posts_ids));

            // Loop through product Ids
            foreach ($posts_ids as $post_id) {
                $product = wc_get_product($post_id); // Get the product object

                // Reset sale price from discounted products only
                if ( $product->get_sale_price() > 0 ) {
                    $reg_price = $product->get_regular_price(); // Get regular price
                    $product->set_price($reg_price); // Set back the regular price
                    // Clear sale price
                    $product->set_sale_price('');
                    $product->set_date_on_sale_from('');
                    $product->set_date_on_sale_to('');

                    $product->save(); // Save the product to trigger WooCommerce cache refresh

                    do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // Refresh price for translations
                    do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // Refresh sale price for translations
                    do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // Refresh field for translations
                    do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // Refresh field for translations

                    // Log the action in the log file
                    fwrite($log_handle, date('[d-M-Y H:i:s]') . " Cleared discount for Product ID: {$post_id}" . PHP_EOL);
                }
            }

            // Apply discounts to a random 25% of products
            for ($i = 0; $i < $discount_count; $i++) {
                $post_id    = $posts_ids[$i];
                $product    = wc_get_product($posts_ids[$i]); // Get the product object
                $reg_price  = $product->get_regular_price(); // Get regular price
                $sale_price = $reg_price * 0.9; // Calculate 10% discount

                // Set the new discount price (sale price)
                $product->set_price($sale_price);
                $product->set_sale_price($sale_price);
                $product->set_date_on_sale_from(time());

                $product->save(); // Save the product to trigger WooCommerce cache refresh

                do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // Refresh price for translations
                do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // Refresh sale price for translations
                do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // Refresh field for translations
                do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // Refresh field for translations

                // Log the action in the log file with the new price
                fwrite($log_handle, date('[d-M-Y H:i:s]') . " Applied discount for Product ID: {$post_id}, New Price: {$sale_price}" . PHP_EOL);
            }
        }
        // Log a timestamp indicating the completion of the custom function
        fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function completed." . PHP_EOL);
        fclose($log_handle); // Close the log file
    }
}

Another failed attempt

// Define a custom 1-minute interval
function custom_1_minute_interval($schedules) {
    $schedules['1minute'] = array(
        'interval' => 60, // 1 minute in seconds
        'display'  => __('Every 1 Minute'),
    );
    return $schedules;
}
add_filter('cron_schedules', 'custom_1_minute_interval');

// Schedule the event to run the custom function every 1 minute
add_action('init', 'schedule_custom_function');

function schedule_custom_function() {
    if (!wp_next_scheduled('every_1_minute_custom_function')) {
        wp_schedule_event(time(), '1minute', 'every_1_minute_custom_function');
    }
}

add_action('every_1_minute_custom_function', 'custom_function_to_manage_discounts');

function custom_function_to_manage_discounts() {
    // Define the log file
    $log_file = WP_CONTENT_DIR . '/promo.log';

    // Open the log file for writing (creates a new file if it doesn't exist)
    $log_handle = fopen($log_file, 'a');

    // Check if the log file was successfully opened
    if ($log_handle) {
        // Log a timestamp indicating the start of the custom function
        fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function started." . PHP_EOL);

        // Get all products in category ID 2465 in the Polish language version
        $category_id = 2465; // Category ID
        $language_code = 'pl'; // Language code for Polish

        $posts_ids = get_posts( array(
            'post_type'      => 'product',
            'post_status'    => 'publish',
            'posts_per_page' => -1,
            'fields'         => 'ids',
            'orderby'        => 'rand',
            'tax_query'      => array(
                array(
                    'taxonomy' => 'product_cat',
                    'field'    => 'term_id',
                    'terms'    => $category_id,
                    'include_children' => true,
                ),
            ),
            'lang'           => $language_code, // Specify the language code
        ) );

        if ( count($posts_ids) > 0 ) {
            fwrite($log_handle, date('[d-M-Y H:i:s]') . " Product IDs Retrieved from Category ID {$category_id} (Polish version): " . implode(', ', $posts_ids) . PHP_EOL);

            // Loop through product Ids
            foreach ($posts_ids as $post_id) {
                // Get the default language of the site
                $default_site_language = apply_filters('wpml_default_language', NULL);

                // Get the product's default language
                $product_default_language = apply_filters('wpml_element_language_code', NULL, array(
                    'element_id' => $post_id,
                    'element_type' => 'post_product'
                ));

                // Check if the product's default language is different from the site's default language
                if ($product_default_language !== $default_site_language) {
                    // The product's default language is different, so you can get its language ID
                    $product_language_id = apply_filters('wpml_get_language_id', NULL, array(
                        'code' => $product_default_language
                    ));

                    // Log the product's language ID
                    fwrite($log_handle, date('[d-M-Y H:i:s]') . " Product Language ID (Product ID: {$post_id}): $product_language_id" . PHP_EOL);
                } else {
                    // Log that the product is in the site's default language
                    fwrite($log_handle, date('[d-M-Y H:i:s]') . " Product (ID: {$post_id}) is in the site's default language." . PHP_EOL);
                }

                $product = wc_get_product($post_id); // Get the product object

                // Reset sale price from discounted products only
                if ( $product->get_sale_price() > 0 ) {
                    $reg_price = $product->get_regular_price(); // get regular price
                    $product->set_price($reg_price); // Set back the regular price
                    // Clear sale price
                    $product->set_sale_price('');
                    $product->set_date_on_sale_from('');
                    $product->set_date_on_sale_to('');

                    $product->save(); // Save the product to trigger WooCommerce cache refresh

                    do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // refresh price for translations
                    do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // refresh sale price for translations
                    do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // refresh field for translations
                    do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // refresh field for translations

                    // Log the action in the log file
                    fwrite($log_handle, date('[d-M-Y H:i:s]') . " Cleared discount for Product ID: {$post_id}" . PHP_EOL);
                }
            }

            // Calculate the number of products to apply discounts to (25% of total)
            $discount_count = ceil(0.25 * count($posts_ids));

            // Shuffle the products array randomly
            shuffle($posts_ids);

            // Apply discounts to a random 25% of products
            for ($i = 0; $i < $discount_count; $i++) {
                $post_id    = $posts_ids[$i];
                $product    = wc_get_product($posts_ids[$i]); // Get the product object
                $reg_price  = $product->get_regular_price(); // get regular price
                $sale_price = $reg_price * 0.9; // Calculate 10% discount

                // Set the new discount price (sale price)
                $product->set_price($sale_price);
                $product->set_sale_price($sale_price);
                $product->set_date_on_sale_from(time());

                $product->save(); // Save the product to trigger WooCommerce cache refresh

                do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // refresh price for translations
                do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // refresh sale price for translations
                do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // refresh field for translations
                do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // refresh field for translations

                // Log the action in the log file with the new price
                fwrite($log_handle, date('[d-M-Y H:i:s]') . " Applied discount for Product ID: {$post_id}, New Price: {$sale_price}" . PHP_EOL);
            }
        }
        // Log a timestamp indicating the completion of the custom function
        fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function completed." . PHP_EOL);
        fclose($log_handle); // Close the log file
    }
}

Solution

  • There are some few mistakes in your code.

    I have first started searching in WPML website and I came across multiple support thread related product (or post) syncing translations:

    The action hook to be used is wpml_sync_all_custom_fields to refresh/sync all the metadata from the translations of a post (or a product).

    Then searching more, I found wpml_sync_custom_field hook that allows to "Sync custom field value across all translations of a given post".

    Here is the revisited code version of your main function, that should update/refresh the product translations too (untested):

    add_action('every_1_minute_custom_function', 'custom_function_to_manage_discounts');
    function custom_function_to_manage_discounts() {
        // Define the log file
        $log_file = WP_CONTENT_DIR . '/promo.log';
    
        // Open the log file for writing (creates a new file if it doesn't exist)
        $log_handle = fopen($log_file, 'a');
    
        // Check if the log file was successfully opened
        if ($log_handle) {
            // Log a timestamp indicating the start of the custom function
            fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function started." . PHP_EOL);
    
            // Get all products in category ID 29 for the original language version
            $category_id = array(29); // <== Changed variable as an array
    
            $posts_ids = get_posts( array(
                'post_type'      => 'product',
                'post_status'    => 'publish', // <== Added (published products only)
                'posts_per_page' => -1,
                'fields'         => 'ids', // <== Get an array of product IDs
                'orderby'        => 'rand', // <== Random order (replace shuffle)
                'tax_query'      => array(
                    array(
                        'taxonomy' => 'product_cat',
                        'field'    => 'term_id', // <== Mistake corrected (not 'id')
                        'terms'    => $category_id,
                        'include_children' => true,
                    ),
                ),
            ) );
    
            if ( count($posts_ids) > 0 ) {
                fwrite($log_handle, date('[d-M-Y H:i:s]') . " Product IDs Retrieved from Category ID {$category_id}: " . implode(', ', $posts_ids) . PHP_EOL);
    
                // Calculate the number of products to apply discounts to (25% of total)
                $discount_count = ceil(0.25 * count($posts_ids));
    
                // Loop through product Ids
                foreach ($posts_ids as $post_id) {
                    $product = wc_get_product($post_id); // Get the product object
    
                    // Reset sale price from discounted products only
                    if ( $product->get_sale_price() > 0 ) {
                        $reg_price = $product->get_regular_price(); // get regular price
                        $product->set_price($reg_price); // Set back the regular price
                        // Clear sale price
                        $product->set_sale_price('');
                        $product->set_date_on_sale_from('');
                        $product->set_date_on_sale_to('');
    
                        $product->save(); // Save the product to trigger WooCommerce cache refresh
    
                        do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // refresh price for translations
                        do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // refresh sale price for translations
                        do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // refresh field for translations
                        do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // refresh field for translations
    
                        // Log the action in the log file
                        fwrite($log_handle, date('[d-M-Y H:i:s]') . " Cleared discount for Product ID: {$post_id}" . PHP_EOL);
                    }
                }
    
                // Apply discounts to a random 25% of products
                for ($i = 0; $i < $discount_count; $i++) {
                    $post_id    = $posts_ids[$i];
                    $product    = wc_get_product($posts_ids[$i]); // Get the product object
                    $reg_price  = $product->get_regular_price(); // get regular price
                    $sale_price = $reg_price * 0.9; // Calculate 10% discount
    
                    // Set the new discount price (sale price)
                    $product->set_price($sale_price);
                    $product->set_sale_price($sale_price);
                    $product->set_date_on_sale_from(time());
    
                    $product->save(); // Save the product to trigger WooCommerce cache refresh
    
                    do_action( 'wpml_sync_custom_field', $post_id, '_price' ); // refresh price for translations
                    do_action( 'wpml_sync_custom_field', $post_id, '_sale_price' ); // refresh sale price for translations
                    do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_from' ); // refresh field for translations
                    do_action( 'wpml_sync_custom_field', $post_id, '_sale_price_dates_to' ); // refresh field for translations
    
                    // Log the action in the log file with the new price
                    fwrite($log_handle, date('[d-M-Y H:i:s]') . " Applied discount for Product ID: {$post_id}, New Price: {$sale_price}" . PHP_EOL);
                }
            }
            // Log a timestamp indicating the completion of the custom function
            fwrite($log_handle, date('[d-M-Y H:i:s]') . " Custom function completed." . PHP_EOL);
            fclose($log_handle); // Close the log file
        }
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). It may work.


    Addition - WPML: Get the post IDs of the translations from a post ID

    Using the code from "get all other languages for a post", you can get the translated product ids from the parent Id. I have embedded the code in a separate reusable function:

    function get_wpml_translated_post_ids( $post_id ) {
        $type = apply_filters( 'wpml_element_type', get_post_type( $post_id ) );
        $trid = apply_filters( 'wpml_element_trid', false, $post_id, $type );
        $product_ids  = [];  
        $translations = apply_filters( 'wpml_get_element_translations', array(), $trid, $type );
        foreach ( $translations as $lang => $data ) {
            $product_ids[] = $data->element_id;
        }
        return $product_ids;
    }
    

    Code goes in functions.php file of your child theme (or in a plugin).