{"id":254174,"date":"2025-12-09T22:04:59","date_gmt":"2025-12-09T22:04:59","guid":{"rendered":"https:\/\/en-ca.wordpress.org\/plugins\/tricot\/"},"modified":"2026-04-29T14:03:37","modified_gmt":"2026-04-29T14:03:37","slug":"tricot","status":"publish","type":"plugin","link":"https:\/\/eu.wordpress.org\/plugins\/tricot\/","author":23353082,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","version":"3.6.9","stable_tag":"3.6.9","tested":"6.9.4","requires":"6.4","requires_php":"7.4","requires_plugins":null,"header_name":"Tricot","header_author":"Tricot","header_description":"Tricot \u2013 Translate and manage your multilingual website differently","assets_banners_color":"","last_updated":"2026-04-29 14:03:37","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/tricotwp.com\/","rating":5,"author_block_rating":0,"active_installs":10,"downloads":1086,"num_ratings":1,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","faq","changelog"],"tags":{"3.2.6":{"tag":"3.2.6","author":"tricot","date":"2025-12-10 14:26:33"},"3.3.3":{"tag":"3.3.3","author":"tricot","date":"2025-12-11 15:19:03"},"3.3.4":{"tag":"3.3.4","author":"tricot","date":"2025-12-12 16:48:07"},"3.3.5":{"tag":"3.3.5","author":"tricot","date":"2025-12-16 18:22:10"},"3.3.6":{"tag":"3.3.6","author":"tricot","date":"2026-01-13 16:45:24"},"3.3.7":{"tag":"3.3.7","author":"tricot","date":"2026-01-26 14:08:32"},"3.4.0":{"tag":"3.4.0","author":"tricot","date":"2026-01-26 14:08:32"},"3.4.1":{"tag":"3.4.1","author":"tricot","date":"2026-02-13 20:30:18"},"3.4.2":{"tag":"3.4.2","author":"tricot","date":"2026-03-02 19:51:37"},"3.5.12":{"tag":"3.5.12","author":"tricot","date":"2026-04-10 18:51:15"},"3.5.2":{"tag":"3.5.2","author":"tricot","date":"2026-03-26 19:29:54"},"3.5.3":{"tag":"3.5.3","author":"tricot","date":"2026-03-26 19:38:45"},"3.5.5":{"tag":"3.5.5","author":"tricot","date":"2026-04-08 14:55:39"},"3.5.9":{"tag":"3.5.9","author":"tricot","date":"2026-04-10 15:42:17"},"3.6.0":{"tag":"3.6.0","author":"tricot","date":"2026-04-21 14:02:49"},"3.6.1":{"tag":"3.6.1","author":"tricot","date":"2026-04-21 18:44:04"},"3.6.8":{"tag":"3.6.8","author":"tricot","date":"2026-04-28 15:42:41"},"3.6.9":{"tag":"3.6.9","author":"tricot","date":"2026-04-29 14:03:37"}},"upgrade_notice":[],"ratings":{"1":0,"2":0,"3":0,"4":0,"5":1},"assets_icons":{"icon.svg":{"filename":"icon.svg","revision":3416519,"resolution":false,"location":"assets","locale":false}},"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["3.2.6","3.3.3","3.3.4","3.3.5","3.3.6","3.3.7","3.4.0","3.4.1","3.4.2","3.5.12","3.5.2","3.5.3","3.5.5","3.5.9","3.6.0","3.6.1","3.6.8","3.6.9"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3416641,"resolution":"1","location":"assets","locale":""},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3416641,"resolution":"2","location":"assets","locale":""},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3416641,"resolution":"3","location":"assets","locale":""}},"screenshots":{"1":"A user-friendly validation table","2":"Automatic translation by AI","3":"Translation of links and media"},"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[2333,252010],"plugin_category":[48],"plugin_contributors":[230567,252011],"plugin_business_model":[],"class_list":["post-254174","plugin","type-plugin","status-publish","hentry","plugin_tags-translation","plugin_tags-tricot","plugin_category-language-tools","plugin_contributors-horizoncumulus","plugin_contributors-tricot","plugin_committers-tricot"],"banners":[],"icons":{"svg":"https:\/\/ps.w.org\/tricot\/assets\/icon.svg?rev=3416519","icon":"https:\/\/ps.w.org\/tricot\/assets\/icon.svg?rev=3416519","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/tricot\/assets\/screenshot-1.png?rev=3416641","caption":"A user-friendly validation table"},{"src":"https:\/\/ps.w.org\/tricot\/assets\/screenshot-2.png?rev=3416641","caption":"Automatic translation by AI"},{"src":"https:\/\/ps.w.org\/tricot\/assets\/screenshot-3.png?rev=3416641","caption":"Translation of links and media"}],"raw_content":"<!--section=description-->\n<p><strong>Description<\/strong>\nDo you manage a WordPress website? Whether you're a beginner or an expert, with or without technical knowledge, Tricot gives you full control over your translations. By intelligently combining AI and human expertise, Tricot makes multilingual management accessible to all WordPress website managers.<\/p>\n\n<p><strong>The new way to translate your WordPress site<\/strong>\nTricot revolutionizes the way WordPress site owners manage their translations by combining the power of a cutting-edge artificial intelligence engine with an intuitive interface. Our technical architecture is based on a distributed system where a lightweight extension installed on your WordPress site communicates securely with our central application via a dedicated programming interface. This application processes your translation requests using artificial intelligence technologies recognized worldwide for their accuracy and reliability.<\/p>\n\n<p><strong>Your translations, your property<\/strong>\nOne of the fundamental features of our approach is that the translations generated are stored directly in your WordPress database. This architecture ensures that your translations remain accessible and under your control at all times. You benefit from the power of our translation infrastructure while retaining complete autonomy over your multilingual content.<\/p>\n\n<p><strong>A full range of features<\/strong>\nMachine translation using artificial intelligence, multilingual content management, a validation table for reviewing and adjusting translations, automatic detection of content requiring translation, and advanced import and export tools. Everything is accessible via a centralized interface that allows you to efficiently manage all aspects of your multilingual strategy.<\/p>\n\n<h3>Why Tricot<\/h3>\n\n<p><strong>1. Installation in just a few clicks<\/strong>\nForget complex configurations. Activate the Tricot extension, launch AI translation... and your WordPress site is translated!<\/p>\n\n<p><strong>2. Always up to date, in all languages<\/strong>\nTricot detects new content and automatically generates a machine translation. A multilingual site that is always up to date is possible.<\/p>\n\n<p><strong>3. The power of AI and human expertise<\/strong>\nTricot is designed to enhance human intervention. Easily validate and modify machine translations in your validation table.<\/p>\n\n<p><strong>4. Your translations, your property<\/strong>\nThe translated texts belong to you, even without a subscription (but you won't want to do without us!)<\/p>\n\n<p><strong>For more information<\/strong>\nvisit <a href=\"https:\/\/tricotwp.com\/\">tricotwp.com<\/a><\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"can%20i%20edit%20ai-generated%20translations%3F\"><h3>Can I edit AI-generated translations?<\/h3><\/dt>\n<dd><p>Absolutely! Our validation table allows you to validate and edit each AI-generated translation. You can do this directly in your WordPress site interface, or export to CSV, have it reviewed by a professional, and then re-import it (with a PREMIUM subscription). Tricot always informs you of the percentage of your content validated by a human!<\/p><\/dd>\n<dt id=\"how%20long%20does%20it%20take%20to%20translate%20an%20entire%20site%3F\"><h3>How long does it take to translate an entire site?<\/h3><\/dt>\n<dd><p>The initial translation usually takes between 2 and 15 minutes, depending on the size of your WordPress site. Our extension automatically detects all your content and translates it with AI. Then, you can validate the important texts at your own pace.<\/p><\/dd>\n<dt id=\"how%20do%20i%20calculate%20the%20number%20of%20credits%20needed%20to%20translate%20my%20wordpress%20site%3F\"><h3>How do I calculate the number of credits needed to translate my WordPress site?<\/h3><\/dt>\n<dd><p>Credits are needed to activate automatic AI translation. With us, there are no complicated calculations. <strong>1 credit = 1 word translated into 1 language.<\/strong>\nThe average website contains between 10,000 and 20,000 words. That's exactly how many credits you'll need to translate with Tricot! Does your website have more like 50,000 words? Plan on 50,000 credits!\nThen, count on about 20% new content per year.<\/p><\/dd>\n<dt id=\"is%20machine%20translation%20really%20reliable%20for%20a%20professional%20website%3F\"><h3>Is machine translation really reliable for a professional website?<\/h3><\/dt>\n<dd><p>Translations generated by artificial intelligence are high quality and can be suitable for 90% of your content. That said, we recommend always having a human review, especially for critical texts (legal, marketing). Fortunately, our interface is brilliantly designed to simplify the review process!<\/p><\/dd>\n<dt id=\"i%27m%20not%20comfortable%20checking%20translations.%20do%20you%20offer%20a%20professional%20review%20service%3F\"><h3>I'm not comfortable checking translations. Do you offer a professional review service?<\/h3><\/dt>\n<dd><p>Yes! We rely on the services of language experts to review your translations!\nSimply submit a language review request directly in the Tricot interface and a professional will validate your content. Changes will be made directly in your Tricot validation table!\nNo action is required on your part: we take care of everything. The service is billed on demand, according to your plan and the volume.<\/p><\/dd>\n<dt id=\"is%20tricot%20compatible%20with%20my%20theme%20and%20plugins%3F\"><h3>Is Tricot compatible with my theme and plugins?<\/h3><\/dt>\n<dd><p>The Tricot extension works with the vast majority of the most popular WordPress themes and plugins. We support popular builders, form plugins, and even dynamic content.<\/p><\/dd>\n<dt id=\"does%20tricot%20work%20with%20woocommerce%3F\"><h3>Does Tricot work with WooCommerce?<\/h3><\/dt>\n<dd><p>We are working on creating a complete integration that handles not only basic translations (products, descriptions, categories) but also e-commerce subtleties such as dynamic pages, attributes, and automated emails.\nIn the meantime, Tricot already translates your store's standard pages (home, product, about, policy). For a complete multilingual e-commerce solution, we recommend waiting for our upcoming WooCommerce update.<\/p><\/dd>\n<dt id=\"what%20happens%20if%20i%20cancel%20my%20subscription%3F\"><h3>What happens if I cancel my subscription?<\/h3><\/dt>\n<dd><p>Your translations remain active on your site. You keep everything that has been translated. You simply lose access to paid features such as AI translation, automatic content detection, import\/export, etc. That's the advantage of our local architecture.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>3.6.9 - 2026-04-29<\/h4>\n\n<ul>\n<li>FIX - Prevent Tricot from deleting Elementor's generated <code>post-*.css<\/code> files during the frontend translation buffer, avoiding temporary unstyled translated pages caused by 404s on Elementor page CSS.<\/li>\n<\/ul>\n\n<h4>3.6.8 - 2026-04-24<\/h4>\n\n<ul>\n<li>FIX - Two stranded write paths in <code>ajax_update_translation()<\/code> now sync to the Tricot app. (1) Manually adding a media translation in the validation table (<code>type === 'medias'<\/code> branch, <code>tricot_ajax.php<\/code> ~ line 2293) inserted the row locally but never called <code>send_translations()<\/code> \u2014 the app's domain DB stayed unaware of the manual value, and a subsequent re-translation request for the same hash would have hit DeepL again instead of reusing the admin's input. (2) Manually adding a translation for a NEW target language (<code>tricot_ajax.php<\/code> ~ line 2325, the new-lang-variant insert from a source row) had the same gap. Both branches now sync : with <code>auto=false<\/code> if the admin provided a value (manual translation), with <code>auto=true<\/code> if the field was left blank (request a fresh DeepL pass for the new language)<\/li>\n<li>ADD - <code>Tricot_Editor::frontend_editable_types()<\/code> and <code>Tricot_Editor::is_type_frontend_editable($type)<\/code> \u2014 single source of truth for which translation types can be edited in-place via the front-end editor versus types that are only editable in the validation table. Lists <code>content<\/code>, <code>content-html<\/code>, <code>attr<\/code>, <code>link<\/code> (external), <code>image<\/code>, <code>video<\/code>, <code>iframe<\/code>, <code>media-attr<\/code>, <code>title<\/code>, <code>excerpt<\/code>. Excludes <code>meta:*<\/code> (in <code>&lt;head&gt;<\/code>, not clickable), <code>attachment<\/code> (URL-only), <code>gravityforms<\/code> \/ <code>wpforms<\/code> \/ <code>formidable<\/code> \/ <code>fluentforms<\/code> \/ <code>woocommerce<\/code> \/ <code>media:*<\/code> (rendered via plugin filters outside the DOM scanner's reach \u2014 the form wrappers are explicitly excluded from DOM parsing by design). Helper available for future UI work (3.7.0 will add a \"scope\" badge in the validation table)<\/li>\n<li>ADD - Front-end editor markers now extended to <code>video<\/code> and <code>iframe<\/code> elements. Admin can click a translated video \/ iframe URL on the live site and edit it in-place via the editor tooltip, same as external links. The <code>hash<\/code> is now propagated through <code>check_translations()<\/code> for these types so <code>apply_translations()<\/code> can attach the <code>tricot<\/code> \/ <code>original<\/code> \/ <code>hash<\/code> attributes when the front-end translator session is active. Coverage previously stopped at text and image markers \u2014 gap closed for embed-style media<\/li>\n<li>DEV - Audit compl\u00e8te des chemins d\u00e9tection \u2192 app : <code>tricot_ajax<\/code> (corrig\u00e9), <code>tricot_dom<\/code> (queue + flush \u2713), <code>tricot_url::cron_indexation<\/code> (passe par DOM scanner du wp_remote_get \u2713), <code>Tricot_Tierce\/*<\/code> (queue via <code>string_translate<\/code> + flush shutdown \u2713), <code>tricot_media_library::index_attachment_meta<\/code> (call direct \u2713), <code>tricot_media_library::attachment_fields_to_save<\/code> (call direct \u2713). Aucun autre orphelin identifi\u00e9<\/li>\n<\/ul>\n\n<h4>3.6.7 - 2026-04-24<\/h4>\n\n<ul>\n<li>MOD - \"Clean stuck placeholders\" button moved from the Glossary page to Advanced Settings (new \"Maintenance\" section). This is an emergency tool, not a day-to-day glossary operation \u2014 it now lives alongside the other maintenance toggles (debug level, cron interval, detection depth) and no longer clutters the Glossary admin UI. Also no longer gated on <code>can('glossary')<\/code> : an ex-Pro site that downgraded to Free must still be able to clean up contaminated rows (the Glossary page redirect is gated, the Advanced Settings page is only gated on <code>manage_options<\/code>, so this fix unlocks the maintenance for every site)<\/li>\n<li>FIX - \"Force replace existing translations\" (Glossary page) is now actually forcing re-translation when a new glossary term needs to apply to existing rows. Before 3.6.7, pass 3 (the re-translation via API path, used when local substitution cannot align the existing translation with the new glossary) was silently broken : the plugin cleared <code>translated<\/code> and re-queued the IDs, but the app's <code>receive_text()<\/code> short-circuited on its cached <code>translation_auto<\/code> column and returned the OLD translation \u2014 the one that predates the glossary change \u2014 without ever calling DeepL again. <code>restore_masked_terms()<\/code> then ran on a string that never contained the mask tokens, producing a no-op. Result : admin clicks \"Force apply\", sees \"N translations updated\", and sees zero actual change on the front-end. The plugin now calls the new App 0.9.7 endpoint <code>POST \/wp-json\/tricot\/v1\/flush_auto_cache<\/code> with the exact list of hashes to invalidate BEFORE re-submitting \u2014 forcing the app to run DeepL fresh with the new masking, and glossary terms actually propagate to existing translations. Same pattern as the 3.6.5 stuck-placeholders fix, but scoped by hash list rather than LIKE scan of the domain. Answers the recurring report \"le glossaire ne s'applique pas aux traductions existantes\"<\/li>\n<\/ul>\n\n<h4>3.6.6 - 2026-04-24<\/h4>\n\n<ul>\n<li>FIX - Priority rule on the <code>type<\/code> column when two capture paths land on the same hash. Before this release, a string captured by the generic DOM scanner (type <code>content<\/code>) and also captured by a dedicated integration (type <code>gravityforms<\/code>, <code>wpforms<\/code>, <code>formidable<\/code>, <code>fluentforms<\/code>, <code>woocommerce<\/code>, <code>meta:title<\/code>, <code>meta:description<\/code>) would oscillate between the two values depending on hook order from one request to the next \u2014 making the \"Type\" filter in the validation table unreliable. The integration type now always wins against a DOM type; <code>title<\/code> and <code>excerpt<\/code> keep their previous override behavior; any other transition leaves the first capture in place (avoids ping-pong). New helper <code>Tricot_Translate::known_types()<\/code> centralizes the type list \u2014 extension point for future integrations<\/li>\n<li>ADD - Warning log when <code>send_translations()<\/code> sees an unknown type reaching the app. Detects typos (<code>woocomerce<\/code> vs <code>woocommerce<\/code>) and silent regressions when a new integration forgets to register its type in <code>Tricot_Translate::known_types()<\/code>. Does not block the send \u2014 the <code>type != 'link'<\/code> exclusion remains the only hard gate \u2014 just surfaces the new type in the debug log for audit<\/li>\n<li>ADD - Anonymous visitor throttle on <code>send_translations()<\/code> (2-second global window, transient-backed). Since 3.6.4, detection is open to anonymous visitors \u2014 without throttling, a traffic spike (bot, malicious crawler, post going viral) could fire 1000+ API calls in seconds and burn credits + saturate DeepL. Admin users, the Tricot crawler user-agent, and AJAX calls from the validation table all bypass the throttle. Strings skipped by the throttle stay in the DB with <code>translated = NULL<\/code> and are picked up by the next authenticated visit, a later shutdown flush, or the detection cron<\/li>\n<li>ADD - Informational notice on the Validation table for Free-plan sites explaining that detection continues even without auto-translation \u2014 empty rows are expected and represent future translation work that will unlock once a paid plan is active. Previous users coming back from Pro\/Premium keep seeing their existing translations rendered normally on the front-end (nothing is purged on downgrade except trial-flagged rows)<\/li>\n<li>ADD - Chunking on \"Force replace existing translations\" (Glossary page). Before 3.6.6, the button scanned every translation in one request and sent the full batch to the API \u2014 a site with 10k+ rows would timeout on PHP execution limit or produce an oversized API payload. The button now processes 500 rows per click (configurable via the <code>tricot_glossary_force_apply_chunk<\/code> filter) and reports a \"More remain \u2014 click again\" message when additional rows are pending. No UI change, no background job, just a safe cap that preserves idempotence<\/li>\n<li>FIX - Companion to App 0.9.6 : the app now also detects HTML content heuristically via <code>string_looks_like_html()<\/code>, so integration-tagged strings (<code>gravityforms<\/code>, <code>wpforms<\/code>, <code>fluentforms<\/code>, <code>formidable<\/code>, <code>complianz<\/code>, <code>woocommerce<\/code>) containing real HTML markup (form descriptions with styling tags, confirmation messages, RGPD banner copy, transactional emails) are now passed to DeepL with <code>tag_handling: html<\/code> \u2014 tags preserved, attributes intact, entities not mangled. Previously, only the literal type string <code>content-html<\/code> (emitted by the Unified HTML DOM mode) triggered HTML mode; everything else went through as plain text<\/li>\n<\/ul>\n\n<h4>3.6.5 - 2026-04-24<\/h4>\n\n<ul>\n<li>ADD - New \"Clean stuck placeholders\" button on the Glossary page. Scans the local translations table with <code>LIKE '%TRICOTGLOSSARYTOKEN%'<\/code> and <code>LIKE '%XZQTGM%QZX%'<\/code> \u2014 portable across MySQL versions\/collations and broad enough to catch placeholders whose suffix was mutilated by DeepL (e.g. <code>TRICOTGLOSSARYTOKEN1KNITTING<\/code> where the \"TRICOT\" tail was translated). Clears <code>translated<\/code> and <code>suggested<\/code>, resets <code>validated<\/code> to 0, invalidates the in-process glossary mask cache, and re-queues those rows through the auto-translation pipeline so DeepL returns clean values. Answers the case where admins cannot remove stuck placeholders manually : <code>force_apply_to_existing_translations()<\/code> skips rows whose originating glossary entry has been deleted since, leaving the tokens visible in the validation table with no UI path to flush them<\/li>\n<li>ADD - The button also calls the new Tricot App endpoint <code>POST \/wp-json\/tricot\/v1\/clean_stuck_placeholders<\/code> (App 0.9.5+) BEFORE re-submitting the affected IDs for auto-translation. Without this server-side flush, the retry was a no-op : the app's <code>receive_text()<\/code> handler short-circuits to the cached <code>translation_auto<\/code> column when it is non-empty, so re-submitting a contaminated hash returned the same stuck placeholder from the app instead of calling DeepL again. The plugin now guarantees the app's <code>translation_auto<\/code> \/ <code>translation_user<\/code> \/ <code>translation<\/code> columns for the affected hashes are NULLed first, so the next <code>send_translations()<\/code> triggers a fresh DeepL pass with the safe placeholder masking. The admin notice now reports both local and app-side cleanup counts<\/li>\n<\/ul>\n\n<h4>3.6.4 - 2026-04-23<\/h4>\n\n<ul>\n<li>FIX - Glossary mask placeholders (<code>XZQTGM****QZX<\/code>) stayed stuck in translations for batches that crossed multiple target languages at once. Root cause : <code>Tricot_Glossary<\/code> kept the mask-to-target mapping keyed by source hash alone. Since the same source text has one hash but N language-specific target mappings, processing a batch for ES \u2192 EN \u2192 DE \u2192 KO in sequence caused each <code>mask_terms_for_api()<\/code> call to overwrite the previous language's mapping \u2014 at restore time, only the last language had a valid mapping, and every other language ended up with raw placeholders surviving in the DB (and often with a completely wrong language in the output because DeepL got confused by what survived in the prompt). The cache is now keyed by <code>hash + target_lang<\/code>, so each language keeps its own mapping intact<\/li>\n<li>FIX - Gravity Forms placeholders, labels and <code>customLabel<\/code> on sub-inputs were detected but not actually propagated to the rendered HTML when the field was a <code>GF_Field<\/code> object rather than a plain array. <code>$field['placeholder'] = $translated<\/code> via ArrayAccess did not update the public <code>$field-&gt;placeholder<\/code> property that GF's rendering code actually reads, and <code>$field['inputs']<\/code> sometimes returned a copy of the internal array \u2014 modifications via <code>foreach (&amp;$input)<\/code> wrote to the copy, never the original. The integration now writes directly to public properties for objects and reassigns nested arrays in full after local modification, guaranteeing the translations land where GF actually looks for them<\/li>\n<li>FIX - Gravity Forms submit \/ next \/ previous buttons now translated even when the rendered HTML bypasses <code>$form['button']['text']<\/code>. Some themes, add-ons or locale overrides rebuild the button HTML from their own strings, so modifying the form object via <code>gform_pre_render<\/code> wasn't enough \u2014 the final rendered text remained in the source language. Added filters on <code>gform_submit_button<\/code>, <code>gform_next_button<\/code> and <code>gform_previous_button<\/code> that translate the <code>value=\"\"<\/code> attribute of <code>&lt;input type=\"submit\"&gt;<\/code> and the inner text of <code>&lt;button&gt;...&lt;\/button&gt;<\/code> directly on the rendered HTML, as a safety net over the upstream form-object filter<\/li>\n<li>ADD - Validation table's \"Type\" filter dropdown now builds dynamically from the types actually present in the translations table. Instead of showing every possible integration (Gravity Forms, WPForms, Fluent Forms, Formidable, WooCommerce) whether or not they're used, only types with at least one row in <code>wp_tricot_translations<\/code> appear \u2014 a site that only uses Gravity Forms won't see empty \"WPForms\" or \"Formidable\" options in the filter<\/li>\n<li>FIX - Detection and auto-translation now run for anonymous visitors (not only admins and the Tricot crawler). Previously two gates in <code>tricot_dom.php<\/code> were scoped to <code>is_user_logged_in() || TricotCrawler<\/code> : the send-to-App step in <code>check_translations()<\/code> and the <code>table_sources.timestamp<\/code> refresh that marks a page as \"recently seen\". That meant strings rendered only to public visitors \u2014 meta:title via Yoast \/ SEOPress \/ RankMath, ACF-driven content, conditional blocks \u2014 stayed in the database with <code>translated = NULL<\/code> until an admin happened to visit the same page, and the admin had no feedback that detection had actually occurred. Both gates are now open by default. Can be restored to the previous restricted behavior by defining <code>TRICOT_ADMIN_ONLY_AUTO_TRANSLATE<\/code> in <code>wp-config.php<\/code><\/li>\n<li>FIX - Gravity Forms specifically : the <code>.gform_wrapper<\/code> DOM subtree is explicitly excluded from Tricot's DOM parser (by design, since GF uses its own <code>gform_pre_render<\/code> filter), so <code>check_translations()<\/code> never flushes GF strings. Added a dedicated flush at the end of <code>translate_form()<\/code> that sends pending GF translations to the App right after the form has been processed \u2014 with full request context (source_id, urls, license, api all guaranteed initialised) rather than waiting for the shutdown hook where some of that context can be missing. Idempotent across multiple form renders per request<\/li>\n<li>FIX - Third-party plugin strings (Gravity Forms, WPForms, Fluent Forms, Formidable, WooCommerce) were silently dropped from the translation batch sent to the App. The whitelist in <code>send_translations()<\/code> only kept <code>content<\/code>, <code>title<\/code>, <code>excerpt<\/code>, <code>meta:*<\/code> and <code>media:*<\/code> \u2014 every integration-specific type was filtered out before reaching DeepL, leaving rows stuck with <code>translated = NULL<\/code> in the validation table. Replaced the whitelist with a narrower exclusion that only skips <code>link<\/code> (which has its own URL pipeline), so every textual type now reaches the App regardless of its origin plugin<\/li>\n<li>FIX - Auto-translation now triggers reliably for strings detected outside the DOM pipeline \u2014 WPForms, Fluent Forms, Formidable, Yoast \/ SEOPress \/ RankMath SEO (meta:title, meta:description), ACF, etc. Previously, strings picked up by these third-party filters landed in the database with <code>translated = NULL<\/code> and waited for an admin or the Tricot crawler to visit the page before being sent to the App. Now a centralized end-of-request flush (<code>shutdown<\/code> hook) sends any pending new translations regardless of the detection channel, so anonymous visitors to a public form or a SEO-driven page will get translated content on subsequent visits without waiting for an admin pass<\/li>\n<li>FIX - Gravity Forms : placeholders and labels now reliably translated on field types that stored them outside the main <code>placeholder<\/code> key. Added coverage for <code>chooseFile<\/code> (fileupload button), <code>checkboxLabel<\/code> (consent fields), <code>nextButton<\/code> \/ <code>previousButton<\/code> on multi-step page fields, the form-level <code>lastPageButton<\/code>, and <code>customLabel<\/code> \/ <code>defaultValue<\/code> on sub-inputs of name, address, and email\/password-with-confirmation fields. Also hardened the traversal against fields\/choices\/inputs returned as objects instead of plain arrays<\/li>\n<\/ul>\n\n<h4>3.6.3 - 2026-04-21<\/h4>\n\n<ul>\n<li>ADD - New \"Group formatted sentences\" toggle in Advanced settings (Site indexing section) to disable the automatic grouping of sentences with inline styling. Useful on themes that produce many structural widgets where grouping causes unwanted reordering<\/li>\n<\/ul>\n\n<h4>3.6.2 - 2026-04-21<\/h4>\n\n<ul>\n<li>FIX - Price widgets and other structural blocks (e.g. \"15 $ \/ mois\" with inline-styled spans) are no longer mistakenly unified as one translation string. Tricot now requires at least one direct text node around inline elements before treating a parent as a prose paragraph \u2014 widgets made of pure span-only structure are kept fragmented and translated token by token, preserving numbers and currency positioning<\/li>\n<\/ul>\n\n<h4>3.6.1 - 2026-04-21<\/h4>\n\n<ul>\n<li>ADD - Free 7-day trial with 3,000 credits and most Premium features \u2014 new option in the installation wizard, with countdown banner, automatic conversion to Pro\/Premium on payment, and post-expiration retention window<\/li>\n<li>ADD - License expiration date now displayed next to the Active badge on the License activation page, plus new \"Upgrade my license\" button that redirects to the customer portal<\/li>\n<li>ADD - Credit management page redesigned with dynamic display of the 3 credit bundles available for the current plan<\/li>\n<li>ADD - Range selection (Shift+Click) on the Validation table and Links\/Media table bulk-select checkboxes \u2014 standard file-manager behaviour<\/li>\n<li>ADD - Dedicated compatibility modules for Yoast SEO, Rank Math, All In One SEO, The SEO Framework, Slim SEO, SmartCrawl, Gravity Forms, WPForms, Formidable Forms, Fluent Forms, Elementor, Divi, The Events Calendar, Complianz (RGPD)<\/li>\n<li>ADD - Automatic cache invalidation on translation changes for WP Rocket, W3 Total Cache, LiteSpeed, WP Super Cache, WP Fastest Cache, SG Optimizer, Hummingbird, Cache Enabler, Breeze<\/li>\n<li>ADD - Configurable detection cron frequency and start hour in Advanced settings \u2014 from every 30 minutes to once a day, with a 2 AM default to scan during off-peak hours<\/li>\n<li>ADD - Advanced ACF integration toggle (Advanced settings \u2192 ACF integration) for themes that read ACF values outside standard HTML rendering (REST API, JavaScript, Options Pages)<\/li>\n<li>ADD - Glossary now available on the Pro plan (previously Premium-only) \u2014 no more lockout for clients who add terms during trial and convert to Pro<\/li>\n<li>MOD - Wizard pricing updated \u2014 PRO: $240\/year, PREMIUM: $480\/year (was $260 and $486)<\/li>\n<li>MOD - Menu label \"Gestion du cr\u00e9dit\" corrected to \"Gestion des cr\u00e9dits\" (plural)<\/li>\n<li>MOD - Trial countdown hour\/day rollover is now intuitive \u2014 a freshly-started 7-day trial displays \"7 jours\" instead of \"6 jours\"<\/li>\n<li>FIX - Glossary terms are now reliably applied to new and existing translations \u2014 placeholder masking is more robust against DeepL quirks, and the \"Re-apply to existing translations\" button now re-translates through the API when a simple substitution is not enough<\/li>\n<li>FIX - WordPress native spinners (inline edit save, media uploads, updates) no longer break due to a CSS class collision<\/li>\n<li>FIX - Yoast SEO and Gravity Forms integrations are now effectively loaded (previously dormant due to an initialization oversight)<\/li>\n<li>FIX - Conversion from trial to paid plan now correctly deducts credits consumed during the trial from the new plan's pack<\/li>\n<li>FIX - \"License partially converted \u2014 repair required\" banner no longer stays displayed on already-converted licenses<\/li>\n<li>SEC - All new REST endpoints protected by license + API key validation on the public side, and <code>manage_options<\/code> capability on the administration side<\/li>\n<\/ul>\n\n<h4>3.5.12 - 2026-04-10<\/h4>\n\n<ul>\n<li>FIX - SEOPress meta titles and descriptions are now captured during manual detection as long as the \"SEO content\" option is enabled in Manage Languages. The legacy <code>tricot_crawler_seo<\/code> option (only set by the old crawler) is no longer the sole gatekeeper for meta:title\/meta:description insertion \u2014 the global <code>automatic_options[\"seo\"]<\/code> setting now takes precedence, which matches user expectation<\/li>\n<li>FIX - Automatic placement toggle in the Language selector page now actually disables the feature when unchecked: the menu_locations list is cleared on save, so the language selector is no longer injected in any menu even if checkboxes remained ticked in the (now hidden) settings panel<\/li>\n<li>ADD - New <code>auto_placement_enabled<\/code> boolean field in the <code>tricot_language_switcher_options<\/code> schema with backward-compatible default inferred from the presence of existing menu_locations<\/li>\n<\/ul>\n\n<h4>3.5.11 - 2026-04-10<\/h4>\n\n<ul>\n<li>FIX - Detection progress polling no longer aborts on the first transient network error. A consecutive-failure counter with exponential backoff (up to 30 seconds between retries) lets the detection resume automatically when the server recovers. The polling only surrenders after 10 consecutive failures (about 2 minutes of sustained disconnection)<\/li>\n<li>FIX - AJAX polling requests now have a 60-second timeout instead of the jQuery default, accommodating slow servers that occasionally need longer to respond during heavy detection batches<\/li>\n<li>MOD - Detection error counter is reset at the start of a new manual detection run and after every successful poll, so brief hiccups don't accumulate across sessions<\/li>\n<\/ul>\n\n<h4>3.5.10 - 2026-04-10<\/h4>\n\n<ul>\n<li>ADD - New <code>Tricot::ui_excluded_post_types()<\/code> helper and <code>tricot_ui_excluded_post_types<\/code> filter centralizing the list of custom post types hidden from selection menus (wizard, indexation, manage languages, crawler)<\/li>\n<li>FIX - SEOPress meta title and meta description translation filters (<code>seopress_titles_title<\/code>, <code>seopress_titles_desc<\/code>) are now guaranteed to run regardless of the SEOPress 404\/bot custom post type exclusions \u2014 the CPT filters only hide entries from user selection UIs and never block the filter-based integration<\/li>\n<li>MOD - CPT exclusions (elementor_library, e-floating-buttons, seopress_404, seopress_bot) are now sourced from a single list in the core class instead of being hardcoded in 6 separate files, preventing drift and making the list extensible via filter<\/li>\n<\/ul>\n\n<h4>3.5.9 - 2026-04-10<\/h4>\n\n<ul>\n<li>ADD - New \"Migrated\" option in the status filter of the validation table, export modal and validation request modal, letting administrators quickly isolate translations imported from the Tricot Migration plugin<\/li>\n<li>ADD - New \"migrated\" localized string in tricotValidation JavaScript strings<\/li>\n<\/ul>\n\n<h4>3.5.8 - 2026-04-10<\/h4>\n\n<ul>\n<li>ADD - New validation state \"Migrated\" (value 4) for translations imported from Tricot Migration plugin, displayed with distinct #97A5FF toggle color<\/li>\n<li>ADD - CSV\/XLIFF export now labels migrated translations as \"Migrated\" instead of \"No\"<\/li>\n<li>ADD - Import recognizes \"Migrated\" as a validation state and preserves it on round-trips<\/li>\n<li>MOD - Validation filter \"Validated\" now includes state 4 (migrated) alongside states 1 and 3<\/li>\n<li>MOD - Validation statistics count migrated translations as validated<\/li>\n<li>FIX - User interaction with a migrated toggle (uncheck then recheck) correctly downgrades the state from 4 to 1 (user-validated)<\/li>\n<\/ul>\n\n<h4>3.5.6 - 2026-04-09<\/h4>\n\n<ul>\n<li>ADD - XLIFF 1.2 export and import support for professional translation tool interoperability<\/li>\n<li>ADD - Bulk media metadata translation button on the Links &amp; Media page with progress indicator<\/li>\n<li>ADD - Floating language selector options in the setup wizard (enable, position, display style)<\/li>\n<li>ADD - Language detection hint in wizard step 2 with link to WordPress general settings<\/li>\n<li>ADD - Automatic placement toggle and responsive visibility settings (hide on mobile\/desktop with independent breakpoint) for menu-based selector<\/li>\n<li>ADD - All content types now checked by default on first wizard run for automatic translation<\/li>\n<li>MOD - Language selector settings page reorganized into four clear sections: Floating selector with live preview, WordPress menu integration, Automatic placement, and Manual integration (shortcodes &amp; PHP)<\/li>\n<li>MOD - Post editor Tricot meta box redesigned with URL slug prefix preview and clear action links<\/li>\n<li>MOD - Import file upload now registers custom MIME types to prevent WordPress upload restrictions on CSV, TSV, JSON, XML, XLIFF files<\/li>\n<li>MOD - XLIFF and structured format imports bypass column mapping step automatically<\/li>\n<li>MOD - SEOPress 404\/bot post types excluded from detection across all entry points (crawler, manual detection, wizard, indexation UI)<\/li>\n<li>MOD - Default floating selector colors updated (text: #232323, accent: #424242)<\/li>\n<li>FIX - Frontend editor save button no longer spins indefinitely<\/li>\n<li>FIX - Frontend editor tooltip remains responsive after a network error<\/li>\n<li>FIX - Content detection no longer stalls when WP-Cron is unavailable<\/li>\n<li>FIX - Redundant link translation call on every page load<\/li>\n<li>MOD - Improved page rendering performance with media URL caching and reduced autoloaded options<\/li>\n<li>SECURITY - Hardened frontend HTML sanitization and DOM error handling<\/li>\n<\/ul>\n\n<h4>3.5.5 - 2026-04-08<\/h4>\n\n<ul>\n<li>ADD - Manual detection now runs as a dedicated resilient background job independent from cron, save_post and page-load detection flows<\/li>\n<li>ADD - Manual detection batches process a few sources at a time with heartbeat, locking and automatic continuation in background<\/li>\n<li>ADD - Automatic retry handling for failed manual detection items before marking them as final errors<\/li>\n<li>ADD - Stalled manual detection jobs are now revived automatically instead of leaving the progress indicator stuck indefinitely<\/li>\n<li>MOD - Manage Languages manual detection now resumes and tracks the dedicated background job instead of relying on the legacy global cron progress state<\/li>\n<li>MOD - Wizard detection step now starts the dedicated manual detection job on the progress screen instead of triggering the legacy cron launch during redirect<\/li>\n<li>FIX - Manual detection no longer reports success when nothing new was actually started because an old scheduled cron task already existed<\/li>\n<li>FIX - Manual detection progress polling now stops cleanly on completion or failure instead of waiting forever for an exact 100% state<\/li>\n<\/ul>\n\n<h4>3.5.4 - 2026-04-07<\/h4>\n\n<ul>\n<li>ADD - Detection of media URLs used in inline background and background-image CSS declarations so background images can be translated like standard media<\/li>\n<li>ADD - Detection of media URLs in background-related HTML attributes such as data-bg, data-background, data-image, data-img and data-parallax when they reference WordPress attachments<\/li>\n<li>ADD - New DOM media-attribute translation flow to rewrite translated media URLs directly inside style and supported data-* attributes<\/li>\n<li>ADD - Frontend translator support for background-based media through new editable media markers on non-img elements<\/li>\n<li>ADD - Frontend image\/media tooltip can now target elements using translated background media, not only  tags<\/li>\n<li>ADD - Frontend media editor now previews original and translated background media and updates the corresponding attribute on save<\/li>\n<li>ADD - Media background elements now expose frontend translation metadata such as original URL, translated URL, original attachment ID and translated attachment ID for editing support<\/li>\n<li>Fix \u2014 Code mort dans tricot_rewrit_endpoint()<\/li>\n<li>Fix \u2014 Correction sur l'initialisation des cookies qui entre en conflit avec le header<\/li>\n<li>Fix \u2014 Early return pour les webhooks POST JSON<\/li>\n<li>Fix \u2014 Null guard sur tricot_home_url<\/li>\n<\/ul>\n\n<h4>3.5.3 - 2026-03-24<\/h4>\n\n<ul>\n<li>ADD - Unified HTML translation mode to keep formatted blocks (<br \/>, inline tags, WYSIWYG output) as a single translation string<\/li>\n<li>ADD - Helper tricot_wrap_unified_html() and dedicated advanced settings documentation for unified HTML translation<\/li>\n<li>ADD - ACF integration for unified translation on text, textarea and WYSIWYG fields<\/li>\n<li>ADD - Glossary and translation memory page with preferred terms management and force apply on existing translations<\/li>\n<li>ADD - Glossary suggestions displayed directly in the validation table<\/li>\n<li>ADD - Glossary terms injected in translation requests and exact glossary matches applied automatically when possible<\/li>\n<li>ADD - Language switcher floating mode with flags, positioning, style controls, responsive visibility options and live preview<\/li>\n<li>ADD - Improved language switcher rendering with flag assets and new display combinations<\/li>\n<li>ADD - Validation by Tricot workflow from the validation table with request summary, checkout flow and dedicated import page<\/li>\n<li>ADD - Distinct \"validated by Tricot\" status in the validation table<\/li>\n<li>ADD - Export now supports CSV, TSV, JSON, XML and XLSX formats<\/li>\n<li>ADD - Import now supports CSV, TSV, TXT, JSON, XML and XLSX formats with column mapping and validation mode selection<\/li>\n<li>ADD - Unified HTML is now available as a dedicated type in the validation filters and preserves HTML during manual edits<\/li>\n<li>ADD - Media metadata translation support for title, alt text, caption and description, including auto-translation support<\/li>\n<\/ul>\n\n<h4>3.4.2 - 2026-03-02<\/h4>\n\n<ul>\n<li>FIX - URL auto translations<\/li>\n<li>FIX - URL where slug begin with the language<\/li>\n<li>REMOVE - Tricot banner with Free license<\/li>\n<\/ul>\n\n<h4>3.4.1 - 2026-02-13<\/h4>\n\n<ul>\n<li>ADD - WooCommerce translate url redirection to language on add to cart<\/li>\n<li>ADD - Domain switcher \u2013 auto-detection of new domain to swap license and authorize a second domain for development<\/li>\n<li>MOD - Optimised date format<\/li>\n<li>FIX - Translate if debug is active but non debug display<\/li>\n<\/ul>\n\n<h4>3.4.0 - 2026-01-22<\/h4>\n\n<ul>\n<li>ADD - Support Woocommerce<\/li>\n<li>ADD - Warning if PHP DOM is not active<\/li>\n<li>ADD - Meta type in validation filter<\/li>\n<li>ADD - Send context for better translation to DeepL<\/li>\n<li>ADD - Translate Placeholder for textarea<\/li>\n<li>FIX - Media order show from recent to oldest<\/li>\n<\/ul>\n\n<h4>3.3.7 - 2026-01-20<\/h4>\n\n<ul>\n<li>FIX - Support url translation under subdirectory<\/li>\n<\/ul>\n\n<h4>3.3.6 - 2026-01-13<\/h4>\n\n<ul>\n<li>ADD - Translation capture - Advance mode VS Legacy mode<\/li>\n<\/ul>\n\n<h4>3.3.5 - 2025-12-16<\/h4>\n\n<ul>\n<li>FIX - error with image on save translation<\/li>\n<\/ul>\n\n<h4>3.3.4 - 2025-12-12<\/h4>\n\n<ul>\n<li>FIX - Compatibility issue with Gravity Form Ajax (iframe src=about:)<\/li>\n<\/ul>\n\n<h4>3.3.3 - 2025-12-10<\/h4>\n\n<ul>\n<li>Message change for Popup on new language for indexation<\/li>\n<li>French Canada translation updated<\/li>\n<\/ul>\n\n<h4>3.3.2 - 2025-12-03<\/h4>\n\n<ul>\n<li>ADD - Support Wordpress 6.9<\/li>\n<li>ADD - Popup on new language for indexation<\/li>\n<li>ADD - Button at the end of wizard<\/li>\n<li>ADD - Color base on low credits<\/li>\n<li>MOD - Remove Custom CSS<\/li>\n<li>MOD - Remplace ob_start by worpdress inner function pour html buffer<\/li>\n<li>FIX - Translation of Portuguese (Brazilian)<\/li>\n<\/ul>\n\n<h4>3.3.1 - 2025-11-27<\/h4>\n\n<ul>\n<li>FIX - Saving public language<\/li>\n<li>ADD - Allow translation of placeholder<\/li>\n<li>ADD - Allow translation of video and iframe<\/li>\n<li>ADD - Frondend Translator(Beta)<\/li>\n<\/ul>\n\n<h4>3.2.6 - 2025-10-29<\/h4>\n\n<ul>\n<li>FIX - Wizard wasn't sending correctly language to server<\/li>\n<li>FIX - Error on some languages configuration<\/li>\n<\/ul>\n\n<h4>3.2.4 - 2025-10-28<\/h4>\n\n<ul>\n<li>ADD - Configuration wizard<\/li>\n<li>ADD - Manually add a custom link for translation<\/li>\n<li>MOD - Enhanced visual for restricted option on free plan<\/li>\n<li>MOD - Review visual of the manage language page<\/li>\n<li>MOD - Change logic for automatic detection for autotranslation<\/li>\n<li>MOD - Automatic detection run by CRON<\/li>\n<li>MOD - Separate the Language Selector page from the language management page.<\/li>\n<li>FIX - API Call when deleting translation<\/li>\n<li>FIX - Free plan if invalid license<\/li>\n<li>FIX - Automatic translation of the permalink<\/li>\n<li>SECURITY - Review SQL to remove implode Where<\/li>\n<\/ul>\n\n<h4>3.1.2 - 2025-09-19<\/h4>\n\n<ul>\n<li>Version for publication.<\/li>\n<\/ul>\n\n<h4>3.0.1 - 2025-05-27<\/h4>\n\n<ul>\n<li>Plugin created.<\/li>\n<\/ul>","raw_excerpt":"Tricot \u2013 Translate your website quickly and easily","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/eu.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/254174","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/eu.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/eu.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/eu.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=254174"}],"author":[{"embeddable":true,"href":"https:\/\/eu.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/tricot"}],"wp:attachment":[{"href":"https:\/\/eu.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=254174"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/eu.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=254174"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/eu.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=254174"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/eu.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=254174"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/eu.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=254174"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/eu.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=254174"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}