GUIDE · 03 · VERIFIED 2026-10allwpcare.com/guides/move-settings-staging-to-live/
Guides / Moving sites / move-settings-staging-to-live

Move WordPress Settings from Staging to Live Without Overwriting Content

Copy only the settings you changed on staging to your live site. A safe, option-by-option routine with WP-CLI, plus the options that must never travel.

Last verified Oct 2026Tested with WordPress 7.19 min read

To move settings from staging to live without touching content, copy the individual options you changed, not the database. Record the old live values first so you can put them back, and leave out the options that describe the server, such as the site address and active plugins.

The risk is easy to underestimate. A staging site is a copy of live from some earlier day. Live has kept moving since: new orders, new comments, new form entries. Overwrite live with staging, and those are gone.

Why a database push is the wrong tool#

Hosts often offer a "push staging to live" button. Look at what it overwrites. Typical choices are the files, the whole database, or a list of tables. Exact options differ by host, so read the screen carefully.

Pushing the database replaces:

  • Posts, pages and comments created on live since the copy
  • WooCommerce orders, customers and stock
  • Form plugin entries
  • User accounts and password changes
  • Every setting, including the ones that identify the live site

Settings sit in the same table as some of that data. The wp_options table holds both your tagline and the address of your site. So "just push the options table" is not a clean answer either: it brings the staging address with it, and some plugins keep working data in options, such as counters and queues.

A settings-only move is smaller and safer. It does take more care.

Decide what is a setting#

Sort your staging changes into three bins before you start:

  • Settings you chose. Site title, date format, comment rules, SEO templates, a plugin's toggles. These are candidates.
  • Content. Posts, pages, menus, media. These move with a content tool or by editing live. Do not move them as settings.
  • Environment. Anything that identifies a server or an account, such as the site address, the admin email, active plugins, the cron queue, user roles, and keys or passwords. These stay as they are on live.

Write the list of option names for bin one. Everything below works from that list.

Three rows. Settings you chose are copied option by option. Content moves with a content tool or by editing live. Environment options such as siteurl, home, admin_email, active_plugins, cron, roles, keys and passwords stay as they are on live.
Sort every staging change into one of three bins.

If you do not know the option name, change the setting on staging and compare before and after. The finding-changes guide shows the diff method. A short version:

Terminal (on staging)
wp option list --orderby=option_name --unserialize --format=json > ~/before.json# change the setting in the admin, then:wp option list --orderby=option_name --unserialize --format=json > ~/after.jsondiff <(jq -r '.[] | "\(.option_name)=\(.option_value)"' ~/before.json) <(jq -r '.[] | "\(.option_name)=\(.option_value)"' ~/after.json)

The output names the option that changed. That is the name to put on your list.

Options that must not travel#

Do not copy these between environments:

  • siteurl and home. They hold each site's own address.
  • blog_public. This is the "Discourage search engines from indexing this site" checkbox under Settings → Reading. Staging sites usually set it. Copy it to live and your live site asks search engines to stay away.
  • admin_email. It controls where system notices go.
  • active_plugins. A list of plugin files. If staging has a plugin live does not, importing it can break live.
  • cron. The scheduled-task queue.
  • Transients (_transient_*, _site_transient_*) and rewrite_rules. WordPress regenerates them.
  • Names ending in _db_version. They track which database upgrades have run on that site.
  • The user roles option (wp_user_roles, with your own prefix). Overwriting it changes what every role can do.
  • API keys, tokens, license keys, SMTP passwords, and payment gateway settings. The keys on staging are often test keys. Putting them on live can switch real checkout to test mode or break it.

WordPress can tell you which kind of environment it is running in. On the test site used for this guide:

Terminal
wp eval 'echo wp_get_environment_type();'

printed local. The possible values are local, development, staging and production. WordPress takes it from the WP_ENVIRONMENT_TYPE constant or environment variable and falls back to production if neither is set. Some plugins use it to behave differently, so it is worth setting on staging.

