
Leaving Divi is a rebuild, not a migration. Here is what it bought.
There is no Divi-to-blocks converter, so leaving Divi means rebuilding. On a fintech site, five matching pages went from 42 to 93 on mobile Lighthouse and from 347 requests to 30. The decision log, the rules file the AI agent followed, the near-misses, and the browser features that replaced plugins.

You can’t migrate a Divi site to blocks. There is no converter, because Divi stores pages as nested shortcodes that only Divi can render. You rebuild it. On a fintech marketing site I moved off Divi this year, the rebuild took five matching pages from an average mobile Lighthouse score of 42 to 93, from 347 requests to 30, and from 9.1 MB to 1.3 MB, with layout shift going from 0.81 to zero. What made it work wasn’t clever code. It was deciding early what “done” means for every section, writing those rules down where an AI coding agent and I both had to follow them, and checking what the old site did, not what it looked like.
- Plan a Divi exit as a rebuild with a URL map, not a migration. Budget for the parts nobody sees: redirects, feeds, tag containers, user accounts.
- Inventory the custom code, not the pages. The two things that almost broke here were an RSS feed another system depended on and a gate that opened on its own.
- Keep a decision log and a short rules file for the agent. Every conflict between the old site and the new design gets one line: what, which way, why.
- Use what the browser already does:
<details>,<dialog>, CSS scroll-snap. Each one replaced a plugin and its script.
What the rebuild bought
Both sites ran on the same machine with the same content, Lighthouse 13 on its default mobile and desktop presets, twenty runs across five matching pages: home, the article hub, an article, a product page and About.
| Five-page average | Mobile, Divi | Mobile, blocks | Desktop, Divi | Desktop, blocks |
|---|---|---|---|---|
| Performance score | 42 | 93 | 76 | 99 |
| LCP | 6.3 s | 2.9 s | 1.4 s | 0.9 s |
| Layout shift (CLS) | 0.81 | 0 | 0.34 | 0 |
| Page weight | 9.1 MB | 1.3 MB | 9.8 MB | 1.6 MB |
| Requests | 347 | 30 | 347 | 34 |
| JavaScript transferred | 5.6 MB | 502 KB | 5.7 MB | 502 KB |
| Accessibility score | 84 | 98 | 84 | 98 |
The honest headline is “about a tenth of the requests and the JavaScript”, not “ten times faster”. LCP roughly halved on average; the article page went from 10.3 s to 2.7 s. One page didn’t improve: the product page stayed at about 4.6 s. The builder wasn’t what made it slow, and that turned out to be the pattern for the slowest pages after launch too. More on that below.
132 KB → 10 KBHome page content: Divi shortcodes before, seven blocks after
31 → 13Active plugins
0.99 → 0Layout shift on the home page: the page visibly jumped while Divi assembled it
Why it has to be a rebuild
The home page alone was 132 KB of shortcodes, 116 nested modules deep. Across the site: 522 text modules, 227 call-to-action modules, 213 icon-and-text blurbs, 189 images, 129 buttons, 35 raw code modules. Strip Divi out and that becomes text in square brackets. Every section has to be rebuilt as a block that renders the same content, so you might as well rebuild it properly: one stylesheet, one small script, and per-block CSS and JavaScript that load only where the block is used.
A rebuild also means the old site stops being the specification. Here the new design existed in Figma, but the file was about two years older than the live content. The rule became: layout from Figma, words from the old site. Every disagreement between them went into one log.
The decision log, and the rules file the agent read
I built this with an AI coding agent doing much of the typing. That only works if the agent can’t improvise, so the project had two documents.
The decision log is a table: date, the conflict, what was chosen, why. It ended up with about 355 rows, most of them small. The old site faded between two background images with a transition that can’t animate, so it simply snapped: rebuilt as a real image fade. An old heading had a Cyrillic letter hiding inside a Latin word: fixed. Two cards repeated the same text: flagged, not copied. Any question about why a section looks the way it does is one search away, for me, the client and the agent.
The rules file is what the agent loads before it touches a section. It is short, and most of its lines came from a mistake:
## Sources of truth
- Layout, spacing, type: Figma. Words, links, order: the live site.
- A conflict goes into DECISIONS.md before any code. Never pick silently.
## Rules
- Never invent a value. No spacing, color or size that isn't a token; ask.
- Spacing only from the --s-N scale. No raw px.
- Content only from block fields. No hard-coded copy in templates.
- Reuse before adding: extend an existing block with a field before creating a new one.
## Done means measured
- Compare computed styles with Figma, number by number, at desktop and phone widths.
- Check the block in the editor too: same fonts, spacing and colors as the page.The last section is the one that made the work predictable. “Looks right” drifts; computed font size, padding and gap against the design don’t. The same check found the editor problem: comparing every core block’s computed styles in the editor against the front end turned up 16 differences, 11 of them real. Editors now see in WordPress what visitors will see.
Inventory what the site does, not what it shows
A crawl of the live site tells you what visitors see. It doesn’t tell you what the site does for other systems, and that is where the near-misses were.
- A feed with a hidden dependency. Articles were also published to the client’s own platform through a private RSS feed. It relied on three things: a per-post destination field, token authentication, and each post’s original GUID. A fresh import would have given every post a new GUID, and the platform would have imported all 161 articles a second time.
- A gate that opened by itself. An audit that searched for buttons and links that opened a disclosure gate declared everything migrated. The gate also opened automatically on certain categories, from code no button pointed at. Reading the custom code line by line found it.
- Content that was never rendered. Divi lets an editor switch a module off. The live HTML doesn’t show it, so a crawl misses it, but it is still in the shortcodes, and an inventory built from a crawl missed whole sections because of it.
- Two tag containers. One tag manager container was set in the theme options, another hard-coded in the child theme. Together they counted every form submission four times. They were merged into one, and 82 click triggers that targeted Divi’s markup were deleted.
# Divi modules an editor switched off: invisible on the page, still in the content
wp db query "SELECT ID, post_title FROM wp_posts
WHERE post_status = 'publish' AND post_content LIKE '%disabled=\"on\"%'"Plugins that store secrets often encrypt them with the site’s salts. The CRM plugin’s connection token here was unreadable on the new install until its key and salt constants moved with it. Users are the other quiet trap: recreated author accounts got a digit added to their slugs, which would have turned every indexed author archive into a 404.
Redirects were the biggest single cleanup
The old site had 730 redirect rules, collected over years by two plugins. Moving them as they were would have kept every mistake:
- 85 chains went through a retired subdomain, three hops and 2.2 seconds each. They now go straight to the final page.
- 237 rules sent old URLs to the homepage. Each now points at the page that actually replaced it.
- 126 rules were junk, and 181 had never fired once.
- One rule sent a URL with almost 24,000 hits to the careers page by mistake.
- A plugin that “recovered” unknown URLs answered 200 with a random article, a soft 404 Google would have kept indexing. It was replaced by 224 explicit 301s.
One more lesson: a cleanup can break things too. Removing “duplicate” rules by their source URL deleted 21 rules that differed only by tracking parameters, and those had to be restored. Diff the redirect list before and after, and test the top 50 old URLs by traffic, not a sample.
Let the browser do the work
Most of the JavaScript Divi shipped was there to do things browsers now do natively. The new theme has no slider library, no modal library and no accordion script.
- AccordionsNative
<details>and<summary>, animated in CSS. Keyboard and screen reader support come free. - ModalsNative
<dialog>withshowModal(): focus trap, Escape to close and the backdrop are built in. - SlidersCSS scroll-snap on a flex row, plus a few lines of JavaScript for the arrows.
- Glows and soft shapesRadial gradients in CSS instead of decorative images.
- jQueryDropped, with a check that turns the removal off if any plugin still declares it as a dependency. 34 KB less on every page.
/* A native <details> that opens smoothly, no script */
:root { interpolate-size: allow-keywords; }
details::details-content {
block-size: 0;
overflow: clip;
transition: block-size 0.3s ease, content-visibility 0.3s allow-discrete;
}
details[open]::details-content { block-size: auto; }Browsers without these two features simply open the accordion without animation. Nothing breaks.
The heavy files weren’t Divi’s
The product page that didn’t improve pointed at the last lesson. After launch, the slowest pages had the same problem: animated GIFs and a hero video, carried over from the old site unchanged.
- A 1.0 MB hero GIF became a 122 KB MP4. That page’s mobile LCP went from 11.8 s to 3.1 s.
- A 7 MB GIF on a resource page became a 559 KB video, taking the page from 7.8 MB to 3.2 MB.
- The home hero video was 77% of the home page. A WebM version is a quarter of the size, and the MP4 fallback dropped from 3.0 MB to 0.9 MB by removing an audio track from a video that always plays muted.
- Decorative videos further down a page now start loading only as they approach the screen: 54 KB up front instead of about 2.2 MB.
# GIF to a looping MP4 that starts playing before it has fully downloaded
ffmpeg -i animation.gif -movflags +faststart -pix_fmt yuv420p \
-vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" animation.mp4
# A muted background video doesn't need its audio track
ffmpeg -i hero.mp4 -an -c:v copy -movflags +faststart hero-muted.mp4A rebuild removes the builder’s weight. It doesn’t touch the media an editor uploaded years ago. Check the five heaviest files on every template before calling the speed work done.
The same process, if you are planning one
- Map URLs and integrations firstEvery URL with its traffic, every redirect, every feed, form, tag container and API that reads the site.
- Count the modulesThe most used ones become blocks first. One-offs are redesigned or dropped.
- Write the rules downA decision log for choices, a short rules file for whoever writes code, person or agent.
- Measure sections, not pagesComputed styles against the design, editor against front end.
- Test what the site doesFeeds, gates, form submissions, tag counts, logins, not just pages that return 200.
- Fix the media lastGIFs, videos and oversized images survive any rebuild unless someone looks for them.
From the first decision in the log to launch took about six weeks. The client’s editors work in native blocks with fields, there are 13 plugins to keep updated instead of 31, and the site passed its post-launch SEO check with every sitemap URL answering 200 and pointing its canonical at itself.
Related servicePlanning to leave Divi, Elementor or WPBakery?Page builder migration, fixed price from $2,400: a URL and integration map, native blocks your editors can use, redirects cleaned up, and every template measured before and after.See the serviceIf you want to see where your own site stands first, the free scan on this site shows the page weight, requests, layout shift and scripts it finds, and which plugins it can detect from outside.
Questions from this article.
Not one I would trust on a live site. Divi saves pages as nested shortcodes that only Divi can render, and tools that convert them mostly wrap the shortcodes in a block. Text and images can be extracted by script, but layout and components have to be rebuilt.
For a marketing site with around 40 pages, a blog and a few custom post types, about six weeks from the first decision to launch in this case, then a few weeks of tuning on the live site. The number of distinct layouts matters more than the number of pages.
Only if you want it to. Here the site moved to a newer design from Figma while every word, link and URL came from the old site. A rebuild can also keep the existing design exactly.
They are the part to plan first. Every redirect, feed, form, tag container and CRM connection goes on a list before any block is built, and each is tested after launch with real submissions, not just page loads.
More on speed and leads.


Why your WordPress site is slow on mobile, and why another caching plugin won’t help
The desktop score is green, the phone still shows a blank screen for four seconds. Here is where the time actually goes on a slow WordPress site, in the order I fix it.