GUIDE · 01 · VERIFIED 2026-10allwpcare.com/guides/export-import-wordpress-settings/
Guides / Settings / export-import-wordpress-settings

How to Export and Import WordPress Settings

WordPress has no built-in settings export. Here is what Tools → Export really covers, and how to copy core, theme and plugin settings safely with WP-CLI.

Last verified Oct 2026Tested with WordPress 7.19 min read

WordPress core cannot export your settings. Tools → Export only exports content, so to copy settings you read options one by one with WP-CLI (wp option get) or copy them by hand, and leave a short list of site-specific options alone.

That sounds like bad news, and a little of it is. But it is also a clear rule once you see where settings live. This guide shows where, how to move them, and which ones you must never move.

What Tools → Export actually exports#

Open Tools → Export in the admin. You get a choice of All content, Posts, Pages, Media, and any custom post types your site registers. The file you download is a WXR file, short for WordPress eXtended RSS.

The Export screen in WordPress 7.1. It says the XML file will contain posts, pages, comments, custom fields, categories and tags, then Choose what to export: All content, Posts, Pages and Media, and a Download Export File button.
Tools → Export on a fresh WordPress 7.1 site. Every choice is a kind of content. None is a setting.

That file contains content. It does not contain:

  • The settings under Settings → General, Writing, Reading, Discussion, Media, Permalinks or Privacy
  • Your theme's customizer values and widget layout
  • Any plugin's settings screen

The WP-CLI equivalent, wp export, is described by WP-CLI itself as exporting "WordPress content to a WXR file". Same scope, same limit.

If you imported a WXR file into a new site and found the settings missing, this is why. It worked as designed.

Three rows. Tools → Export carries content only. wp option get and update with --format=json carry one setting at a time. siteurl, home, active_plugins, cron, user roles and secrets should never be copied.
Where each kind of data travels, and what to leave behind.

Where settings live#

Almost every setting is a row in the wp_options table. The table prefix may differ on your site, but the structure is the same: four columns named option_id, option_name, option_value and autoload.

There is no "last modified" column. WordPress does not record when an option changed or who changed it.

Three kinds of settings matter for an export:

  • Core options. Plain names such as blogname, blogdescription, permalink_structure and default_role. Most hold a single value.
  • Theme mods. Customizer and theme settings are stored in one option per theme, named theme_mods_ followed by the theme's folder name, for example theme_mods_twentytwentyfive. The value is an array. WP-CLI has a dedicated wp theme mod command for it.
  • Plugin options. Each plugin picks its own names. Many store everything in one array under one name (WP Mail SMTP uses wp_mail_smtp). Others spread settings over dozens of rows with a shared prefix (WooCommerce uses woocommerce_).

Block themes also keep some design data as posts (global styles and templates) rather than as options, so those do not follow the option commands below. Check them on the new site.

Reading settings#

You can look at options without WP-CLI. Visit /wp-admin/options.php while logged in as an administrator. WordPress calls it All Settings, and it is not linked from the menu. It lists simple values in text fields. Arrays show as SERIALIZED DATA and cannot be read there. Treat the page as read-only. It offers none of the help or guard rails of the normal screens, and it will write values no screen would let you enter.

The All Settings screen. A warning says the page allows direct access to your site settings and you can break things. Four rows: active_plugins shows SERIALIZED DATA in a greyed box, and admin_email, blogdescription and blogname show plain text in editable boxes.
/wp-admin/options.php on WordPress 7.1, cropped to four real settings (the long list of cached values above them is left out). Simple values are editable text. Arrays such as active_plugins show as SERIALIZED DATA.

With WP-CLI, read a single option:

Terminal
wp option get blogname

Find every option that belongs to a plugin by searching the name. The search accepts * and ? wildcards:

Terminal
wp option list --search="woocommerce_default_*" --format=csv

On the test site used for this guide, that returned two rows: woocommerce_default_country and woocommerce_default_customer_address.

Exporting a single option#

For simple values, the output of wp option get is all you need. For anything that is an array, ask for JSON:

Terminal
wp option get wpseo_titles --format=json > ~/wpseo_titles.json

Replace wpseo_titles with the option you want. I picked that one because Yoast SEO keeps its title templates in it. The file now holds the decoded structure, readable and diffable.

