Skip Navigation

This is the technical support forum for WPML - the multilingual WordPress plugin.

Everyone can read, but only WPML clients can post here. WPML team is replying on the forum 6 days per week, 22 hours per day.

Sun Mon Tue Wed Thu Fri Sat
- - 9:00 – 18:00 9:00 – 18:00 9:00 – 18:00 9:00 – 18:00 9:00 – 18:00
- - - - - - -

Supporter timezone: America/Lima (GMT-05:00)

This topic contains 18 replies, has 2 voices.

Last updated by Andreas W. 2 months, 3 weeks ago.

Assisted by: Andreas W..

Author Posts
August 8, 2024 at 3:49 pm #16053680

Marco

Background of the issue:
I am trying to create/update a variation on a variable product via the REST API and then run wpml_make_post_duplicates_action on it so that the duplicates for each language are also created or updated.

This is on WooCommerce, and WooCommerce Multilingual is used.

Here's what we're doing:

get_default_language();
		// Force that language from now on
		$sitepress->switch_lang( $def_lang );
	});
	// Product insert/update -> Create translations (duplicates) if they do not exist
	add_action( 'woocommerce_rest_insert_product_object', function( $product, $request, $inserting ) {
		// Duplicate
		wpml_make_post_duplicates_action( $product->get_id() ); // Check: https://wpml.org/forums/topic/why-is-the-wpml_make_post_duplicates-hook-being-removed/
	}, 10, 3 );
	// Product variation insert/update -> Create translations (duplicates) if they do not exist
	add_action( 'woocommerce_rest_insert_product_variation_object', function( $product_variation, $request, $inserting ) {
		// Duplicate
		wpml_make_post_duplicates_action( $product_variation->get_id() ); // Check: https://wpml.org/forums/topic/why-is-the-wpml_make_post_duplicates-hook-being-removed/
		// Try to set correct attributes on variation, without success - If we uncomment this it will work but we need to wp_die()
		// global $woocommerce_wpml;
		// $woocommerce_wpml->sync_variations_data->sync_product_variations_action( $product_variation->get_parent_id() );
		// wp_die(); // If we uncomment this, it will work, as something else is running after and overwriting the attribute_pa_* variation product meta
	}, 10, 3 );
}

Running wpml_make_post_duplicates_action after inserting the main product via the REST API works just fine. But when doing the same to variations, it works only partially and the attribute_pa_* variation product metas is just copied over and not set correctly with the translated attributes.

For example, for a 'Color' attribute, and if English is the main language, when running the wpml_make_post_duplicates_action action, what will happen is this:
English variation: attribute_pa_color = black (as set by us via the REST API)
Portuguese variation: attribute_pa_color = black (copied over as regular meta and not translated to the corresponding 'preto' attribute term translation).

Here's a visual example on a variation with two attributes in three languages.
This is what happens: hidden link
This is what should happen: hidden link

I suspect this is happening because on class-wcml-synchronize-product-data.php you're not adding the icl_make_duplicate action unless is_admin() or isCli() which is not true when using the REST API. But that might not be enough, as I tried to tweak the code there and it still didn't worked correctly.

To try to fix this for us, we run $woocommerce_wpml->sync_variations_data->sync_product_variations_action( $product_variation->get_parent_id() ); after wpml_make_post_duplicates_action, which works and sets the correct values on attribute_pa_* but something else is running after because if we don't wp_die() the meta are overwritten again.

Symptoms:
Running wpml_make_post_duplicates_action after inserting the main product via the REST API works just fine. But when doing the same to variations, it works only partially and the attribute_pa_* variation product metas is just copied over and not set correctly with the translated attributes.

Questions:
Can you fix this?

August 8, 2024 at 9:47 pm #16054382

Andreas W.
Supporter

Languages: English (English ) German (Deutsch )

Timezone: America/Lima (GMT-05:00)

Hello,

