diff --git a/CHANGELOG.md b/CHANGELOG.md index 15f6739..77ae6f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +- **The migration guides**, now four posts on wpvilla.in: [migrating a site to Trellis and Bedrock](https://wpvilla.in/migrate-wordpress-to-trellis-bedrock-step-by-step/), [testing before the DNS cutover](https://wpvilla.in/trellis-migration-test-etc-hosts-letsencrypt-dns-cutover/), [migrating several sites onto one server](https://wpvilla.in/migrate-multiple-wordpress-sites-one-trellis-server/) and [wp search-replace for domain and path changes](https://wpvilla.in/wp-search-replace-wordpress-url-domain-https-bedrock-paths/). `wp-cli/migration/` is gone, and the README, `CLAUDE.md` and `wp-cli/README.md` no longer point at it. - **The documentation feature.** The guides are moving to [wpvilla.in](https://wpvilla.in/), so wp-ops no longer searches or links documentation. - `wp-ops docs` is gone, along with the "the documentation mentions it" hint in `search`. - The `@doc` manifest directive is gone: the catalog `doc` field, the `Docs:` line in `--help`, the `doc` key in `list --json`, the `docs:` line in the MCP command detail, and the lint that checked the path. The `# @doc` lines are stripped from every script header. diff --git a/CLAUDE.md b/CLAUDE.md index 2ce60b8..92a4e50 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,7 +17,6 @@ This is a collection of tools, scripts, and documentation for WordPress operatio - **wp-cli/** - WordPress command-line operations - `wp-cli/content-creation/` - WP-CLI content creation, block patterns, and the `wp imagewize pattern-validate` command - `wp-cli/diagnostics/` - WordPress diagnostic tools - - `wp-cli/migration/` - WordPress migration documentation and URL update methods - `wp-cli/security/` - Malware detection and security scanning - **scripts/** - General utility scripts - `scripts/backup/` - Standalone backup shell scripts diff --git a/README.md b/README.md index 3f9fbcd..5eca301 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,6 @@ sites are run with: | **Monitoring** | AI-crawler traffic, error surfacing, traffic by country, cron-scheduled reports | [→](trellis/monitoring/README.md) | | **Security** | Malware scanners with checksum verification, fail2ban, manual IP blocking, AbuseIPDB lookup | [scanners](wp-cli/security/README.md) · [server](trellis/security/README.md) | | **Content & SEO** | Page creation, block pattern validation, redirect/schema/orphan-page audits | [content](wp-cli/content-creation/README.md) · [SEO](wp-cli/seo/README.md) | -| **Migration** | Moving single and multisite installs onto Trellis/Bedrock, URL update methods | [→](wp-cli/migration/README.md) | | **Nginx** | WebP/AVIF serving, browser caching and redirect templates for Trellis `nginx-includes/` | [images](docs/nginx/image-optimization/README.md) · [caching](docs/nginx/browser-caching/README.md) · [redirects](docs/nginx/redirects/README.md) | | **Bedrock** | Testing unreleased packages via Composer `path` repos, standard `wp-cli.yml` | [packages](docs/bedrock/local-package-development/README.md) · [wp-cli.yml](docs/bedrock/wp-cli-config/README.md) | | **Troubleshooting** | PHP-FPM, MariaDB, OOM and mail diagnostics | [→](docs/troubleshooting/README.md) | diff --git a/trellis/provision/CRON.md b/trellis/provision/CRON.md index bf2acfa..8255b85 100644 --- a/trellis/provision/CRON.md +++ b/trellis/provision/CRON.md @@ -393,5 +393,5 @@ tail -f /var/log/syslog | grep -i cron ## Related Documentation - [Provisioning Guide](README.md) - Trellis provisioning commands -- [Migration Guide](../../wp-cli/migration/REGULAR-TO-TRELLIS.md) - Migrating from traditional WordPress +- [Migration guide](https://wpvilla.in/migrate-wordpress-to-trellis-bedrock-step-by-step/) - Migrating from traditional WordPress - [Deployment](https://roots.io/trellis/docs/deployments/) - Trellis deployment process diff --git a/wp-cli/README.md b/wp-cli/README.md index d6d7175..9ac2a02 100644 --- a/wp-cli/README.md +++ b/wp-cli/README.md @@ -17,7 +17,6 @@ This directory contains production-tested WP-CLI utilities for: wp-cli/ ├── content-creation/ # Block patterns, page creation, automation scripts ├── diagnostics/ # Troubleshooting and debugging tools -├── migration/ # Site migration documentation and workflows └── seo/ # SEO audit tools and scripts ``` @@ -289,200 +288,12 @@ Production-safe diagnostic scripts for identifying and troubleshooting WordPress ## 3. Migration -**Location:** `migration/` +The migration guides live on the blog: -Comprehensive guides for migrating WordPress sites to Trellis/Bedrock infrastructure. - -### Features - -- **Single-Site Migration** - Traditional WordPress to Trellis/Bedrock -- **Multi-Site Migration** - Consolidating multiple sites to Trellis -- **Full Bedrock Adoption** - Recommended approach with composer dependencies -- **Path Compatibility Mode** - Quick migration without restructuring -- **Domain Migration** - URL replacement workflows -- **Testing Methodology** - `/etc/hosts` testing before DNS cutover - -### Documentation - -| File | Purpose | -|------|---------| -| `README.md` | Migration overview and quick reference (100+ lines) | -| `REGULAR-TO-TRELLIS.md` | Complete single-site migration guide | -| `MULTI-SITE-MIGRATION.md` | Multi-site consolidation strategies | - -### Migration Approaches - -#### Full Bedrock Adoption (Recommended) - -**Pros:** -- Modern Composer-based dependency management -- Improved security (wp-admin outside web root) -- Environment-specific configuration (.env files) -- Better version control (gitignore for WordPress core) -- Trellis deployment integration - -**Cons:** -- Requires path updates in database -- More initial setup time -- Plugin compatibility review needed - -#### Path Compatibility Mode - -**Pros:** -- Faster migration -- Minimal database changes -- Lower risk for simple sites - -**Cons:** -- Doesn't leverage Bedrock benefits -- Future maintenance complexity -- May need conversion later - -### Common Migration Workflow - -1. **Preparation** - - Backup current site (database + files) - - Document current configuration - - Test locally with Trellis development environment - - Identify custom code and plugins - -2. **Database Migration** - ```bash - # Export from old site - wp db export backup.sql - - # Import to new site - wp db import backup.sql --path=web/wp - - # Update URLs (Bedrock adoption) - wp search-replace '/wp-content/' '/app/' --all-tables --path=web/wp - wp search-replace 'http://old-domain.com' 'https://new-domain.com' --all-tables --path=web/wp - ``` - -3. **File Migration** - ```bash - # Copy uploads - rsync -av old-site/wp-content/uploads/ \ - bedrock/web/app/uploads/ - - # Copy themes (if custom) - rsync -av old-site/wp-content/themes/custom-theme/ \ - bedrock/web/app/themes/custom-theme/ - - # Install plugins via Composer (recommended) - composer require wpackagist-plugin/plugin-name - ``` - -4. **Testing with /etc/hosts** - ```bash - # Edit /etc/hosts before DNS change - sudo nano /etc/hosts - - # Add line: - 123.45.67.89 example.com www.example.com - - # Test in browser before DNS cutover - # Remove line after DNS propagation - ``` - -5. **DNS Cutover** - - Update A records to new server IP - - Monitor for issues - - Keep old site available for rollback - -6. **Post-Migration** - - Verify all pages load correctly - - Test forms and contact submissions - - Check SSL certificate - - Configure WordPress cron (Trellis uses system cron) - - Update Google Search Console - - Submit updated sitemap - -### Multi-Site Migration Strategies - -**Time-Saving Tips:** -- **Batch preparation**: Set up all sites before first provision -- **Descriptive naming**: Use clear directory names from start (`site-1-domain.com` not `site-1`) -- **Configure together**: Add all sites to `wordpress_sites.yml` before provisioning -- **Template configs**: Reuse vault structure and settings - -**Time Estimates:** -- First site: 3-5 hours (learning curve) -- Subsequent sites: 2-2.5 hours each -- Multi-site batch: ~2 hours per site (after first) - -### Domain Migration Commands - -```bash -# Simple domain change -wp search-replace 'old-domain.com' 'new-domain.com' --all-tables --path=web/wp - -# HTTP to HTTPS -wp search-replace 'http://example.com' 'https://example.com' --all-tables --path=web/wp - -# With dry run (test first) -wp search-replace 'old-domain.com' 'new-domain.com' --all-tables --dry-run --path=web/wp - -# Precise mode (exact matches only) -wp search-replace 'old-domain.com' 'new-domain.com' --all-tables --precise --path=web/wp -``` - -### Bedrock Path Conversion - -```bash -# Update content paths -wp search-replace '/wp-content/uploads/' '/app/uploads/' --all-tables --path=web/wp -wp search-replace '/wp-content/themes/' '/app/themes/' --all-tables --path=web/wp -wp search-replace '/wp-content/plugins/' '/app/plugins/' --all-tables --path=web/wp - -# Update includes paths (less common) -wp search-replace 'wp-includes' 'wp/wp-includes' --all-tables --path=web/wp -``` - -### WordPress Cron Configuration - -Trellis disables WP-Cron and uses system cron instead: - -```bash -# Trellis sets in .env -DISABLE_WP_CRON=true - -# System cron runs every 15 minutes -*/15 * * * * cd /srv/www/example.com/current && wp cron event run --due-now --path=web/wp - -# Verify cron is working -ssh web@example.com "cd /srv/www/example.com/current && \ - wp cron event list --path=web/wp" -``` - -### Troubleshooting Common Issues - -**Database connection errors:** -- Check `.env` file database credentials -- Verify database exists and user has permissions -- Test connection: `wp db check --path=web/wp` - -**Missing uploads:** -- Verify rsync completed successfully -- Check file permissions: `chown -R web:www-data uploads/` -- Confirm path in database matches Bedrock structure - -**Plugin compatibility:** -- Test plugins individually -- Check for hardcoded paths -- Review plugin requirements (some may need Composer installation) - -**SSL errors:** -- Verify Trellis SSL configuration in `wordpress_sites.yml` -- Check nginx SSL certificates: `ls -la /etc/nginx/ssl/` -- Test SSL: `curl -I https://example.com` - -**Permalink errors:** -- Flush rewrite rules: `wp rewrite flush --path=web/wp` -- Verify nginx configuration includes WordPress permalinks -- Check `.htaccess` equivalent in nginx config - -**See also:** [migration/README.md](migration/README.md) and subdirectory documentation. +- [Migrating a WordPress site to Trellis and Bedrock](https://wpvilla.in/migrate-wordpress-to-trellis-bedrock-step-by-step/) +- [Testing a migration before DNS, and the cutover](https://wpvilla.in/trellis-migration-test-etc-hosts-letsencrypt-dns-cutover/) +- [Migrating several sites onto one Trellis server](https://wpvilla.in/migrate-multiple-wordpress-sites-one-trellis-server/) +- [wp search-replace for domain, HTTPS and Bedrock path changes](https://wpvilla.in/wp-search-replace-wordpress-url-domain-https-bedrock-paths/) --- @@ -604,15 +415,6 @@ cd /srv/www/example.com/current 4. **Delete web diagnostic files** - Remove after use for security 5. **Regular health checks** - Run diagnostics monthly for proactive monitoring -### Migration - -1. **Backup everything** - Database and files before migration -2. **Test with /etc/hosts** - Verify before DNS change -3. **Use dry-run first** - Test search-replace before applying -4. **Document custom code** - Track plugins, themes, custom functionality -5. **Plan rollback strategy** - Keep old site available during migration -6. **Communicate changes** - Inform users of potential downtime -7. **Verify after migration** - Check all functionality works correctly ### SEO diff --git a/wp-cli/migration/MULTI-SITE-MIGRATION.md b/wp-cli/migration/MULTI-SITE-MIGRATION.md deleted file mode 100644 index 4d720f3..0000000 --- a/wp-cli/migration/MULTI-SITE-MIGRATION.md +++ /dev/null @@ -1,1058 +0,0 @@ -# Migrating Multiple WordPress Sites to Trellis - -This guide covers strategies and best practices for migrating **multiple WordPress sites to a single Trellis server**. This is particularly useful for agencies, consultants, or anyone consolidating multiple client sites onto modern infrastructure. - -## Prerequisites - -Before using this guide, you should: - -1. **Read the [core migration guide](REGULAR-TO-TRELLIS.md)** - This document assumes you understand the basic single-site migration process -2. Have a working Trellis installation -3. Understand Bedrock directory structure -4. Be familiar with WP-CLI commands - -## Table of Contents - -- [Overview](#overview) -- [Time-Saving Tips for Multiple Sites](#time-saving-tips-for-multiple-sites) -- [Managing Multiple Sites on One Server](#managing-multiple-sites-on-one-server) -- [Common Pitfalls When Migrating Multiple Sites](#common-pitfalls-when-migrating-multiple-sites) -- [Multi-Site Troubleshooting](#multi-site-troubleshooting) - -## Overview - -One of Trellis's strengths is the ability to host **multiple WordPress sites on a single server**. When migrating multiple sites, you can save significant time by: - -- Batching preparation work -- Configuring all sites before first provision -- Running operations in parallel -- Using reusable scripts and templates -- Learning from the first migration to speed up subsequent ones - -**Expected Timeline:** -- **First site**: 3-5 hours (learning curve) -- **Second site**: 2-3 hours (process is familiar) -- **Third site**: 2-2.5 hours (optimized workflow) -- **Total for 3 sites**: 8-10 hours (vs. 12-15 hours without optimization) - -## Time-Saving Tips for Multiple Sites - -When migrating three sites to a single Trellis server, use these strategies to minimize time and maximize efficiency. - -### 1. Batch Preparation Phase - -Before starting any migrations, prepare all three sites at once: - -**Checklist for all sites:** -- [ ] Download all databases from old hosting (export as `.sql` or `.sql.gz`) -- [ ] Download all file backups (themes, plugins, uploads) to organized local folders -- [ ] Document all active plugins for each site in a spreadsheet -- [ ] Generate all WordPress salts at once (visit https://roots.io/salts.html three times, save to text files) -- [ ] Create all three Git repositories on GitHub/GitLab -- [ ] Document any special configurations from old `wp-config.php` files - -**Organize your downloads:** -```bash -# Create organized backup structure -mkdir -p ~/migrations/site1/{database,files} -mkdir -p ~/migrations/site2/{database,files} -mkdir -p ~/migrations/site3/{database,files} - -# This organization saves time when you're ready to migrate each site -``` - -### 2. Use Descriptive Directory Names from Start - -Instead of using generic `site/` directory, use descriptive names immediately to avoid confusion: - -```bash -# For first site -trellis new example.com -cd example.com -mv site site-example - -# Update trellis/group_vars/*/wordpress_sites.yml -# Change: local_path: ../site -# To: local_path: ../site-example - -# Then add second and third sites -composer create-project roots/bedrock site-clienttwo -composer create-project roots/bedrock site-clientthree -``` - -**Benefits:** -- No confusion about which site is which -- Easier to reference in commands -- Clear Git history -- Better for team collaboration - -### 3. Configure All Sites Before First Provision - -Add all three sites to `wordpress_sites.yml` before provisioning. This way: - -- **Single provisioning run** sets up all three databases -- **All SSL certificates** created at once with Let's Encrypt -- **Nginx configured** for all sites simultaneously -- **Saves ~30 minutes** vs. provisioning three times - -**Example `trellis/group_vars/production/wordpress_sites.yml`:** -```yaml -wordpress_sites: - example.com: - site_hosts: - - canonical: example.com - local_path: ../site-example - repo: git@github.com:yourusername/trellis-multi.git - repo_subtree_path: site-example - # ... rest of config ... - - clienttwo.com: - site_hosts: - - canonical: clienttwo.com - local_path: ../site-clienttwo - repo: git@github.com:yourusername/trellis-multi.git - repo_subtree_path: site-clienttwo - # ... rest of config ... - - clientthree.com: - site_hosts: - - canonical: clientthree.com - local_path: ../site-clientthree - repo: git@github.com:yourusername/trellis-multi.git - repo_subtree_path: site-clientthree - # ... rest of config ... -``` - -Then run once: -```bash -trellis provision production -``` - -### 4. Parallel Operations - -Take advantage of independent operations that can run simultaneously: - -**While database is importing on Site 1:** -```bash -# In one terminal: Import database for site 1 -ssh admin@server "cd /srv/www/example.com/current && wp db import /tmp/backup1.sql" - -# In another terminal: Upload files for site 2 -rsync -avz ~/migrations/site2/files/uploads/ admin@server:/srv/www/clienttwo.com/shared/uploads/ - -# In another terminal: Work on site 3 locally -cd ~/code/trellis-project/site-clientthree -# Copy theme and plugins -``` - -**While running search-replace on one site:** -- Deploy the next site -- Prepare the third site's uploads for transfer -- Run tests on a completed site - -### 5. Create Reusable Scripts - -Save time by scripting repetitive tasks: - -**Script: `migrate-uploads.sh`** -```bash -#!/bin/bash -# Usage: ./migrate-uploads.sh site1 example.com - -SITE_NAME=$1 -DOMAIN=$2 -LOCAL_UPLOADS=~/migrations/$SITE_NAME/files/uploads -SERVER_PATH=/srv/www/$DOMAIN/shared/uploads - -echo "Migrating uploads for $DOMAIN..." -rsync -avz --progress $LOCAL_UPLOADS/ admin@your.server.ip:$SERVER_PATH/ - -echo "Setting permissions..." -ssh admin@your.server.ip "sudo chown -R web:www-data $SERVER_PATH && sudo chmod -R 775 $SERVER_PATH" - -echo "Done!" -``` - -**Script: `import-database.sh`** -```bash -#!/bin/bash -# Usage: ./import-database.sh site1 example.com - -SITE_NAME=$1 -DOMAIN=$2 -LOCAL_DB=~/migrations/$SITE_NAME/database/backup.sql - -echo "Uploading database for $DOMAIN..." -scp $LOCAL_DB admin@your.server.ip:/tmp/backup-$SITE_NAME.sql - -echo "Importing database..." -ssh admin@your.server.ip "cd /srv/www/$DOMAIN/current && wp db import /tmp/backup-$SITE_NAME.sql && rm /tmp/backup-$SITE_NAME.sql" - -echo "Done!" -``` - -### 6. Use Workflow B for Maximum Efficiency - -For three sites, **Workflow B** (Local-First Migration) with backup playbooks is most efficient: - -**Advantages for multiple sites:** -1. Test each migration locally before production -2. Use automated playbooks for consistency -3. Easy to repeat if something goes wrong -4. Can work on next site while previous deploys - -**Timeline for three sites using Workflow B:** -- **Day 1 (4-5 hours):** Site 1 - Full setup, local test, push to production -- **Day 2 (3 hours):** Site 2 - Faster since server/process established -- **Day 3 (2.5 hours):** Site 3 - Fastest, everything is familiar - -**Total: 9-10.5 hours** vs. 12-15 hours with direct migration - -### 7. Maintain a Migration Checklist - -Track progress across all sites with a simple checklist: - -```markdown -## Migration Progress Tracker - -### Site 1: example.com -- [x] Backups downloaded -- [x] Bedrock created (site-example) -- [x] Theme/plugins copied -- [x] Deployed to production -- [x] Database migrated -- [x] Uploads synced -- [x] Paths converted -- [x] Tested -- [x] DNS updated - -### Site 2: clienttwo.com -- [x] Backups downloaded -- [x] Bedrock created (site-clienttwo) -- [ ] Theme/plugins copied -- [ ] Deployed to production -... -``` - -### 8. Common Configuration Across Sites - -If all three sites share similar requirements, create templates: - -**Template: Search-replace commands** -```bash -# Save as search-replace-template.sh -# Update domain for each site - -DOMAIN=$1 -wp search-replace '/wp-content/themes/' '/app/themes/' --all-tables -wp search-replace '/wp-content/plugins/' '/app/plugins/' --all-tables -wp search-replace "https://$DOMAIN/wp-content/uploads/" "https://$DOMAIN/app/uploads/" --all-tables --precise -wp search-replace "http://$DOMAIN/wp-content/uploads/" "https://$DOMAIN/app/uploads/" --all-tables --precise -wp cache flush -wp rewrite flush -``` - -**Usage:** -```bash -# Run on each site -ssh admin@server "cd /srv/www/example.com/current && bash" < search-replace-template.sh example.com -``` - -### Summary: Optimal Multi-Site Migration Strategy - -1. ✅ **Batch prepare** all three sites upfront (1 hour) -2. ✅ **Configure all sites** in Trellis before provisioning (30 mins) -3. ✅ **Provision once** for all three sites (15 mins) -4. ✅ **Use Workflow B** with backup playbooks (most efficient) -5. ✅ **Run operations in parallel** where possible -6. ✅ **Create reusable scripts** for repetitive tasks -7. ✅ **Track progress** with checklist - -**Expected timeline for three sites: 8-10 hours total** (vs. 12-15 hours without optimization) - -## Managing Multiple Sites on One Server - -One of Trellis's strengths is the ability to host **multiple WordPress sites on a single server**. This is common for agencies or when consolidating multiple client sites. - -### Important: Directory Structure for Multiple Sites - -When you use `trellis new example.com`, it creates a directory structure with a `site/` folder for your Bedrock installation. However, when managing **multiple sites on the same server**, you should: - -1. **Use descriptive directory names** instead of generic `site/` -2. **Each site gets its own Bedrock installation** in the Trellis project -3. **All sites share the same Trellis configuration** - -### Scenario 1: First Site on Server (Using trellis new) - -For your first site, you can use `trellis new`: - -```bash -cd ~/code - -# This creates the Trellis project with default 'site/' directory -trellis new example.com -cd example.com - -# Your structure: -# example.com/ -# ├── trellis/ -# └── site/ # Bedrock for example.com -``` - -**However**, if you know you'll be adding more sites later, it's better to rename `site/` immediately: - -```bash -# Rename site to something descriptive -mv site site-imagewize - -# Update trellis/group_vars/*/wordpress_sites.yml -# Change: local_path: ../site -# To: local_path: ../site-imagewize -``` - -### Scenario 2: Adding a Second Site to Existing Trellis - -When you need to add a second site to your existing Trellis server: - -#### Step 1: Create New Bedrock Installation - -Use Composer to create a new Bedrock installation with a descriptive name: - -```bash -# Navigate to your Trellis project root -cd ~/code/example.com # Your existing Trellis project - -# Create new Bedrock installation for second site -composer create-project roots/bedrock site-clientname - -# Or for a specific site -composer create-project roots/bedrock site-name -``` - -This creates: -``` -example.com/ -├── trellis/ -├── site-imagewize/ # First site -└── site-name/ # Second site -``` - -#### Step 2: Configure the New Site in Trellis - -**Edit development configuration** - `trellis/group_vars/development/wordpress_sites.yml`: - -```yaml -wordpress_sites: - # First site - example.com: - site_hosts: - - canonical: imagewize.test - local_path: ../site-imagewize - # ... other settings ... - - # Second site (NEW) - jasperfrumau.com: - site_hosts: - - canonical: jasperfrumau.test - local_path: ../site-jasperfrumau # Points to new Bedrock directory - admin_email: admin@jasperfrumau.com - multisite: - enabled: false - ssl: - enabled: false # Development doesn't need SSL - cache: - enabled: false -``` - -**Edit production configuration** - `trellis/group_vars/production/wordpress_sites.yml`: - -```yaml -wordpress_sites: - # First site - example.com: - site_hosts: - - canonical: example.com - redirects: - - www.example.com - local_path: ../site-imagewize - repo: git@github.com:yourusername/example.com.git - repo_subtree_path: site-imagewize - branch: main - multisite: - enabled: false - ssl: - enabled: true - provider: letsencrypt - cache: - enabled: true - - # Second site (NEW) - jasperfrumau.com: - site_hosts: - - canonical: jasperfrumau.com - redirects: - - www.jasperfrumau.com - local_path: ../site-jasperfrumau - repo: git@github.com:yourusername/example.com.git # Same repo! - repo_subtree_path: site-jasperfrumau # Different path in repo - branch: main - multisite: - enabled: false - ssl: - enabled: true - provider: letsencrypt - cache: - enabled: true -``` - -**Edit vault for both environments** - `trellis/group_vars/*/vault.yml`: - -```bash -# Edit development vault -cd trellis -trellis vault edit development - -# Edit production vault -trellis vault edit production -``` - -Add configuration for the new site: - -```yaml -vault_wordpress_sites: - # First site - example.com: - env: - db_password: "secure_password_1" - # ... salts ... - - # Second site (NEW) - jasperfrumau.com: - env: - db_password: "secure_password_2" # Different password! - # Generate new salts at: https://roots.io/salts.html - auth_key: "generateme" - secure_auth_key: "generateme" - logged_in_key: "generateme" - nonce_key: "generateme" - auth_salt: "generateme" - secure_auth_salt: "generateme" - logged_in_salt: "generateme" - nonce_salt: "generateme" -``` - -#### Step 3: Add New Site to Git Repository - -Since both sites share the same Trellis configuration, they should be in the same Git repository: - -```bash -# From project root -cd ~/code/example.com - -# Add new Bedrock installation -git add site-jasperfrumau/ - -# Commit -git commit -m "Add jasperfrumau.com site" - -# Push -git push origin main -``` - -#### Step 4: Re-Provision Server (REQUIRED for New Sites) - -**IMPORTANT:** When adding a new site to an existing server, you **MUST re-provision** to create the necessary infrastructure for the new site: - -```bash -cd trellis - -# Re-provision production to create infrastructure for new site -trellis provision production -``` - -**What this does for the new site:** -- ✅ Creates new MySQL database (`jasperfrumau_production`) -- ✅ Creates new database user with credentials from vault -- ✅ Generates Nginx virtual host configuration (`/etc/nginx/sites-available/jasperfrumau.com.conf`) -- ✅ Requests and installs Let's Encrypt SSL certificate for new domain -- ✅ Creates base directory structure (`/srv/www/jasperfrumau.com/`) -- ✅ Updates firewall rules if needed - -**Without re-provisioning:** -- ❌ Database won't exist → deployment fails -- ❌ No Nginx config → site shows 502 Bad Gateway -- ❌ No SSL certificate → HTTPS won't work -- ❌ No directory structure → deployment fails - -**Alternative (Advanced):** If you only changed Nginx-related settings and know the database already exists: -```bash -# Only update Nginx configuration (faster, but less safe) -ansible-playbook server.yml -e env=production --tags nginx -``` - -**Best practice:** Always use full `trellis provision production` when adding a new site. It's safer and ensures everything is configured correctly. - -#### Step 5: Deploy the New Site - -```bash -cd trellis - -# Deploy the new site -trellis deploy production jasperfrumau.com - -# Or deploy all sites -trellis deploy production -``` - -#### Step 6: Migrate the Second Site's Data - -Follow the same migration steps as the first site: - -1. **Import database** to the new site: - ```bash - ssh admin_user@your.server.ip.address - cd /srv/www/jasperfrumau.com/current - wp db import /path/to/backup.sql - ``` - -2. **Transfer uploads**: - ```bash - rsync -avz --progress /path/to/backup/wp-content/uploads/ \ - admin_user@your.server.ip.address:/srv/www/jasperfrumau.com/shared/uploads/ - ``` - -3. **Update paths** (choose your strategy from [main guide](REGULAR-TO-TRELLIS.md#8-choose-your-path-migration-strategy)) - -### Directory Structure Example - -Here's what a multi-site Trellis setup looks like: - -``` -example.com/ # Project root (Git repository) -├── .git/ -├── trellis/ # Shared Trellis configuration -│ ├── group_vars/ -│ │ ├── all/ -│ │ ├── development/ -│ │ │ ├── wordpress_sites.yml # Both sites configured here -│ │ │ └── vault.yml # Both sites' dev secrets -│ │ └── production/ -│ │ ├── wordpress_sites.yml # Both sites configured here -│ │ └── vault.yml # Both sites' prod secrets -│ └── hosts/ -│ ├── development -│ └── production # Same server IP for both sites -├── site-imagewize/ # First site (Bedrock) -│ ├── composer.json -│ ├── config/ -│ └── web/ -│ └── app/ -│ ├── themes/ -│ └── plugins/ -└── site-jasperfrumau/ # Second site (Bedrock) - ├── composer.json - ├── config/ - └── web/ - └── app/ - ├── themes/ - └── plugins/ -``` - -### On the Server - -Each site gets its own directory structure: - -``` -/srv/www/ -├── example.com/ -│ ├── current -> releases/20241023... -│ ├── releases/ -│ │ └── 20241023.../ -│ └── shared/ -│ └── uploads/ -└── jasperfrumau.com/ - ├── current -> releases/20241023... - ├── releases/ - │ └── 20241023.../ - └── shared/ - └── uploads/ -``` - -### Best Practices for Multiple Sites - -1. **Use descriptive directory names**: `site-clientname` instead of `site/`, `site1/`, `site2/` - -2. **Separate databases**: Each site gets its own MySQL database automatically - -3. **Separate database passwords**: Use different passwords in vault for each site - -4. **Same server, same Trellis**: All sites on the same server share one Trellis configuration - -5. **One Git repository**: Keep all sites and Trellis in the same repository using `repo_subtree_path` - -6. **Consider resource limits**: Monitor server resources (RAM, CPU) as you add more sites - -7. **SSL certificates**: Let's Encrypt handles multiple domains automatically - -### Common Commands for Multiple Sites - -```bash -# Deploy specific site -trellis deploy production example.com - -# Deploy all sites -trellis deploy production - -# Re-provision to update all sites -trellis provision production - -# SSH and access specific site -ssh admin_user@your.server.ip.address -cd /srv/www/example.com/current - -# WP-CLI for specific site -wp --path=/srv/www/example.com/current/web plugin list -wp --path=/srv/www/jasperfrumau.com/current/web plugin list -``` - -### When NOT to Use Multiple Sites on One Server - -Consider separate servers if: -- Sites have vastly different traffic patterns -- Different PHP version requirements -- Regulatory/security isolation requirements -- One site is mission-critical and needs dedicated resources - -## Common Pitfalls When Migrating Multiple Sites - -Avoid these common mistakes when migrating multiple WordPress sites to a single Trellis server. - -### 1. Forgetting to Update `local_path` for Each Site - -**Problem:** All sites point to `../site` instead of unique paths like `../site-example`, `../site-clienttwo`. - -**Symptom:** Deployments fail or deploy the wrong site's code. - -**Solution:** Always verify unique paths in `wordpress_sites.yml`: - -```yaml -wordpress_sites: - example.com: - local_path: ../site-example # ✅ Unique path - # ... - - clienttwo.com: - local_path: ../site-clienttwo # ✅ Unique path - # ... -``` - -**How to check:** -```bash -# From trellis directory -grep -A 5 "local_path" group_vars/production/wordpress_sites.yml -``` - -### 2. Reusing Database Passwords Across Sites - -**Problem:** Copy-pasting vault configuration without changing passwords for each site. - -**Security Risk:** If one site is compromised, all sites are at risk. - -**Solution:** Generate unique passwords for each site: - -```bash -# Generate secure password for each site -openssl rand -base64 32 - -# Edit vault and paste unique password for each site -trellis vault edit production -``` - -**Vault structure should look like:** -```yaml -vault_wordpress_sites: - example.com: - env: - db_password: "unique_password_1_here" # Different! - # ... - - clienttwo.com: - env: - db_password: "unique_password_2_here" # Different! - # ... -``` - -### 3. Not Testing Path Conversions Thoroughly - -**Problem:** Assuming search-replace worked without verification. - -**Symptom:** Some images or assets still have old paths, causing 404 errors. - -**Solution:** Always verify after running search-replace: - -```bash -# SSH into server -cd /srv/www/example.com/current - -# Check for any remaining wp-content references -wp db search 'wp-content/uploads' --all-tables -wp db search 'wp-content/themes' --all-tables -wp db search 'wp-content/plugins' --all-tables - -# Should return no results if conversion was successful -``` - -**If you find remaining references:** -```bash -# Run additional search-replace for specific cases -wp search-replace '//example.com/wp-content/' '//example.com/app/' --all-tables --precise -``` - -### 4. Skipping DNS Propagation Time - -**Problem:** Going live immediately after DNS change, causing confusion when some users see old site and others see new site. - -**Impact:** Mixed analytics, confused users, potential lost transactions. - -**Solution:** - -```bash -# 24-48 hours BEFORE migration: -# Lower TTL on DNS records (via your DNS provider) -# Change from 3600 (1 hour) to 300 (5 minutes) - -# After DNS update: -# Check DNS propagation -dig example.com +short - -# Check from multiple global locations -# Use: https://www.whatsmydns.net/ - -# Keep old server running for 24-48 hours as fallback -``` - -### 5. Incorrect File Permissions on Uploads - -**Problem:** Uploads directory has wrong owner or permissions after transfer. - -**Symptom:** Can't upload new media, or existing images don't display. - -**Solution:** Always set correct permissions after file transfer: - -```bash -# After rsync/scp of uploads -ssh admin@server - -# Set ownership (web:www-data is the Trellis default) -sudo chown -R web:www-data /srv/www/example.com/shared/uploads - -# Set permissions (775 allows web server to write) -sudo chmod -R 775 /srv/www/example.com/shared/uploads - -# Verify -ls -la /srv/www/example.com/shared/uploads -``` - -### 6. Not Updating All Environment Files - -**Problem:** Updating `production/wordpress_sites.yml` but forgetting `development/wordpress_sites.yml`. - -**Symptom:** Local development breaks or uses wrong configuration. - -**Solution:** Always update both environments: - -```bash -# Update both files when adding a new site -trellis/group_vars/development/wordpress_sites.yml -trellis/group_vars/production/wordpress_sites.yml - -# And both vault files -trellis vault edit development -trellis vault edit production -``` - -### 7. Mixing Up `repo_subtree_path` Values - -**Problem:** Multiple sites pointing to same subtree path in Git repo. - -**Symptom:** Deployment pulls wrong code for a site. - -**Solution:** Ensure each site has unique `repo_subtree_path`: - -```yaml -wordpress_sites: - example.com: - repo: git@github.com:user/trellis-multi.git - repo_subtree_path: site-example # ✅ Unique - - clienttwo.com: - repo: git@github.com:user/trellis-multi.git - repo_subtree_path: site-clienttwo # ✅ Unique -``` - -### 8. Forgetting to Re-Provision After Adding New Site - -**Problem:** Adding second or third site to config but not re-provisioning server before deployment. - -**Symptom:** -- Deployment fails with database connection errors -- Site shows 502 Bad Gateway (no Nginx config) -- SSL certificate missing or invalid -- Directory structure `/srv/www/newsitedomain.com/` doesn't exist - -**Why this happens:** When you add a new site to `wordpress_sites.yml`, Trellis doesn't automatically create the infrastructure. You must re-provision to: -- Create MySQL database for the new site -- Generate Nginx virtual host configuration -- Request and install Let's Encrypt SSL certificate -- Create base directory structure - -**Solution:** Always re-provision after adding sites to configuration: - -```bash -cd trellis - -# STEP 1: Add new site to wordpress_sites.yml -# STEP 2: Re-provision to create all infrastructure -trellis provision production - -# STEP 3: Now you can deploy the new site -trellis deploy production example.com - -# Alternative: Just update Nginx if that's all that changed -# (Use this only if you know the database and other components exist) -ansible-playbook server.yml -e env=production --tags nginx -``` - -**Best Practice for Multiple Sites:** -Configure all three sites in `wordpress_sites.yml` BEFORE the first provision. This way you provision once and create infrastructure for all sites simultaneously. - -### 9. Using Same WordPress Salts Across Sites - -**Problem:** Copy-pasting salts from first site to second and third sites. - -**Security Risk:** Reduces security isolation between sites. - -**Solution:** Generate unique salts for each site: - -```bash -# Visit https://roots.io/salts.html three times -# Save each set of salts separately -# Paste unique salts into vault for each site - -trellis vault edit production -``` - -### 10. Not Testing Locally First (When Using Workflow B) - -**Problem:** Pushing directly to production without local testing. - -**Risk:** Database issues, path problems, or plugin conflicts discovered only in production. - -**Solution:** Always test in local development first: - -```bash -# Start local VM -trellis vm start - -# Import database locally -cd ~/code/trellis-project/site-example -wp db import ~/migrations/site1/database/backup.sql - -# Test at https://example.test -# Fix any issues locally before pushing to production -``` - -### 11. Incorrect Branch Names in Configuration - -**Problem:** Configuration uses `branch: main` but Git repo uses `master` (or vice versa). - -**Symptom:** Deployment fails with "branch not found" error. - -**Solution:** Verify branch name matches your Git repository: - -```bash -# Check what branch your repo uses -cd ~/code/trellis-project -git branch - -# Update wordpress_sites.yml to match -wordpress_sites: - example.com: - branch: main # or 'master' - must match your repo! -``` - -### 12. Overwriting Production Database Accidentally - -**Problem:** Running database-push playbook and forgetting it will overwrite production. - -**Risk:** Loss of production data (orders, users, posts created since migration). - -**Solution:** Always use the backup features: - -```bash -# The database-push playbook includes automatic backup -# But verify backup exists before running: - -# Manual backup before push -ssh admin@server "cd /srv/www/example.com/current && wp db export /tmp/pre-push-backup.sql" - -# Then run push -ansible-playbook database-push.yml -e site=example.com -e env=production - -# Playbook will create backup automatically in site/database_backup/ -``` - -### Prevention Checklist - -Before migrating sites 2 and 3, verify these for each site: - -- [ ] Unique `local_path` in `wordpress_sites.yml` -- [ ] Unique database password in vault -- [ ] Unique WordPress salts in vault -- [ ] Unique `repo_subtree_path` (if using same Git repo) -- [ ] Correct branch name (`main` vs `master`) -- [ ] Both development and production configs updated -- [ ] File permissions set correctly after upload -- [ ] Path conversions verified with `wp db search` -- [ ] DNS TTL lowered 24 hours before switching -- [ ] Local testing completed (if using Workflow B) - -## Multi-Site Troubleshooting - -### Issue: Wrong Site Code Deployed - -**Symptom:** After deployment, site shows content or theme from a different site. - -**Cause:** Usually due to incorrect `local_path` or `repo_subtree_path` configuration. - -**Solution:** - -```bash -# Verify configuration -cd trellis -grep -A 10 "example.com:" group_vars/production/wordpress_sites.yml - -# Check that: -# 1. local_path points to correct Bedrock directory -# 2. repo_subtree_path matches the directory name in Git - -# If incorrect, fix the configuration and redeploy -trellis deploy production example.com -``` - -### Issue: Database Connection Error on One Site Only - -**Symptom:** One site works, but newly added site shows database connection error. - -**Cause:** Usually means re-provision wasn't run, so database doesn't exist. - -**Solution:** - -```bash -# Check if database exists -ssh admin@server -mysql -u root -p -e "SHOW DATABASES;" - -# If database is missing, re-provision -cd trellis -trellis provision production - -# This will create the missing database -``` - -### Issue: SSL Certificate Not Created for New Site - -**Symptom:** HTTPS doesn't work for newly added site, or shows certificate for wrong domain. - -**Cause:** Re-provision wasn't run, or DNS doesn't point to server yet. - -**Solution:** - -```bash -# Ensure DNS points to your server -dig newsitedomain.com +short - -# Re-provision to request SSL certificate -cd trellis -trellis provision production - -# Or just update SSL certificates -trellis provision production --tags letsencrypt - -# Verify certificate was created -ssh admin@server -sudo certbot certificates -``` - -### Issue: Site Shows 502 Bad Gateway - -**Symptom:** New site shows "502 Bad Gateway" error. - -**Cause:** Nginx configuration doesn't exist for this site. - -**Solution:** - -```bash -# Check if Nginx config exists -ssh admin@server -ls -la /etc/nginx/sites-available/ | grep newsitedomain - -# If missing, re-provision -cd trellis -trellis provision production - -# If config exists but not enabled, check symlink -ls -la /etc/nginx/sites-enabled/ | grep newsitedomain - -# Reload Nginx -sudo systemctl reload nginx -``` - -### Issue: Confusion About Which Database Belongs to Which Site - -**Symptom:** Unsure which database to import data into for multi-site setup. - -**Solution:** - -Each site gets its own database. The naming convention is: - -``` -{site_key}_{environment} -``` - -For example: -```yaml -wordpress_sites: - example.com: # site_key is example.com - # Database will be: example_com_production - - client-two.com: # site_key is client-two.com - # Database will be: client_two_com_production -``` - -**List all databases:** -```bash -ssh admin@server -mysql -u root -p -e "SHOW DATABASES;" -``` - -**Check which database a site uses:** -```bash -ssh admin@server -cd /srv/www/example.com/current -wp db query "SELECT DATABASE();" -``` - -## Additional Resources - -- [Core Migration Guide](REGULAR-TO-TRELLIS.md) - Single-site migration process -- [Trellis Documentation](https://roots.io/trellis/docs/) -- [Bedrock Documentation](https://roots.io/bedrock/docs/) -- [Roots Discourse Community](https://discourse.roots.io/) - -## Need More Help? - -- Review the [core migration guide](REGULAR-TO-TRELLIS.md) for detailed migration steps -- Check the main [Migration README](README.md) for other scenarios -- See [Backup Tools](../../trellis/backup/README.md) for data management -- Visit [Provisioning Guide](../../trellis/provision/README.md) for server setup help diff --git a/wp-cli/migration/README.md b/wp-cli/migration/README.md deleted file mode 100644 index 7a18a80..0000000 --- a/wp-cli/migration/README.md +++ /dev/null @@ -1,159 +0,0 @@ -# WordPress Migration Guide - -This guide documents various commands and techniques for migrating WordPress sites, particularly when using Roots Trellis and Bedrock stacks. These commands are especially useful when: - -1. Migrating from local development to production environments -2. Setting up and fixing multisite installations -3. Converting regular WordPress image URLs to Bedrock-compatible paths -4. Migrating from traditional WordPress hosting to Trellis/Bedrock - -## Migration Scenarios - -This directory contains guides for different migration scenarios: - -### Single-Site Migration -- **[Regular WordPress to Trellis/Bedrock Migration](REGULAR-TO-TRELLIS.md)** - Complete step-by-step guide for migrating a single WordPress site from traditional hosting (shared hosting, Plesk, cPanel) to Trellis with Bedrock. Includes modern Trellis CLI workflow, `/etc/hosts` testing before DNS cutover, database migration, uploads transfer, and strategies for handling Bedrock path changes while maintaining compatibility with non-Sage themes. - -### Multi-Site Migration -- **[Multi-Site Migration Guide](MULTI-SITE-MIGRATION.md)** - Strategies and best practices for migrating **multiple WordPress sites** to a single Trellis server. Covers time-saving tips, batch operations, parallel processing, managing multiple Bedrock installations, and common pitfalls to avoid when consolidating sites. - -### Quick Reference -- **Current Document** - Commands and techniques for domain migrations and path conversions - -## Domain Migration Commands - -When moving a site between environments (e.g., from local to production), you need to update all URLs in the database: - -### Basic Domain Migration - -```bash -# Preview changes with --dry-run -wp search-replace 'http://example.test' 'https://example.com' --dry-run - -# Apply the changes -wp search-replace 'http://example.test' 'https://example.com' - -# Replace domain without protocol (for places where only the domain is stored) -wp search-replace 'example.test' 'example.com' -``` - -### Multisite Domain Migration - -For WordPress multisite installations, use these flags for more precise control: - -```bash -# Update URLs for a specific site in a multisite network -wp search-replace 'http://subsite.example.test' 'https://subsite.example.com' --all-tables --url=subsite.example.test - -# Update across the entire network -wp search-replace 'http://subsite.example.test' 'https://subsite.example.com' --all-tables --network --url=subsite.example.test -``` - -### Practical Example: HTTPS Migration Across Multiple Subsites - -When running search-replace on a multisite network, WP-CLI will process **all subsites** that contain the matching string. Here's a real-world example showing the importance of using `--dry-run` first: - -```bash -# ALWAYS run dry-run first to preview changes -wp search-replace 'http://example.com/app/themes' 'https://example.com/app/themes' \ - --all-tables \ - --precise \ - --url=https://example.com/spa \ - --path=web/wp \ - --dry-run \ - --report-changed-only - -# If dry-run looks correct, execute the actual replacement -wp search-replace 'http://example.com/app/themes' 'https://example.com/app/themes' \ - --all-tables \ - --precise \ - --url=https://example.com/spa \ - --path=web/wp \ - --report-changed-only -``` - -**Expected output:** -``` -+-------------+--------------+--------------+------+ -| Table | Column | Replacements | Type | -+-------------+--------------+--------------+------+ -| wp_10_posts | post_content | 8 | PHP | -| wp_2_posts | post_content | 10 | PHP | -| wp_5_posts | post_content | 13 | PHP | -| wp_6_posts | post_content | 10 | PHP | -| wp_8_posts | post_content | 11 | PHP | -| wp_9_posts | post_content | 4 | PHP | -| wp_posts | post_content | 25 | PHP | -+-------------+--------------+--------------+------+ -Success: Made 81 replacements. -``` - -**Key observations:** -- Even with `--url=https://example.com/spa`, WP-CLI found matches across **all subsites** because the search string existed in their content -- The `--report-changed-only` flag shows exactly which tables were affected -- Main site (`wp_posts`) had 25 replacements, subsites had varying counts (wp_2_posts, wp_5_posts, etc.) -- **Total: 81 replacements** across 7 sites - -> **Best practice:** Use `--dry-run` first, then verify with `--dry-run` again after execution to confirm 0 remaining matches. - -## Bedrock Path Conversion - -When migrating from a standard WordPress installation to a Bedrock-based installation, you'll need to update file paths in your database: - -### Theme Path Migration - -```bash -# Convert theme paths from standard WordPress to Bedrock structure -wp search-replace '/wp-content/themes/' '/app/themes/' --all-tables --url=example.com - -# If you need to target a specific theme -wp search-replace '/wp-content/themes/specific-theme' '/app/themes/specific-theme' --all-tables --url=example.com -``` - -### Upload Path Migration - -```bash -# Preview upload path changes -wp search-replace 'https://example.com/wp-content/uploads/' 'https://example.com/app/uploads/' --all-tables --precise --report-changed-only --dry-run - -# Apply upload path changes -wp search-replace 'https://example.com/wp-content/uploads/' 'https://example.com/app/uploads/' --all-tables --precise --report-changed-only -``` - -## Command Options Explained - -- `--dry-run`: Preview changes without modifying the database -- `--all-tables`: Search through all tables in the database, not just WordPress core tables -- `--network`: Apply changes across all sites in a multisite installation -- `--url=example.com`: Specify which site in a multisite installation to operate on -- `--precise`: Perform a slower but more thorough search, useful for encoded data -- `--report-changed-only`: Only show tables where changes were made (reduces output noise) - -## Best Practices - -1. **Always backup your database** before running search-replace operations -2. Always test with `--dry-run` first to preview changes -3. For multisite installations, run commands for each subsite individually -4. After migration, flush caches and permalinks with: - ```bash - wp cache flush - wp rewrite flush - ``` -5. Test the site thoroughly after migration, especially forms and dynamic content - -## Common Migration Workflow - -1. Migrate the database from source to destination environment -2. Run appropriate domain search-replace commands -3. Update path structures if moving between different WordPress setups -4. Flush caches and permalinks -5. Test site functionality - -## Troubleshooting - -If you encounter issues after migration: - -1. Check for hardcoded URLs in theme files and plugins -2. Look for serialized data issues (the `--precise` flag helps with this) -3. Inspect browser console for missing assets or 404 errors -4. Verify that all database tables were included in the search-replace operations \ No newline at end of file diff --git a/wp-cli/migration/REGULAR-TO-TRELLIS.md b/wp-cli/migration/REGULAR-TO-TRELLIS.md deleted file mode 100644 index 411b668..0000000 --- a/wp-cli/migration/REGULAR-TO-TRELLIS.md +++ /dev/null @@ -1,1666 +0,0 @@ -# Migrating from Regular WordPress to Trellis with Bedrock - -This guide covers the complete process of migrating a **single WordPress site** from standard hosting (shared hosting, Plesk, cPanel, etc.) to a [Roots Trellis](https://roots.io/trellis/) server running [Bedrock](https://roots.io/bedrock/). This is particularly useful when you need to modernize your WordPress infrastructure while maintaining a non-Sage theme. - -> **Migrating multiple sites?** See the [Multi-Site Migration Guide](MULTI-SITE-MIGRATION.md) for strategies on migrating 2+ sites to a single Trellis server, including time-saving tips and batch operations. - -## Table of Contents - -- [Overview](#overview) -- [Prerequisites](#prerequisites) -- [Migration Approaches](#migration-approaches) -- [Choosing Your Migration Workflow](#choosing-your-migration-workflow) -- [Pre-Migration Checklist](#pre-migration-checklist) -- [Quick Migration Checklist (Per Site)](#quick-migration-checklist-per-site) -- [Step-by-Step Migration Process](#step-by-step-migration-process) - - [Migration Workflow Overview](#migration-workflow-overview) - - [1. Set Up Trellis and Bedrock Locally](#1-set-up-trellis-and-bedrock-locally) - - [2. Provision Your Server](#2-provision-your-server) - - [3. Prepare Your Existing WordPress Site](#3-prepare-your-existing-wordpress-site) - - [4. Transfer Theme and Plugins to Local Bedrock](#4-transfer-theme-and-plugins-to-local-bedrock) - - [5. Deploy Bedrock to Server](#5-deploy-bedrock-to-server) - - [6. Migrate the Database](#6-migrate-the-database) - - [7. Migrate Uploads](#7-migrate-uploads) - - [Alternative: Using Automated Backup Playbooks](#alternative-using-automated-backup-playbooks-workflow-b) - - [8. Choose Your Path Migration Strategy](#8-choose-your-path-migration-strategy) - - [9. Test and Verify](#9-test-and-verify) - - [10. Test with /etc/hosts Before DNS Cutover](#10-test-with-etchosts-before-dns-cutover) - - [WordPress Cron: System Cron vs WP-Cron](#wordpress-cron-system-cron-vs-wp-cron) - - [11. DNS and Go-Live](#11-dns-and-go-live) -- [Troubleshooting](#troubleshooting) -- [Post-Migration Optimization](#post-migration-optimization) - -## Overview - -Bedrock restructures WordPress directories from the traditional layout to a more modern, secure structure: - -**Traditional WordPress:** -``` -/ -├── wp-admin/ -├── wp-content/ -│ ├── themes/ -│ ├── plugins/ -│ └── uploads/ -├── wp-includes/ -└── wp-config.php -``` - -**Bedrock Structure:** -``` -/ -├── web/ -│ ├── app/ -│ │ ├── themes/ -│ │ ├── plugins/ -│ │ ├── uploads/ -│ │ └── mu-plugins/ -│ ├── wp/ # WordPress core (subdirectory) -│ └── wp-config.php -├── config/ -│ └── application.php -└── composer.json -``` - -## Prerequisites - -- SSH access to your destination server (or a fresh server to provision) -- Root or sudo access for Trellis provisioning -- **Trellis CLI** installed (see installation below) -- Ansible installed locally (Trellis CLI will prompt if needed) -- WP-CLI installed on destination server (Trellis installs this automatically) -- Database backup of your existing site -- Download of your existing site's files (themes, plugins, uploads) -- Git repository for your project (GitHub, GitLab, Bitbucket, etc.) - -## Migration Approaches - -You have two main approaches for handling file paths: - -### Approach A: Full Bedrock Adoption (Recommended) -Convert all database paths to Bedrock structure (`/app/uploads/`, `/app/themes/`). This is the cleanest approach and fully embraces Bedrock conventions. - -**Pros:** -- Full compatibility with Bedrock ecosystem -- Cleaner, more maintainable structure -- Better for long-term maintenance - -**Cons:** -- Requires database search-replace operations -- More steps in initial migration - -### Approach B: Path Compatibility Mode -Keep using `/wp-content/uploads/` paths in the database by modifying Bedrock's configuration. - -**Pros:** -- Minimal database changes -- Faster initial migration -- Useful if you need to maintain compatibility with legacy systems - -**Cons:** -- Goes against Bedrock conventions -- May cause confusion for other developers -- Could complicate future updates - -## Choosing Your Migration Workflow - -You have two primary workflows for migrating your site(s), depending on whether you want to test locally first or migrate directly to production. - -### Workflow A: Direct Server-to-Server Migration -**Best for:** Sites currently on shared hosting without local dev environment, or when you need to go live quickly. - -**Process:** -1. Set up Trellis and Bedrock locally (Steps 1-2) -2. Deploy empty Bedrock to server (Step 5) -3. **Manually** transfer database and files from old hosting to new server (Steps 6-7) -4. Apply path conversions (Step 8) -5. Test and go live (Steps 9-10) - -**Time per site:** 3-4 hours (first site), 2-3 hours (additional sites) - -**Pros:** -- Fewer steps overall -- No need to set up local development environment -- Direct migration from old to new hosting - -**Cons:** -- Less opportunity to test before going live -- Manual file transfers can be error-prone -- Harder to repeat if something goes wrong - -### Workflow B: Local-First Migration (Recommended) -**Best for:** When you want to test locally before going live, or when managing multiple sites. - -**Process:** -1. Set up Trellis and Bedrock locally (Steps 1-2) -2. Start local development environment (`trellis vm start`) -3. Import database and files to local environment -4. Test everything locally at `https://example.test` -5. Provision production server (Step 2) -6. **Use automated backup playbooks** to push from local to production -7. Test production and go live - -**Time per site:** 4-5 hours (first site), 2.5-3.5 hours (additional sites) - -**Pros:** -- Test thoroughly before going live -- Repeatable, automated process using playbooks -- Safer - production remains untouched until ready -- Easy to iterate if issues are found - -**Cons:** -- Requires local development setup -- Additional step to transfer data twice (old → local → production) -- Requires Vagrant/VirtualBox for local VM - -**Recommended for:** Three-site migration projects where consistency and testing are important. - -## Pre-Migration Checklist - -Before starting the migration: - -- [ ] **Backup everything** from your current site - - Database export (`.sql` or `.sql.gz`) - - Complete file backup (themes, plugins, uploads) - - Copy of `wp-config.php` for reference -- [ ] Document all active plugins and their versions -- [ ] Note any custom configurations or constants in `wp-config.php` -- [ ] Identify any hardcoded URLs in theme files -- [ ] Check for any symlinks or special file permissions -- [ ] Verify PHP version compatibility (source vs. destination) -- [ ] Test your site backup locally if possible - -## Quick Migration Checklist (Per Site) - -Use this condensed checklist to track progress for each site during migration. - -### Pre-Migration (15-30 mins) -- [ ] Download database backup (`.sql` or `.sql.gz`) -- [ ] Download files (themes, plugins, uploads) -- [ ] Document active plugins and versions -- [ ] Generate WordPress salts (https://roots.io/salts.html) -- [ ] Create Git repository on GitHub/GitLab -- [ ] Note any custom `wp-config.php` settings - -### Trellis Setup (First Site: 60 mins, Additional: 15 mins) -- [ ] Create Bedrock installation with descriptive name (`site-example`) -- [ ] Configure `wordpress_sites.yml` for development and production -- [ ] Edit vault files with database credentials and salts -- [ ] Update `hosts/production` with server IP -- [ ] Provision server (first site only - run once for all sites) -- [ ] Commit Trellis configuration to Git - -### Site Preparation (30 mins) -- [ ] Copy theme to `site/web/app/themes/` -- [ ] Copy plugins to `site/web/app/plugins/` -- [ ] Add plugins to `composer.json` where possible -- [ ] Run `composer install` -- [ ] Commit and push to Git repository - -### Deployment (15 mins) -- [ ] Deploy to production: `trellis deploy production` -- [ ] Verify deployment created correct directory structure -- [ ] Check symlinks are correct - -### Data Migration (45-60 mins) - -**Option A: Manual Migration (Workflow A)** -- [ ] Import database via WP-CLI or MySQL -- [ ] Update domain URLs with search-replace -- [ ] rsync/scp uploads directory -- [ ] Set correct permissions on uploads -- [ ] Run path conversion search-replace commands - -**Option B: Automated with Playbooks (Workflow B - Recommended)** -- [ ] Import database and uploads to local development -- [ ] Test locally at `https://example.test` -- [ ] Run `ansible-playbook database-push.yml` -- [ ] Run `ansible-playbook files-push.yml` -- [ ] Verify on production - -### Path Conversion (15 mins) -- [ ] Run search-replace for `/wp-content/themes/` → `/app/themes/` -- [ ] Run search-replace for `/wp-content/uploads/` → `/app/uploads/` -- [ ] Run search-replace for `/wp-content/plugins/` → `/app/plugins/` -- [ ] Verify no remaining `wp-content` references -- [ ] Flush cache and permalinks - -### Testing (30 mins) -- [ ] Verify homepage loads correctly -- [ ] Check all images display properly -- [ ] Test navigation menus -- [ ] Verify forms work -- [ ] Test admin panel access -- [ ] Check plugin functionality -- [ ] Test media upload -- [ ] Check browser console for errors - -### Pre-DNS Testing with /etc/hosts (15 mins) -- [ ] Add server IP to local `/etc/hosts` file -- [ ] Flush local DNS cache -- [ ] Test site with production domain (via /etc/hosts) -- [ ] Verify all functionality works with real domain -- [ ] Fix any issues found during testing -- [ ] Re-enable SSL with `provider: letsencrypt` in wordpress_sites.yml -- [ ] Commit configuration changes -- [ ] Remove `/etc/hosts` entry when ready for DNS cutover - -### Go-Live (20 mins) -- [ ] Lower DNS TTL 24 hours before migration -- [ ] Update DNS A record to new server IP -- [ ] Monitor DNS propagation (`dig example.com +short`) -- [ ] Wait for DNS to propagate (5-30 minutes typically) -- [ ] Run `trellis provision production --tags letsencrypt` -- [ ] Verify SSL certificate is valid (`sudo certbot certificates`) -- [ ] Test HTTPS in browser (no warnings) -- [ ] Test site from multiple locations -- [ ] Keep old server running 24-48 hours - -### Post-Migration (15 mins) -- [ ] Set up automated backups -- [ ] Enable Redis caching -- [ ] Configure monitoring -- [ ] Document any issues encountered -- [ ] Update team documentation - -**Total Time Estimates:** -- **First site:** 4-6 hours (includes learning curve and server setup) -- **Second site:** 2.5-3.5 hours (server already provisioned) -- **Third site:** 2-3 hours (process is familiar) - -**For three sites: 8-12 hours total** - -## Step-by-Step Migration Process - -### Migration Workflow Overview - -The migration process follows this sequence: - -1. **Local Setup**: Set up Trellis and Bedrock locally -2. **Configure Environments**: Configure your server settings and site configuration -3. **Provision Server**: Provision your production/staging server (creates directory structure, installs software) -4. **Prepare Bedrock Site**: Add your theme and plugins to local Bedrock site -5. **Initial Deployment**: Deploy Bedrock to server (creates `/srv/www/example.com/` structure) -6. **Migrate Database**: Import and transform database on server -7. **Migrate Uploads**: Transfer uploads directory to server -8. **Path Migration**: Choose and implement path migration strategy -9. **Test & Verify**: Comprehensive testing -10. **Test with /etc/hosts**: Test site using local DNS before DNS cutover -11. **DNS & Go-Live**: Update DNS, get Let's Encrypt SSL, and go live - -### 1. Set Up Trellis and Bedrock Locally - -#### Install Trellis CLI - -First, install the Trellis CLI if you haven't already: - -```bash -# macOS (using Homebrew) -brew install roots/tap/trellis-cli - -# Linux (using installation script) -curl -sL https://roots.io/trellis/cli/get | bash - -# Verify installation -trellis --version -``` - -For other installation methods, see [Trellis CLI Installation](https://roots.io/trellis/docs/installation/). - -#### Create New Trellis Project - -The modern way to set up Trellis and Bedrock is using the Trellis CLI: - -```bash -# Navigate to your projects directory -cd ~/code - -# Create new project (this creates both Trellis and Bedrock) -trellis new example.com - -# Navigate into the project -cd example.com -``` - -This command automatically: -- Creates the project directory -- Clones Trellis -- Clones Bedrock (in the `site/` directory) -- Installs Ansible Galaxy dependencies -- Initializes a Git repository -- Sets up basic configuration - -#### Review and Configure Your Site - -Now review and configure your site settings: - -**1. Review development configuration:** - -Edit `trellis/group_vars/development/wordpress_sites.yml` - this is already pre-configured for local development with `trellis vm`. - -**2. Configure production environment:** - -**Edit `trellis/group_vars/production/wordpress_sites.yml`:** - -```yaml -wordpress_sites: - example.com: - site_hosts: - - canonical: example.com - redirects: - - www.example.com - local_path: ../site - repo: git@github.com:yourusername/example.com.git # Your Git repo URL - repo_subtree_path: site - branch: main # Or master, depending on your Git setup - multisite: - enabled: false - ssl: - enabled: true - provider: letsencrypt - cache: - enabled: true # Enable FastCGI cache and Redis -``` - -**3. Configure production vault (encrypted secrets):** - -Use Trellis CLI to edit the encrypted vault file: - -```bash -# Edit production vault file -cd trellis -trellis vault edit production - -# This opens the vault file in your default editor -# Update the WordPress salts and database password: -``` - -```yaml -vault_wordpress_sites: - example.com: - env: - db_password: "generate_secure_password_here" - # Generate salts at: https://roots.io/salts.html - auth_key: "generateme" - secure_auth_key: "generateme" - logged_in_key: "generateme" - nonce_key: "generateme" - auth_salt: "generateme" - secure_auth_salt: "generateme" - logged_in_salt: "generateme" - nonce_salt: "generateme" -``` - -**Important:** Generate WordPress salts at [https://roots.io/salts.html](https://roots.io/salts.html) - -**4. Add your production server IP:** - -Edit `trellis/hosts/production`: -```ini -[production] -your.server.ip.address - -[web] -your.server.ip.address -``` - -**5. (Optional) Test locally first:** - -Before provisioning production, you can test locally using Vagrant: - -```bash -# Start local development VM -trellis vm start - -# This provisions a local VM and deploys your site -# Access at: https://example.test -``` - -**6. Create Git repository and push:** - -```bash -# From project root (example.com/) -cd ~/code/example.com - -# Add all files (Git repo already initialized by trellis new) -git add . - -# Initial commit -git commit -m "Initial Trellis and Bedrock setup" - -# Create repository on GitHub/GitLab, then add remote -git remote add origin git@github.com:yourusername/example.com.git - -# Push to remote -git push -u origin main -``` - -### 2. Provision Your Server - -**IMPORTANT**: You must provision your server before deploying. This step installs all necessary software (Nginx, PHP, MariaDB, etc.) and creates the directory structure. - -**Prerequisites for provisioning:** -- Fresh Ubuntu 22.04 or 24.04 server -- Root or sudo user access -- SSH key-based authentication set up - -```bash -# From the trellis directory -cd ~/code/example.com/trellis - -# Provision production server (this will take 10-15 minutes) -trellis provision production - -# Alternative: Use ansible-playbook directly -# ansible-playbook server.yml -e env=production -``` - -This command will: -- Install and configure Nginx -- Install PHP and required extensions -- Install and configure MariaDB (MySQL) -- Create the directory structure at `/srv/www/example.com/` -- Set up SSL certificates with Let's Encrypt -- Configure Redis (if enabled) -- Set up proper user permissions - -**Troubleshooting Provisioning:** - -If provisioning fails, check: -```bash -# Verify SSH access to server (default user is usually 'root' or 'admin') -ssh root@your.server.ip.address - -# Or if using a different user -ssh admin_user@your.server.ip.address - -# Check Ansible can connect (from trellis directory) -cd ~/code/example.com/trellis -ansible production -m ping - -# Verify server meets requirements (Ubuntu 22.04 or 24.04) -ssh root@your.server.ip.address "lsb_release -a" - -# Check Ansible version (should be 2.10+) -ansible --version -``` - -For detailed provisioning commands and troubleshooting, see the [Provisioning Guide](../../trellis/provision/README.md). - -### 3. Prepare Your Existing WordPress Site - -On your current hosting: - -```bash -# Export the database -wp db export backup.sql --add-drop-table - -# Or if WP-CLI is not available, use phpMyAdmin or command line: -mysqldump -u username -p database_name > backup.sql - -# Create a compressed archive of your files -tar -czf site-backup.tar.gz wp-content/ - -# Or download specific directories: -# themes, plugins, and uploads -``` - -### 4. Transfer Theme and Plugins to Local Bedrock - -Copy your theme(s) and plugins to your **local** Bedrock directory structure: - -```bash -# In your local Bedrock directory (site/) - -# Copy theme (from your backup) -cp -r /path/to/backup/wp-content/themes/your-theme web/app/themes/ - -# Copy plugins (from your backup) -cp -r /path/to/backup/wp-content/plugins/* web/app/plugins/ - -# Note: Try to install plugins via Composer when possible -# Example: composer require wpackagist-plugin/plugin-name -``` - -**Update `site/composer.json`** to include plugins available via Composer: - -```json -{ - "require": { - "php": ">=8.0", - "roots/bedrock": "^1.21", - "wpackagist-plugin/wordpress-seo": "^22.0", - "wpackagist-plugin/wordfence": "^7.11" - } -} -``` - -Run `composer install` to install plugins via Composer. - -**Commit your changes to Git:** - -```bash -# In your project root (not trellis directory) -cd /path/to/example.com - -# Initialize git if not already done -git init - -# Add site directory -git add site/ - -# Commit -git commit -m "Initial Bedrock setup with theme and plugins" - -# Add remote (create repo on GitHub/GitLab first) -git remote add origin git@github.com:yourusername/example.com.git - -# Push to remote -git push -u origin main -``` - -### 5. Deploy Bedrock to Server - -Now deploy your Bedrock site to the provisioned server. This creates the directory structure and symlinks. - -**Important for Multiple Sites:** If you're adding a second or third site to an already-provisioned server, you must **re-provision first** to create the new site's infrastructure (database, Nginx configuration, SSL certificate, and directory structure): - -```bash -# From trellis directory -cd trellis - -# FIRST: Re-provision if adding a new site to existing server -# This creates database, Nginx config, SSL cert for the new site -trellis provision production - -# THEN: Deploy the site -trellis deploy production -``` - -**For the first site only** (server not yet provisioned), you can skip directly to deploy since you already provisioned in Step 2. - -**What deployment does:** - -This will: -- Clone your Git repository to `/srv/www/example.com/releases/TIMESTAMP/` -- Run `composer install` to install WordPress core and plugins -- Create symlinks: - - `/srv/www/example.com/current` → latest release - - `/srv/www/example.com/current/web/app/uploads` → `/srv/www/example.com/shared/uploads` -- Create `.env` file with database credentials -- Set proper permissions - -**Verify deployment:** - -```bash -# SSH into server -ssh admin_user@your.server.ip.address - -# Check directory structure was created -ls -la /srv/www/example.com/ -# Should show: current, releases, shared - -# Check current symlink -ls -la /srv/www/example.com/current -# Should point to latest release - -# Check uploads symlink -ls -la /srv/www/example.com/current/web/app/ -# Should show: uploads -> ../../../shared/uploads -``` - -At this point, if you visit your domain (assuming DNS is pointed), you'll see the WordPress installation screen. **Don't run it yet** - we need to import your database first. - -### 6. Migrate the Database - -#### Option A: Using WP-CLI (Recommended) - -On your source site, export the database: - -```bash -# On source server or via SSH -wp db export source-backup.sql --add-drop-table -``` - -Import to your Trellis/Bedrock environment: - -```bash -# SSH into your Trellis server -cd /srv/www/example.com/current - -# Import the database -wp db import /path/to/source-backup.sql - -# Update the site URL if domain is changing -wp search-replace 'http://old-domain.com' 'https://example.com' --dry-run -wp search-replace 'http://old-domain.com' 'https://example.com' - -# Also replace without protocol -wp search-replace 'old-domain.com' 'example.com' -``` - -#### Option B: Manual Import - -```bash -# Copy database dump to server -scp backup.sql admin_user@your.server.ip.address:/tmp/ - -# SSH into server -ssh admin_user@your.server.ip.address - -# Import database (get credentials from .env file) -cd /srv/www/example.com/current -cat .env | grep DB_ - -# Import -mysql -u db_user -p database_name < /tmp/backup.sql - -# Clean up -rm /tmp/backup.sql -``` - -### 7. Migrate Uploads - -Transfer your uploads directory to the server's **shared** uploads directory. You have several options: - -#### Option A: Using rsync (Recommended) - -Best for large uploads directories - resumable and preserves permissions: - -```bash -# From your local machine -rsync -avz --progress /path/to/backup/wp-content/uploads/ \ - admin_user@your.server.ip.address:/srv/www/example.com/shared/uploads/ - -# Set correct permissions on server -ssh admin_user@your.server.ip.address \ - "sudo chown -R web:www-data /srv/www/example.com/shared/uploads && \ - sudo chmod -R 775 /srv/www/example.com/shared/uploads" -``` - -#### Option B: Using SCP - -For smaller uploads directories: - -```bash -# From your local machine -scp -r /path/to/backup/wp-content/uploads/* \ - admin_user@your.server.ip.address:/tmp/uploads/ - -# SSH into server and move to correct location -ssh admin_user@your.server.ip.address - -# Move uploads and set permissions -sudo mv /tmp/uploads/* /srv/www/example.com/shared/uploads/ -sudo chown -R web:www-data /srv/www/example.com/shared/uploads -sudo chmod -R 775 /srv/www/example.com/shared/uploads -``` - -#### Option C: Using Trellis Backup Tools - -If you want to use this repository's backup tools for ongoing sync: - -```bash -# First, manually copy uploads using rsync or scp (Option A or B above) -# Then set up automated sync using the backup playbooks - -# See: ../../trellis/backup/README.md for details -ansible-playbook backup/trellis/files-pull.yml -e site=example.com -e env=production -``` - -**Verify uploads are accessible:** - -```bash -# SSH into server -ssh admin_user@your.server.ip.address - -# Check uploads directory -ls -la /srv/www/example.com/shared/uploads/ - -# Verify symlink works -ls -la /srv/www/example.com/current/web/app/uploads -# Should show it's a symlink to ../../../shared/uploads - -# Test a sample file is accessible -ls -la /srv/www/example.com/shared/uploads/2024/ -``` - -### Alternative: Using Automated Backup Playbooks (Workflow B) - -If you're following **Workflow B** (Local-First Migration) and have set up your local development environment with the database and files already imported, you can use the automated backup playbooks instead of manual Steps 6-7. - -#### Prerequisites for Using Backup Playbooks - -1. Local development environment is running (`trellis vm start`) -2. Database and uploads are already in your local Bedrock installation -3. Production server is provisioned and deployed -4. Backup playbooks are available in this repository at `../../trellis/backup/` - -#### Push Database Using Playbook (Alternative to Step 6) - -```bash -# From trellis directory -cd trellis - -# Push database from development to production -ansible-playbook ../../trellis/backup/database-push.yml -e site=example.com -e env=production -``` - -**What this playbook does automatically:** -- Exports database from local development environment -- Creates backup of production database (saved to `site/database_backup/`) -- Imports development database to production -- Performs search-replace for domain URLs (old domain → new domain) -- Performs search-replace for path conversions (wp-content → app) if needed -- Cleans up temporary files -- Provides detailed progress output - -#### Push Files Using Playbook (Alternative to Step 7) - -```bash -# From trellis directory -cd trellis - -# Push uploads from development to production -ansible-playbook ../../trellis/backup/files-push.yml -e site=example.com -e env=production -``` - -**What this playbook does automatically:** -- Syncs uploads directory from local to production -- Preserves file permissions and ownership -- Shows progress during transfer -- Includes confirmation prompt before overwriting -- Handles symlinks correctly -- Sets correct permissions on destination - -#### When to Use the Backup Playbooks - -**✅ Use backup playbooks when:** -- You have local development environment running -- Files and database are already in local Bedrock structure -- You want automated, repeatable process -- Migrating multiple sites (consistency is key) -- You need to test migrations before going live -- You want built-in safety features (backups, confirmations) - -**❌ Don't use backup playbooks when:** -- Migrating directly from old server to production (use manual rsync/wp db import) -- Local development environment is not set up -- You need to customize the migration process significantly -- Source files are not yet in Bedrock structure locally - -#### Benefits of Using Backup Playbooks for Migration - -1. **Automated Path Conversion**: The database-push playbook can handle path conversions automatically -2. **Built-in Backups**: Production database is backed up before import -3. **Repeatable**: Easy to re-run if something goes wrong -4. **Consistent**: Same process for all three sites -5. **Time-Saving**: Faster than manual operations for multiple sites -6. **Error Handling**: Better error messages and rollback capabilities - -For detailed documentation on the backup playbooks, see [backup/README.md](../../trellis/backup/README.md). - -### 8. Choose Your Path Migration Strategy - -#### Strategy A: Full Bedrock Adoption (Recommended) - -Update all file paths in the database to match Bedrock structure: - -```bash -# SSH into Trellis server -cd /srv/www/example.com/current - -# Preview theme path changes -wp search-replace '/wp-content/themes/' '/app/themes/' --all-tables --dry-run - -# Apply theme path changes -wp search-replace '/wp-content/themes/' '/app/themes/' --all-tables - -# Preview uploads path changes -wp search-replace 'https://example.com/wp-content/uploads/' 'https://example.com/app/uploads/' --all-tables --precise --dry-run - -# Apply uploads path changes -wp search-replace 'https://example.com/wp-content/uploads/' 'https://example.com/app/uploads/' --all-tables --precise - -# Also handle protocol-relative and non-HTTPS URLs -wp search-replace '//example.com/wp-content/uploads/' '//example.com/app/uploads/' --all-tables --precise -wp search-replace 'http://example.com/wp-content/uploads/' 'https://example.com/app/uploads/' --all-tables --precise - -# Search for any remaining wp-content references -wp search-replace '/wp-content/plugins/' '/app/plugins/' --all-tables -``` - -**After path migration:** - -```bash -# Flush caches and permalinks -wp cache flush -wp rewrite flush - -# Regenerate thumbnails if needed -wp media regenerate --yes -``` - -#### Strategy B: Path Compatibility Mode - -Keep existing paths by modifying Bedrock configuration: - -**Edit `site/config/application.php`:** - -```php -/** - * Custom Content Directory - * Keep wp-content paths for compatibility with existing database - */ -Config::define('CONTENT_DIR', '/wp-content'); -Config::define('WP_CONTENT_DIR', $webroot_dir . Config::get('CONTENT_DIR')); -Config::define('WP_CONTENT_URL', Config::get('WP_HOME') . Config::get('CONTENT_DIR')); -``` - -**Adjust your directory structure:** - -```bash -# On Trellis server, create symlinks or move directories -cd /srv/www/example.com/current/web - -# Option 1: Rename app to wp-content (if you want actual directory) -mv app wp-content - -# Option 2: Create symlink (more flexible) -ln -s app wp-content -``` - -**Important:** If using this approach, ensure your deployment process maintains this structure. - -#### Strategy C: Hybrid Approach - -Use Bedrock structure for new uploads but keep compatibility for existing ones: - -**Edit `site/config/application.php`:** - -```php -/** - * Hybrid Content Directory - * New uploads go to /app/uploads, but old paths still work - */ -Config::define('CONTENT_DIR', '/app'); -Config::define('UPLOADS', 'uploads'); // Still uses /app/uploads for new - -// Add rewrite rules in Nginx or .htaccess to redirect old paths -``` - -**Add to Trellis Nginx configuration** (`trellis/roles/wordpress-setup/templates/wordpress-site.conf.j2`): - -```nginx -# Redirect old wp-content paths to new app paths -location ~ ^/wp-content/uploads/(.*)$ { - return 301 /app/uploads/$1; -} - -location ~ ^/wp-content/themes/(.*)$ { - return 301 /app/themes/$1; -} -``` - -**Important**: If using Strategy B or C, you'll need to re-provision or reload Nginx: - -```bash -# From trellis directory -cd trellis - -# Re-provision with nginx tag only -trellis provision --tags nginx production - -# Or just reload Nginx -ssh admin_user@your.server.ip.address "sudo systemctl reload nginx" -``` - -### 9. Test and Verify - -Comprehensive testing checklist: - -```bash -# Verify WordPress installation -wp core verify-checksums - -# Check database -wp db check - -# List active plugins -wp plugin list --status=active - -# Check theme status -wp theme list - -# Test search-replace was successful -wp db search 'wp-content/uploads' --all-tables - -# Verify upload functionality -# Upload a test image via WordPress admin -``` - -**Manual Testing:** -- [ ] Homepage loads correctly -- [ ] All images display properly -- [ ] Theme styles are applied -- [ ] Navigation menus work -- [ ] Forms submit correctly -- [ ] Admin panel is accessible -- [ ] Plugins function as expected -- [ ] Custom post types display -- [ ] Search functionality works -- [ ] User login/logout works -- [ ] Media library displays all images -- [ ] Upload new media works - -**Performance Testing:** -```bash -# Check site load time -curl -o /dev/null -s -w "Time: %{time_total}s\n" https://example.com - -# Test HTTPS -curl -I https://example.com | grep "HTTP" - -# Verify cache headers -curl -I https://example.com/app/uploads/2024/01/image.jpg | grep -i cache -``` - -### 10. Test with /etc/hosts Before DNS Cutover - -**IMPORTANT**: Before changing DNS to point to your new server, test the site by temporarily mapping the domain to your new server's IP using your local `/etc/hosts` file. This allows you to verify everything works correctly without affecting live traffic. - -#### Why Use /etc/hosts for Testing? - -- ✅ Test the site with the actual production domain (not a temporary URL) -- ✅ Verify SSL certificates work (if using self-signed for testing) -- ✅ Find and fix issues before DNS cutover -- ✅ No impact on live traffic - old site remains accessible to everyone else -- ✅ Easy to switch back and forth between old and new server for comparison - -#### Step 1: Add Entry to /etc/hosts - -On your local computer (not the server), edit `/etc/hosts`: - -```bash -# macOS/Linux -sudo nano /etc/hosts - -# Windows -# Edit C:\Windows\System32\drivers\etc\hosts as Administrator -``` - -Add this line (replace with your actual server IP and domain): -``` -123.456.789.123 example.com -123.456.789.123 www.example.com -``` - -**Save and close the file.** - -#### Step 2: Flush DNS Cache - -Clear your local DNS cache so the changes take effect: - -```bash -# macOS (Big Sur and later) -sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder - -# Linux -sudo systemd-resolve --flush-caches - -# Windows (Command Prompt as Administrator) -ipconfig /flushdns -``` - -#### Step 3: Test the Site (Without SSL Initially) - -At this point, SSL won't work yet because Let's Encrypt requires DNS to be pointed to your server. You have two options: - -**Option A: Test Without SSL (Temporary)** - -Temporarily disable SSL requirement in Trellis configuration: - -Edit `trellis/group_vars/production/wordpress_sites.yml`: -```yaml -wordpress_sites: - example.com: - site_hosts: - - canonical: example.com - ssl: - enabled: false # Temporarily disable for testing -``` - -Re-provision to update Nginx configuration: -```bash -cd trellis -trellis provision production --tags nginx -``` - -Now test in browser: -``` -http://example.com # Note: HTTP, not HTTPS -``` - -**Option B: Use Self-Signed Certificate (Better for Testing)** - -Keep SSL enabled but temporarily use a self-signed certificate: - -```bash -# SSH into server -ssh admin@your.server.ip.address - -# Create self-signed certificate for testing -sudo mkdir -p /etc/nginx/ssl/example.com -sudo openssl req -x509 -nodes -days 30 -newkey rsa:2048 \ - -keyout /etc/nginx/ssl/example.com/server.key \ - -out /etc/nginx/ssl/example.com/server.crt \ - -subj "/C=US/ST=State/L=City/O=Organization/CN=example.com" - -# Update Nginx to use self-signed cert temporarily -# Edit: /etc/nginx/sites-available/example.com.conf -# Change ssl_certificate paths to point to self-signed cert - -# Reload Nginx -sudo systemctl reload nginx -``` - -Test in browser (you'll see a certificate warning - this is expected): -``` -https://example.com # Accept the security warning -``` - -#### Step 4: Comprehensive Testing with Real Domain - -Now that you can access the site using the production domain, test thoroughly: - -- [ ] Homepage loads with correct domain in URL bar -- [ ] All images display (check absolute URLs work correctly) -- [ ] Navigation menus work -- [ ] Contact forms submit correctly -- [ ] WordPress admin accessible at `https://example.com/wp/wp-admin/` -- [ ] Media library shows all images -- [ ] Test uploading new media -- [ ] Check for any hardcoded URL issues -- [ ] Verify redirects (www to non-www or vice versa) - -**Check for mixed content issues:** -```bash -# In browser console, look for: -# - Mixed content warnings -# - 404 errors on assets -# - JavaScript errors - -# On server, check error logs -sudo tail -f /var/log/nginx/error.log -``` - -#### Step 5: Fix Any Issues Found - -If you find issues during testing: - -```bash -# Common fixes: -# 1. URL issues - run additional search-replace -ssh admin@server -cd /srv/www/example.com/current -wp search-replace 'http://example.com' 'https://example.com' --all-tables - -# 2. Path issues - verify uploads path conversion -wp db search 'wp-content/uploads' --all-tables - -# 3. Permission issues - fix uploads permissions -sudo chown -R web:www-data /srv/www/example.com/shared/uploads -sudo chmod -R 775 /srv/www/example.com/shared/uploads - -# 4. Cache issues - flush all caches -wp cache flush -wp rewrite flush -``` - -#### Step 6: Prepare for DNS Cutover - -Once testing is complete and everything works: - -1. **Re-enable SSL with Let's Encrypt in Trellis** (if you disabled it for testing): - - Edit `trellis/group_vars/production/wordpress_sites.yml`: - ```yaml - wordpress_sites: - example.com: - site_hosts: - - canonical: example.com - redirects: - - www.example.com - ssl: - enabled: true - provider: letsencrypt # Important: Set provider to letsencrypt - ``` - - **Important**: Make sure this configuration is in place BEFORE you change DNS. This way, after DNS propagation, you can simply run the provision command to get your SSL certificate. - -2. **Commit this configuration** (if using version control): - ```bash - cd trellis - git add group_vars/production/wordpress_sites.yml - git commit -m "Re-enable SSL with Let's Encrypt for production" - ``` - -3. **Remove /etc/hosts entry** from your local computer: - ```bash - sudo nano /etc/hosts - # Delete or comment out the line you added: - # 123.456.789.123 example.com - ``` - -4. **Flush DNS cache again**: - ```bash - # macOS - sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder - ``` - -5. **Now proceed with DNS cutover** (see next section) - -#### Notes About Let's Encrypt SSL - -**IMPORTANT**: Let's Encrypt SSL certificates can only be generated **AFTER** DNS is pointed to your new server. This is because Let's Encrypt validates domain ownership by checking DNS. - -**Timeline:** -1. ✅ **Before DNS cutover**: Test with `/etc/hosts` and either HTTP or self-signed certificate -2. ✅ **Update DNS**: Point your domain to new server IP -3. ✅ **Wait for DNS propagation**: Usually 5-30 minutes, but can take up to 48 hours -4. ✅ **Request Let's Encrypt SSL**: Trellis does this automatically on next provision - -**After DNS is live and has propagated**, provision with the letsencrypt tag to get your certificate: - -```bash -cd trellis - -# Wait for DNS to propagate (check with: dig example.com +short) -# Should return your new server IP - -# RECOMMENDED: Use --tags letsencrypt for faster, focused provisioning -trellis provision production --tags letsencrypt - -# Alternative: Re-provision everything (takes longer) -trellis provision production -``` - -**Why use `--tags letsencrypt`?** -- ⚡ Much faster - only runs SSL certificate tasks -- ✅ Safer - doesn't re-run all provisioning tasks -- 🎯 Focused - specifically requests and installs Let's Encrypt certificate - -**What Trellis does automatically:** -- Detects that DNS now points to the server -- Validates domain ownership via Let's Encrypt's DNS challenge -- Requests SSL certificate from Let's Encrypt -- Installs the certificate to `/etc/letsencrypt/` -- Updates Nginx configuration to use the certificate -- Sets up auto-renewal cron job (certificates renewed every 60 days) - -**Verify SSL is active:** -```bash -# SSH into server -ssh admin@your.server.ip - -# Check certificate details -sudo certbot certificates - -# Should show: -# Certificate Name: example.com -# Domains: example.com www.example.com -# Expiry Date: [60 days from now] -# Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem -# Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem -``` - -**Test SSL in browser:** -``` -https://example.com # Should show valid certificate, no warnings -``` - -**Check SSL grade:** -- Visit: https://www.ssllabs.com/ssltest/ -- Should achieve A+ rating with Trellis's default SSL configuration - -### WordPress Cron: System Cron vs WP-Cron - -**IMPORTANT**: Trellis automatically disables WordPress's built-in WP-Cron and uses **system cron** instead for more reliable scheduled task execution. - -#### What Changed After Migration - -**Before (Traditional WordPress):** -- WP-Cron runs when someone visits your site -- Unreliable on low-traffic sites -- Can cause performance overhead - -**After (Trellis):** -- System cron runs every 15 minutes via `/etc/cron.d/wordpress-{site}` -- Reliable, predictable execution -- No dependency on site traffic - -#### Verification After Migration - -```bash -# SSH into your Trellis server -ssh admin@your.server.ip - -# 1. Verify WP-Cron is disabled -cd /srv/www/example.com/current -grep DISABLE_WP_CRON .env -# Should show: DISABLE_WP_CRON=true - -# 2. Check system cron job exists -cat /etc/cron.d/wordpress-example_com -# Should show: -# #Ansible: example.com WordPress cron -# */15 * * * * web cd /srv/www/example.com/current && wp cron event run --due-now > /dev/null 2>&1 - -# 3. List WordPress scheduled events (these are preserved from your database) -wp cron event list - -# 4. Manually test cron execution -sudo -u web bash -c "cd /srv/www/example.com/current && wp cron event run --due-now" -``` - -#### What You Need to Know - -1. **Scheduled posts still work** - Your scheduled posts will publish on time via system cron -2. **Plugin schedules are preserved** - All scheduled tasks (backups, cache clearing, etc.) are stored in the database and migrate with your data -3. **More reliable** - Tasks run every 15 minutes regardless of site traffic -4. **No action needed** - Trellis configures this automatically during provisioning - -#### Troubleshooting Cron Issues - -If scheduled tasks aren't running after migration: - -```bash -# Check if events are scheduled -wp cron event list - -# Manually trigger overdue events -wp cron event run --due-now - -# Check system cron logs -sudo grep -i cron /var/log/syslog | tail -20 - -# Verify cron service is running -sudo systemctl status cron -``` - -For detailed cron documentation, customization, and troubleshooting, see [provision/CRON.md](../../trellis/provision/CRON.md). - -### 11. DNS and Go-Live - -When ready to go live: - -1. **Lower TTL** on your current DNS records (24 hours before migration) - ``` - example.com. 300 IN A old.server.ip - ``` - -2. **Update DNS** to point to your new Trellis server - ``` - example.com. 300 IN A new.server.ip - ``` - -3. **Monitor** DNS propagation: - ```bash - # Check DNS propagation locally - dig example.com +short - # Should return: 123.456.789.123 (your new server IP) - - # Check from multiple locations worldwide - # Use: https://www.whatsmydns.net/ - ``` - -4. **Wait for DNS to fully propagate** (typically 5-30 minutes, but can take up to 48 hours) - -5. **CRITICAL: Provision to get Let's Encrypt SSL certificate:** - - Once DNS is confirmed to point to your server: - ```bash - cd trellis - - # RECOMMENDED: Use --tags letsencrypt for fast SSL setup - trellis provision production --tags letsencrypt - ``` - - This will: - - Request SSL certificate from Let's Encrypt - - Install certificate - - Configure Nginx to use HTTPS - - Set up automatic renewal - - **Verify SSL certificate:** - ```bash - # SSH into server - ssh admin@server.ip - - # Check certificate was issued - sudo certbot certificates - # Should show valid certificate for example.com - ``` - -6. **Test HTTPS in browser:** - ``` - https://example.com # Should load with valid SSL, no warnings - ``` - -7. **Redirect old server** (optional, keep old hosting active for a few days): - - Add to old server's `.htaccess`: - ```apache - - RewriteEngine On - RewriteCond %{HTTP_HOST} ^example\.com$ [OR] - RewriteCond %{HTTP_HOST} ^www\.example\.com$ - RewriteRule ^(.*)$ https://example.com/$1 [R=301,L] - - ``` - -8. **Final verification:** - ```bash - # Check SSL score (should be A+) - # Visit: https://www.ssllabs.com/ssltest/ - - # Test all site functionality over HTTPS - curl -I https://example.com | grep "HTTP" - - # Monitor server logs for any errors - ssh admin@server.ip - sudo tail -f /var/log/nginx/error.log - ``` - -## Troubleshooting - -### Issue: Images Not Displaying - -**Symptoms:** Broken image links, 404 errors on media files - -**Solutions:** - -```bash -# 1. Check upload directory permissions -ls -la /srv/www/example.com/shared/uploads/ -sudo chown -R web:www-data /srv/www/example.com/shared/uploads -sudo chmod -R 775 /srv/www/example.com/shared/uploads - -# 2. Verify symlink is correct -ls -la /srv/www/example.com/current/web/app/ -# Should show: uploads -> ../../../shared/uploads - -# 3. Check for mixed path references -wp db search 'wp-content/uploads' --all-tables - -# 4. Regenerate thumbnails -wp media regenerate --yes - -# 5. Check Nginx error logs -sudo tail -f /var/log/nginx/error.log -``` - -### Issue: White Screen of Death (WSOD) - -**Symptoms:** Blank white screen, no error messages - -**Solutions:** - -```bash -# 1. Enable debug mode -# Edit site/config/environments/production.php -Config::define('WP_DEBUG', true); -Config::define('WP_DEBUG_LOG', true); -Config::define('WP_DEBUG_DISPLAY', false); - -# 2. Check PHP error logs -sudo tail -f /var/log/php8.2-fpm.log - -# 3. Verify file permissions -sudo chown -R web:www-data /srv/www/example.com/current -sudo chmod -R 755 /srv/www/example.com/current - -# 4. Check for plugin conflicts -wp plugin deactivate --all -wp plugin activate plugin-name # Activate one by one -``` - -### Issue: Database Connection Errors - -**Symptoms:** "Error establishing database connection" - -**Solutions:** - -```bash -# 1. Verify database credentials -cat site/.env | grep DB_ - -# 2. Check database exists -mysql -u db_user -p -e "SHOW DATABASES;" - -# 3. Test database connection -wp db check - -# 4. Verify MariaDB is running -sudo systemctl status mariadb - -# 5. Check database user permissions -mysql -u root -p -# Then in MySQL: -SELECT user, host FROM mysql.user; -SHOW GRANTS FOR 'db_user'@'localhost'; -``` - -### Issue: Permalinks Not Working (404 Errors) - -**Symptoms:** Homepage works, but all other pages show 404 - -**Solutions:** - -```bash -# 1. Flush rewrite rules -wp rewrite flush - -# 2. Regenerate .htaccess (if using Apache) -wp rewrite flush --hard - -# 3. Check Nginx configuration -sudo nginx -t - -# 4. Verify WordPress .htaccess rules are in place -cat /srv/www/example.com/current/web/.htaccess - -# 5. Restart Nginx -sudo systemctl restart nginx -``` - -### Issue: Plugin or Theme Compatibility - -**Symptoms:** Plugins not working, theme breaking - -**Solutions:** - -```bash -# 1. Check for hardcoded paths in theme -grep -r "wp-content" /srv/www/example.com/current/web/app/themes/your-theme/ - -# 2. Search for ABSPATH usage -grep -r "ABSPATH" /srv/www/example.com/current/web/app/themes/your-theme/ - -# 3. Update plugins to latest versions -wp plugin update --all - -# 4. Check plugin compatibility with PHP version -wp plugin list - -# 5. Review plugin-specific logs -wp plugin deactivate problematic-plugin -# Check if issue resolves -``` - -### Issue: Slow Performance After Migration - -**Symptoms:** Site loads slowly compared to old server - -**Solutions:** - -```bash -# 1. Enable object caching (Redis) -# Edit trellis/group_vars/production/wordpress_sites.yml -cache: - enabled: true - -# 2. Install Redis plugin -composer require wpackagist-plugin/redis-cache - -# 3. Check query monitor for slow queries -composer require wpackagist-plugin/query-monitor --dev - -# 4. Optimize database -wp db optimize - -# 5. Check server resources -htop -free -h -df -h - -# 6. Enable FastCGI cache in Nginx (already in Trellis) -# Verify it's working: -curl -I https://example.com | grep "X-FastCGI-Cache" -``` - -### Issue: Mixed Content Warnings (HTTP/HTTPS) - -**Symptoms:** Browser shows "not secure" warnings, mixed content errors - -**Solutions:** - -```bash -# 1. Update all URLs to HTTPS -wp search-replace 'http://example.com' 'https://example.com' --all-tables --dry-run -wp search-replace 'http://example.com' 'https://example.com' --all-tables - -# 2. Check for hardcoded HTTP URLs in theme -grep -r "http://" /srv/www/example.com/current/web/app/themes/your-theme/ - -# 3. Install SSL insecure content fixer plugin (temporary) -wp plugin install ssl-insecure-content-fixer --activate - -# 4. Verify SSL certificate -sudo certbot certificates - -# 5. Check browser console for specific mixed content URLs -# Fix them individually in database or theme files -``` - -## Post-Migration Optimization - -After successful migration, consider these optimizations: - -### 1. Set Up Backups - -```bash -# Use the backup tools in this repository -# See: ../../trellis/backup/README.md - -# Set up automated database backups -ansible-playbook backup/trellis/database-backup.yml -e site=example.com -e env=production - -# Set up automated file backups -ansible-playbook backup/trellis/files-backup.yml -e site=example.com -e env=production -``` - -### 2. Enable Redis Object Caching - -```bash -# Install Redis plugin -composer require wpackagist-plugin/redis-cache - -# Activate and enable -wp plugin activate redis-cache -wp redis enable -``` - -### 3. Configure Browser Caching - -See the [Browser Caching Guide](../../docs/nginx/browser-caching/README.md) in this repository. - -### 4. Optimize Images - -See the [Image Optimization Guide](../../docs/nginx/image-optimization/README.md) for WebP/AVIF support. - -### 5. Set Up Monitoring - -```bash -# Install monitoring tools -composer require wpackagist-plugin/query-monitor --dev - -# Set up server monitoring -# Consider: New Relic, Datadog, or Prometheus -``` - -### 6. Security Hardening - -```bash -# Install security plugin -composer require wpackagist-plugin/wordfence - -# Disable file editing in WordPress admin -# Add to site/config/application.php: -Config::define('DISALLOW_FILE_EDIT', true); - -# Set up fail2ban for SSH protection -sudo apt install fail2ban -``` - -### 7. Performance Monitoring - -```bash -# Install performance monitoring -wp plugin install query-monitor --activate - -# Check page load times -curl -o /dev/null -s -w "Total time: %{time_total}s\n" https://example.com - -# Use tools like: -# - GTmetrix: https://gtmetrix.com/ -# - Google PageSpeed Insights: https://pagespeed.web.dev/ -# - Pingdom: https://tools.pingdom.com/ -``` - -### 8. Regular Maintenance Schedule - -Create a maintenance schedule: - -```bash -# Weekly tasks -- Review error logs -- Update plugins and themes -- Check site backups -- Monitor site performance - -# Monthly tasks -- Security audit -- Database optimization -- Review and update dependencies -- Check for WordPress core updates - -# Quarterly tasks -- Full backup verification -- Disaster recovery drill -- Performance audit -- Security penetration testing -``` - -## Additional Resources - -- [Trellis Documentation](https://roots.io/trellis/docs/) -- [Bedrock Documentation](https://roots.io/bedrock/docs/) -- [WP-CLI Commands](https://developer.wordpress.org/cli/commands/) -- [Roots Discourse Community](https://discourse.roots.io/) - -## Need More Help? - -- Review the main [Migration Guide](README.md) for other migration scenarios -- Check the [Backup Tools](../../trellis/backup/README.md) for data management -- See [Provisioning Guide](../../trellis/provision/README.md) for server setup help diff --git a/wp-cli/migration/URL-UPDATE-METHODS.md b/wp-cli/migration/URL-UPDATE-METHODS.md deleted file mode 100644 index 7df21b5..0000000 --- a/wp-cli/migration/URL-UPDATE-METHODS.md +++ /dev/null @@ -1,145 +0,0 @@ -# Updating WordPress Site and Home URLs After Migration - -When migrating a WordPress site to a new domain or URL, you need to update the site and home URLs in multiple places. Here are the most common and effective methods. - -## Method 1: Using WP-CLI (Recommended) - -WP-CLI is the fastest and most reliable method for updating URLs: - -```bash -# Update both home and site URL -wp option update home 'https://newdomain.com' -wp option update siteurl 'https://newdomain.com' - -# Search and replace old URLs in content -wp search-replace 'https://olddomain.com' 'https://newdomain.com' - -# Include uploads if you have hardcoded URLs in content -wp search-replace 'https://olddomain.com/wp-content/uploads' 'https://newdomain.com/wp-content/uploads' - -# Flush rewrite rules -wp rewrite flush -``` - -## Method 2: Using wp-config.php (Temporary Fix) - -Add these constants to your `wp-config.php` file **before** the `/* That's all, stop editing! */` line: - -```php -// Force WordPress to use these URLs -define('WP_HOME', 'https://newdomain.com'); -define('WP_SITEURL', 'https://newdomain.com'); -``` - -**Note:** This is a temporary solution. Remove these lines once you've updated the database permanently. - -## Method 3: Direct Database Update - -**⚠️ Always backup your database before making direct changes!** - -### Update options table: - -```sql -UPDATE wp_options -SET option_value = 'https://newdomain.com' -WHERE option_name = 'home'; - -UPDATE wp_options -SET option_value = 'https://newdomain.com' -WHERE option_name = 'siteurl'; -``` - -### Update content URLs (if needed): - -```sql --- Update post content -UPDATE wp_posts -SET post_content = REPLACE(post_content, 'https://olddomain.com', 'https://newdomain.com'); - --- Update meta values -UPDATE wp_postmeta -SET meta_value = REPLACE(meta_value, 'https://olddomain.com', 'https://newdomain.com'); - --- Update comments -UPDATE wp_comments -SET comment_content = REPLACE(comment_content, 'https://olddomain.com', 'https://newdomain.com'); -``` - -## Method 4: Using WordPress Admin Panel - -If you can access the admin panel: - -1. Go to **Settings > General** -2. Update **WordPress Address (URL)** and **Site Address (URL)** -3. Save changes - -## Method 5: Using functions.php (Temporary) - -Add to your theme's `functions.php`: - -```php -// Temporary URL override -update_option('siteurl', 'https://newdomain.com'); -update_option('home', 'https://newdomain.com'); -``` - -**Remove this code after the URLs are updated!** - -## Post-Migration Checklist - -After updating URLs, verify these items: - -- [ ] WordPress admin is accessible -- [ ] Frontend loads correctly -- [ ] Images and media files display properly -- [ ] Internal links work correctly -- [ ] SSL certificate is properly configured -- [ ] Redirect old domain to new domain (if applicable) -- [ ] Update any hardcoded URLs in theme files -- [ ] Check and update any plugins with domain-specific settings -- [ ] Update CDN settings if applicable -- [ ] Test contact forms and other functionality - -## Troubleshooting - -### Can't Access Admin Panel -If you can't access the admin after URL change: - -1. Use wp-config.php method first -2. Then use WP-CLI or database method to make permanent changes -3. Remove wp-config.php constants - -### Mixed Content Issues -If you're moving from HTTP to HTTPS: - -```bash -# Use WP-CLI to replace HTTP with HTTPS -wp search-replace 'http://yourdomain.com' 'https://yourdomain.com' -``` - -### Multisite Networks -For WordPress multisite: - -```bash -# Update main site -wp option update home 'https://newdomain.com' --url=olddomain.com -wp option update siteurl 'https://newdomain.com' --url=olddomain.com - -# Update each subsite -wp search-replace 'olddomain.com' 'newdomain.com' --network -``` - -## Best Practices - -1. **Always backup** your database before making changes -2. Use **WP-CLI** when possible - it's the safest method -3. **Test thoroughly** after making changes -4. Keep wp-config.php constants as **temporary solutions only** -5. Update your **DNS records** and **SSL certificates** accordingly -6. Set up **301 redirects** from old domain to new domain if applicable - -## Additional Resources - -- [WP-CLI Official Documentation](https://wp-cli.org/) -- [WordPress Codex: Changing The Site URL](https://wordpress.org/support/article/changing-the-site-url/) -- [WordPress Migration Guide](https://wordpress.org/support/article/moving-wordpress/) \ No newline at end of file