Without --format=json, WP-CLI prints arrays in PHP var_export style, which is awkward to reuse.

Exporting many options at once#

To capture a whole group, list it as JSON and tell WP-CLI to decode arrays:

Terminal
wp option list \  --search="woocommerce_*" \  --unserialize \  --format=json > ~/woocommerce-options.json

The --unserialize flag matters. Without it, arrays arrive as PHP serialized strings like a:1:{s:1:"a";i:2;}, which you cannot read or diff sensibly. With it, you get real JSON.

To snapshot every option for later comparison, sort by name so two exports line up, and leave out the volatile ones. Transients are already left out by default. --exclude takes only one pattern, so use jq to drop several names:

Terminal
wp option list \  --orderby=option_name \  --unserialize \  --format=json \  | jq 'map(select(.option_name | IN("cron", "recently_activated", "fresh_site") | not))' > ~/options-before.json

This file is for comparing, not for importing. It still contains secrets and site-specific values, so do not email it or commit it to a public repository. Write exports outside the WordPress folder, as these commands do with ~/. Anything inside the folder can be fetched by URL.

Importing a single option#

This is where people lose an afternoon. Importing a value has two forms, and only one is right for arrays.

For a simple string or number, pass the value directly:

Terminal
wp option update blogdescription "Plain-English WordPress help"

For an array, read the JSON from the file and pass --format=json:

Terminal
wp option update wpseo_titles --format=json < ~/wpseo_titles.json

If you leave out --format=json, WordPress stores your JSON as a plain text string. I checked this on a scratch option: adding '{"a":1}' without the flag stored the literal text, and updating it with --format=json stored a real array. The plugin that owns the option then sees text where it expects an array.

A round trip is exact. I exported wpseo_titles to a file, added it back under a new name with --format=json, read it again, and the two files were byte-identical. That is the property you want from any export format.

To change one nested value without rewriting the whole option, use wp option patch:

Terminal
wp option patch update wpseo_titles separator sc-dash

The command finds the separator key inside the array, changes it, and leaves the rest alone. That avoids editing serialized strings by hand, which is how people corrupt options. Serialized strings store the length of every text value, so changing a character in a text editor breaks the length and the whole value becomes unreadable.

Theme settings#

Customizer values travel as theme mods:

Terminal
wp theme mod listwp theme mod get custom_logowp theme mod set custom_logo 123

Be careful with any mod whose value is a number that refers to something in the media library or the database. Examples are custom_logo, header images, and nav_menu_locations. Those numbers are IDs on the source site. On the target site the same ID points at a different file, or at nothing. Copy the content first, find the new IDs, then set the theme mods.

Only copy theme mods between sites running the same theme. The option name includes the theme's folder name. A child theme has its own theme_mods_ option.

What not to copy#

Some options describe the machine, not your preferences. Leave these alone when you move settings between sites:

  • siteurl and home. They tell WordPress where it lives. Copying them from staging to live points your public site at the staging address.
  • admin_email. It receives system mail and password resets.
  • active_plugins. It lists which plugins are on. Importing it can activate a plugin that is not installed on the target, or deactivate one that is.
  • cron. The scheduled task queue. It contains hook names and timestamps from the source site.
  • Transients. Rows named _transient_* and _site_transient_* are cached values that expire. They are noise, and WordPress rebuilds them.
  • rewrite_rules. Generated from your permalink settings. Run wp rewrite flush on the target instead of copying it.
  • Database version options. Names ending in _db_version, such as woocommerce_db_version. They track which schema upgrade has run. Copying a newer number onto an older database skips an upgrade that needed to happen.
  • The user roles option. It is named wp_user_roles, with your own table prefix in place of wp_. It holds capabilities for every role, and plugins add to it. Overwriting it can lock people out or give them access they should not have.
  • Secrets. API keys, license keys, SMTP passwords and tokens. Plugins store these in ordinary options. WP Mail SMTP, for example, keeps its settings in one array, so exporting the whole option can include credentials depending on the mailer you picked.

When a value looks like a key, a token or a password, leave it out of any file that leaves your machine.

Serialized data: why it bites#