First of all, a duplicate will always share the same information as the original content. A duplicate in WPML is not a real translation. It is supposed to get overwritten anytime the original content is being saved.

This means, that it would be expected that a duplicated product uses the same product details (here attributes) as the original product.

Another problem with this approach is, that if you use custom attributes, that are created directly on the products, then you can only translate them with the WPML Translation Editor.

This means, that if you open the translated product on the WordPress Editor, those fields are blocked and not editable. This is controlled by our addon WooCommerce Multilingual & Multi-Currency.

The alternative might be to use global attributes, which are created at Products > Attributes.

Those global attributes will be translatable at WooCommerce > WooCommerce Multilingual & Multi-Currency > Attributes.

Best regards
Andreas

August 9, 2024 at 6:33 am #16054937

Marco

Hi Andreas,

Thanks of your reply.

We are aware duplicates are copies and not translations per se, but the goal here is that when the ERP creates products via the REST API, all the duplicates are created as placeholders, as the shop owner will then do one of two things:
- Click the "translate independently" button and manually translate whatever needs to be translated;
- Use your automated translation services; (for single products we already have this in place in another customer and it works just fine, and the shop owner doesn't even need to click the "translate independently" button as when the translations are returned from your service the product is automagically set on that state - non-duplicate but a proper translation)

As I mentioned above, we have this working flawlessly on another customer, he just doesn't have variable products like this new one.

Moving on, regarding attributes, we are using global attributes related at Products > Attributes already translated at WooCommerce > WooCommerce Multilingual & Multi-Currency > Attributes. The API is not creating attributes. We ensure those exist previously to create products and it's variations.

Going back to the "A duplicate in WPML is not a real translation" issue, if I create a product manually on wp-admin, set its variations and then create duplicates via your Language metabox, the attributes show up as translated, even before I click the "translate independently" button, as you can see: hidden link
Even on the database, it's correct: hidden link

If we do it via the REST API, the attributes are correct on the original product but the duplicates/translations show "any attribute" hidden link because the values are not correctly set on the database hidden link

As you can see by our shared code, we currently are doing this:
- Product created -> Run wpml_make_post_duplicates_action() on it (all good)
- Create each variation for original product -> Run wpml_make_post_duplicates_action() on it (duplicates have incorrect attributes)

Another approach I just tried was to:
- Create product via the REST API
- Create each variation via the REST API
- Only after run wpml_make_post_duplicates_action() on the original product (It did create the main product duplicates but not any variations as it would if I created the duplicate via the backend)

So, in conclusion: even when the product is still a duplicate, the attributes are correctly set if the duplicate is created on the backend. Why is not possible to achieve the same via the REST API? Or, what is the preferred way of achieving it?

August 9, 2024 at 6:44 pm #16057560

Andreas W.
Supporter

Languages: English (English ) German (Deutsch )

Timezone: America/Lima (GMT-05:00)

Thank you for the detailed answer!

I will try to recreate this issue on a test site and then get back to you.

In the meantime, can you please confirm if going to WooCommerce > WooCommerce Multilingual & Multi-Currency > Status > Troubleshooting and running the available options to sync variable products can solve this issue?

August 9, 2024 at 7:16 pm #16057576

Andreas W.
Supporter

Languages: English (English ) German (Deutsch )

Timezone: America/Lima (GMT-05:00)

I created a test site and did the following:

Login: hidden link

1) Create global product attributes and translate them
- It does usually not matter if they are created by REST API.

2) Create two variable products in the site's default language

3) Duplicate both products with Translation Management
- I am using the WPML UI in this case, as it should work similarly to your coded approach.

Result:
At this point, the duplicated products are showing the translated variations on my test site.

4) Product B was then sent to automatic translation
- Also this worked as expected.

Take note, that this workflow depends on, that on the original product the "WPML Translation Editor" is set as the translation method inside the right sidebar of the WordPress Editor.

If the client wants to set the product to "Translate independently" and edit it inside the WordPress Editor, the translation method needs to be set to "WordPress Editor" first.

