Switching SEO plugins guide
Translate SEO Title Variables Without Broken or Empty Titles
Find the title variables an import removes or changes, compare translated and rendered titles, and replace each unsupported variable on purpose.
On this page
Before you import titles from another SEO plugin, list every variable your stored titles use, check which ones have a direct equivalent, and decide what replaces the rest. A variable that has no equivalent does not fail loudly. It disappears from the translated text, and the title that remains can be shorter, repetitive, or reduced to the site name.
This guide covers the translation step only. The ordinary setup of templates is in Set Title and Description Templates, and the full field list for each source is in its migration doc.
What an import translates, and what it never sees
Two kinds of title text exist on a typical site, and an import treats them differently.
- Stored titles and descriptions. Per-post values, per-term values (Yoast and Rank Math only), and the homepage title and description (every source except All in One SEO). WP Visibility’s importer reads these and translates their variables into its own
{variable}syntax. Social and X titles and descriptions go through the same translation. Canonical URLs skip the translation, so a percent-encoded URL is never mistaken for a variable. - Templates. The per post type, archive, and taxonomy templates in the source plugin’s settings. These are not imported at all. You set them again in WP Visibility, so their variables need no translation, only a decision.
Each source uses its own syntax. Yoast and SEOPress write %%title%%, Rank Math writes %title%, and All in One SEO writes tags such as #post_title. The SEO Framework does not transform this kind of syntax and warns when a title shows syntax such as %%sitename%% (checked September 27, 2026), so its plain text titles arrive as written.
In WP Visibility 2.10.3, a double or single percent variable without an equivalent is removed. An All in One SEO # tag without an equivalent is left in place as literal text, because # also appears in ordinary writing, and a tag that begins with a translated one, such as #post_excerpt_only, comes out half translated as {excerpt}_only. The All in One SEO migration doc lists the seven tags that translate.
The Yoast and Rank Math translation table
The meanings in the second column come from the vendors’ own references: Yoast’s snippet variable list and Rank Math’s variable reference, both checked September 27, 2026. The third column is what WP Visibility 2.10.3 writes.
| Source variable | Source meaning | Becomes | Check |
|---|---|---|---|
%%title%%, %title% |
Post or page title | {title} |
Renders empty on a term archive |
%%sitename%%, %sitename% |
Site title | {site} |
None |
%%sitedesc%%, %sitedesc% |
Tagline | {tagline} |
Empty tagline drops with its separator |
%%sep%%, %sep% |
Separator | {sep} |
The separator setting itself imports separately |
%%excerpt%%, %excerpt% |
Excerpt, auto-generated if missing | {excerpt} |
Close match |
%%excerpt_only%%, %excerpt_only% |
Excerpt only, no auto-generation | {excerpt} |
{excerpt} falls back to the content |
%%primary_category%% |
Primary category | {category} |
{category} is the first category, not a chosen primary |
%%category%% |
Yoast: all categories, comma separated | {category} |
One category instead of a list |
%%page%%, %page% |
Page number with context, such as “page 2 of 4”; Rank Math shows it on page 2 and later only | {page} |
See the page 2 check below |
%%currentyear%%, %currentyear% |
Current year | {currentyear} |
None |
%%cf_KEY%%, %customfield(KEY)% |
A custom field | {custom_field:KEY} |
Posts only; a Yoast key with characters other than letters, digits, underscores, or hyphens is not translated |
SEOPress aliases such as %%post_title%%, %%sitetitle%%, and %%tagline%% map to the same targets; the SEOPress migration doc has the list. SEOPress’s own custom field form, %%_cf_KEY%% in its variable list (checked September 27, 2026), does not match the %%cf_KEY%% rule and is removed.
Variables that disappear even though an equivalent exists
Several source variables are removed during translation although WP Visibility has a variable that does a similar job. These are the ones to fix by hand after the import.
| Source variable | Removed during import | Manual replacement |
|---|---|---|
%%term_title%%, %term% |
Yes | {term_title} |
%%date%%, %date% |
Yes | {date} |
%%modified%%, %modified% |
Yes | {modified} |
%%pt_single%%, %pt_single% |
Yes | {post_type_singular} |
%%pt_plural%%, %pt_plural% |
Yes | {post_type_plural} |
%%pagenumber%%, %pagenumber% |
Yes | {pagenumber} |
%%name%%, %name% |
Yes | {author} (display name; Yoast’s list describes %%name%% as the author’s “nicename”) |
%%term_description%%, %term_description% |
Yes | {term_description} |
%%searchphrase%%, %search_query% |
Yes | {search_query} |
%%currentdate%%, %currentdate% |
Yes | {currentdate} |
Other variables, such as a focus keyword variable, may have no counterpart. Check each one against the variable list in Set Title and Description Templates, and rewrite it as plain text or remove it when nothing matches.
Inventory the variables before you import
Find every stored value that contains a variable. On a Yoast site, run this from the site root with WP-CLI. Replace wp_ with your table prefix, which wp db prefix prints.
wp db query "SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE meta_key IN ('_yoast_wpseo_title','_yoast_wpseo_metadesc','_yoast_wpseo_opengraph-title','_yoast_wpseo_opengraph-description','_yoast_wpseo_twitter-title','_yoast_wpseo_twitter-description') AND meta_value LIKE '%\%\%%'" > yoast-variables.tsv
wp option get wpseo_taxonomy_meta --format=json > yoast-terms.json
On a Rank Math site, the post and term values are ordinary meta under rank_math_ keys:
wp db query "SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE meta_key IN ('rank_math_title','rank_math_description','rank_math_facebook_title','rank_math_facebook_description','rank_math_twitter_title','rank_math_twitter_description') AND meta_value LIKE '%\%%'" > rankmath-post-variables.tsv
wp db query "SELECT term_id, meta_key, meta_value FROM wp_termmeta WHERE meta_key IN ('rank_math_title','rank_math_description') AND meta_value LIKE '%\%%'" > rankmath-term-variables.tsv
In 2.10.3 the importer finds a post only by its source title key, _yoast_wpseo_title or rank_math_title, and finds Rank Math terms the same way. A row from a post or Rank Math term with no stored title appears in these results but is not imported, so plan to set that value by hand.
Sort the results by variable and count them. When many rows share a few patterns, you make a few decisions, not hundreds. Screenshot the homepage title and description settings in the source plugin as well; they go through the same translation.
Compare translated and rendered values
A translated string can look correct and still render badly, because empty variables and separators are cleaned up at render time. When a variable renders empty, WP Visibility removes the leftover separator, and it strips separators from the start and end of the title.
An illustrative example on garden.example, a site named Garden Notes with a pipe separator. Yoast stored this title on the Pruning category:
%%term_title%% %%page%% %%sep%% %%sitename%%
Under the 2.10.3 rules, %%term_title%% is removed and the rest translates, giving {page} {sep} {site}. On page 1, {page} is empty, so the category title renders as just Garden Notes. On page 2 it renders Page 2 of 3 | Garden Notes, and WP Visibility then appends its own separator and page number, which it adds to every title on page 2 and later. The result repeats the page:
Page 2 of 3 | Garden Notes | Page 2
Test this on staging, not by reading the table:
- Run the preview (Preview changes, or
wp visibility import yoast --dry-run --user=admin). It shows the first ten changed posts with title and description before and after, variables already translated. Term titles and the homepage values are not in the preview. - Look for titles that shrank, a title that is only the site name, and a missing word where a variable used to be.
- Run the import on staging, then fetch the rendered title of each pattern you found, including page 2 of a paginated archive:
curl -s https://garden.example/category/pruning/page/2/ | grep -o '<title>[^<]*</title>'
- Record the source’s rendered title for the same URL from your baseline. Keep cases where the translated text is valid but the output differs from what the old plugin printed. Those are the rows that need a decision.
Replace unsupported variables on purpose
For each pattern, choose one of these and write it down:
- Add the equivalent. Put
{term_title},{date}, or{post_type_singular}back into the stored value on the term or post edit screen, or, for a post, withwp visibility set <id> --title="{title} {sep} {date} {sep} {site}". - Delete the stored value. If the stored title only repeated what a template would produce, clear it. An empty field falls back to the template, so the fix moves to one setting instead of many rows.
- Remove
{page}from stored titles. WP Visibility appends the page number on later pages, so{page}in a stored title duplicates it. - Rewrite as plain text. For variables with no counterpart, write the words you want.
- Leave a literal
#tag nowhere. On an All in One SEO import, search the preview and a few live titles for#before you deactivate the source.
Also check any stored title that contains HTML, since titles are saved as plain text, or a backslash, which the 2.10.3 save path can drop.
Checklist
- Every stored variable pattern listed, with a count.
- Each pattern marked: translates, removed with a manual equivalent, or no counterpart.
- Page 1 and page 2 of one archive checked for every term pattern.
- Homepage title and description checked after the live import.
- Templates set again in WP Visibility, since none are imported.
For the rest of the switch, including backups and redirects, follow How to Switch SEO Plugins With a Verification Plan. The field mappings per source are in Migrate from Yoast SEO and Migrate from Rank Math.
