The WordPress runtime environment as of August 2026
A homepage that opens normally on the new server does not mean the WordPress migration is finished. That state is usually closer to the first check that files and the database can also be read in the new environment. A safe migration finishes only after confirming that everything created up to the moment of the move is reflected, that real traffic reaches the new environment, that TLS, mail, cron, cache, and external integrations work there, and how far back and by what route a problem can be reversed. At the end, writes on the old environment are blocked and backups, credentials, DNS, firewall, and monitoring are all tidied up.
So a WordPress migration is safer managed in five stages — preflight, rehearsal, cutover, validation, decommission — than as a file copy plus a database import.
The latest WordPress release is 7.1. The 7.1 branch in the official release archive still lists only 7.1, so no maintenance release in the 7.1 line is visible at this point.[7]
The WordPress Hosting Handbook recommends PHP 8.4 or above for production. It states that PHP 8.5 is supported from WordPress 6.9 onward. PHP 8.2 and 8.3 sit in security support upstream while 8.4 and 8.5 are in active support.[2]
On databases, the baselines in different documents have to be kept apart. MySQL 8.0 or later in the WordPress requirements is a broad compatibility statement, yet MySQL 8.0's end-of-life date already passed in April 2026.[8] MariaDB 10.6 likewise carries an end-of-life date of 6 July 2026 in the Hosting Handbook. Pick an LTS line still in support for a new environment, and never read "WordPress core supports it" as meaning plugins and custom queries are automatically compatible too.[2]
- WordPress core
- Current official position: Latest release 7.1 / Baseline for a new migration target: Do not raise it during the migration merely because it is the latest
- PHP public recommendation
- Current official position: 8.3 or above / Baseline for a new migration target: A modern recommendation, not a floor
- PHP operational recommendation
- Current official position: Hosting Handbook recommends 8.4 or above / Baseline for a new migration target: Take 8.4 as the default candidate after verifying every plugin, theme, and custom code
- PHP core minimum
- Current official position: WordPress 7.1 requires PHP 7.4 or above / Baseline for a new migration target: A runnable floor, not a target version for a new environment
- PHP 8.5
- Current official position: Supported by WordPress core 7.1 and in active support upstream / Baseline for a new migration target: Choose it once all extension code and PHP extensions pass verification
- Database public recommendation
- Current official position: MariaDB 10.11 or later, or MySQL 8.0 or later / Baseline for a new migration target: Check the product's current support lifetime as well
- Database legacy floor
- Current official position: Runs on MySQL 5.5.5 or later / Baseline for a new migration target: End of life, so not for a new target
- Current LTS candidates
- Current official position: MySQL 8.4, MariaDB 10.11, 11.4, 11.8 / Baseline for a new migration target: Decide after testing plugins, custom queries, charset, collation, and SQL mode
- HTTPS
- Current official position: A baseline condition in WordPress requirements / Baseline for a new migration target: Verify redirects, proxy headers, and callback URLs, not only certificate issuance
Why core upgrades and infrastructure migration do not go together
Consider bundling a server and OS change, PHP 8.1 to 8.5, MySQL 8.0 to 8.4, WordPress 7.0 to 7.1, and simultaneous plugin and theme updates into one cutover. When an error appears, separating server configuration from PHP compatibility, from database behaviour, from a core change, from a plugin update is hard. The bigger problem is that once an update has altered database structure or stored data, reversing traffic to the old environment is not a safe rollback.
The WordPress 7.1 field guide likewise explains that changes to some bundled libraries affect the behaviour or styling of plugins that use them, so testing is required. The PHP compatibility table for WordPress core is a judgment about core's own scope and says nothing about the compatibility of installed plugins, themes, MU plugins, and custom code.[9]
The safe default order has three steps. Rehearse the new infrastructure against the existing WordPress, plugin, and theme versions. Complete the infrastructure migration and clear the observation window. Then perform the core, PHP, database, or plugin upgrade as a separate change.
Where the existing PHP or database is simply unavailable in the new environment and a change is unavoidable, record it not as a plain server move but as an infrastructure migration combined with a runtime upgrade. Split the acceptance criteria and rollback triggers per environment as well.
Map dependencies and rehearse the transition — Group dependent systems, rehearse the move and agree rollback conditions before cutover.
Bulk copy, final sync, traffic cutover
The transition splits into three actions. The bulk copy makes the first copy of files, uploads, and database into the new environment. In that state the new environment is a rehearsal target, with external mail, payment, webhooks, and cron blocked or in test mode. Meanwhile the old environment keeps taking real changes.
Next comes the write freeze. Once writes from admin, forms, comments, the REST API, payment callbacks, cron, and queues are controlled, the final sync moves the last database state, the uploads delta, and any other mutable files. The new environment is now a cutover candidate, where the smoke test and data consistency checks happen.
Last is the traffic cutover. DNS, the reverse proxy, or the load balancer is changed so the new environment takes reads and writes, and the old environment stays write blocked with cron and queues disabled. Only after the observation window is cleared does the old environment get decommissioned.
If orders, registrations, comments, and uploads kept arriving on the old site after the bulk copy, the first copy is not the state as of cutover. Switching traffic without a final sync produces a site that loads but has lost its most recent data.
Master migration checklist
The five stages below are the body of this article. Preflight fixes what is being moved. Rehearsal performs the transition end to end once, and cutover moves current data and real traffic together. Validation approves on function and operational evidence rather than on a screen. Decommission treats shutting the old server down as migration work.
Each stage's table is a template filled with real values. Recording an owner and evidence per item is what stops the next person from making the same judgment again.
1. Preflight: fix what is being moved
Preflight is not just gathering server facts. It is the stage that decides what state is in scope for copying, what lives in external systems, and which environment is authoritative before and after cutover.
The environment compatibility matrix is a template to fill with real values. MATCH means a simple match, TEST_REQUIRED means a rehearsal is needed, and BLOCK means it must be resolved before cutover. Record the old and new values side by side and leave a verdict.
The WordPress Hosting Handbook describes json and mysqli as required PHP extensions. It recommends several more separately for remote requests, media, character handling, TLS, and compression. That is why matching PHP versions is not enough to call two server environments the same.[2]
Check each of the 23 Preflight Checklist entries below, retaining its completion mark and evidence.
After environment, plugins, themes, and custom code, verify write paths, uploads, caches, cron, and queues.
Verify mail, integrations, DNS, TLS, proxy, security rules, and restore capability; then finalize sources of truth and cutover approval. Each checklist item identifies its evidence record.
The source of truth is settled in one sentence. Write down which environment is authoritative at each moment, as below. Writing that only the WordPress database is authoritative is not enough. If uploads live on the filesystem, payment results at the external gateway, and mail status at the sending provider, the migration scope is already spread across several systems.
- □ Preflight 1 / Scope document
- Separate infrastructure changes, URL changes, and any Core/PHP/DB upgrades
- □ Preflight 2 / Environment Matrix
- Record WordPress, PHP, and DB versions and PHP extensions
- □ Preflight 3 / Plugin Inventory
- Record all active/inactive plugins, versions, required PHP, and custom tables
- □ Preflight 4 / Theme Inventory
- Record parent/child themes, custom templates, and build artifacts
- □ Preflight 5 / MU Plugin·Drop-in inventory
- Check mu-plugins, object-cache.php, advanced-cache.php, and other drop-ins
- □ Preflight 6 / Custom Code Register
- Check functions.php, snippets, standalone PHP, deployment scripts, and other custom code
- □ Preflight 7 / Network Map
- Check multisite status, site count, domain mapping, and subdomain/subdirectory structure
- □ Preflight 8 / Writer Inventory
- Classify write-heavy features including WooCommerce, booking, membership, comments, and forms
- □ Preflight 9 / Uploads Inventory
- Measure wp-content/uploads, separate upload paths, external storage, and recent changes
- □ Preflight 10 / Cache Map
- Check page-cache location and bypass routes
- □ Preflight 11 / Object Cache Map
- Check object-cache prefix, DB, drop-in, and sharing
- □ Preflight 12 / CDN Configuration
- Check CDN origin, cache rules, and purge paths
- □ Preflight 13 / Cron Inventory
- Check WP-Cron versus system cron and what runs on which server
- □ Preflight 14 / Queue Snapshot
- Check plugin queues, pending/failed jobs, and worker locations
- □ Preflight 15 / Mail Flow Map
- Record SMTP/mail API, sending domain, authentication, and bounce inspection
- □ Preflight 16 / Integration Register
- Check endpoints and secrets for forms, webhooks, payment callbacks, and external APIs
- □ Preflight 17 / DNS Export
- Check DNS records, current TTL, proxy status, and access holders
- □ Preflight 18 / Certificate Inventory
- Check every hostname’s TLS certificate and renewal owner
- □ Preflight 19 / Proxy Contract
- Check Host, Scheme, and Client IP headers forwarded by the reverse proxy
- □ Preflight 20 / Security Rule Export
- Check WAF and access-control rules affecting Admin, REST, and webhooks
- □ Preflight 21 / Restore Evidence
- Check that database, file, and configuration backups exist and can actually be restored
- □ Preflight 22 / Source-of-Truth Table
- Declare the source of truth for DB, uploads, and external transaction data
- □ Preflight 23 / Cutover Runbook
- Finalize acceptance criteria, rollback triggers, approvers, and contact routes
- During rehearsal
- The WordPress database and uploads are authoritative in the old environment. Cron and queues run only there, and payment and mail use the real external systems.
- Write freeze and final sync
- The database and uploads remain authoritative in the old environment but with writes stopped. Cron and queues are stopped or drained, and inbound callbacks are controlled separately.
- Cutover candidate
- The candidate authoritative copy of the database and uploads moves to the new environment. Cron and queues are still held back, and integrations accept test requests only.
- After acceptance
- The database and uploads become authoritative in the new environment. Cron and queues run only there, and consistency with the new endpoints is confirmed.
- Observation window
- Both authority and execution sit in the new environment, and reconciliation against external systems continues.
Layer | What must be compared | Pass evidence |
|---|---|---|
| WordPress core | Version, auto-update policy, whether core was modified | Version, checksum, change record |
| PHP | Version, SAPI, FPM settings, memory and timeout | phpinfo or configuration export, functional test |
| PHP extensions | json, mysqli, curl, mbstring, intl, openssl, xml, zip, image processing modules | Extension list plus upload and remote request tests |
| Database | MySQL or MariaDB and version, charset, collation, SQL mode, timezone, packet size | Import log, key queries, character and sort validation |
| Web server | Nginx or Apache, rewrite, upload limit, compression, static file handling | Permalink, admin, REST, and large upload tests |
| Plugins | Active and inactive lists, versions, PHP and core requirements, licences, custom tables | Acceptance test per feature |
| Theme | Parent and child theme, version, build artefacts, template overrides | Key templates, responsive layout, admin screens |
| MU plugins | File list, load order, per-environment conditions | Bootstrap and admin function tests |
| Custom code | Theme functions, drop-ins, snippets, separate apps and APIs | Code register and critical flow tests |
| Multisite | Subdomain or subdirectory, network tables, domain mapping, cookie and upload paths | Network admin and per-site tests |
| Uploads and storage | Paths, ownership, permissions, external object storage, generated files | Counts, size, recent files, thumbnail validation |
| Object cache | Redis or Memcached, database index, prefix, serializer, drop-in | Read, write, and session tests after a flush |
| Page cache and CDN | Cache key, bypass routes, purge, origin | HIT and MISS, admin exclusion, purge confirmation |
| WP-Cron and system cron | Invocation method, interval, user, DISABLE_WP_CRON | Event list and execution log |
| Queue | Worker location, pending and failed jobs, retries | Queue state and absence of duplicate execution |
| SMTP or API method, from domain, authentication, bounce and log | Actual delivery plus provider log | |
| Webhooks and callbacks | Endpoint, secret, IP restrictions, retry, idempotency | A unique test ID and the receipt log |
| DNS, TLS, proxy, WAF | Records, TTL, certificates, origin, forwarded headers, rules | Tests from outside and against the origin |
| Monitoring | Uptime, PHP errors, web logs, database, disk, queue, alerts | Dashboard and alert routing verification |
2. Rehearsal: run the whole thing once before the real switch
Rehearsal is not a test that brings up a home page on the new server. It performs the copy, import, configuration, and validation in the same order as the cutover, and records how long each takes and where it fails.
If the production domain stays the same, using a hosts override or temporary proxy routing on an approved test machine reduces unnecessary database changes compared with rewriting every URL in the database to a temporary domain. If a temporary hostname is unavoidable, block real mail, payment, webhooks, and cron separately, not just search engine indexing.
Consider a URL change. WordPress options, widgets, theme settings, and plugin data can hold PHP serialized data. A serialized string stores the length of each value alongside it, so replacing a URL of different length with a global SQL REPLACE() corrupts the data. The official WordPress migration document warns about this and explains that WP-CLI's search-replace recognises and handles serialized data.[1]
The safe default is a dry run on a copy of the new environment first. Give wp search-replace the old and new addresses with --skip-columns=guid and --dry-run to see only what would change and how many rows. Remove --dry-run from the same command only after reviewing the result and the database backup. If a plugin uses custom tables not registered with WordPress, inspect the tables first and then decide about --all-tables-with-prefix. Targeting an entire multisite needs --network, but that flag alone does not complete the review of the network structure. WP-CLI's default behaviour targets tables registered to the current site, and --network and --all-tables-with-prefix widen that scope.[3]
Do not change guid even though it looks like a URL. WordPress uses it as a permanent identifier for a post and the official documentation states it stays the same when the domain changes. Changing guid makes feed readers treat existing posts as new ones.[1]
A successful dry run is not final evidence either. After the change, verify menus, block and widget settings, background images in CSS, media URLs, SEO metadata, plugin custom tables, and redirects on the real screens and in the database.
- Isolate the staging or temporary host from production traffic
- Pass criterion: No ordinary user reaches it, and search indexing and real external side effects are blocked
- Run on the actual target PHP, database, and web server
- Pass criterion: Critical flows work without fatal errors or a flood of deprecations
- Restore file ownership and permissions
- Pass criterion: WordPress writes only where required, with no excessive global write permission
- Perform the database export and import
- Pass criterion: No import errors, and key table and entity counts land in the expected range
- Dry run and then apply the URL change
- Pass criterion: Serialized data survives and guid values are unchanged
- Configure permalinks and rewrites
- Pass criterion: Posts, pages, REST API, and admin paths respond correctly
- Upload creation and thumbnail generation
- Pass criterion: Originals and derivatives are created and readable from public URLs
- Run plugins, theme, MU plugins, and custom code
- Pass criterion: Acceptance criteria pass per critical flow
- Verify mail, webhooks, and payment in test mode
- Pass criterion: No side effect reaches real users or real transactions
- Time the bulk copy and the final sync
- Pass criterion: Both fit inside the planned maintenance window
- Rehearse the rollback
- Pass criterion: Traffic reversal and reactivation of the old environment work as documented
- Fix the rollback trigger
- Pass criterion: Who stops it, on what evidence, and when is explicit
3. Cutover: move current data and real traffic together
The cutover runs in twelve steps. It starts from confirming the bulk copy, moves through the write freeze and cron and queue control, the final database and upload syncs, the final configuration, and the smoke test, then switches traffic. TLS and caches are checked before writes are opened on the new environment.
A write freeze does not end with an admin notice. WordPress write paths do not live only under /wp-admin/. Comments and registration, enquiry, booking and survey forms, the REST API, admin-ajax.php, payment, shipping and CRM callbacks, scheduled publishing and WP-Cron, plugin queues and retry workers, and application password and API requests from external programs are all write paths. Even with a maintenance notice on the admin screens, webhooks and cron that keep running change the data again after the final database sync. On write-heavy sites, stop every writer, or record the writes that cannot be stopped in a separate ledger and reconcile them.
For a site that cannot tolerate even a short write freeze, the plain final dump in this runbook is not enough. It calls for a separate online migration design with replication or change data capture, callback reprocessing, and consistency reconciliation.
A DNS TTL does not fix the completion time. Lowering the TTL in advance makes resolvers fetch the new record sooner once their existing cache expires. But a TTL already fetched keeps counting down, and some resolvers serve expired data temporarily to survive an outage. So never promise a cutover time on the basis that "the TTL is 300 seconds, so the whole world sees the new server in five minutes".[6][10] After the switch, check results from several resolvers and networks, and identify which backend served a request from server logs or a deployment marker made for the test. Never put sensitive information such as an origin IP or an internal hostname into that marker.
Seven things get checked on TLS, proxy, and WAF. Whether every real hostname is in the certificate. Whether TLS between edge and origin is also correct. Whether the HTTP to HTTPS redirect creates a loop. Whether the reverse proxy passes the original host and the HTTPS scheme to WordPress correctly. Whether the new origin IP, port, and health check are in place. Whether the WAF wrongly blocks login, admin, the REST API, webhooks, or payment callbacks. And whether a write can still be created by connecting directly to the old origin.
Step | Action | Completion condition |
|---|---|---|
| 1 | Confirm the bulk copy is complete | The database and files as of the baseline exist in the new environment |
| 2 | Announce the change and start the write freeze | Write paths for admins, users, APIs, and callbacks are controlled |
| 3 | Control cron and queues in the old environment | No new data or external side effect arises during the final sync |
| 4 | Final database sync | The database up to the freeze point is reflected in the new environment |
| 5 | Final upload sync | Files added, changed, or deleted since the bulk copy are reflected |
| 6 | Apply final URL and environment configuration | Production URL, database, secrets, and proxy settings match the target |
| 7 | Cutover candidate smoke test | No blocker on login, read, write, or upload |
| 8 | Switch DNS, proxy, or load balancer | External requests arrive at the new environment |
| 9 | Verify TLS | Certificate, chain, redirects, and forwarded scheme are correct |
| 10 | Invalidate page cache, object cache, and CDN | Old responses, old origin, and stale objects are gone |
| 11 | Open writes on the new environment | Only the new environment writes as the authoritative copy |
| 12 | Keep the write block on the old environment | No new data is created through a bypass route |
4. Validation: approve on function and operational evidence, not on a screen
Validation does not end with "someone looked around and it seemed fine". Fix owners and pass criteria per item in advance. Then leave re-checkable evidence such as request IDs, logs, and delivery results.
WP-Cron and system cron are different things. WP-Cron is not a scheduler that runs continuously like a traditional system cron. By default it checks for due tasks when a page load occurs. With no traffic, work runs later than its scheduled time.[11] Sites configured to call wp-cron.php or WP-CLI on a system cron often disable the page-load path with DISABLE_WP_CRON. When migrating, confirm two things separately: that the scheduled events still exist inside WordPress, and that the new server's OS scheduler actually calls WordPress cron. The wp cron test command inspects WP-Cron spawn behaviour. In a system cron setup, also check the OS scheduler's execution log and the completion record of actual events. If the old and new servers both run cron, mail, subscriptions, bookings, and inventory sync get processed twice.[4]
Mail function success and mail delivery are different. wp_mail() returning true does not mean the recipient received anything. The official function documentation states the value only means the transport used handled the request without error.[5] Mail validation needs six pieces of evidence. Whether WordPress or a plugin created the send request. Whether the SMTP or mail API provider accepted it. Whether the sending domain and its authentication are correct. Whether it arrived in a real test mailbox. What the spam, bounce, and block status is. And whether each template — password reset, order, form — was checked. Never pass on a PHP mail() call or a wp_mail() return value alone.
An all-green Site Health is still not full acceptance. Site Health is useful for checking configuration facts and known problems across WordPress, plugins, theme, server, database, and filesystem permissions. It also catches disabled uploads, loopback failures, outdated PHP, and blocked HTTP requests.[12] It does not, however, validate order payment, real mail delivery, external webhooks, analytics, current-data consistency, DNS switchover, or rollback capability. So an all-green Site Health is one item of migration acceptance, not the whole evidence.
Subject | Default owner | Pass criterion |
|---|---|---|
| Home | WordPress owner | The expected home page opens on the production domain and is served by the new backend |
| Read | Content owner | Representative posts, pages, search, taxonomy, and media work and recent content is present |
| Admin | WordPress owner | Dashboard, menus, editor, and plugin screens show no errors or redirect loops |
| Login | App owner | Login, logout, password reset, and role-based access all work |
| Session | App owner | Sessions persist across requests and are not wrongly shared with the old environment |
| Write | Content owner | A test post and a settings change save to the new database and appear on the front end |
| Upload | Content owner | File upload, thumbnail generation, retrieval, and deletion all work |
| Form | Business owner | Submitted data is stored and the downstream processing state is confirmed |
| Mail owner | Not only request handling but actual receipt, provider log, and bounce status | |
| Webhook | Integration owner | A unique test ID passes signature verification and is processed exactly once |
| Payment | Commerce owner | In an approved test or sandbox flow, callback and order state agree |
| WP-Cron | WordPress owner | Scheduled events run through the intended invocation and do not run twice |
| System cron | Infrastructure owner | Runs as the intended user, interval, and command, and calls only the new environment |
| Queue | App owner | Pending and failed counts are in range and old and new workers do not run together |
| Object cache | App owner | Regenerates correctly after a flush and its keys do not collide with another environment |
| Page cache | Web owner | Dynamic routes bypass the cache and HIT and MISS on public pages match intent |
| CDN | Web owner | Uses the new origin and no old content survives a purge |
| Redirects | SEO and web owner | HTTP, WWW, and legacy URLs land correctly with no chains or loops |
| Canonical URL | SEO owner | Only the public URL is emitted as canonical and no temporary host remains |
| robots | SEO owner | Matches the production policy with no leftover staging-wide block |
| Sitemap | SEO owner | Uses production URLs, includes key content, and responds correctly |
| Analytics | Analytics owner | Page views and key events are collected and tags do not fire twice |
| Logs | Operations owner | PHP fatals, database errors, permission errors, and 5xx do not rise abnormally |
| Monitoring | Operations owner | Uptime, latency, error, disk, database, and queue monitoring target the new environment |
| Site Health | WordPress owner | No migration-related critical issue, and environment information matches the matrix |
| Business acceptance | Business approver | Every core business journey passes and unresolved risk sits inside the approved range |
Operations connected from observation to improvement — Respond using service indicators and alerts, then connect change records and incident reviews to improvements.
5. Decommission: turning off the old server is migration work too
Do not delete the old server the moment the new one looks healthy. Leaving the old environment alive indefinitely is not safe either. Stale servers, plugins, credentials, and firewall rules linger unmanaged and create new attack surface and operational confusion.
The length of the observation window cannot be identical for every site. It has to be long enough to actually observe one cycle of the critical scheduled jobs, a real or approved synthetic write flow, mail, webhooks and payment callbacks, cache expiry and regeneration, real traffic during business hours, and the scheduled runs of backup and monitoring. Where a critical job runs once a month, two days of a healthy homepage is not grounds for calling that job validated.
- Run the observation window
- Closing condition: No unresolved critical issue and the exit criteria are met
- Write block on the old environment
- Closing condition: No new data can be created through a bypass domain, IP, or admin route
- Stop old cron and queues
- Closing condition: No external side effects and no duplicated work
- Final backup of the old environment
- Closing condition: A restorable copy of database, files, and configuration, with its identifier kept
- Fix backup retention
- Closing condition: A deletion date and owner consistent with legal, contractual, and operating policy
- Credential rotation
- Closing condition: Database, SMTP, API, and webhook secrets held by the old server are rotated as needed
- DNS cleanup
- Closing condition: Old records, temporary hosts, and verification entries removed
- TLS cleanup
- Closing condition: Unused certificates, challenges, and renewal jobs cleared
- Firewall and allowlist cleanup
- Closing condition: Old IPs, ports, and admin access grants removed
- Monitoring cleanup
- Closing condition: Duplicate alerts removed and required historical data retained
- Backup and security agent cleanup
- Closing condition: Unnecessary cost, permissions, and duplicate jobs removed
- Shutdown approval
- Closing condition: Approval recorded from business, application, and infrastructure owners
- Server termination
- Closing condition: Termination time, asset ID, and final evidence recorded
- Post-migration document update
- Closing condition: Runbook, architecture, credential owners, and asset registry brought current
WordPress-specific rollback contract
A rollback contract is not the sentence "if something goes wrong we put DNS back". In WordPress, the database, uploads, cron, queues, forms, orders, mail, and callbacks all change state at once, so the first thing to settle is how late a simple return is still possible.
If the new environment has not yet taken real writes, reversing traffic to the old environment and lifting the write block is generally available. That stage is the simplest rollback window.
Once writes have started in the new environment, orders and payment states, registrations, logins and password changes, comments, posts and bookings, uploaded files, form submissions, webhook processing results, changes made by cron and queues, and mail already sent all exist there. Reversing traffic alone at that point makes data created in the new environment disappear from users' view, or gets the same callback and queue processed twice.
So one of four things is needed: safely replay the new writes into the old environment; reconcile both databases against the external ledger by hand; forward fix in the new environment instead of returning to the old one; or lock new writes again and run in a restricted mode until the risk clears. Which of these is possible has to be decided before cutover. Raising it at rollback time means the data has already diverged.
The general rollback architecture spanning code, configuration, database, and traffic is covered in a separate document. This article concentrates on the execution contract that applies those principles to WordPress databases, uploads, cron, plugins, and external callbacks.
Field | What it records |
|---|---|
| Rollback authority | The role that approves a return, and its deputy |
| Decision deadline | The last moment after cutover at which a simple return is still a judgment call |
| Old environment mode | Write blocked, cron and queues disabled |
| Source of truth before freeze | The old database and uploads |
| Source of truth after acceptance | The new database and uploads |
| Traffic reversal method | Execution order for DNS, proxy, and load balancer |
| Restore point | Backup identifiers immediately before and after the final sync |
| Rollback trigger | Concrete conditions on login, write, payment, data integrity, and errors |
| New-write detection | The posts, users, orders, uploads, forms, and queue items created in the new environment |
| External reconciliation | How payment, webhook, mail, and CRM state is reconciled |
| Cache action | The order of object, page, and CDN cache invalidation |
| Cron and queue authority | Which environment is reactivated, and when |
| Evidence owner | Who collects logs, database comparisons, and request IDs |
| Business approval | The role that approves the risk of data loss and duplicate processing |
| Closure criteria | The conditions that declare the rollback complete and operations normal |
Additional items by site type
Each site type adds items on top of the base checklist. Six strands are set out below.
The official WordPress migration document likewise explains that multisite is more complex than a single site because server names and paths exist in several places in the database. wp_site, wp_blogs, per-site options, and settings such as SUBDOMAIN_INSTALL have to be reviewed separately.[1]
- General content site
- What to add: Confirm whether comments, registration, and forms really create writes; scheduled publishing and sitemap refresh; recent uploads delta
- Write-heavy site
- What to add: The full set of APIs under write freeze, the order, booking, inventory, and subscription ledgers, payment callback retry and idempotency, queue drain, final entity counts, and tracking of new writes after cutover
- WooCommerce
- What to add: Validate orders, payments, refunds, inventory, coupons, mail, webhooks, and scheduled actions separately, and reconcile state against the external payment gateway ledger
- Membership and LMS
- What to add: Login sessions, roles, enrolment state, progress, subscription renewal, password mail, and background jobs
- Multisite
- What to add: wp_site, wp_blogs, per-site options, domain mapping, network-activated plugins, upload paths, wildcard DNS and TLS, cookie domain, and network admin
- Multisite URL change
- What to add: Confirm the WP-CLI --network scope, review each site's home and siteurl and upload settings and the network tables by hand, and confirm whether the subdomain or subdirectory mode changes
Observation log template
Do not copy credentials, personal data, or full payment details into the observation log. Where necessary, keep only a minimal identifiable request ID or internal evidence ID. Record one observation per row and fill in the timestamp, observer, test ID, observed value, result, and the action and its owner alongside it.
When closing the observation window, record at least the start and end times, the core journeys and scheduled jobs observed, mail delivery confirmation, webhook and payment reconciliation results, whether any write was detected on the old environment, open incidents, whether rollback artefacts were verified, and who approved the shutdown.
- Cutover
- Function or event: Login / Backend serving it: New / Expected: Login succeeds and the session persists / Evidence: Log ID
- Validation
- Function or event: Upload / Backend serving it: New / Expected: Original and thumbnail are generated / Evidence: Screenshot or log
- Validation
- Function or event: Mail / Backend serving it: New / Expected: Actual receipt / Evidence: Provider message ID
- Observation
- Function or event: Cron and queue / Backend serving it: New / Expected: Runs on schedule, exactly once / Evidence: Event or job ID
- Observation
- Function or event: Error review / Backend serving it: New / Expected: No abnormal rise against the baseline / Evidence: Dashboard
What counts as a finished migration
"The site looks fine on the new server" is closer to the first row of validation. To say a migration finished safely, six questions all need an answer. Where does the final data live? Did writes ever occur in the old and new environments at the same time? Did the real functions used by users, admins, and external systems pass? Do mail, cron, queues, cache, and webhooks run only in the new environment? If something fails, how far back and by what route can it be reversed? And when, on whose approval, do the old server and its credentials go away?
Start by copying this article's master migration checklist into a real runbook and filling in owners and evidence. General rollback design and backup restorability are each covered in separate documents, and the division of WordPress operating responsibility after the move is managed in its own operations document.



