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.

Tagged: 

This topic contains 13 replies, has 2 voices.

Last updated by cons-2 1 year, 9 months ago.

Assisted by: Dražen Duvnjak.

Author Posts
January 31, 2023 at 12:41 pm #12929615

cons-2

Hi.

We're having trouble with a feature we built a while ago after a recent update (of WooCommerce Multilingual?).

(WordPress, WooCommerce and all WPML-Plugins are up to date.)

Our function retrieves ratings from all languages of a product and then lets us work with them.
A use case from us is: Give us 10 reviews of product_id XY that were created before date Z.
We load reviews via a REST endpoint so the frontend-script can display them as needed.

We usually process the get_comments-results further with wp_list_comments to convert reviews to html.

$args = array (
  'post_type' => 'product',
  'status'=> 'approve',
  'post_status' => 'publish',
  'comment__not_in' => $exclude_comment_ids, // exclude some comments, e.g. pinned reviews
  'number' => $number,
  'offset' => count($exclude_comment_ids),
  'orderby' => 'comment_date',
  'order' => 'DESC',
  'post_id' => $product_id,
  'date_query' => array(
    'before' => $date_before,
    'inclusive' => false,
  )
);

$comments = get_comments( $args );

// sometimes we need to return html:
$comments_fix_order = array_reverse($comments);
wp_list_comments( apply_filters( 'woocommerce_product_review_list_args', array( 'callback' => 'woocommerce_comments' ) ), $comments_fix_order );

All reviews of all languages were displayed correctly in the past.
All reviews are now also displayed.
However, not in the language of the current product, but in the language of the product with which the rating was submitted.
In addition, the flag of the current product language is always displayed.

So when I look at a product DE, all reviews have the DE flag.
Text languages vary by comment author - sometimes DE, sometime EN, sometimes FR.

Expected behavior:
When I view a DE product, the comment text language should always be DE - with the addition "(translated)".
Flag should always represent the language of the product with which the rating was submitted.

We've been using this function for about a year.
Has always worked.
All of a sudden not anymore.

We haven't changed anything.

What exactly are the arguments to run get_comments correct and make it compatible with the current versions of WPML?

Input:
- $product_id => id of product in current lang
- $number => max rows to fetch
- $exclude_comment_ids => maybe excluude some comments from results
- $date_before => filter results by date

Expected result:
Text in the language of the specified product.
Flag in the language of the rated product when displayed with wp_list_comments.

(Since it is a general question, I am not presenting any links or access information to our site.
The question should be answerable without private messages so that the community also benefits from it.)

If it needs multiple steps and code tweaks, that's fine too.
e.g. first make a query to find all comment_ids for a product, then query the original ids of it and only then get the reviews via get_comments. Also ok.

Just need an approach because the magic WPML applied under the hood isn't working anymore.

I look forward to your answer.

February 2, 2023 at 7:35 am #12944305

Dražen Duvnjak
Supporter

Languages: English (English )

Timezone: Europe/Zagreb (GMT+01:00)

Hello,

thanks for contacting us.

In order to check this out further and consult with our 2nd tier, can you please recreate a simple example of the issue on our test site:

- hidden link

No need to create content or install any additional plugins, 1-2 products, and 1-2 reviews should be enough, please share all steps and code you used and how we can see the issue.

Thanks,
Drazen

February 2, 2023 at 12:12 pm #12947033

cons-2

Hi.

I set up a page.
DE as main language. EN + FR as translations.

You can find the link to the product in the footer - recent comments.

Haven't added any custom code yet.

What I have done
- WCML: Show reviews of all languages on product page
- submitted reviews translated with string translation

Now the following error is visible: Translated reviews have the wrong flag.
Translated reviews should show the flag of the source language. Not that of translation.

- "Markus" original lang: DE
- "Ron" original lang: DE
- "From EN" original lang: EN

(I'll add my custom code later if necessary.
At first, the default display should run smoothly.)

wpml_Screenshot_20230202_130358.png
February 2, 2023 at 12:24 pm #12947137

Dražen Duvnjak
Supporter

Languages: English (English )

Timezone: Europe/Zagreb (GMT+01:00)

Hello,

thanks for getting back and taking the time to reproduce.

I have checked further on this and this is how it is expected to work once the review is translated, since WCML 4.12.

This is because of search engine crawling and to keep the flag (language) consistent of the text review language. If the review is translated to EN, and in EN text it will show the EN flag and note (translated).

If you wish you can proceed with reproducing your issue and we can continue to check further.

Regards,
Drazen

February 2, 2023 at 5:02 pm #12950013

cons-2

Thanks for the feedback.
We are a bit puzzled that it is desired behavior that all flags are the same.
But okay.
That's the least of the problems.

Let's get to the important topic.
Screenshots attached.

I made the following changes on your test site.
- Plugin-File-Editor: woocommerce/templates/single-product-reviews.php (adjusted line 46 to 86)
- In line 48 I installed a "switch" for you. Toggling between true and false allows you to toggle the frontend between default WooCommerce and my customization.

