---
title: "PerfLocale 1.0.7 - Changelog - PerfLocale"
description: "What changed in PerfLocale 1.0.7, released 2026-10-03. Safer language deletes and Merge imports, bulk translation that survives host time limits, more reliable custom fields, WooCommerce stock and imports from WPML, Polylang and TranslatePress, a model choice for the WordPress AI Client, and new filters"
canonical: "https://perflocale.com/changelog/1.0.7/"
source: "https://perflocale.com/changelog/1.0.7/"
format: "markdown"
---
[← All releases](https://perflocale.com/changelog/)

# PerfLocale 1.0.7

2026-10-03 — Safer language deletes and Merge imports, bulk translation that survives host time limits, more reliable custom fields, WooCommerce stock and imports from WPML, Polylang and TranslatePress, a model choice for the WordPress AI Client, and new filters

-   Security hardening.
-   Behaviour change: a language that still has posts, pages or products outside the Trash cannot be deleted. The Languages screen lists that content with links to it and offers no delete button, the REST API answers 409 language\_has\_content with the counts, and wp perflocale languages delete stops before its prompt. Move the content to the Trash first, or deactivate the language instead: an inactive language keeps its translations linked, so shared stock and SKUs keep working. Terms, media and block theme template copies do not block a delete; they are unlinked and kept.
-   Behaviour change: a Merge import no longer changes this site's settings, add-on settings, add-on list or role capabilities. It counts them as skipped, and the admin notice, the job's details and a WP-CLI warning say that Replace applies them. A file with only the Settings and Roles & Capabilities sections deletes no rows in Replace mode.
-   Behaviour change: with the language cookie turned off, and no code hooking perflocale/language\_cookie/enabled, the browser-language, GeoIP and edge-hint first-visit redirects no longer run, so the default language stays reachable and its entry pages stay cacheable.
-   Behaviour change: saving a product no longer overwrites the stock of a language copy that manages its own stock. Stock moves between languages through sales, refunds and explicit stock changes, so a sale made while the product is being saved, for example by an ERP over the REST API, is never lost. To re-align a copy whose stock has drifted, set its quantity; saving the same number again does not move it.
-   Behaviour change: a password-protected post is sent to a machine translation service only when someone picks that post: in the editor, with a bulk action on selected posts, through the REST API, or by its ID with WP-CLI. The automatic runs (Auto-Translate on Publish, Auto-Translate on Create and the site-wide run) and wp perflocale translate --all skip it. Every machine-translation path asks the new perflocale/mt/send\_password\_protected filter before it sends such a post, so a site can change this for any run.
-   Custom fields: ACF, Meta Box and SEO values stay correct however a post is saved (editor, REST API, WP-CLI, WooCommerce saves from code), including nested groups, repeaters and flexible content. A field a translator empties stays empty.
-   Sync Fields: when a synced field is copied to the other language versions, only that field changes. Their content, title, excerpt, status and publish date (unless the publish date is the synced field) stay exactly as they are, whoever saves; their modified date moves, as on any save.
-   WooCommerce: language copies of a product share one stock at checkout, in the cart and when adding to the cart, including stock held by pending orders. Product blocks and the Store API products route show WooCommerce's own limit per copy; the perflocale/woocommerce/count\_shared\_holds\_in\_catalog filter counts every copy there too.
-   WooCommerce: the block Cart and Checkout show product names, short descriptions and images in the page language from the first view; order line names no longer start with "Protected:"; a sold-individually product cannot be bought twice as two language copies; variations follow the shared stock status.
-   WooCommerce: product translations get the source's catalog visibility, featured flag, shipping class and brand when they are created; a site that makes shipping classes or brands translatable gets the translated terms. On WooCommerce 10.8 or newer they also get their product lookup row, so simple, grouped and external translations sort by price, match price and stock filters and are found by SKU search from the start. On older WooCommerce versions, and for translations created before this release, WooCommerce → Status → Tools → Product lookup tables → Regenerate builds the missing rows.
-   WooCommerce: shop managers can create product translations. On WooCommerce sites the Shop Manager role gets perflocale\_translate once, without machine translation; an owner who removes it keeps it removed, and the new perflocale/roles/shop\_manager\_caps filter returning an empty array grants nothing.
-   WooCommerce: each order email renders in its own language, also after an earlier email stopped part-way, and a stock notification after it in the shop's language. Prices in an order email use the exchange rate of the email's language. Exchange rates must be numbers above zero, and Sync Now shows the rates the sync stored.
-   New filter perflocale/language\_cookie/enabled decides per request whether the language cookie is written; it takes precedence over the cookieless-mode setting, and consent still comes first.
-   New filter perflocale/addon/enabled turns an add-on off (or on) per request, and perflocale()->is\_addon\_active() tells whether it runs.
-   New filter perflocale/sync/seed\_meta\_value changes a meta row before content sync seeds it into a translation that has no value for that key.
-   Admin notices appear above the PerfLocale tab strip and no longer move after the page loads.
-   Saving a settings tab without changes keeps every setting the tab does not show.
-   Excluded paths match whole path segments for redirects and cache tags, and work with non-Latin paths.
-   Uninstall with "Delete all plugin data" also removes PerfLocale's WooCommerce order data (including High-Performance Order Storage) and its scheduled actions.
-   Field changes made during a front-end page view are copied to translations on the next save, so page views never write to other languages. On multisite, each site follows its own Sync Fields setting.
-   Importers: the TranslatePress import reports translations it skipped, import errors no longer show database details, and two import messages can be translated.
-   WordPress AI Client: a small, low-cost model is requested by default, and the new model key of the perflocale/mt/wp\_ai\_client\_args filter chooses another. A model that refuses the temperature setting is asked once more without it. The Machine Translation settings link to Settings → Connectors.
-   Block editor: "Fill in from source" writes each text to its own place (an image's alt text, caption and title; a quote's citation). Blocks marked "Do not translate", and everything inside them, are kept as they are by every block-level action.
-   Strings: "Translate all" continues where the previous run stopped, plural strings get every plural form of the language, Overwrite runs are counted in the estimate, and a run that translated nothing can be retried from the Jobs page.
-   Bulk translation jobs finish on hosts that stop long requests: a background bulk translation job runs in slices of at most 20 seconds or 500 source-target pairs and continues from where the last slice stopped. Under WP-CLI it runs without a time limit and frees memory every 500 pairs. New filters perflocale/jobs/bulk\_translate/slice\_seconds and perflocale/jobs/bulk\_translate/slice\_max\_pairs.
-   Background jobs: a job that stops on a PHP fatal error, such as running out of memory, is marked failed at once, in WP-Cron and Action Scheduler requests and in WP-CLI processes that run them, and releases its locks, so it can be retried right away. A job whose worker was killed holds up the Action Scheduler queue, WooCommerce's actions included, only until its lock expires, and is then marked failed; a job retried after Cancel waits for that lock instead of failing.
-   WooCommerce: machine translation also covers variation descriptions and custom attribute options, and stock and price sync keep pairing the variations.
-   Machine translation: the monthly character limit also covers Create Taxonomy Translations and Create Page Translations; a post is never translated into its own language; wp perflocale translate honours --include-meta.
-   Machine translation: a machine-translation server on a private network, for example a self-hosted LibreTranslate, must be listed with the perflocale/mt/trusted\_hosts filter; the error message names the filter.
-   Imports from WPML, Polylang and TranslatePress: the first import is refused when the default language differs or a language is missing (--dry-run shows the check), only one import runs at a time, an import that loses its lock to another one stops with a message and keeps what it imported, and skipped rows are reported with the reason.
-   WPML import: menus, WooCommerce order languages and category assignments come across, and large string tables import in the background in a fraction of the time; a row whose item already belongs to another WPML translation set is reported, not relinked. Polylang import: menus, site title, tagline and date formats. TranslatePress import: term names, menus, site title and tagline, and each post's author, dates and slug.
-   Assign Default Language, Generate Missing Translations and the other bulk tools ask before running while translations from another plugin have not been imported.
-   WooCommerce: order line names use the checkout language, customer emails use the order's language (or the default language) when sent from the admin, a scheduled task or WP-CLI, and shop notifications use the default language.
-   New filters perflocale/migration/wpml/skipped\_element\_types and perflocale/migration/translatepress/include\_gettext\_copies, and a new action perflocale/language/restored.
-   WooCommerce: every order is tagged with its language whenever the WooCommerce add-on is active, whether or not order emails are translated. An order without a language that is paid on a translated order-pay page (classic or block) takes that page's language before its emails are sent.
-   WooCommerce: an order's personal-data export includes its language, and in the block Cart and Checkout the notice for a sold-individually product names it in the page language.
-   Machine translation: bulk and site-wide runs say how many new translations kept the source content because a "Do not translate" section was lost, on the Translations screen and the Jobs page. In the block editor, a block inside a "Do not translate" block shows why it cannot be translated.
-   WordPress AI Client: when no connected provider is ready, Site Health and the editor's "Set up machine translation" link point to Settings → Connectors. The suggested privacy-policy text names the selected machine-translation provider.
-   Imports: the Jobs page shows each running import's current stage and how many of its items are done. A background import whose worker stopped can be started again after 15 minutes. The TranslatePress import also copies WooCommerce order languages.
-   Changing an existing post's language (on its edit screen, in Quick Edit or with WP-CLI) swaps its categories, tags and other translatable terms for their translations in the new language; a term without one is kept.
-   Translations screen: the status filters and cells, the Dashboard and wp perflocale status take each translation's status from the translation's own post. The Published, Draft and Pending Review filters list every such translation, a translation in the Trash shows Empty and counts as missing, and with All languages a status filter looks at the translations only. A draft source shows Draft in the default-language column, so Dashboard progress numbers can change.
-   Strings: in files mode, translation files are rebuilt when a language is activated, when an active language's locale changes and when the default language changes, and after a plugin update one background run writes any missing file. Site Health names each language whose translations have no compiled file.
-   Roles: changes a site owner makes to the Translator role are kept when a plugin update re-applies capabilities and across a deactivate/activate cycle; a full delete removes them. New filter perflocale/roles/translator\_caps changes the role's defaults.
-   Block themes: customising a template part again after Reset to theme default brings its translations back, marked Needs Update, without creating new copies. A Navigation block without a chosen menu, as in the stock headers, shows the default-language menu on default-language pages and its translation on translated pages.
-   TranslatePress import: only what TranslatePress translated on the page is translated. Whole texts, the alt, title and aria-label attributes, form placeholders and button labels, block settings, shortcode texts and translation blocks, classic-editor paragraphs included, are replaced as a whole; words inside longer text, links and other attributes keep their original text, and a post whose only matches were parts of longer text gets no translation. A part of a post that cannot be read keeps its original text, and the import reports that post.
-   Multisite: network activation is refused, listing the IDs of the sites that failed, when any site cannot be set up.
-   The Languages screen's actions follow the perflocale\_manage\_languages capability, as the REST API does.
-   Domain mode with the default language on the site's own host: the language switcher, hreflang (including x-default) and every default-language link on a language domain point to the site's own host, and the redirect to the default language for an untranslated page goes there. With WooCommerce, untranslated default-language shop pages such as the cart are then on the site's own host.
-   First-visit redirects (browser language, GeoIP, edge hint) go only to a page that shows content in the visitor's language. A page that would answer 404, or send the visitor back to the default language, gets no redirect.
-   Fallback chains work in subdomain and domain mode when the fallback translation keeps the same slug.
-   Subdomain mode no longer shows the per-language domain table, which applies to domain mode only; domains already stored are kept for a switch back to domain mode.
-   The Addons page says when a site filter turns on an add-on whose stored setting is Off. The WPML default-language check states its result in text, and more messages can be translated, with correct plural forms.
-   Fixed: a request with an unusual post\_type query parameter could cause a server error.
-   Fixed: deleting a language with an empty code removed the language tag from every menu.
-   Fixed: a failed database query could make links show untranslated slugs for one request.
-   Fixed: in domain and subdomain URL mode, redirects to another language's host went to the admin area.
-   Fixed: posts without a translation link are shown on their own URL with every missing-translation option, with hreflang tags.
-   Fixed: unknown two-segment URLs showed the front page instead of a 404.
-   Fixed: hreflang tags on page 2 and later of a listing pointed to pages that do not exist in another language.
-   Fixed: after a translation was deleted permanently, its siblings could keep an hreflang tag pointing to it for up to 12 hours.
-   Fixed: the perflocale() helper could not be called from a perflocale/loaded listener.
-   Fixed: page 2 and later, and the feeds, of translated category, tag and product-category archives redirected to page 1.
-   Fixed: wp perflocale languages delete reported success for a delete that was rolled back; it now exits with an error.
-   Fixed: custom fields such as book\_author or \_author\_bio, whose names hold a credential word inside a longer word, were not copied into a new translation.
-   Fixed: in a store whose prices have no decimals, a price or shipping cost converted to a language's currency could round to zero; a converted amount above zero is now at least the smallest unit at the price decimals in use.
-   Performance: on sites without a persistent object cache, a cached translation list that had expired was rebuilt on every request; it is now rebuilt once and then served from the cache.
-   Performance: a front-end search keeps WordPress's own result count, so PerfLocale no longer stores a cached count for each search term.