---

It looks as if a third plugin might be causing the unexpected issues on your site.

Did you already run a test in a minimal setup or do you maybe have a staging site ready on which I could investigate the issue?

August 12, 2024 at 5:34 pm #16063438

Marco

Hi again Andreas,

"I am using the WPML UI* in this case, as it should work similarly to your coded approach**.
Result:
At this point, the duplicated products are showing the translated variations on my test site."

* I mentioned in my previous reply that I tested this and it worked just fine.
** It does not.

The problem is when using code (wpml_make_post_duplicates_action()) to create the duplicates, as concluded on my last paragraph:

"So, in conclusion: even when the product is still a duplicate, the attributes are correctly set if the duplicate is created on the backend*. Why is not possible to achieve the same via the REST API?** Or, what is the preferred way of achieving it?"

* The WPML UI as you mentioned.
** REST API or any other way, by code.

Please re-read my reply from August 9, 2024 at 6:33 am and let me know if there's something not clear in my explanation.

All tests were always performed only with WooCommerce and your plugins active and the used theme is Storefront. No other plugin or custom code is involved.

August 13, 2024 at 6:31 pm #16067724

Andreas W.
Supporter

Languages: English (English ) German (Deutsch )

Timezone: America/Lima (GMT-05:00)

This would usually mean, that the issue is inside your custom function. Take kindly note that our support is usually not supposed to provide any custom code solutions.

I have not tested this apporach yet, but could you please give this a try:

// Ensure $sitepress is available
$sitepress = isset($sitepress) ? $sitepress : null;

if ($sitepress) {
    // Get the default language (ensure this function is defined and returns the expected language code)
    $def_lang = get_default_language();

    // Force the language to default (make sure this is the correct way to set the language for your case)
    $sitepress->switch_lang($def_lang);
}

// Product insert/update -> Create translations (duplicates) if they do not exist
add_action('woocommerce_rest_insert_product_object', function ($product, $request, $inserting) {
    // Ensure WPML function exists and is valid
    if (function_exists('wpml_make_post_duplicates_action')) {
        // Duplicate product
        wpml_make_post_duplicates_action($product->get_id());
    }
}, 10, 3);

// Product variation insert/update -> Create translations (duplicates) if they do not exist
add_action('woocommerce_rest_insert_product_variation_object', function ($product_variation, $request, $inserting) {
    // Ensure WPML function exists and is valid
    if (function_exists('wpml_make_post_duplicates_action')) {
        // Duplicate variation
        wpml_make_post_duplicates_action($product_variation->get_id());
    }

    // Try to set correct attributes on variation if needed
    // Note: Ensure $woocommerce_wpml is available if uncommenting this code
    /*
    global $woocommerce_wpml;
    if (isset($woocommerce_wpml) && method_exists($woocommerce_wpml->sync_variations_data, 'sync_product_variations_action')) {
        $woocommerce_wpml->sync_variations_data->sync_product_variations_action($product_variation->get_parent_id());
    }
    */

    // If you face issues with attributes being overwritten, consider debugging why it's happening
    // Instead of wp_die(), use error logging or debugging tools to investigate
}, 10, 3);

If this will still not solve the issue, I further invite you to recreate the issue on the earlier provided test site and to provide me detailed steps about how to recreate the issue.

August 14, 2024 at 8:47 am #16069359

Marco

Hi Andreas,

I'm not asking for you to provide custom code solutions. I'm trying to use your available functions to replicate the "create duplicate" function on your plugin, but I'm thinking there might be a bug somewhere as it does not work as intended: again, the attributes are not correctly set, and I'm trying to help you fix this, so I and other users can use it.

The solution you sent me is the same we're doing, but there's a function_exists('wpml_make_post_duplicates_action') check.