I commented out the query limits and date filters.
We use these in production, but the error occurs even without these arguments.

Here is a brief summary for readers:

$args = array (
  'post_type' => 'product',
  'status'=> 'approve',
  'post_status' => 'publish',
  'orderby' => 'comment_date',
  'order' => 'DESC',
  'post_id' => $product->get_id(),
);

$comments = get_comments( $args );

// sometimes we need to return html:
$comments_fix_order = array_reverse($comments);
wp_list_comments( apply_filters( 'woocommerce_product_review_list_args', array( 'callback' => 'woocommerce_comments' ) ), $comments_fix_order );

The code shown above results in reviews being displayed untranslated. See image captioned "Mode: custom" above reviews.

Normally the query should come out the same as the standard WooCommerce query, I think.
Image 1 and Image 2 should show the same ratings.

First and foremost, it would be important for us that the reviews are also displayed in translated form for individual get_comments() calls.
Also with the addition "translated".

How must the get_comments() call be adjusted so that the reviews are displayed correctly - as in the standard Woocommerce implementation?

Why are the reviews shown untranslated at all?

default_Screenshot_20230202_174433.png
custom_Screenshot_20230202_174446.png
February 2, 2023 at 5:08 pm #12950069

cons-2

Edit:
"Why are the reviews shown untranslated at all?"

With that I refer to the last review on the screenshots.
"From EN" comment text is not translated in the custom get_comments() query - screenshot with heading "mode: custom".

February 3, 2023 at 7:47 am #12953139

Dražen Duvnjak
Supporter

Languages: English (English )

Timezone: Europe/Zagreb (GMT+01:00)

Hello,

thanks for such descriptive reply and taking the time to reproduce it.

I have now shared this case with our 2nd tier to check and advise.

We will update you soon.

Regards,
Drazen

February 3, 2023 at 2:23 pm #12956461

Dražen Duvnjak
Supporter

Languages: English (English )

Timezone: Europe/Zagreb (GMT+01:00)

Hello,

our 2nd tier checked, I am sharing his thoughts on this.

Let me know if this helps and if you need more information:

- As far I can see we do not do any filtering on get_comments method, we translate the comments on `woocommerce_review_before` hook. Probably user is not calling that hook.

Regards,
Drazen

February 3, 2023 at 4:13 pm #12957343

cons-2

Hello.

Thanks for the feedback.

Checked where the "woocommerce_review_before" hook is called by default.

By default the hook is called in woocommerce/templates/single-product/review.php.
This is the template file called by the "wp_list_comments" callback.

We have not changed the callback.
We call "wp_list_comments" with the default callback "woocommerce_comments".

So the hook "woocommerce_review_before" should be called normally.

I also tested it on your test site.
Screenshot attached.
It works normally.

add_action('woocommerce_review_before', function(){
  echo '<small><strong>woocommerce_review_before - added at the end of woocommerce.php plugin file - you can remove it if neccessary</strong></small>';
});

We can thus rule out that the hook is not called.
The hook is called normally.

In general: The only thing I do with my customization is fetch the reviews and pass them to wp_list_comments.

I have not changed the WooCommerce display logic.
That's why I turn to you.

The faulty translation of the reviews when called by get_comments() has only recently appeared.
Must have happened in recent updates of WPML/WCML.

I'm curious what other ideas you have.
You can also try to get the test snippet to work on the test page.
see file: woocommerce/templates/single-product-reviews.php, line 46 to 86

If you can get it to work, we might have new insights.

wpml_Screenshot_20230203_165603.png
February 3, 2023 at 5:02 pm #12957713

cons-2

I followed your function:
add_action( 'woocommerce_review_before', [ $this, 'translateReview' ] );

This brought new insights.

When I retrieve reviews with get_comments(), then the comment_post_ID your getReviewStringName() function retrieves is different than the default.
- wp_list_comments(): product-{product_ID of language the user has submitted review}-review-{comment_ID}
- wp_list_comments() with results of get_comments() query: product-{product_ID from get_comments-call}-review-{comment_ID}

Here is an example from our online shop (live page).
I'm retrieving reviews from a DE product and displaying a review from a FR user.
This is the result of getReviewStringName():
- default: product-{FR product_id}-review-48743
- custom get_comments() query: product-{DE product_id}-review-48743

Here is a modification in WPML code that I tried.
Worked.

- file: wp-content/plugins/woocommerce-multilingual/classes/Reviews/Translations/FrontEndHooks.php
- function: getReviewStringName()