WordPress stores arrays as PHP serialized strings. A serialized string records the exact character count of every text value inside it. That has three consequences:

  • A plain find-and-replace on a database dump corrupts any serialized value where the text length changes.
  • Raw SQL UPDATE statements have the same problem.
  • Reading from a file you edited by hand is risky for the same reason.

The safe tools are the ones that decode first and encode afterwards: wp option with --format=json, wp option patch, and wp search-replace. The last one understands serialized data and fixes the lengths for you.

Never unserialize() a file from a source you do not trust. PHP can create objects while unserializing, and a crafted file can abuse that. JSON does not have that risk, which is another reason to prefer it.

A cautious import routine#

  1. Export the target site's current options with the "snapshot everything" command above, so you can compare afterwards.
  2. List the options you intend to copy. Cross every name against the "what not to copy" list.
  3. Export those options from the source site, using --format=json for arrays.
  4. Look at the files. Search them for words like key, secret, token and password.
  5. Import each option on the target with wp option update.
  6. Flush rewrite rules if you changed permalinks (wp rewrite flush), and clear caches (wp cache flush).
  7. Export the target's options again and compare with the file from step 1. The next section shows how.

Checking what changed#

You can diff two exports with ordinary tools. This is the shape of the check:

Terminal
diff \  <(jq -r '.[] | "\(.option_name)=\(.option_value)"' ~/options-before.json) \  <(jq -r '.[] | "\(.option_name)=\(.option_value)"' ~/options-after.json)

It prints each option that was added, removed or changed. jq is a separate tool and may not be installed on a shared host.

I ran the same comparison on a test site after changing the tagline. The result was one line pair: blogdescription= on the left, blogdescription=x on the right. That precision is the goal. Array options print as compact JSON on one line, so a change inside one shows as a changed line and you open the two values to see where.

Skip the option-by-option work.

WellTend Snapshots exports your settings to one JSON file, shows a diff before you import, and keeps an undo.

secrets redacted   WP-CLI included  
Get notified

What this method cannot do#

Be clear about the limits so you pick the right tool:

  • It is manual. There is no single "import this file" command in core or WP-CLI. You loop over options, or write a script.
  • It does not validate. WordPress will happily store a wrong value. Nothing checks that permalink_structure is a valid pattern.
  • It does not know about plugin versions. An option saved by version 5 of a plugin may not suit version 4.
  • It carries no undo. A snapshot you took yourself is the undo, and you have to take it.

For a handful of options on one site, the commands above are enough. For regular moves between staging and live, a repeatable routine is worth more than cleverness. The staging-to-live guide builds one.

Quick reference#

Related: moving settings from staging to live and finding what changed.

FAQ

Does Tools → Export include my settings?

No. Tools → Export produces a WXR file of content: posts, pages, media entries, custom post types, comments, terms and menus. It does not include general settings, permalink structure, theme options or plugin settings.

Can I export plugin settings with WP-CLI?

You can read and write any plugin's options with wp option get and wp option update, and list them with wp option list --search. There is no single command that exports and imports everything as one file, so you do it per option.

Is it safe to copy the whole wp_options table?

No. The table holds site-specific values such as siteurl, home, active_plugins, scheduled tasks, transients and often API keys. Copying all of it from one site to another overwrites those and can break the target site.

Why did my imported option turn into text?

WP-CLI treats the value as a plain string unless you pass --format=json. Without it, a JSON object is stored as a string instead of an array, and the plugin that reads it will usually ignore it or misbehave.

Do I need WP-CLI to do this?

No, but it is the most reliable route. Without it you can read values on the hidden Settings → All Settings screen at /wp-admin/options.php, which shows simple values but displays arrays as SERIALIZED DATA.

Sources

  1. WP-CLI: wp option · get, update and patch, and the --format=json flag
  2. WP-CLI: wp option list · --search, --unserialize, --orderby
  3. WP-CLI: wp export · Exports content to a WXR file
  4. WP-CLI: wp theme mod
  5. WP-CLI: wp search-replace · Understands serialized data
  6. Core: options.php (All Settings screen) · The SERIALIZED DATA branch for array values
  7. PHP: unserialize() · Warning about untrusted input
Newsletter

One email when something breaks or changes.

New plugins and re-tested guides, about twice a month. Never a sales pitch.