{"id":333807,"date":"2026-07-01T12:55:52","date_gmt":"2026-07-01T12:55:52","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/wpml-translation-cleaner\/"},"modified":"2026-07-06T10:14:16","modified_gmt":"2026-07-06T10:14:16","slug":"translation-cleaner-for-wpml","status":"publish","type":"plugin","link":"https:\/\/kab.wordpress.org\/plugins\/translation-cleaner-for-wpml\/","author":15452977,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.1.0","stable_tag":"1.1.0","tested":"7.0","requires":"5.9","requires_php":"7.4","requires_plugins":null,"header_name":"Translation Cleaner for WPML","header_author":"Klemens Hechenberger","header_description":"Safely identify and clean WPML translation issues \u2014 orphan translations, broken groups, and more.","assets_banners_color":"014e86","last_updated":"2026-07-06 10:14:16","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/hechenbros.ch\/plugins\/translation-cleaner-for-wpml\/","header_author_uri":"https:\/\/hechenbros.ch","rating":0,"author_block_rating":0,"active_installs":0,"downloads":70,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"klemensh","date":"2026-07-01 12:55:18"},"1.1.0":{"tag":"1.1.0","author":"klemensh","date":"2026-07-06 10:14:16"}},"upgrade_notice":{"1.1.0":"<p>Adds the Menu Translations module and fixes a bulk action form collision bug that caused the wrong action to fire on delete.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3597568,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3597568,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3597568,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3597568,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0","1.1.0"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"Module overview \u2014 three cards for Orphan Translations, Misassigned Originals, and Orphan Originals","2":"Orphan Translations scan results with reason codes and bulk actions","3":"Misassigned Originals results with per-row language reassignment dropdown","4":"Orphan Originals results with per-row Fix Original action"}},"plugin_section":[],"plugin_tags":[3786,732,99,2333,103],"plugin_category":[48,52],"plugin_contributors":[269729],"plugin_business_model":[],"class_list":["post-333807","plugin","type-plugin","status-publish","hentry","plugin_tags-cleanup","plugin_tags-maintenance","plugin_tags-multilingual","plugin_tags-translation","plugin_tags-wpml","plugin_category-language-tools","plugin_category-performance","plugin_contributors-klemensh","plugin_committers-klemensh"],"banners":{"banner":"https:\/\/ps.w.org\/translation-cleaner-for-wpml\/assets\/banner-772x250.png?rev=3597568","banner_2x":"https:\/\/ps.w.org\/translation-cleaner-for-wpml\/assets\/banner-1544x500.png?rev=3597568","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/translation-cleaner-for-wpml\/assets\/icon-128x128.png?rev=3597568","icon_2x":"https:\/\/ps.w.org\/translation-cleaner-for-wpml\/assets\/icon-256x256.png?rev=3597568","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>Translation Cleaner for WPML helps you keep your multilingual WordPress site clean by identifying and fixing three common categories of WPML data corruption, all from a single admin tool under <strong>Tools \u2192 Translation Cleaner for WPML<\/strong>.<\/p>\n\n<p><strong>Module 1 \u2014 Orphan Translations<\/strong><\/p>\n\n<p>Finds translated posts whose main-language counterpart no longer exists (deleted or trashed). These orphaned records consume storage, clutter your admin, and break WPML's translation groups.<\/p>\n\n<ul>\n<li>Bulk action: Move to Trash (reversible) or Permanently Delete<\/li>\n<li>Reason codes per row: <em>Missing original<\/em>, <em>Original deleted<\/em>, <em>Original trashed<\/em><\/li>\n<li>Every deletion is re-validated immediately before execution \u2014 if the original was restored since the scan, the item is skipped<\/li>\n<\/ul>\n\n<p><strong>Module 2 \u2014 Misplaced Originals<\/strong><\/p>\n\n<p>Finds posts that WPML treats as originals (<code>source_language_code = NULL<\/code>) but are registered under a language that is not your main language \u2014 with no main-language version in that translation group at all.<\/p>\n\n<p>This typically happens when content is created directly in a secondary language without going through the main language first. Left uncorrected, these posts can cause translation workflow issues and incorrect language flags.<\/p>\n\n<ul>\n<li>Per-row fix: select the post's actual language from a dropdown and reassign it \u2014 no bulk guessing<\/li>\n<\/ul>\n\n<p><strong>Module 3 \u2014 Orphan Originals<\/strong><\/p>\n\n<p>Finds cases where a secondary-language post carries the \"original\" flag while a live main-language version exists in the same translation group. WPML incorrectly treats the secondary post as the source, which inverts the translation relationship for both posts.<\/p>\n\n<ul>\n<li>Per-row fix: one click to promote the main-language post to original and demote the secondary to a translation \u2014 the trid (translation group) is preserved<\/li>\n<\/ul>\n\n<p><strong>Common features across all modules<\/strong><\/p>\n\n<ul>\n<li>Scan all WPML-tracked post types, including custom post types<\/li>\n<li>Filter by post type and main language<\/li>\n<li>Detailed results table with sort, search, and pagination<\/li>\n<li>Export results to CSV before taking any action<\/li>\n<li>Developer hooks: <code>wmtc_protected_post_ids<\/code>, <code>wmtc_orphan_results<\/code>, <code>wmtc_before_delete<\/code>, <code>wmtc_after_delete<\/code><\/li>\n<\/ul>\n\n<p><strong>Requirements<\/strong><\/p>\n\n<ul>\n<li>WPML must be installed and active<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>translation-cleaner-for-wpml<\/code> folder to <code>\/wp-content\/plugins\/<\/code><\/li>\n<li>Activate the plugin through <strong>Plugins \u2192 Installed Plugins<\/strong><\/li>\n<li>Navigate to <strong>Tools \u2192 Translation Cleaner for WPML<\/strong><\/li>\n<li>Select a module, choose your main language and post types, then click <strong>Run Scan<\/strong><\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20work%20with%20woocommerce%20multilingual%20%28wcml%29%3F\"><h3>Does this work with WooCommerce Multilingual (WCML)?<\/h3><\/dt>\n<dd><p>Yes. The scanners detect issues regardless of how WPML or WCML registered the content, including products managed in WCML's independent mode.<\/p><\/dd>\n<dt id=\"will%20it%20delete%20or%20modify%20content%20incorrectly%3F\"><h3>Will it delete or modify content incorrectly?<\/h3><\/dt>\n<dd><p>For orphan deletions, every item is re-validated against a fresh database scan immediately before the action runs. For reassignment actions (Misplaced Originals, Orphan Originals), the fix is performed via WPML's own <code>wpml_set_element_language_details<\/code> API \u2014 no raw data is modified outside of WPML's own logic.<\/p><\/dd>\n<dt id=\"can%20i%20undo%20a%20deletion%3F\"><h3>Can I undo a deletion?<\/h3><\/dt>\n<dd><p>Use <strong>Move to Trash<\/strong> for reversible cleanup. <strong>Permanently Delete<\/strong> is irreversible \u2014 always export a CSV and back up your database first. Note: menu translations cannot be trashed and are always permanently deleted.<\/p><\/dd>\n<dt id=\"can%20i%20undo%20a%20language%20reassignment%3F\"><h3>Can I undo a language reassignment?<\/h3><\/dt>\n<dd><p>Not automatically. Before running fixes in bulk, export a CSV so you have a record of the original state. The CSV can be used as a reference to manually revert if needed.<\/p><\/dd>\n<dt id=\"what%20post%20types%20are%20scanned%3F\"><h3>What post types are scanned?<\/h3><\/dt>\n<dd><p>All post types that WPML is tracking in <code>icl_translations<\/code>. Nav menu items are handled separately by the Menu Translations module.<\/p><\/dd>\n<dt id=\"how%20do%20i%20exclude%20specific%20posts%20from%20cleanup%3F\"><h3>How do I exclude specific posts from cleanup?<\/h3><\/dt>\n<dd><p>Use the <code>wmtc_protected_post_ids<\/code> filter:<\/p>\n\n<pre><code>add_filter( 'wmtc_protected_post_ids', function( $ids ) { $ids[] = 42; return $ids; } );\n<\/code><\/pre><\/dd>\n<dt id=\"is%20this%20plugin%20affiliated%20with%20wpml%20or%20onthegosystems%3F\"><h3>Is this plugin affiliated with WPML or OnTheGoSystems?<\/h3><\/dt>\n<dd><p>No. This is an independent tool built to work alongside WPML. WPML is a trademark of OnTheGoSystems.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Fixed: bulk delete and trash actions were being intercepted by per-row action forms (nested form collision) \u2014 permanently delete now works correctly<\/li>\n<li>Fixed: Move to Trash now falls back to permanent delete for post types that do not support trash (e.g. nav_menu_item)<\/li>\n<li>Fixed: scan results were cleared after a bulk action due to missing module key in session refresh<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release<\/li>\n<li>Module: Orphan Translations \u2014 find and delete orphaned translation posts<\/li>\n<li>Module: Misassigned Originals \u2014 find and reassign posts flagged as originals in the wrong language<\/li>\n<li>Module: Orphan Originals \u2014 fix inverted original\/translation relationships within a translation group<\/li>\n<\/ul>","raw_excerpt":"Find and fix WPML data issues \u2014 orphaned translations, misplaced originals, and swapped original flags.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/kab.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/333807","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kab.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/kab.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/kab.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=333807"}],"author":[{"embeddable":true,"href":"https:\/\/kab.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/klemensh"}],"wp:attachment":[{"href":"https:\/\/kab.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=333807"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/kab.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=333807"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/kab.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=333807"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/kab.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=333807"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/kab.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=333807"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/kab.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=333807"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}