private static function getReviewStringName( $review ) {
  // lang code in which review was submitted by user
  // same as lang_code of product the user has commented on
  // not sure how to query it programmatically
  $comment_original_lang = 'fr';

  // get product_id in language the user has submitted the review
  $post_id = apply_filters('wpml_object_id', Obj::prop( 'comment_post_ID', $review ), 'product', true, $comment_original_lang);


  return 'product-' . $post_id . '-review-' . Obj::prop( 'comment_ID', $review );


  // WPML default code
  // return 'product-' . Obj::prop( 'comment_post_ID', $review ) . '-review-' . Obj::prop( 'comment_ID', $review );
}

In my test on the live site I hardcoded FR because I don't know how to get the original comment language and it was okay for testing on a single review.

The language used for the product that the user commented on would have to be used dynamically in your function getReviewStringName().

So user commented on FR, then insert FR product id.

Independent of the current frontend display language.
This is how it worked in my test.

Feel free to rebuild and test.

Please leave feedback.
Can you reproduce this solution?

February 3, 2023 at 5:28 pm #12957809

cons-2

Perhaps the question is why an individual query brings different results than when wp_list_comments() loads comments itself.

- For wp_list_comments without get_comments() the comment_post_ID of the results varies
- when querying via get_comments(), the comment_post_ID is always the same

It seems like some filter magic is implemented by default.
This seems to be dropped for individual wp_list_comments() calls populated with results from get_comments() queries.

I'll stop spamming and wait for your feedback.

February 6, 2023 at 7:02 am #12965533

Dražen Duvnjak
Supporter

Languages: English (English )

Timezone: Europe/Zagreb (GMT+01:00)

Hello,

thanks.

Sharing this with our 2nd tier, since this is a bit out of my knowledge and expertise.

Will update you soon.

Regards,
Drazen

February 7, 2023 at 6:40 am #12973947

Dražen Duvnjak
Supporter

Languages: English (English )

Timezone: Europe/Zagreb (GMT+01:00)

Hello,

thanks for your patience.

We have checked and could found the problem. Currently, this issue is escalated to our developers. We will use this example to find some other ways (more appropriate) to hook our filters, but we can't give any guarantee that we'll fix it one day.

You are obtaining the comments, but they are obtained untranslated. Then passing them to wp_list_comments but because the ID is the current product ID instead of the translation - we cannot find a translation and thus we return the original.The problem is rather complex, because we filter the comment_clauses so we add comments from the translations, but then we make the comment as if it belongs to the current product ID so that the comment is displayed.

The workaround here for your to use is: To call wpml_translate_single_string

// customization

					//$limit = 2;
					$args = array (
						'post_type' => 'product',
						'status'=> 'approve',
						'post_status' => 'publish',
						//'comment__not_in' => $exclude_comment_ids, // exclude some comments, e.g. pinned reviews
						//'number' => $limit,
						//'offset' => count($exclude_comment_ids),
						'orderby' => 'comment_date',
						'order' => 'DESC',
						'post_id' => $product->get_id(),
						/*'date_query' => array(
						'before' => $date_before,
						'inclusive' => false,
					)*/
					);

					$comments = get_comments( $args );

					// sometimes we need to return html:
					$comments_fix_order = array_reverse($comments);
                    foreach ($comments_fix_order as $id => $comment){
                        $test = get_comment($comments_fix_order[$id]->comment_ID); //this is necessary so that we get the product ID to which this comment belong instead of the current product ID
                        $comments_fix_order[$id]->comment_content = apply_filters( 'wpml_translate_single_string', $comments_fix_order[$id]->comment_content,  'wcml-reviews',  'product-'.$test->comment_post_ID. '-review-'. $comments_fix_order[$id]->comment_ID );
                    }
					wp_list_comments( apply_filters( 'woocommerce_product_review_list_args', array( 'callback' => 'woocommerce_comments' ) ), $comments_fix_order );
				}

Hope this helps, if you wish I can leave this ticket open and in the status " Escalated to WPML developers team" so if any news in the future I will update here.

Regards,
Drazen

February 7, 2023 at 11:25 am #12976977

cons-2

Hello.

Thanks for the feedback and the suggested solution.

We applied your fix and everything is working again.

It's interesting for me to get a notification if you roll out a fix globally with a plugin update.
In the changelog of WCML would be enough for me.

You can mark the thread as "solved" from my side.

Here's a small adjustment I made.
In case anyone else is reading this...

foreach ($comments as $id => $comment){
  // get the product ID to which this comment belong instead of the current product ID
  $_o_comment = get_comment($comments[$id]->comment_ID); 
  $_o_product_id = $_o_comment->comment_post_ID; // id the user has submitted to

  $_translated_content = apply_filters( 'wpml_translate_single_string', $comments[$id]->comment_content,  'wcml-reviews',  'product-'.$_o_product_id. '-review-'. $comments[$id]->comment_ID );

  $comments[$id]->is_translated = $_translated_content !== $comments[$id]->comment_content; // fixes wcml open_lang_div: <div lang="" /> 
  $comments[$id]->comment_post_ID = $_o_product_id; // fixes review title translation (another plugin)
  $comments[$id]->comment_content = $_translated_content;
}