Migration
PerfLocale ships with importers for the three most common multilingual plugins. Each one reads the source plugin’s data and writes equivalent rows into PerfLocale’s own tables - your original plugin’s data is left untouched, so you can re-run or abandon a migration at any point without losing work.
Supported sources
- WPML - posts, terms, strings.
- Polylang - posts, terms. (String translations are not imported; see the page for details.)
- TranslatePress - posts (reconstructed from the string dictionary), strings, translated slugs.
Imports from qTranslate-X, Multisite Language Switcher, GTranslate, or other multilingual plugins are not currently bundled. If you’re on one of those, you can export via WPML’s importer first (many of them offer a WPML-compatible bridge) then run the PerfLocale WPML importer.
Before you start
- Back up your database. The importer doesn’t modify the source plugin’s data, but it does write new rows into PerfLocale’s own tables, and a backup is always the right baseline before a structural change.
- Install and activate PerfLocale. The source plugin can stay active - the importer reads its database tables, not its runtime. Leaving both plugins active during the import means PerfLocale can validate against live data.
- Add every language you intend to migrate in PerfLocale → Languages before running the importer. Language matching is done by
slugfirst (e.g.fron both sides) then falls back to alocaleprefix match (e.g. PerfLocale’sfr_FRagainst WPML’sfr). Any source language without a PerfLocale match is reported as an error and its content is skipped - the importer doesn’t auto-create languages for you, by design. - Decide whether to run the admin UI or WP-CLI. For sites with more than a few hundred posts, use WP-CLI: it avoids PHP max-execution-time limits that the admin-request path can run into on shared hosting.
How it works
Every importer follows the same shape:
- Detection.
can_import()checks that the source plugin’s data exists (e.g. WPML’sicl_translationstable, Polylang’slanguagetaxonomy, TranslatePress’strp_original_stringstable). If not found, the import is refused with a clear error. - Language mapping. Every language code in the source is matched to a PerfLocale language ID. Unmatched languages produce a warning and their content is skipped - the rest of the import proceeds.
- Data migration. Posts and terms are grouped into PerfLocale translation groups. Strings get hashed and inserted into
wp_perflocale_strings, then their translations are linked per language. - Idempotent re-runs. If a translation group already exists for one of the items being imported, the importer reuses that group and adds any missing siblings. Re-running after a partial failure fills the gaps instead of creating duplicates.
Safety model
What the importer guarantees:
- Source data is read-only. The importer never writes to WPML’s, Polylang’s, or TranslatePress’s tables. Even if something goes wrong mid-run, reactivating the source plugin gives you back your original setup unchanged.
- Pre-flight validation. Language mapping is resolved before any data is written. If half your source languages don’t match PerfLocale languages, the importer tells you up front rather than writing partial results.
- Dry-run via WP-CLI.
wp perflocale migrate <source> --dry-runconfirms the source is detected and would be importable, without writing anything. - Resumable. Re-running the importer after a partial run completes the gaps; already-linked items are skipped.
What the importer doesn’t guarantee (and you should know):
- No automatic rollback. There is no “undo migration” button. If you want to abandon an import mid-way through verification, the cleanest path is: restore the database backup you took in step 1, or delete the newly-created translation posts manually from Posts → All Posts in the admin while the source plugin is still active.
- No transaction wrapping. The importer isn’t a single atomic DB transaction - it’s a sequence of
INSERTs. If your host kills the PHP process halfway (timeout, OOM), partial data may be written. Re-running is safe and fills the gaps (see idempotency above), but it’s not all-or-nothing. - No count preview.
--dry-runonly confirms that data exists; it doesn’t report “this will import 234 posts, 89 terms, 1 412 strings.” You’ll see the totals only after the run finishes.
Running the import
From the admin
Go to PerfLocale → Settings → Export & Import. The page shows a status badge for each source plugin whose data is detected on your site:
- “Import from WPML” - visible when
wp_icl_translationsexists. - “Import from Polylang” - visible when the
languagetaxonomy is present. - “Import from TranslatePress” - visible when
wp_trp_original_stringsexists.
Click the button, confirm the prompt, and wait for the page to reload with an import summary.
From WP-CLI
# Confirm the source is detected (no data written).
wp perflocale migrate wpml --dry-run
# Run the real import (prompts for confirmation).
wp perflocale migrate wpml
# Skip the confirmation prompt (for scripting / CI).
wp perflocale migrate wpml --yes
Replace wpml with polylang or translatepress as appropriate. Output:
$ wp perflocale migrate wpml
Migrating from wpml...
Success: Migration complete. Imported: 234 posts, 89 terms, 1412 strings.
After the import
- Spot-check translations. Open a multilingual post in the standard editor and use the PerfLocale Translations panel to confirm all the expected language versions are linked.
- Verify URLs resolve. Visit
/fr/your-post/,/de/your-post/, etc. and confirm the prefixed language URLs return the correct translated posts. - Check the hreflang tags. View the page source of any translated post and confirm
<link rel="alternate" hreflang="…">tags point at the correct sibling URLs. - Flush caches. If you use an object cache or page cache, flush it - PerfLocale’s internal caches are invalidated automatically, but external caches aren’t.
- Deactivate the source plugin. Only after you’re confident the import succeeded. Keep a database backup for at least a week in case you need to roll back. The source plugin’s data can stay in the database indefinitely - PerfLocale ignores it.
Per-source details
Each source plugin has its own quirks - what’s imported, what isn’t, language-code edge cases, and specific verification steps:
For the CLI command reference, see WP-CLI: wp perflocale migrate.