Moving your WordPress website can be a daunting task, but with the right knowledge and preparation, it becomes a manageable process. Whether you’re changing domains, upgrading hosting, or restructuring your site architecture, this comprehensive guide will walk you through every step of the WordPress migration process.
WordPress address vs site address URL
Before diving into migration techniques, it’s crucial to understand the two fundamental URL settings in WordPress:
- WordPress Address (URL): This is where your WordPress core files reside
- Site Address (URL): This is the address visitors type in their browser to reach your site
Both settings should include the https:// part and should not have a trailing slash / at the end. These settings control how WordPress displays URLs throughout your site, including the admin section and frontend.
Why WordPress migration becomes necessary
Several scenarios might require you to migrate your WordPress site:
- Domain Changes: Rebranding or switching to a better domain name
- Hosting Migration: Moving to a better hosting provider
- Server Changes: Upgrading server infrastructure
- Site Restructuring: Moving WordPress to a subdirectory or root directory
- Development to Production: Moving from staging to live environment
- HTTP to HTTPS: Implementing SSL certificates
How to back up WordPress before migration
What to back up before a WordPress migration
Before attempting any migration, create comprehensive backups:
- Database Backup: Export your WordPress database via phpMyAdmin or WP-CLI
- File Backup: Download all WordPress files and directories
- Configuration Backup: Save your wp-config.php file separately
- Plugin/Theme Settings: Document custom configurations
How to test a migration on a staging copy
Always test migrations in a staging environment before going live:
## Create a test subdirectory
mkdir /var/www/html/test-site
## Copy files to test location
cp -r /var/www/html/wordpress/* /var/www/html/test-site/How to change WordPress URLs after migration
Method 1: set WP_HOME and WP_SITEURL in wp-config.php
For temporary URL changes, add these lines to your wp-config.php:
define('WP_HOME', 'https://example.com');
define('WP_SITEURL', 'https://example.com');Pros: Quick and immediate Cons: Hard-coded values, can’t edit in WordPress admin anymore
Method 2: update siteurl and home in functions.php
If you have FTP access but can’t access WordPress admin:
- Access your active theme’s functions.php file
- Add these lines after the opening
<?phptag:
update_option('siteurl', 'https://example.com');
update_option('home', 'https://example.com');- Upload the file and visit your admin panel
- Important: Remove these lines after the site is working
Method 3: the RELOCATE constant in wp-config.php
WordPress includes an automatic relocation method:
- Edit wp-config.php and add before “That’s all, stop editing!”:
define('RELOCATE', true);- Visit
https://yoursite.com/wp-login.php - Login normally
- Check Settings > General to verify URLs
- Remove the RELOCATE constant afterward
Security Warning: Never leave RELOCATE constant in wp-config.php as it creates security vulnerabilities.
Method 4: edit siteurl and home in phpMyAdmin
For precise control, edit URLs directly in the database:
- Access phpMyAdmin
- Select your WordPress database
- Find wp_options table (prefix may vary)
- Edit the ‘siteurl’ and ‘home’ rows
- Update option_value to new URLs
Critical: Always backup your database before making direct edits!
Manual WordPress migration to a new server or domain
How to move WordPress to a new server
When migrating to a new server:
- Backup Everything: Complete site and database backup
- Export Database: Use phpMyAdmin or WP-CLI
- Transfer Files: Use FTP, SFTP, or rsync
- Import Database: Create new database and import
- Update wp-config.php: Modify database credentials
- Update URLs: Use one of the methods above
- Test Thoroughly: Check all functionality
How to change the WordPress domain with WP-CLI
Changing domains requires special attention to serialized data:
## Using WP-CLI (recommended)
wp search-replace 'olddomain.com' 'newdomain.com' --skip-columns=guid
## Or use specialized plugins like:
## - Better Search ReplaceImportant: Never update the GUID column in wp_posts table. GUID stands for Globally Unique Identifier and should never change to maintain feed reader compatibility.
Subdirectory to root migration
Moving WordPress from a subdirectory to root:
- Update URLs in WordPress Admin: Settings > General
- Copy Files: Move WordPress files to new location
- Update .htaccess: Modify rewrite rules
- Update Permalinks: Resave permalink structure
- Check Internal Links: Update hardcoded URLs
Multisite migration
WordPress Multisite requires additional considerations:
- Backup Network: All sites and databases
- Edit wp-config.php: Update multisite constants
- Update .htaccess: Modify multisite rewrite rules
- Database Updates: Update wp_blogs and wp_site tables
- Individual Site Options: Update each site’s options tables
WordPress post-migration checklist
What to test right after the migration
- Test frontend functionality
- Verify admin access
- Check all forms and submissions
- Test e-commerce functionality
- Verify user login/registration
301 redirects and sitemap after a domain change
- Implement 301 redirects from old URLs
- Update sitemap.xml
- Submit new sitemap to search engines
- Update Google Analytics property
- Verify Google Search Console
Cache, database and SSL checks after migration
- Clear all caches
- Optimize database tables
- Check plugin compatibility
- Test site speed
- Verify SSL certificate
WordPress migration errors and how to fix them
White screen of death after migration
Usually caused by:
- Memory limit exhaustion
- Plugin conflicts
- Theme incompatibility
Solution: Increase memory limit in wp-config.php:
define('WP_MEMORY_LIMIT', '256M');Error establishing a database connection after migration
Check wp-config.php settings:
define('DB_NAME', 'database_name');
define('DB_USER', 'username');
define('DB_PASSWORD', 'password');
define('DB_HOST', 'localhost');Mixed content warnings after moving to HTTPS
HTTP resources on HTTPS pages cause security warnings:
## Find mixed content
grep -r "http://" wp-content/Image and media link problems
Update media URLs in database:
UPDATE wp_posts SET post_content = REPLACE(post_content,'olddomain.com/wp-content/uploads','newdomain.com/wp-content/uploads');WordPress migration plugins and WP-CLI tools
Best WordPress migration plugins
- All-in-One WP Migration: Complete site migration tool
- Duplicator: Create migration packages easily
- WP Migrate Lite (formerly WP Migrate DB): database export with find and replace
- Better Search Replace: search and replace in the dashboard, with serialized data support (Velvet Blues Update URLs was closed in the plugin directory on 3 May 2024)
- Migrator: single-file backup and migration with no artificial size cap (All-in-One WP Migration’s own FAQ says the import limit comes from the host’s upload size, not from the plugin) and serialization-safe URL rewriting. See the backup and migration guide.
WP-CLI commands for export, import and search-replace
## How to export a WordPress database with WP-CLI
wp db export backup.sql
## WP-CLI database import
wp db import backup.sql
## Search and replace
wp search-replace 'old-url' 'new-url' --dry-runWordPress migration security checklist
- Use HTTPS: Ensure SSL is configured on new server
- Update File Permissions: Secure wp-config.php (600) and directories (755)
- Remove Migration Scripts: Delete temporary files and constants
- Update Security Keys: Generate new WordPress keys in wp-config.php
- Monitor Logs: Watch for unusual activity post-migration
How to speed up WordPress after migration
How to optimize database tables with OPTIMIZE TABLE
OPTIMIZE TABLE wp_posts;
OPTIMIZE TABLE wp_postmeta;
OPTIMIZE TABLE wp_options;Caching and CDN setup on the new host
- Configure page caching
- Set up browser caching
- Enable CDN integration
- Optimize database caching
How to test a WordPress site after migration
Testing menus, forms, search and media
- Navigation: All menu items work correctly
- Forms: Contact forms and submissions function
- Search: Site search returns results
- Comments: Comment system works
- Media: Images and videos load properly
Checking meta tags, canonical URLs and schema
- Meta Tags: Titles and descriptions display correctly
- Canonical URLs: Point to new domain
- Structured Data: Schema markup validates
- Internal Links: All links work and redirect properly
Monitoring WordPress after a migration
Uptime, Search Console and 404 monitoring
- Set up uptime monitoring
- Monitor Google Search Console for errors
- Track analytics for traffic patterns
- Watch for 404 errors in logs
Ongoing maintenance after the move
- Regular database optimization
- Image optimization and compression
- Plugin performance monitoring
- Security scan implementation
How to move WordPress without downtime using DNS TTL
A resolver may cache a DNS record for as long as its TTL allows (RFC 1035, section 3.2.1). That fixes the order of the steps:
- Lower the TTL in advance. Set the A and AAAA records to a short TTL, for example 300 seconds, at least one full old TTL before the switch. If the old value was 86400 seconds, that means a day ahead, because until it expires resolvers keep answering with the old IP.
- Test the new server through the hosts file. Map the domain to the new IP in your local hosts file and go through checkout, login and forms on the target server before the public record changes. Visitors still reach the old server.
- Freeze writes for the final dump. Orders, comments and form entries that reach the old server after the last
wp db exportdo not travel. Put the old site into maintenance mode, or stop publishing, for the final export and import.
How to transfer a large WordPress media library with rsync
FTP copies every file again on every attempt. rsync over SSH compares source and destination and sends only the differences, so a second run moves only what changed since the first one (rsync manual).
- Run it twice. The first pass copies
wp-content/uploadswhile the old site is still live. The second pass, during the write freeze, picks up the files added in the meantime. - Replace URLs with WP-CLI, not with SQL. WordPress stores options and widget settings as serialized PHP arrays that record string lengths.
wp search-replacerewrites those lengths, a plain SQLREPLACE()does not. - Regenerate thumbnails if the theme changed.
wp media regeneraterebuilds thumbnails for the image sizes registered on the new install, and--only-missinglimits it to images that lack some sizes (WP-CLI: wp media regenerate).
How to check SEO, SSL and Core Web Vitals after a WordPress migration
- Crawl the old URL list. Every old URL should answer with a 301 to its new counterpart, and no internal link should return a 404. Google recommends server-side permanent redirects from old to new URLs for a site move, and a Change of Address in Search Console when the domain changes (Google Search Central: site moves with URL changes).
- TLS and HSTS. Install the certificate on the new server before the switch. HTTP Strict Transport Security makes browsers use HTTPS only for the domain for the whole max-age period (RFC 6797), so turn it on only once HTTPS works on every subdomain it covers.
- Measure before and after. Run PageSpeed Insights on the same templates on the old and the new server. Page cache, OPcache, object cache and gzip or Brotli compression on the new host show up in the server response time.
GDPR obligations when changing WordPress hosting
For a site run by a company in the EU, a new host is also a new processor of personal data:
- A data processing agreement with the new host. Article 28 GDPR requires a contract that sets out the subject matter, duration, nature and purpose of the processing, and binds the processor to the security measures of Article 32 (GDPR, Regulation (EU) 2016/679).
- Update the privacy policy. If the move adds a CDN, a new backup location or a new host, the list of recipients in the privacy policy changes with it.
- Deletion at the old host. Under Article 28(3)(g) the processor deletes or returns the personal data at the end of the service, at the controller’s choice. Once the new server runs stable, ask the old host to confirm that files, databases and backups are deleted.
WordPress deployment with GitHub Actions and rollback
- Deploy from the repository. A GitHub Actions or GitLab CI workflow builds theme assets and ships code on every push to the main branch, so the server never carries hand-edited files.
- Keep the previous release. Deploy each release into its own directory and switch a symlink. Rolling back code means pointing the symlink at the previous release. Take a
wp db exportbefore any step that changes the database, because a code rollback does not undo changes to tables or content. - The same versions everywhere. Match the PHP and MySQL or MariaDB versions between local, staging and production, so a migration tested on staging behaves the same way in production.
How wp search-replace handles serialized data
The WordPress handbook warns that a blanket search and replace over the database can break serialized data, and that the guid column in wp_posts must never be changed (Moving WordPress). wp search-replace is built for this case: it handles PHP serialized data and does not change primary key values (WP-CLI: wp search-replace). The flags that matter during a migration:
--dry-runreports what would change and saves nothing.--skip-columns=guidkeeps post GUIDs as they are.--preciseforces PHP processing for every column. It is slower and more reliable for complex serialized data.--networkcovers all tables of a multisite network. Without it, only the current site’s tables are searched.--all-tables-with-prefixadds tables that plugins created with the WordPress prefix without registering them, and--all-tablestakes every table in the database.--export=file.sqlwrites the changed data to an SQL file instead of the database, which helps when the target database sits on another server.
Tables without a primary key are skipped, so a plugin table without one needs a separate check. On multisite the handbook also lists what to review by hand: the wp_blogs and wp_site tables and the home, siteurl and fileupload_url options of every site.
wp db export and wp db import round this off. Export runs mysqldump with the credentials from wp-config.php and accepts any mysqldump flag, and wp db export - writes to STDOUT (WP-CLI: wp db export). Import does not create the database, it only runs the SQL from the file, and wp db import - reads from STDIN (WP-CLI: wp db import). Create the empty database on the target first.
WordPress migration case studies
Case study 1: moving a 50,000-product store to a new domain
Scenario: A popular online store with 50,000+ products needed to migrate from store-old.com to brandnew.com while maintaining SEO rankings and customer trust.
Challenges Faced:
- Massive product database with complex variations
- Active shopping cart sessions during migration
- Third-party payment gateway integrations
- Customer email campaigns with old domain links
Migration Strategy:
Pre-migration preparation (2 weeks):
- Created complete site backup including customer data
- Set up temporary staging environment
- Tested all payment gateway integrations
- Prepared email templates for customer notification
Technical implementation (4 hours):
- Used WP-CLI for database URL replacement
- Implemented custom 301 redirect rules
- Updated all third-party API endpoints
- Configured SSL certificate for new domain
Post-migration optimization (1 week):
- Monitored Google Search Console for indexing issues
- Updated all marketing automation workflows
- Implemented enhanced tracking for migration impact
- Conducted customer satisfaction survey
Results:
- Nearly all SEO rankings maintained within 2 weeks
- Zero data loss during migration
- Customer complaints fell sharply with proper communication
- Site speed improved on the new hosting infrastructure
Key Lessons Learned:
- Customer communication is as important as technical execution
- Testing payment gateways in staging environment prevents revenue loss
- Having rollback plan ready provides confidence during execution
Case study 2: moving a 200-site multisite network to the cloud
Scenario: A educational institution with 200+ subdomain sites needed to migrate from shared hosting to dedicated cloud infrastructure.
Technical Complexity:
- 201 individual WordPress sites
- Custom user roles and permissions across sites
- Shared media library with 100GB+ of content
- Complex plugin dependencies between sites
Migration Approach:
Network Analysis Phase:
- Mapped all site interdependencies
- Identified custom plugin configurations
- Documented user role hierarchies
- Analyzed media library usage patterns
Staging Environment Setup:
- Replicated exact server configuration
- Created automated testing scripts
- Implemented performance monitoring
- Set up rollback procedures
Phased Migration:
- Migrated 10 pilot sites first
- Documented and refined process
- Batch migrated remaining sites
- Continuous monitoring and optimization
Technical Solutions:
## Custom script for batch multisite migration
#!/bin/bash
for site in $(wp site list --field=url); do
echo "Migrating $site"
wp search-replace 'old-domain.com' 'new-domain.com' --url=$site
wp cache flush --url=$site
doneOutcomes:
- 99.8% uptime during migration process
- 40% improvement in page load times
- Zero data corruption across all sites
- Simplified administration through centralized management
Case study 3: moving a blog to HTTPS and fixing mixed content
Scenario: A content-heavy blog with 10,000+ posts and extensive media library needed HTTPS implementation.
Mixed Content Challenges:
- Hardcoded HTTP links in post content
- External resources without HTTPS alternatives
- Embedded iframes from non-secure sources
- Custom CSS with HTTP references
Full pipeline:
- Content Audit and Cleanup:
-- Find and replace HTTP references in posts
UPDATE wp_posts
SET post_content = REPLACE(post_content, 'http://example.com', 'https://example.com')
WHERE post_content LIKE '%http://example.com%';
-- Leave the guid column alone: the WordPress docs say never change it- Plugin Configuration Updates:
// Custom functions.php additions for HTTPS enforcement
add_action('template_redirect', function() {
if (!is_ssl() && !is_admin()) {
wp_redirect('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], 301);
exit;
}
});- Advanced .htaccess Configuration:
## How to force HTTPS for all WordPress traffic
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]Performance Impact:
- Initial 5% traffic dip during first week
- Full recovery within 3 weeks
- 10% improvement in search rankings
- Enhanced user trust and security metrics
Migrating large WordPress databases and serialized data
Database migration optimization strategies
Handling large databases efficiently
For databases exceeding 1GB, standard export/import methods often fail. Here are advanced techniques:
Method 1: Chunked Export with WP-CLI
## Export in chunks for large databases
wp db export chunk1.sql --tables=wp_posts,wp_postmeta --add-drop-table
wp db export chunk2.sql --tables=wp_options,wp_users,wp_usermeta --add-drop-table
## Combine and import separately
mysql new_database < chunk1.sql
mysql new_database < chunk2.sqlMethod 2: stream the dump through gzip instead of a custom PHP script
## Stream the dump straight into gzip, no uncompressed file on disk
wp db export - --single-transaction --quick | gzip > db.sql.gz
## Import from STDIN on the target
gunzip < db.sql.gz | wp db import -Serialized data handling
WordPress stores many settings as serialized PHP data, which breaks when URL lengths change:
Serialization-safe replacement with WP-CLI:
## Preview first, then run without --dry-run
wp search-replace 'https://olddomain.com' 'https://newdomain.com' --skip-columns=guid --precise --dry-run
wp search-replace 'https://olddomain.com' 'https://newdomain.com' --skip-columns=guid --preciseBash script to automate a WordPress migration
Automated migration framework
Create a comprehensive migration automation script:
#!/bin/bash
## WordPress Migration Automation Script
set -e # Exit on any error
## Configuration
OLD_DOMAIN="old-site.com"
NEW_DOMAIN="new-site.com"
BACKUP_DIR="/path/to/backups"
STAGING_DIR="/path/to/staging"
LOG_FILE="$BACKUP_DIR/migration_$(date +%Y%m%d_%H%M%S).log"
## Logging function
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
## Pre-migration checks
pre_migration_checks() {
log "Starting pre-migration checks"
# Check WordPress installation
if ! wp core is-installed --path=/var/www/html; then
log "ERROR: WordPress installation not found"
exit 1
fi
# Check database connection
if ! wp db check --path=/var/www/html; then
log "ERROR: Database connection failed"
exit 1
fi
# Create backup directory
mkdir -p "$BACKUP_DIR"
mkdir -p "$STAGING_DIR"
log "Pre-migration checks completed"
}
## Backup creation
create_backups() {
log "Creating comprehensive backups"
# Database backup
wp db export "$BACKUP_DIR/database_$(date +%Y%m%d_%H%M%S).sql" --path=/var/www/html
# Files backup
tar -czf "$BACKUP_DIR/files_$(date +%Y%m%d_%H%M%S).tar.gz" /var/www/html
# Configuration backup
cp /var/www/html/wp-config.php "$BACKUP_DIR/wp-config_$(date +%Y%m%d_%H%M%S).php"
log "Backups completed successfully"
}
## URL replacement
replace_urls() {
log "Starting URL replacement process"
# Core WordPress URLs
wp search-replace "$OLD_DOMAIN" "$NEW_DOMAIN" --skip-columns=guid --path=/var/www/html
log "URL replacement completed"
}
## Post-migration validation
post_migration_validation() {
log "Starting post-migration validation"
# Test site accessibility
if curl -f -s "https://$NEW_DOMAIN" > /dev/null; then
log "Site is accessible"
else
log "ERROR: Site is not accessible"
exit 1
fi
# Test WordPress admin
if curl -f -s "https://$NEW_DOMAIN/wp-admin/" > /dev/null; then
log "WordPress admin is accessible"
else
log "ERROR: WordPress admin is not accessible"
exit 1
fi
# Check database integrity
wp db check --path=/var/www/html
log "Post-migration validation completed"
}
## Main execution
main() {
log "Starting WordPress migration process"
pre_migration_checks
create_backups
replace_urls
post_migration_validation
log "Migration completed successfully"
}
## Execute main function
mainNginx, PHP and MySQL settings for a migrated site
Nginx and PHP settings after migration
Nginx configuration for migrated sites
server {
listen 80;
server_name new-site.com www.new-site.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name new-site.com www.new-site.com;
root /var/www/html;
index index.php index.html;
# SSL Configuration
ssl_certificate /path/to/ssl/cert.pem;
ssl_certificate_key /path/to/ssl/private.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
# WordPress-specific configuration
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# Performance optimizations
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
}
# Caching configuration
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
}PHP optimization for migration performance
; PHP configuration optimized for WordPress migration
memory_limit = 512M
max_execution_time = 300
max_input_time = 300
upload_max_filesize = 64M
post_max_size = 64M
max_input_vars = 3000
; OPcache configuration for better performance
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=2
opcache.fast_shutdown=1Database performance tuning
MySQL configuration optimization
-- MySQL optimization for WordPress
SET GLOBAL innodb_buffer_pool_size = 1073741824; -- 1GB
SET GLOBAL innodb_log_file_size = 268435456; -- 256MB
SET GLOBAL innodb_flush_log_at_trx_commit = 2;
SET GLOBAL innodb_flush_method = O_DIRECT;
-- Query cache configuration
SET GLOBAL query_cache_type = ON;
SET GLOBAL query_cache_size = 67108864; -- 64MBDatabase indexing strategy
-- Add indexes for better performance
ALTER TABLE wp_posts ADD INDEX idx_post_type_status (post_type, post_status);
ALTER TABLE wp_postmeta ADD INDEX idx_meta_key_value (meta_key, meta_value(191));
ALTER TABLE wp_options ADD INDEX idx_autoload (autoload, option_name);
-- Optimize large tables
OPTIMIZE TABLE wp_posts;
OPTIMIZE TABLE wp_postmeta;
OPTIMIZE TABLE wp_options;Fix serialized data and memory errors after migration
Serialized data, memory and plugin errors
Issue 1: Serialized data corruption
Problem: After URL replacement, theme options and plugin settings become corrupted.
Diagnosis:
<?php
// List options whose serialized value no longer unserializes (run with wp eval-file)
global $wpdb;
$rows = $wpdb->get_results( "SELECT option_name, option_value FROM {$wpdb->options}" );
foreach ( $rows as $row ) {
$v = $row->option_value;
if ( is_serialized( $v ) && 'b:0;' !== $v && false === @unserialize( $v ) ) {
echo $row->option_name . "\n";
}
}Solution:
## Restore the pre-replace dump and repeat the replacement with WP-CLI
wp db import backup-before-replace.sql
wp search-replace 'https://olddomain.com' 'https://newdomain.com' --skip-columns=guid --preciseIssue 2: Memory exhaustion during large database migration
Problem: PHP memory limits exceeded during database import/export.
Solutions:
Method 1: Chunked Processing
<?php
// Process database in chunks to avoid memory issues
function process_database_in_chunks($table, $chunk_size = 1000) {
global $wpdb;
$offset = 0;
do {
$results = $wpdb->get_results("
SELECT * FROM $table
LIMIT $offset, $chunk_size
");
foreach ($results as $row) {
// Process each row
process_row($row);
}
$offset += $chunk_size;
// Clear memory
$wpdb->flush();
} while (count($results) === $chunk_size);
}
?>Method 2: Streaming Database Export
## Use mysqldump with compression for large databases
mysqldump --single-transaction --quick --lock-tables=false \
--host=localhost --user=username --password=password \
database_name | gzip > backup.sql.gz
## Import with streaming
gunzip < backup.sql.gz | mysql -u username -p database_nameIssue 3: Plugin compatibility after migration
Problem: Plugins fail to work after URL changes due to hardcoded references.
Systematic Solution:
- Create Plugin Compatibility Checker:
<?php
// Plugin compatibility checker
function check_plugin_compatibility() {
$plugins = get_option('active_plugins');
$issues = [];
foreach ($plugins as $plugin_path) {
$plugin_data = get_plugin_data(WP_PLUGIN_DIR . '/' . $plugin_path);
// Check for hardcoded URLs in plugin files
$plugin_files = glob(WP_PLUGIN_DIR . '/' . dirname($plugin_path) . '/*.php');
foreach ($plugin_files as $file) {
$content = file_get_contents($file);
// Look for potential hardcoded URLs
if (preg_match('/https?:\/\/[^\s"\'<]+/', $content, $matches)) {
$issues[] = [
'plugin' => $plugin_data['Name'],
'file' => $file,
'hardcoded_urls' => $matches
];
}
}
}
return $issues;
}
?>- Replace URLs in plugin settings with WP-CLI:
## wp_options only, PHP mode for nested serialized values
wp search-replace 'https://olddomain.com' 'https://newdomain.com' wp_options --precise --dry-runAutomate WordPress migrations with GitHub Actions
How to test migrations in a CI pipeline
GitHub Actions workflow for automated testing
name: WordPress Migration Test
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
migration-test:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: wordpress_test
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
extensions: mysqli, gd, xml, mbstring
- name: Install WordPress
run: |
curl -O https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
cp -r wordpress/* /var/www/html/
- name: Configure WordPress
run: |
cp wp-config-sample.php wp-config.php
sed -i "s/database_name_here/wordpress_test/" wp-config.php
sed -i "s/username_here/root/" wp-config.php
sed -i "s/password_here/password/" wp-config.php
sed -i "s/localhost/127.0.0.1/" wp-config.php
- name: Install WP-CLI
run: |
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
- name: Run Migration Tests
run: |
wp core install --url=http://localhost --title="Test Site" --admin_user=admin --admin_password=password [email protected]
wp plugin install all-in-one-wp-migration --activate
# Add your migration testing scripts here
- name: Validate Migration
run: |
# Add validation scripts
wp option get siteurl
wp option get homeAutomated deployment script
#!/bin/bash
## Automated WordPress Deployment Script
set -e
## Environment variables
ENVIRONMENT=${1:-staging}
BACKUP_DIR="/backups/wordpress"
DEPLOY_LOG="/var/log/deploy.log"
## Logging function
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$ENVIRONMENT] $1" | tee -a "$DEPLOY_LOG"
}
## Pre-deployment checks
pre_deployment_checks() {
log "Starting pre-deployment checks"
# Check if WordPress is installed
if ! wp core is-installed --path=/var/www/html; then
log "ERROR: WordPress not properly installed"
exit 1
fi
# Check database connectivity
if ! wp db check --path=/var/www/html; then
log "ERROR: Database connection failed"
exit 1
fi
# Verify required plugins are active
if ! wp plugin is-active all-in-one-wp-migration --path=/var/www/html; then
log "ERROR: Required migration plugin not active"
exit 1
fi
log "Pre-deployment checks passed"
}
## Create deployment backup
create_deployment_backup() {
log "Creating deployment backup"
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup_file="$BACKUP_DIR/pre_deploy_${ENVIRONMENT}_$timestamp.sql"
wp db export "$backup_file" --path=/var/www/html
# Verify backup integrity
if [ -s "$backup_file" ] && tail -n 1 "$backup_file" | grep -q "Dump completed"; then
log "Backup created and verified: $backup_file"
else
log "ERROR: Backup creation failed"
exit 1
fi
}
## Execute migration
execute_migration() {
log "Executing WordPress migration"
# Update site URLs if needed
if [ "$ENVIRONMENT" = "production" ]; then
wp search-replace "staging.example.com" "example.com" --skip-columns=guid --path=/var/www/html
fi
# Flush all caches
wp cache flush --path=/var/www/html
# Update rewrite rules
wp rewrite flush --path=/var/www/html
log "Migration completed"
}
## Post-deployment validation
post_deployment_validation() {
log "Starting post-deployment validation"
# Check site accessibility
local site_url=$(wp option get siteurl --path=/var/www/html)
if curl -f -s "$site_url" > /dev/null; then
log "Site is accessible: $site_url"
else
log "ERROR: Site is not accessible"
exit 1
fi
# Check WordPress admin
if curl -f -s "$site_url/wp-admin/" > /dev/null; then
log "WordPress admin is accessible"
else
log "ERROR: WordPress admin is not accessible"
exit 1
fi
# Verify database integrity
if wp db check --path=/var/www/html; then
log "Database integrity verified"
else
log "ERROR: Database integrity check failed"
exit 1
fi
# Check critical plugins
local critical_plugins=("all-in-one-wp-migration" "wp-super-cache")
for plugin in "${critical_plugins[@]}"; do
if wp plugin is-active "$plugin" --path=/var/www/html; then
log "Plugin $plugin is active"
else
log "WARNING: Plugin $plugin is not active"
fi
done
log "Post-deployment validation completed"
}
## Main deployment function
main() {
log "Starting WordPress deployment for $ENVIRONMENT environment"
pre_deployment_checks
create_deployment_backup
execute_migration
post_deployment_validation
log "Deployment completed successfully"
# Send notification (optional)
if command -v slack-cli &> /dev/null; then
slack-cli send "WordPress deployment to $ENVIRONMENT completed successfully"
fi
}
## Execute main function
mainConclusion
WordPress migration doesn’t have to be overwhelming when approached systematically. By following this comprehensive guide, preparing thoroughly, and testing diligently, you can successfully migrate your WordPress site with minimal disruption to your users and SEO performance.
Remember that preparation is key, never attempt a migration without complete backups and a clear rollback plan. Take your time, test thoroughly, and don’t hesitate to seek professional help for complex migrations.
With proper planning and execution, your WordPress migration can be a smooth process that sets your site up for future growth and success.
For the delivery side of this topic we keep the work under Next.js or Astro migration.







