Not every shared hosting plan gives you a one-click staging tool, and even when one exists, I still end up doing this manually often enough that it’s worth having the process memorized. A staging site, if you haven’t set one up before, is simply a private copy of your live site — the files and the database — living at a different address, that you can break freely before making real changes to your actual site.
The concept first
A staging site needs two things kept separate from your live site: its own copy of the WordPress files, and its own copy of the database (the place WordPress actually stores your posts, pages, and settings). You can put the files at a subdomain, like staging.yoursite.com, or a subdirectory, like yoursite.com/staging.
A subdomain is the cleaner option. WordPress hardcodes its own URL in a lot of places, and a subdirectory setup can occasionally collide with those paths. Still, a subdirectory works fine on hosts where creating a subdomain isn’t easy.
Why does this need an actual separate database copy, rather than just pointing staging at the live one? Because the whole point of staging is testing things that could go wrong — plugin updates, database changes, content edits — with zero risk of accidentally writing those changes back to your real site.
Step 1: Copy the files
Create the subdomain or subdirectory first, through your hosting control panel’s “Subdomains” tool or similar. Then copy the entire WordPress file tree into it. On shared hosting, the easiest way is usually through your host’s file manager, or SSH (a command-line connection to your server) if it’s available:
# If you have SSH access:
cp -r /home/user/public_html /home/user/public_html/staging
# Or zip on the live site and unzip in the staging folder,
# which is often faster over a slow connection than copying file by file.
If you don’t have SSH, use your file manager’s compress-and-extract feature instead of dragging thousands of individual files through the browser one at a time. It’s dramatically faster, and far less likely to time out or drop files partway through.
Step 2: Export the database
Use phpMyAdmin — a database management tool available on virtually every shared host — or WP-CLI (a command-line tool for managing WordPress) if your host allows it:
# Via WP-CLI, from the live site's directory:
wp db export live-site-backup.sql
If you’re using phpMyAdmin instead, select the database, go to Export, choose “Quick” export with SQL format, and download the file.
Step 3: Create a new database and import
Create a new, separate MySQL database and database user through your host’s database tool — don’t point staging at the live database under any circumstances. Import the exported file into this new database, either through phpMyAdmin’s Import tab, or via WP-CLI if you have shell access:
wp db import live-site-backup.sql
Step 4: Point wp-config.php at the new database
In the staging copy’s wp-config.php — the file that holds your site’s core settings, including its database connection — update the four database constants to the new database’s name, user, password, and host:
define( 'DB_NAME', 'staging_dbname' );
define( 'DB_USER', 'staging_dbuser' );
define( 'DB_PASSWORD', 'staging_dbpassword' );
define( 'DB_HOST', 'localhost' );
If you haven’t touched this file much before, it’s worth a look at my post on the wp-config.php settings I change on every install — staging is a good moment to apply those at the same time.
Step 5: The URL swap — and why a plain search-and-replace breaks things
This is the step people get wrong most often, so it’s worth explaining carefully. WordPress stores its main site address in the database, but it also embeds that same address throughout your post content, widget settings, theme options, and plugin data — anywhere a link or image address was saved.
Running a plain find-and-replace query across your database tables looks like it should fix all of that in one pass. It doesn’t, and the reason is subtle: a lot of that data is stored in a format called PHP serialization, which records the exact character length of each piece of text as part of the format. A plain text replace changes the length of the URL without updating that stored length number, so when WordPress tries to read the data back, it fails — silently. Options come back empty, widgets disappear, theme settings quietly reset. It’s a quiet kind of corruption that often doesn’t show up until you notice a plugin’s settings have vanished for no obvious reason.
WP-CLI has a command built specifically to handle this correctly: search-replace. It reads the serialized data properly, replaces the text inside it, and rewrites the length correctly, table by table:
# Dry run first -- always check what it WOULD change before committing:
wp search-replace 'https://yoursite.com' 'https://staging.yoursite.com' --dry-run
# Then run it for real:
wp search-replace 'https://yoursite.com' 'https://staging.yoursite.com'
# If your staging copy lives in a subdirectory, also account for
# GUIDs if you don't want them changed (GUIDs are meant to be permanent,
# so many people deliberately skip them):
wp search-replace 'https://yoursite.com' 'https://staging.yoursite.com' --skip-columns=guid
If your host doesn’t give you shell access for WP-CLI, some hosts offer a “Terminal” feature inside their control panel, or you can run WP-CLI commands through a plugin that wraps it. I’d genuinely push to get real SSH and WP-CLI access before doing this migration any other way, though — a plugin-based serialized-safe replace works, but it’s slower and more fragile on a large database. This exact same serialized-data problem is also the trickiest part of a full domain move, which I cover in my post on moving a WordPress site to a new domain without losing your rankings.
Keep it out of Google’s index
A staging copy is a full duplicate of your content, sitting at a public address. If it gets crawled and indexed by search engines, you end up with duplicate content competing against your live site — on top of leaving a half-finished copy of your site publicly browsable to anyone who finds the link. Do at least one of the following, ideally both:
- Add a staging-only
robots.txtfile (a plain text file that tells search engine crawlers what they’re allowed to visit) blocking everything:User-agent: * Disallow: /Don’t rely only on WordPress’s own “Discourage search engines from indexing this site” setting, found under Settings and then Reading — it helps, but it’s just a polite suggestion sent via a page tag, and not every crawler respects it.
- Put the staging site behind a simple password prompt, either through your host’s password-protect-directory tool or a “coming soon” plugin. This is the more reliable option, since it stops crawlers and casual visitors alike, not just the well-behaved ones. It’s the same kind of protection worth double-checking if you’ve ever seen a stuck “briefly unavailable for scheduled maintenance” message on a live site — see my post on fixing that stuck maintenance screen for the related issue on the production side.
Once staging has done its job — you’ve tested your changes there thoroughly — apply the same changes to production deliberately. Don’t just point your domain at the staging files directly. The database, URLs, and file locations still need the reverse of the same search-and-replace treatment to work correctly on the live address.
Frequently Asked Questions About WordPress Staging Sites
Do I really need a staging site if I’m careful with updates?
Even careful updates can go wrong in ways you can’t predict in advance, since a plugin conflict often depends on your site’s specific combination of plugins and theme. A staging site costs you a bit of setup time, but it turns a potential live-site outage into a non-event you can fix calmly before anyone else sees it.
Will my visitors ever see my staging site by accident?
Not if you password-protect it or block it in robots.txt, as covered above. Without either of those, though, a staging site is just as publicly reachable as your live one to anyone who happens to find or guess the address.
Can I just copy my live site’s files without touching the database at all?
No — WordPress needs a working database connection to run at all, and using the live database from a staging copy risks writing test changes back to your real site. Staging always needs its own separate database copy, not shared access to the live one.
Do I need a developer to do this, or can I follow the steps myself?
Site owners comfortable with their hosting control panel can usually manage the file copy, database export, and import steps themselves. The URL search-and-replace step is the one place I’d lean on a developer or at least WP-CLI access if you’re not confident with the command line, since getting it wrong is what causes the quiet data corruption described above.
How do I know when it’s safe to apply my staging changes to the live site?
Test everything you changed on staging as if you were an ordinary visitor — check the pages, forms, and any plugin you updated. If it all behaves as expected there, you’re clear to repeat the same specific changes on production, ideally after taking a fresh backup first just in case.
Leave a Reply