I've done some more tests and I'm now convinced this is happening because on class-wcml-synchronize-product-data.php you're not adding the icl_make_duplicate action unless is_admin() or isCli().
I've added a "|| true" to it and it worked just by running wpml_make_post_duplicates_action() on the main product after creating it and each variation. I did this by running the function manually on a PHP script.

I then changed "|| true" to " || wpml_is_rest_request()" and my code already works, with the small change that after creating each variation I need to call the wpml_make_post_duplicates_action() function on the MAIN product and not the newly created variation.

So, can you please replace:

if ( is_admin() || isCli() || wpml_is_rest_request() ) {

by:

if ( is_admin() || isCli() ) {

On WooCommerce Multilingual, wcml-synchronize-product-data.php, function add_hooks() ?
This way anyone can create products via the REST API and create the duplicates, instead of only via WP Admin or WP CLI.

August 14, 2024 at 7:04 pm #16072274

Andreas W.
Supporter

Languages: English (English ) German (Deutsch )

Timezone: America/Lima (GMT-05:00)

I will give this a test and then get back to you.

August 15, 2024 at 6:04 pm #16075713

Andreas W.
Supporter

Languages: English (English ) German (Deutsch )

Timezone: America/Lima (GMT-05:00)

I did some internal research and see that our developers actually provide the following documentation and workflow for this purpose:
https://wpml.org/documentation/related-projects/woocommerce-multilingual/using-wordpress-rest-api-woocommerce-multilingual/#create-product-variation

Did you five this a try already?

August 15, 2024 at 9:18 pm #16076300

Andreas W.
Supporter

Languages: English (English ) German (Deutsch )

Timezone: America/Lima (GMT-05:00)

The issue here might be that, wpml_make_post_duplicates is usually reserved for Frontend calls:
https://wpml.org/wpml-hook/wpml_make_post_duplicates/

Please check the private message next after this comment.

August 16, 2024 at 12:46 pm #16078304

Marco

Hi,

If that hook/function is reserved for frontend calls, than the

if ( is_admin() || isCli() ) {

on WooCommerce Multilingual, wcml-synchronize-product-data.php, function add_hooks() makes no sense.

I went to the provided test server and did this:
- Loaded our plugin which hooks into the REST calls and runs wpml_make_post_duplicates_action() to create the duplicates
- Set WP_LOCAL_DEV to true on wp-config.php -> This is what ensures our plugin hooks are set for direct REST calls (testing without the main plugin from the CRM)
- Created REST credentials on WooCommerce
- Created a variable product (ID 15720, payload https://pastebin.com/LmAiw1sP) and one variation (ID 15722, payload https://pastebin.com/iFE6QvJw) via the REST API: the main English product was created, the main English variation was created with the correct "Att1_1_English" attribute, the duplicated German product was created via our call to wpml_make_post_duplicates_action (ID 15721), the duplicated German variation was created with the correct "Att1_1_German" attribute on the databas

I wasn't expecting this to work before making the proposed changes, but it did. After further investigation on my side, I realized what actually fixed it was to call wpml_make_post_duplicates_action with the main product ID and not with the variation ID, even when creating each variation via the REST API, so I guess the issue is solved.

Still, it does make sense to change it to

if ( is_admin() || isCli() || wpml_is_rest_request() ) {

as REST can also be considered backend or authenticated at least, just like WP Admin and WP CLI.

August 16, 2024 at 7:55 pm #16079246

Andreas W.
Supporter

Languages: English (English ) German (Deutsch )

Timezone: America/Lima (GMT-05:00)

I understand you right, that your implmentation is working as expected now, and the issue was realted to your code?

About your request:

You refer to this file?
woocommerce-multilingual\inc\translation-editor\class-wcml-synchronize-product-data.php

line 39:

if ( is_admin() || isCli() ) {
			// filters to sync variable products.
			add_action( 'save_post', [ $this, 'synchronize_products' ], PHP_INT_MAX, 2 ); // After WPML.

			add_filter( 'icl_make_duplicate', [ $this, 'icl_make_duplicate' ], 110, 4 );

This logic will run if a post is saved or a duplicate is created.

You would like to change this to:

if ( is_admin() || isCli() || wpml_is_rest_request()) {
			// filters to sync variable products.
			add_action( 'save_post', [ $this, 'synchronize_products' ], PHP_INT_MAX, 2 ); // After WPML.

			add_filter( 'icl_make_duplicate', [ $this, 'icl_make_duplicate' ], 110, 4 );

Is this correct?

I need to ask here, as such request will need to be explained in detail to the product manager:

1) With your approach, if a product is saved or duplicated when making a REST call, the variations will be synced.

2) If the third condition will be missing, no syncrhonization would occur, unless you implement a custom code solution.

Did I understand this correctly?

Now, could you please explain me how your REST request exactly looks, so that I get a better understanding about how such change can be a benefit for all users of WPML?

I will need to run test before escalating such request and would like to ask you again to assist in recreating the issue on the provided test site.

We need to make sure if this is not just a workaround for specific use cases and does not cause any issues or unepxected results if different workflows are applied.

August 19, 2024 at 10:46 am #16083077

Marco

Actually it works now, even without that code changed, as mentioned in my last reply:

<quote>I wasn't expecting this to work before making the proposed changes, but it did. After further investigation on my side, I realized what actually fixed it was to call wpml_make_post_duplicates_action with the main product ID and not with the variation ID, even when creating each variation via the REST API, so I guess the issue is solved.</quote>

Anyway, still waiting for the real world testing to be 100% sure about that, so I would ask you to keep this open a few more days.

I mentioned that it would make sense to add "|| wpml_is_rest_request()" as REST can also be considered backend or authenticated at least, just like WP Admin and WP CLI, but for my specific issue, it seems not to be needed after all (still, waiting for the real world testing).

August 20, 2024 at 5:59 pm #16088036

Andreas W.
Supporter

Languages: English (English ) German (Deutsch )

Timezone: America/Lima (GMT-05:00)

Yes, thank you!

The ticket will remain open for a maximum of 14 days and close automatically after this timeframe in case we do not receive any further message from you.

Anyhow, you will be able to open a new ticket anytime and let the suport agent know that we handled a ticket for this issue earlier.

About your request:

"wpml_make_post_duplicates_action on a newly created product variation via REST"

Please visit this test site:

One-Click-Login:
hidden link

Take note that here I implemented the following hook to make sure that products are duplicated when published:

add_action( 'wp_insert_post', 'my_duplicate_on_publish' );

function my_duplicate_on_publish( $post_id ) {
    // Avoid running on autosave
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return;
    }

    // Avoid running on revisions
    if ( wp_is_post_revision( $post_id ) ) {
        return;
    }

    // Get the post object
    $post = get_post( $post_id );

    // Ensure we are dealing with a product post type
    if ( ! $post || 'product' !== $post->post_type ) {
        return;
    }

    // Avoid recursion
    remove_action( 'wp_insert_post', 'my_duplicate_on_publish' );

    // Check if the post is already duplicated or has translations
    $is_translated = apply_filters( 'wpml_element_has_translations', '', $post_id, $post->post_type );

    // Make duplicates if the product does not already have translations
    if ( !$is_translated ) {
        do_action( 'wpml_admin_make_post_duplicates', $post_id );
    }

    // Re-hook the action
    add_action( 'wp_insert_post', 'my_duplicate_on_publish' );
}

Hook: https://wpml.org/wpml-hook/wpml_admin_make_post_duplicates/

This is a dedicated hook for admin calls and it should also fire when for example making a REST API request with Postman.

Once a new product is created, this hook will create a duplicate including variations. Further, the duplicate will get overwritten automatically each time the original content is updated.

Do i understand right, that this what you are trying to achieve?

Could you please give this a test?

The topic ‘[Closed] Running wpml_make_post_duplicates_action on a newly created product variation via REST does not work…’ is closed to new replies.