Appearance
Look at your WordPress site in Laravel before you move it
The worst moment of a migration is the switch, when you find out what the new site does differently. With kitloom you can find out first, on your own data, without touching the live site and without copying anything.
This works because kitloom runs on WordPress's database as it is. If the new application reads the same tables, it can read them while WordPress is still the site.
1. A user that can only read
Create a MySQL user that may read the WordPress database and change nothing:
sql
CREATE USER 'kitloom_read'@'%' IDENTIFIED BY 'a-long-random-password';
GRANT SELECT ON wordpress.* TO 'kitloom_read'@'%';It is safe to hand to whoever does the work: an agency, a freelancer, an AI agent. If the host has a read replica, point it there.
2. An application that writes nothing
Create a kitloom application and point it at that database, with everything kitloom would normally keep in tables of its own moved off the database:
ini
DB_CONNECTION=mysql
DB_HOST=db.example.com
DB_DATABASE=wordpress
DB_USERNAME=kitloom_read
DB_PREFIX=wp_
SESSION_DRIVER=array
CACHE_STORE=array
QUEUE_CONNECTION=sync
PULSE_ENABLED=false
# Images straight from the live site, so nothing is copied
MEDIA_UPLOADS_URL=https://example.com/wp-content/uploadsRun php artisan serve and open it. Every public address works: posts, pages, archives, search, a missing page, robots.txt, the sitemaps, the REST API under /wp-json/, drawn by the kitloom theme you picked. Change something in wp-admin and it shows in kitloom at once, because both read the same rows.
What waits for later is everything that writes (the admin, forms, the cart), since that needs kitloom's own tables. The details, including the one module to leave out in this mode, are in Migrate from WordPress.
3. Compare, address by address
compare-sites.php is one PHP file with no dependencies. It sends only GET requests to both sites and writes down what differs:
bash
curl -O https://kitloom.dev/migrate/compare-sites.php
php compare-sites.php --old=https://example.com --new=http://localhost:8000 --save-htmlIt takes the addresses from both sites' sitemaps, a few probes and any list you give it (the most visited pages from Analytics or Search Console are a good one), and checks for each:
- the status code and where a redirect leads;
- robots (an error when one side says
noindex), title, description and canonical; - the record's content, as the words a visitor reads, from WordPress's REST API against kitloom's page JSON by the same ID;
- leftovers:
[shortcodes]and block comments that reached the page undrawn, the sign of a plugin with no kitloom module; - on archives, the blog and search, whether the same posts are listed in the same order.
The report, compare-report/report.md, groups everything by check and lists the worst addresses first. Since both sites read the same data at the same moment, every difference is kitloom's, never the content's. Fix, run again, until only what you accept is left. The exit code is 1 while there are errors, so the run can sit in CI.
4. Let an agent look at it
A script reads markup. A gallery that does not open, a menu in the wrong order or a price without its currency needs eyes. An agent with a browser (Claude Code, Cursor, anything with a Playwright MCP server) does that pass well. The guide has a ready prompt that keeps it read-only on the live site, makes it group findings by cause rather than by page, and asks for a report you can act on.
5. Then a copy, then the switch
For the admin, forms and redirects, take a copy of the database with the same read-only user (mysqldump --single-transaction), run php artisan migrate on the copy and sign in with your WordPress email and password. Rehearse the switch there: sync the uploads, save a few posts, send the contact form, place a test order, time it all. The switch itself is the same steps on the real database.
At no point before the last step does the live site change. That is the difference between a migration you rehearse and one you hope for.
The whole procedure, with every command: Migrate from WordPress.