Step by step#

Do these in order. Keep both terminals open so you do not mix up the sites. If you have SSH access to live from your own machine, WP-CLI can also run against a remote site with its --ssh option, but most people find it clearer to log into each server.

Four rows. Back up live. Export the staging values and save the live values you are about to replace. Import one option at a time. Check the screens on live, keep the saved files until sure, then delete them.
The order matters: the saved live values are your undo.
  1. Back up live. Use your host's backup or a database export, and confirm that the backup exists. Do not skip this, however small the change looks.
  2. Write the option list. One name per line, taken from the bin-one list above. Keep it short.
  3. Export the values from staging. This command writes one JSON file per option:
    Terminal (on staging)
    mkdir -p ~/settingsfor opt in blogname blogdescription timezone_string date_format posts_per_page; do  wp option get "$opt" --format=json > ~/settings/"$opt".jsondone
  4. Read the files. Open them. Check that nothing in them is a secret and that you recognise every value.
  5. Save the live values you are about to replace. Run the same loop on live into a different folder, for example ~/settings-live-before. This is your undo. Keep both folders outside the WordPress folder, because anything inside it can be fetched by URL.
  6. Copy the ~/settings folder to live, into the home folder there too. Use SFTP, scp, or paste the contents into files by hand.
  7. Import on live. Run:
    Terminal (on live)
    for opt in blogname blogdescription timezone_string date_format posts_per_page; do  wp option update "$opt" --format=json < ~/settings/"$opt".jsondone
  8. Read the output. WP-CLI says "Updated" when it changed a value and "Value passed ... is unchanged" when it did not. I ran this loop on a test site and every option reported "unchanged" when the values already matched, which is the result you want on a repeat run.
  9. Flush and check. Run wp rewrite flush if you changed permalinks, wp cache flush, and clear any page cache. Then load the live site and the changed screens.

If something is wrong, run step 7 again from the ~/settings-live-before folder. That puts back what you replaced.

Arrays and plugin settings#

Plugins usually keep their settings in one array. Export and import that array the same way:

Terminal
wp option get wpseo_titles --format=json > ~/settings/wpseo_titles.jsonwp option update wpseo_titles --format=json < ~/settings/wpseo_titles.json

That replaces the whole array on live with the staging version. If live has settings you did not change on staging, they are overwritten with staging's values. If you only changed one field, patch it instead:

Terminal (on live)
wp option patch update wpseo_titles separator sc-dash

Plugins that store a secret inside the same array are the awkward case. WP Mail SMTP is one: its settings are in a single option with mailer details inside it, and depending on the mailer chosen, credentials may sit in there too. Patch the specific fields you want and leave the rest of the array alone.

Plugin updates add a wrinkle. Staging and live may run different plugin versions, and a newer version may store settings in a different shape. Match the versions first. wp plugin list --fields=name,version shows each site's versions.

Theme settings and IDs#

Customizer values live in one option per theme. Read them with:

Terminal
wp theme mod list

Plain values such as colours and text copy over fine with wp theme mod set. Values that are numeric IDs do not. A logo, header image, or menu location points to a media or menu ID from the staging database. On live, that ID is a different file, or nothing.

For those, recreate the item on live, note its new ID, then set the mod.

Content that comes along for the ride#

Some "settings" are really content in disguise:

  • Menus are stored as terms and posts. Their placement is a theme mod.
  • Widgets are stored in options, but the blocks inside them can reference posts by ID.
  • Block theme styles and templates are stored as posts.
  • Custom CSS from the Customizer is stored as a post, referenced by custom_css_post_id.

If you changed one of these on staging, treat it as content. Copy it with the content export tool or recreate it by hand on live.

Addresses inside content#

If you did bring content along, URLs inside it may still carry the staging address. wp search-replace rewrites them and understands serialized data. Always run a dry run first, and skip the guid column, which should never change:

