When we translate an English post and select the French “Nouvelles” category, the original English post loses its “News” category and gets switched to the French category instead.
The root cause is an interaction between WPML's auto_adjust_ids feature and its taxonomy sync logic. When the client saves a French translation with the "Nouvelles" category, WPML's term ID adjustment filter (which translates terms to the current admin language) is replacing the English "News" category on the original post with the French "Nouvelles" term. The filter's exclusion list covers wp_update_post but does NOT cover wp_set_object_terms, so the wrong-language term slips through during sync. There are 20+ English posts currently affected going back to 2021, plus a secondary issue where Yoast's primary category meta is being copied without translation.
Full investigation doc is here: hidden link
I reviewed the documentation, were you able to run the Troubleshooting action and what are your results after running it?
Also, one thing that I was not able to fully understand is the workflow that causes this issue.
Can you explain to me the steps taken for this issue to be reproduced?
The categories should be translated and linked with each other, therefore when an item is translated the category assigned will automatically be the translation of the default language category.
Issue:
When saving a French translation of an English post, the original English post's category is replaced with the French translated term. The English post assigned to "News" (term_id 31, EN, trid 828) loses that category and gets assigned "Nouvelles" (term_id 49, FR, trid 828) instead. Both the original and translation end up with the French term.
Steps to reproduce:
1. Create an English post and assign the "News" category (term_id 31, language: EN)
2. Create a French translation of the post via WPML
3. Assign the "Nouvelles" category (term_id 49, language: FR) to the French translation
4. Save/publish the French translation
5. Return to the original English post — "News" is no longer assigned; "Nouvelles" is assigned instead
Expected behavior:
English post retains "News" (term_id 31). French post has "Nouvelles" (term_id 49). Each post keeps its language-appropriate category.
Actual behavior:
Both the English and French posts end up with "Nouvelles" (term_id 49). The English "News" category is removed from the original post.
Scope:
- 20+ English posts affected, dating back to 2021
- Consistent and reproducible for the "News"/"Nouvelles" pair (trid 828)
- Other category pairs (e.g. "May Momentum 2025" / "MayMomentum 2025 FR") sync correctly on the same posts
Database evidence:
-- English posts incorrectly assigned to French "Nouvelles" (term_id 49):
SELECT p.ID, p.post_title, icl.language_code, t.name, t.term_id
FROM wp_term_relationships tr
JOIN wp_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
JOIN wp_terms t ON tt.term_id = t.term_id
JOIN wp_icl_translations icl ON tr.object_id = icl.element_id
AND icl.element_type = 'post_post'
WHERE tt.term_id = 49 AND icl.language_code = 'en';
-- Returns 20+ English-language posts with the French category
Suspected cause (from code analysis):
The WPML_Term_Adjust_Id::filter() method (hooked on get_term, priority 1) translates term IDs to the current admin language. Its backtrace exclusion list includes wp_update_post and wp_update_term but does not include wp_set_object_terms. During the taxonomy sync triggered by saving a translation, if the admin language context is French, term lookups on the original English post may return the French term, resulting in the wrong term being written to wp_term_relationships.
Thank for the detailed report, this greatly helps!
this is not something that I can say is a current known issue and most likely we will need to further investigate the environment.
I would like to request temporary access (wp-admin and FTP) to your site to test the issue.
(preferably to a test site where the problem has been replicated if possible)
**Before we proceed It is necessary to take FULL BACKUP of your database and your website. Providing us with access, you agree that a backup has been taken **
I often use the Duplicator plugin for this purpose: http://wordpress.org/plugins/duplicator/
You will find the needed fields for this below the comment area when you log in to leave your next reply.
The information you enter is private which means only you and I have access to it.
NOTE: If access to the live site is not possible and the staging site does not exist please provide me with a duplicator package created with the duplicator plugin.