Terminal
wp search-replace 'https://staging.example.com' 'https://example.com' --dry-run --skip-columns=guid

The --dry-run flag reports how many replacements it would make and changes nothing. Run it again without the flag only after you have read the report. On a clean test it printed Success: 0 replacements to be made.

Do not use raw SQL for this. A plain text replace breaks serialized values whose length changes.

After the move#

  • Open the changed screens on live and read them. Do not trust "Updated".
  • Check Settings → Reading and make sure search engines are not discouraged.
  • Send one test email if you touched mail settings.
  • Keep the ~/settings-live-before folder until you are sure. Delete it, and ~/settings, afterwards, because they may contain secrets.

WellTend Snapshots 0.5.0 does the settings part from the admin, without a terminal. On Export / Import it downloads your settings as one file, leaves passwords and API keys out, and keeps "Include site address settings" off until you switch it on. On the other site you choose the file and it shows what would change before anything is written. It covers settings only: menus and widgets are content in disguise (see above) and still need the content route.

The Export / Import tab of WellTend Snapshots. The Export card has What to include, set to Everything (recommended), 9 areas, a switch for Include site address settings that is off, and a Download settings file button. The Import card has a Choose a file button and a switch for Also import site address settings that is off.
WellTend Snapshots 0.5.0, Export / Import, on WordPress 7.1.4. The site address switches start off, which keeps staging and live addresses apart.
See what changed, in plain language.

Compare two snapshots, or a snapshot with the live site, and read changes like "Comments: open → closed". The raw key is one click away.

owner-readable diff   raw JSON view  
Get notified

The weak point of this routine is that the loop writes first and you check afterwards. A safer order is to read the live value and the incoming value side by side before you apply anything. You can do that by hand: for each option, print both and compare them.

When a database push is fine#

Sometimes the push is the right call. If live is a brochure site with no logins and no forms, and you froze edits before cloning staging, a full push loses nothing. Freeze live for the whole duration of the push, push, fix the addresses, and flush caches. Core maintenance mode (wp maintenance-mode activate) lasts only 10 minutes, then WordPress ignores it, and a database push also replaces the maintenance state with staging's. For a longer freeze, use your host's maintenance toggle or a maintenance plugin, and check it is still on when the push finishes. Anywhere content is created by visitors, use the option-by-option route.

Related: export and import WordPress settings and find and undo changed settings.

FAQ

Can I push a staging database to live to move settings?

Only if you are willing to lose everything that changed on live since you made the staging copy. A database push replaces orders, comments, form entries and posts along with the settings. For a settings-only change, copy the individual options instead.

Which settings should never go from staging to live?

siteurl, home, admin_email, active_plugins, cron, transients, rewrite_rules, database version options, the user roles option, any API keys or payment credentials, and blog_public, which staging sites often set to discourage search engines.

Do my staging hosting tools move settings only?

It depends on the host. Many push buttons copy files, the whole database, or chosen tables. Few copy individual options. Read what your host's tool says it overwrites before you press it, and take a backup of live first.

What if the setting is stored in an array?

Export it with wp option get NAME --format=json and import it with wp option update NAME --format=json. To change one nested key, use wp option patch update.

How do I test the move before touching live?

Make a second copy of live, run the import there, and check it. If you cannot, run the import on live in the quietest hour, with a fresh backup and a saved copy of every option you are about to change.

Sources

  1. WP-CLI: wp option · get and update; --format=json appears in its examples
  2. WP-CLI: wp option patch
  3. WP-CLI: wp search-replace · Handles serialized data
  4. WP-CLI: wp rewrite flush
  5. WP-CLI: wp maintenance-mode
  6. Core: load.php (maintenance mode check) · wp_is_maintenance_mode() and the 10-minute window
  7. Core: wp_options table definition (schema.php) · Definition of the wp_options table
Newsletter

One email when something breaks or changes.

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